The ESP32-CAM module is a cheap, low power consumption module, but it provides many resource for vision, serial communication and GPIOs.
In this project, I try to utilize ESP32-CAM module resource for making a simple surveillance rc robot which can pick small object.
Demonstration and brief explanation how to make it can be found in the following video:
HARDWARE WIRINGRegarding the streaming part, websocket is used and showed a pretty good way for streaming images captured from esp32-cam module to web browser, it is cool because you can view the streaming video and control your robot any where supports web browser, it is better comparing to my previous project when I use raw TCP socket to stream to PC. I have tested with some browsers and see that my code works well on google chrome, so if you follow my project, you should use google chrome for the best performance.
1. Camera driver part:
I use ESP32 Wrover module for this project so the HW definition would be suitable for this module, if you use another module, please consider the HW definition.
For this part, basically It is based on the sample code of the camera driver part of ESP32/Camera/CameraWebServer. In my project, I divided into 3 files: camera_pin.h, camera_wrap.h and camera_wrap.cpp.
camera_pin.h: contains the definition of ESP32 pin used for communication with the attached camera.( It should be changed in case you use another module rather than ESP32 Wrover module)
camera_wrap.cpp: contains a basic configuration for camera initialization and a function for taking image.
camera_wrap.h: contains the prototype functions which used in another module.
Source code can be found in the following github link:
https://github.com/ANM-P4F/ESP32-CAM-ROBOT/tree/master/ESP32CamRobot
2. ESP32-CAM sketch:
This part contains the main working flow of ESP32-CAM. The module play a role of a http server and a web socket server. The http server receives the request from browser and return the main page which is used as a GUI to control the robot, the web socket server is used to send the images repeatedly to the GUI display on the web browser.
#include <WebSocketsServer.h>
#include <WiFi.h>
#include <SPIFFS.h>
#include <FS.h>
#include <ESPAsyncWebServer.h>
#include "camera_wrap.h"
#define DEBUG
// #define SAVE_IMG
const char* ssid = "your ssid"; // <<< change this as yours
const char* password = "your ssid password"; // <<< change this as yours
//holds the current upload
int cameraInitState = -1;
uint8_t* jpgBuff = new uint8_t[68123];
size_t jpgLength = 0;
uint8_t camNo=0;
bool clientConnected[3] = {false,false,false};
WebSocketsServer webSocket = WebSocketsServer(86);
AsyncWebServer httpServer(80);
String html_home;
const int PIN_SERVO = 12;
const int PIN_LED = 2;
unsigned long previousMillisServo = 0;
const unsigned long intervalServo = 100;
bool reqUp = false;
bool reqDown = false;
int posServo = 90;
void setup(void) {
Serial.begin(115200);
Serial.print("\n");
Serial.setDebugOutput(true);
if (!SPIFFS.begin(true)) {
Serial.println("An Error has occurred while mounting SPIFFS");
ESP.restart();
}
else {
delay(500);
Serial.println("SPIFFS mounted successfully");
File root = SPIFFS.open("/");
File file = root.openNextFile();
while(file){
Serial.print("FILE: ");
Serial.println(file.name());
file = root.openNextFile();
}
}
cameraInitState = initCamera();
Serial.printf("camera init state %d\n", cameraInitState);
if(cameraInitState != 0){
return;
}
//WIFI INIT
Serial.printf("Connecting to %s\n", ssid);
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
}
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected! IP address: ");
String ipAddress = WiFi.localIP().toString();;
Serial.println(ipAddress);
// handle index
// Route for root web page
httpServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html");
});
// handle icons load
httpServer.on("/icons/led_on.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/led_on.png", "image/png");
});
httpServer.on("/icons/led_off.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/led_off.png", "image/png");
});
httpServer.on("/icons/move_off.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/move_off.png", "image/png");
});
httpServer.on("/icons/pick_on.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/pick_on.png", "image/png");
});
httpServer.on("/icons/pick_off.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/pick_off.png", "image/png");
});
httpServer.on("/icons/up_on.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/up_on.png", "image/png");
});
httpServer.on("/icons/up_off.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/up_off.png", "image/png");
});
httpServer.on("/icons/down_on.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/down_on.png", "image/png");
});
httpServer.on("/icons/down_off.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/icons/down_off.png", "image/png");
});
//handle command
httpServer.on("/MOVE", HTTP_GET, [](AsyncWebServerRequest *request){
commadProcessing(request);
request->send(200, "text/plain");
});
httpServer.on("/LED", HTTP_GET, [](AsyncWebServerRequest *request){
commadProcessing(request);
request->send(200, "text/plain");
});
httpServer.on("/PICK", HTTP_GET, [](AsyncWebServerRequest *request){
commadProcessing(request);
request->send(200, "text/plain");
});
httpServer.on("/UP", HTTP_GET, [](AsyncWebServerRequest *request){
commadProcessing(request);
request->send(200, "text/plain");
});
httpServer.on("/DOWN", HTTP_GET, [](AsyncWebServerRequest *request){
commadProcessing(request);
request->send(200, "text/plain");
});
httpServer.begin();
webSocket.begin();
webSocket.onEvent(webSocketEvent);
ledcSetup(4, 50, 16);//channel, freq, resolution
ledcAttachPin(PIN_SERVO, 4);// pin, channel
pinMode(PIN_LED, OUTPUT);
}
void servoWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 180) {
// calculate duty, 8191 from 2 ^ 13 - 1
uint32_t duty = (8191 / valueMax) * min(value, valueMax);
ledcWrite(channel, duty);
}
void controlServo(){
if(reqUp){
if(posServo<180){
posServo -= 1;
}
}
if(reqDown){
if(posServo>0){
posServo += 1;
}
}
servoWrite(4,posServo);
}
void commadProcessing(AsyncWebServerRequest *request){
String value = request->getParam(0)->value();
String url = request->url();
if(url.indexOf("UP")!=-1){
if(value.indexOf("ON")!=-1){
reqUp = true;
}else if(value.indexOf("OFF")!=-1){
reqUp = false;
}
}else if(url.indexOf("DOWN")!=-1){
if(value.indexOf("ON")!=-1){
reqDown = true;
}else if(value.indexOf("OFF")!=-1){
reqDown = false;
}
}else if(url.indexOf("LED")!=-1){
if(value.indexOf("ON")!=-1){
digitalWrite(PIN_LED, HIGH);
}else if(value.indexOf("OFF")!=-1){
digitalWrite(PIN_LED, LOW);
}
}else{
String command = url+":"+value+"\n";
Serial.print(command);
}
}
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
if(num<3){
camNo = num;
clientConnected[num] = false;
String command = "/MOVE:0,0";
Serial.print(command);
}
break;
case WStype_CONNECTED:
if(num<3){
clientConnected[num] = true;
}
break;
case WStype_TEXT:
case WStype_BIN:
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
break;
}
}
void loop(void) {
webSocket.loop();
if(clientConnected[camNo] == true){
grabImage(jpgLength, jpgBuff);
webSocket.sendBIN(camNo, jpgBuff, jpgLength);
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillisServo >= intervalServo) {
previousMillisServo = currentMillis;
controlServo();
}
}
The entire source can be found at: https://github.com/ANM-P4F/ESP32-CAM-ROBOT/tree/master/ESP32CamRobot
3. AruinoUno sketch:
This part contains the source code of the Arduino module ESP32-CAM via serial then control DC, RC motors.
The source code can be found at: https://github.com/ANM-P4F/ESP32-CAM-ROBOT/tree/master/ESP32CamRobotMotors
4. System flow
Comments