ESP32平衡小车

回复
ONZHI
网站管理员
帖子: 11
注册时间: 2022年 4月 9日 08:16

ESP32平衡小车

帖子 ONZHI »

若要将ESP32替换为ESP32-CAM,并实现在浏览器网页上监看画面并控制前进、后退和左右移动功能,需要进行以下步骤:

材料:

ESP32-CAM模块

两个N20减速电机

MPU6050陀螺仪和加速度计模块

电池供电模块或锂电池

电机驱动模块(例如L298N驱动模块)

连接线和焊接工具

用于图像传输的WebSocket库(例如ArduinoWebsockets)

代码: 全选

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketServer.h>
#include <MPU6050.h>
#include <esp_camera.h>

// Wi-Fi网络设置
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";

// WebSocket服务器设置
WebSocketServer webSocketServer;

// 电机引脚设置
const int motorPin1 = 2;   // 第一个电机引脚
const int motorPin2 = 3;   // 第二个电机引脚

// MPU6050对象和角度变量
MPU6050 mpu;
float angle;
float angleOffset = 0;

WebServer server(80);

void handleRoot() {
  // 返回Web页面,包括实时图像和控制按钮
  server.send(200, "text/html", "<html><body><h1>ESP32-CAM Control</h1>< img src=\"/stream\" width=\"640\" height=\"480\"><br><button onclick=\"sendCommand('forward')\">Forward</button><button onclick=\"sendCommand('backward')\">Backward</button><button onclick=\"sendCommand('left')\">Left</button><button onclick=\"sendCommand('right')\">Right</button><script>var socket=new WebSocket('ws://'+location.hostname+':81/');socket.onmessage=function(event){console.log(event.data);};function sendCommand(command){socket.send(command);}</script></body></html>");
}

void handleNotFound() {
  // 处理404错误页面
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
  // 处理WebSocket事件
  switch (type) {
    case WStype_TEXT:
      String command = String((char*)payload);
      if (command == "forward") {
        // 前进指令
        // 控制电机前进的代码
      } else if (command == "backward") {
        // 后退指令
        // 控制电机后退的代码
      } else if (command == "left") {
        // 左移指令
        // 控制电机左移的代码
      } else if (command == "right") {
        // 右移指令
        // 控制电机右移的代码
      }
      break;
  }
}

void setup() {
  Serial.begin(115200);

  // 初始化摄像头
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = 5;
  config.pin_d1 = 18;
  config.pin_d2 = 19;
  config.pin_d3 = 21;
  config.pin_d4 = 36;
  config.pin_d5 = 39;
  config.pin_d6 = 34;
  config.pin_d7 = 35;
  config.pin_xclk = 0;
  config.pin_pclk = 22;
  config.pin_vsync = 25;
  config.pin_href = 23;
  config.pin_sscb_sda = 26;
  config.pin_sscb_scl = 27;
  config.pin_pwdn = 32;
  config.pin_reset = -1;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // 启动摄像头
  esp_err_t cam_err = esp_camera_init(&config);
  if (cam_err != ESP_OK) {
    Serial.printf("Camera initialization failed with error 0x%x", cam_err);
    return;
  }

  // 连接Wi-Fi网络
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // 初始化WebSocket服务器
  webSocketServer.begin();
  webSocketServer.onEvent(webSocketEvent);

  // 设置Web服务器处理函数
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  // 启动Web服务器
  server.begin();
  Serial.println("Web server started");

  // 初始化MPU6050模块
  mpu.initialize();

  // 计算初始倾斜角度的偏移量
  for (int i = 0; i < 200; i++) {
    angleOffset += getAngle();
    delay(5);
  }
  angleOffset /= 200.0;

  // 设置电机引脚
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
}

void loop() {
  // 处理WebSocket客户端连接
  webSocketServer.loop();

  // 处理Web服务器请求
  server.handleClient();

  // 获取倾斜角度
  angle = getAngle() - angleOffset;

  // 根据倾斜角度控制电机运动
  // 根据angle的值来调整电机运动的代码
}

float getAngle() {
  int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;
  mpu.getMotion6(&AcX, &AcY, &AcZ, &GyX, &GyY, &GyZ);
  float accelAngleX = atan(-1.0 * AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))) * 180.0 / PI;
  float gyroAngleX = GyX / 131.0;  // 陀螺仪的刻度因数为131
  float angleX = 0.98 * (gyroAngleX + 0.01 * accelAngleX) + 0.02 * accelAngleX;
  return angleX;
}
回复