In this project, we’ll attach the ESP32-CAM to a pan and tilt stand with two SG90 servo motors. With a pan and tilt camera stand, you can move the camera up, down, to the left, and the right— this is great for surveillance. The ESP32-CAM hosts a web server that shows video streaming and buttons to control the servo motors to move the camera.
Boards compatibility: for this project, you need an ESP32 camera development board with
access to two GPIOs to control two servo motors. You can use: ESP32-CAM AI-Thinker, T-Journal, TTGO T-Camera Plus, or ESP32-CAM Freenove boards (Wrover or S3).
Parts Required
For this project, we’ll use the following parts:
- ESP32-CAM AI-Thinker with external antenna
- Pan and tilt stand with SG90 servo motors
- Prototyping circuit board (optional)
- Jumper wires
Pan and Tilt Stand and Motors
For this project, we’ll use a pan and tilt stand that already comes with two SG90 servo motors. The stand is shown in the following figure.
We got our stand from Banggood, but you can get yours from any other store.
Alternatively, you can get two SG90 servo motors and 3D print your own stand.
Servo motors have three wires with different colors:
Wire | Color |
Power | Red |
GND | Black or brown |
Signal | Yellow, orange or white |
How to Control a Servo?
You can position the servo’s shaft at various angles from 0 to 180º. Servos are controlled using a pulse width modulation (PWM) signal. This means that the PWM signal sent to the motor determines the shaft’s position.
To control the servo motor, you can use the PWM capabilities of the ESP32 by sending a signal with the appropriate pulse width. Or you can use a library to make the code simpler. We’ll be using the ESP32Servo library.
Installing the ESP32Servo Library
To control servo motors, we’ll use the ESP32Servo library. Make sure you install that library before proceeding. In your Arduino IDE, go to Sketch > Include Library > Manage Libraries. Search for ESP32Servo and install the library.
Code
Copy the following code to your Arduino IDE.
/*********
Rui Santos
Complete instructions at https://RandomNerdTutorials.com/esp32-cam-projects-ebook/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" // disable brownout problems
#include "soc/rtc_cntl_reg.h" // disable brownout problems
#include "esp_http_server.h"
#include <ESP32Servo.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
#define PART_BOUNDARY "123456789000000000000987654321"
#define CAMERA_MODEL_AI_THINKER
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WITHOUT_PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM_B
//#define CAMERA_MODEL_WROVER_KIT
#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_M5STACK_WITHOUT_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM_B)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 22
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#else
#error "Camera model not selected"
#endif
#define SERVO_1 14
#define SERVO_2 15
#define SERVO_STEP 5
Servo servo1;
Servo servo2;
int servo1Pos = 0;
int servo2Pos = 0;
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
httpd_handle_t camera_httpd = NULL;
httpd_handle_t stream_httpd = NULL;
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<html>
<head>
<title>ESP32-CAM Robot</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial; text-align: center; margin:0px auto; padding-top: 30px;}
table { margin-left: auto; margin-right: auto; }
td { padding: 8 px; }
.button {
background-color: #2f4468;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 18px;
margin: 6px 3px;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
img { width: auto ;
max-width: 100% ;
height: auto ;
}
</style>
</head>
<body>
<h1>ESP32-CAM Pan and Tilt</h1>
<img src="" id="photo" >
<table>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('up');" ontouchstart="toggleCheckbox('up');">Up</button></td></tr>
<tr><td align="center"><button class="button" onmousedown="toggleCheckbox('left');" ontouchstart="toggleCheckbox('left');">Left</button></td><td align="center"></td><td align="center"><button class="button" onmousedown="toggleCheckbox('right');" ontouchstart="toggleCheckbox('right');">Right</button></td></tr>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('down');" ontouchstart="toggleCheckbox('down');">Down</button></td></tr>
</table>
<script>
function toggleCheckbox(x) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/action?go=" + x, true);
xhr.send();
}
window.onload = document.getElementById("photo").src = window.location.href.slice(0, -1) + ":81/stream";
</script>
</body>
</html>
)rawliteral";
static esp_err_t index_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, (const char *)INDEX_HTML, strlen(INDEX_HTML));
}
static esp_err_t stream_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
while(true){
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
res = ESP_FAIL;
} else {
if(fb->width > 400){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
//Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
}
return res;
}
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "go", variable, sizeof(variable)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
sensor_t * s = esp_camera_sensor_get();
//flip the camera vertically
//s->set_vflip(s, 1); // 0 = disable , 1 = enable
// mirror effect
//s->set_hmirror(s, 1); // 0 = disable , 1 = enable
int res = 0;
if(!strcmp(variable, "up")) {
if(servo1Pos <= 170) {
servo1Pos += 10;
servo1.write(servo1Pos);
}
Serial.println(servo1Pos);
Serial.println("Up");
}
else if(!strcmp(variable, "left")) {
if(servo2Pos <= 170) {
servo2Pos += 10;
servo2.write(servo2Pos);
}
Serial.println(servo2Pos);
Serial.println("Left");
}
else if(!strcmp(variable, "right")) {
if(servo2Pos >= 10) {
servo2Pos -= 10;
servo2.write(servo2Pos);
}
Serial.println(servo2Pos);
Serial.println("Right");
}
else if(!strcmp(variable, "down")) {
if(servo1Pos >= 10) {
servo1Pos -= 10;
servo1.write(servo1Pos);
}
Serial.println(servo1Pos);
Serial.println("Down");
}
else {
res = -1;
}
if(res){
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t cmd_uri = {
.uri = "/action",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &cmd_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
servo1.setPeriodHertz(50); // standard 50 hz servo
servo2.setPeriodHertz(50); // standard 50 hz servo
servo1.attach(SERVO_1, 1000, 2000);
servo2.attach(SERVO_2, 1000, 2000);
servo1.write(servo1Pos);
servo2.write(servo2Pos);
Serial.begin(115200);
Serial.setDebugOutput(false);
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if(psramFound()){
config.frame_size = FRAMESIZE_VGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Wi-Fi connection
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("Camera Stream Ready! Go to: http://");
Serial.println(WiFi.localIP());
// Start streaming web server
startCameraServer();
}
void loop() {
}
Network Credentials
Insert your network credentials and the code should work straight away.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
How the Code Works
Let’s take a look at the relevant parts to control the servo motors.
Define the pins the servo motors are connected to. In this case, they are connected to the ESP32-CAM GPIOs 14 and 15.
#define SERVO_1 14
#define SERVO_2 15
Create Servo objects to control each motor:
Servo servo1;
Servo servo2;
Define the servos’ initial position.
int servo1Pos = 0;
int servo2Pos = 0;
Web Page
The INDEX_HTML variable contains the HTML text to build the web page. The following lines display the buttons.
<table>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('up');" ontouchstart="toggleCheckbox('up');">Up</button></td></tr>
<tr><td align="center"><button class="button" onmousedown="toggleCheckbox('left');" ontouchstart="toggleCheckbox('left');">Left</button></td><td align="center"></td><td align="center"><button class="button" onmousedown="toggleCheckbox('right');" ontouchstart="toggleCheckbox('right');">Right</button></td></tr>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('down');" ontouchstart="toggleCheckbox('down');">Down</button></td></tr>
</table>
When you click the buttons, the toggleCheckbox() JavaScript function is called. It makes a request on a different URL depending on the button clicked.
function toggleCheckbox(x) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/action?go=" + x, true);
xhr.send();
}
Here are the requests made depending on the button that is being pressed:
Up:
/action?go=up
Down:
/action?go=down
Left:
/action?go=left
Right:
/action?go=right
Handle Requests
Then, we need to handle what happens when we get those requests. That’s what’s done in the following lines.
if(!strcmp(variable, "up")) {
if(servo1Pos <= 170) {
servo1Pos += 10;
servo1.write(servo1Pos);
}
Serial.println(servo1Pos);
Serial.println("Up");
}
else if(!strcmp(variable, "left")) {
if(servo2Pos <= 170) {
servo2Pos += 10;
servo2.write(servo2Pos);
}
Serial.println(servo2Pos);
Serial.println("Left");
}
else if(!strcmp(variable, "right")) {
if(servo2Pos >= 10) {
servo2Pos -= 10;
servo2.write(servo2Pos);
}
Serial.println(servo2Pos);
Serial.println("Right");
}
else if(!strcmp(variable, "down")) {
if(servo1Pos >= 10) {
servo1Pos -= 10;
servo1.write(servo1Pos);
}
Serial.println(servo1Pos);
Serial.println("Down");
}
To move a motor, call the write() function on the servo1 or servo2 objects and pass the angle (0 to 180) as an argument. For example:
servo1.write(servo1Pos);
setup()
In the setup(), set the servo motor properties: define the signal frequency.
servo1.setPeriodHertz(50); // standard 50 hz servo
servo2.setPeriodHertz(50); // standard 50 hz servo
Use the attach() method to set the servo GPIO and minimum and maximum pulse width in microseconds.
servo1.attach(SERVO_1, 1000, 2000);
servo2.attach(SERVO_2, 1000, 2000);
Set the motors to its initial position when the ESP32 first boots.
servo1.write(servo1Pos);
servo2.write(servo2Pos);
That’s pretty much how the code works when it comes to control the servo motors.
Testing the Code
After inserting your network credentials, you can upload the code to your board. You can use an FTDI programmer or an ESP32-CAM MB programmer. Read one of the following articles:
- How to Program / Upload Code to ESP32-CAM AI-Thinker (Arduino IDE) (FTDI)
- Upload Code to ESP32-CAM AI-Thinker using ESP32-CAM-MB USB Programmer (easiest way)
After uploading, open the Serial Monitor to get the board IP address.
Note: if you’re using an FTDI programmer, don’t forget to disconnect GPIO 0 from GND before opening the Serial Monitor.
Open a browser and type the board IP address to get access to the web server. Click on the buttons and check on the Serial Monitor if everything seems to be working as expected.
If everything is working as expected, you can wire the servo motors to the ESP32-CAM and continue with the project.
Circuit
After assembling the pan and tilt stand, connect the servo motors to the ESP32-CAM as shown in the following schematic diagram. We’re connecting the servo motor data pins to GPIO 15 and GPIO 14.
You can use a mini breadboard to assemble the circuit or build a mini stripboard with header pins to connect power, the ESP32-CAM, and the motors, as shown below.
The following figure shows how the pan and tilt stands looks like after assembling.
Demonstration
Apply power to your board. Open a browser and type the ESP32-CAM IP address. A web page with real-time video streaming should load. Click the buttons to move the camera up, down, left, or right.
You can move the camera remotely using the buttons on the web page. This allows you to
monitor a different area according to the camera position. This is a great solution for surveillance applications.
Wrapping Up
In this tutorial, you’ve learned how to build a pan-and-tilt web server with video streaming to control the ESP32-CAM.
Controlling servo motors with the ESP32-CAM is the same as controlling them using a “regular” ESP32. You can read the following tutorial to learn more about servo motors with the ESP32:
If you want to control your robot outside the range of your local network, you might consider setting the ESP32-CAM as an access point. This way, the ESP32-CAM doesn’t need to connect to your router. It creates its own wi-fi network, and nearby wi-fi devices like your smartphone can connect to it.
For more projects and tutorials with the ESP32-CAM:
Very usefull project. I waited for that. I am going to realize it. Thank’s so much for preparing this.
Can the video be accessed anywhere with your phone?
Hi.
It is just accessible from your local network.
Regards,
Sara
No – if you can to port forwarding, then anything which is accessible on your local network, can be made accessible worldwide via the internet.
where’s the instruction video for that? 🙂
Port forwarding implementation varies according to your router. Should be documented it the router manual or search online for the router set up instructions.
I agree with Sara per these instructions! Thank you Rui and Sara for all your time and great work!!!
With some “EXTRA” work, it can be accessed from anywhere on the Web securely. Currently, I’m able to view/access my HomeAssistant, all my MotionEye Cameras and all the host on my internal home network. My solution uses a VPN, WireGuard specifically. With the VPN connected, I can access from my phone via it’s browser or a ssh client, my remote LAN IP’s like 192.168.1.85, my HomeAssistant server. And still browse from my phone to access other “Public Web Sites”
It’s not the simplest task, but, very useful once completed. I use the following components:
– VPN: Wireguard
It creates an encrypted tunnel from my phone, computer or chromebook to allow/forward “Interesting traffic”, ie, IP addresses that are on my Home LAN to be accessed remotely.
– Duckdns
To determine my router’s current WAN External Public IP’s DHCP address assigned my my Internet Service Provider, ISP.
– Port forwarding
On my router for inbound traffic from the internet into my local network/LAN to establish the Wireguard encrypted tunnel which the “traffic” from my phone, etc passes through securely.
It is possible followingg these steps:
1) subscribe a DDNS service (needed if you have an ISP that assignes a dynmaic IP to your router: best thing if you check before which DDNS services your router will accept);
2) on your router configure the DDNS service ;
3) on your ruoter assign a static IP address to the MAC address of your microcontroller/cam ;
4) on your router assign a TCP/HTTTP port forwording rule to the MAC/IP address of your microcontroller (WAN and LAN ports = 80);
After that you can access your cam locally via its assigned IP address (e.g. on your browser go to the address 192.168.1.XX) or via internet using the address that was given to you by the DDNS provider (e.g. arduinocam.mypc.com).
Many thanks to Rui and Sara for their fantastic site!!
Bonjour,
Merci pour votre mail.
J’ai bien un lien dynamique et ca fonctionne bien.
Le port 80 est le port par défaut et donc avec mon lien DNS je ne peut accéder qu’à un seul montage.
Mon problème c’est que j’ai besoin d’accéder à plusieurs caméras Pan et Tilt et c’est pour cela que je voudrai pouvoir affecter un no de port différent.
ex: arduinocam.mypc.com:49160
Cordialement
Bernard
Bernard,
try these steps:
1) on your router side configure different ports in the portwarding rules: e.g. CAM1: WAN Port = 80 & LAN Port =80
CAM2: WAN Port = 82 & LAN Port =82
2) in the Arduino code change this line: config.server_port = 80; to config.server_port = 82; for CAM2
Now you should be able to access CAM1 on arduinocam.mypc.com:80 (or arduinocam.mypc.com, as port 80 is the dafault one) and CAM2 on arduinocam.mypc.com:82
Let me know …
Bonjour,
désolé pour ce retard…
Je reprend ce tuto.
Pouvez vous me dire à quoi correspond CAM1 et CAM2 dans votre
explication?
cordialement
En fait j’ai testé avec port 82 pour CAM2 en local et je me connecte bien,
j’ai bien les boutons mais pas de flux vidéo?
Merci
Open port 80 on your WAN router is not a secure method to connect on. All traffic passes in “clear text”, ie, any passwords you enter. You might think it only video, well a man-in-the-middle attact could hijack your video and re-post it to the web allowing anyone to see where you live, what you look like, or oh, any valuables you have.
Please use a VPN for your families safety.
I agree. I’m going too…:-) wonderfull project. Tks for all
Vielen Dank für dieses Projekt. Ich bin vermutlich einer von vielen die danach gefragt haben und freue mich sehr das ihr es realisiert habt. Durch dieses Projekt werden die ESP32-CAMs besonders nützlich und ermöglichen mir ganz neue Einblicke in die Tier Welt.
Nochmals Vielen Dank,
Horst Ketter
Translated:
“Thank you for this project. I am probably one of many who asked about it and I am very happy that you have realized it. This project makes the ESP32-CAMs particularly useful and gives me completely new insights into the animal world.
Thanks again,
Horst Ketter”
Thank you.
Hallo Liebe Sara und Team,
Sie schreiben: “Mithilfe der Schaltflächen auf der Webseite können Sie die Kamera aus der Ferne bewegen.”
Mich würde es sehr freuen und helfen wenn der Webseite, zur Steuerung der Cam, auch noch eine “Taste” Ein/Aus für die LED hinzugefügt würde.
Dear Horst,
As it seems a very interesting subject to expand the Pan & Tilt camera project, I’ll suggest you to read Sara’s project : https://randomnerdtutorials.com/esp32-web-server-arduino-ide/ Here will be explained how to switch on and off a Led by means of an ESP- webserver. You can use this code and integrate it in the Pan & Tilt project,
Alex
It Works!!!
Just finished this project and all works fine.
I had trouble with another ESP32 Cam with pan and tilt hanging on me.
I see you solved that problem by creating four servo objects, nice work!
Thanks for sharing this with us!
That’s great!
Regards,
Sara
hi Sara ,
i have tried your fantastic project,vedio streaming is well but navigation keys not working at all, please help me.
thanks a lot
Hi.
Read the comment by David April 6, 2023 at 5:41 pm
Let me know if that solves the problem.
Regards,
Sara
Great, I have that Pan and Tilt gimball, including the servo’s exactly for this purpose, but had not gotten around to program it. Thanks for making it easy for me
Great!
Hi . thank you for this project. is there any way that transfer voice of enviroment with esp32-cam to webserver or webpage?
thanks for attention
regards
No answer?
Hi.
At the moment, we don’t have any projects related to audio with the ESP32.
For that, you would need to add a microphone module or something similar.
Regards,
Sara
Thank you for this project. It works very well.
Is there a safe way to be able to access it from out side the local network without opening any ports on the router.
Hi.
You can use ngrok service, for example.
Regards,
Sara
hello, I want to send data from ESP32Cam webserver via UART with Uno how?. pls help me
Your circuit diagram shows 3.3v connected to the servos but servos specs say operating voltage is 4.8v to 6.5v. Is 3.3v in your circuit diagram correct?
Thanks
Hi Dave.
Yes, you are right.
I was a mistake in designing the diagram.
You should connect to the 5V pin.
If you look closely at the stripboard, you’ll notice that it will connect 5V to the motors.
I’ll fix the schematic now.
Thanks for noticing.
Regards,
Sara
Do you have a picture or schematic of the underside of the stripboard? The wiring and circuit diagram are not making sense to me.
Thanks
Hi Dave.
Unfortunately, we don’t have a scheme for the stripboard.
You just need to take into account the following connections (then, you can build a stripboard to make wiring easier)
Servo 1:
GND –> GND
VCC –> 5V
Data –> GPIO 15
Servo 2:
GND –> GND
VCC –> 5V
Data –> GPIO 14
Because the ESP32 only has one 5V pin, you need to wire both VCC pins to the same ESP32 pin.
I hope this is clear.
Regards,
Sara
Is the esp32 capable of supplying enough current to run both servos?
Hello your program is great.
Thank you, this gives very good possibilities.
I haven’t done this project yet, but I see the photo on the smartphone is tilted 90 degrees.
Is it possible to straighten the streaming image for a good view please?
I answer to myself, if it can be of use to others …
There is a possibility to orient the image by rotating it 90 °. I saw this very interesting link for this problem:
https://projetsdiy.fr/5-astuces-esp32-cam-adresse-ip-fixe-mode-ap-rotation-image-recuperation-automatique-connexion-wifi-stockage-code-html/#rotationimage
Only I have difficulty incorporating it into your program, because I admit to being overwhelmed for programming ….
Can you be interested in the possibility of modifying your program incorporating this suggestion, please?
Hello from France, excellent tutorial, bravo and thank you
Have you been able to see the possibility of incorporating the 90 ° rotation into your program thanks to the link that I put in my previous post please?
Thank you very much for the post. Nice article and great explanation 👏👏.
Hi Sara,
I got the tilt platform to work, the only thing I do have it is that the picture is 90 degree.
Is there any thing to rotate the picture. I know with the normal view in the browser there is a click field to turn the view.
Regards
Willem
Hello from France,
I saw a tutorial concerning the possibility of making 90 ° rotations, I put the link in a post above.
I think this possibility is very interesting, but I don’t know how to integrate it into Sara’s excellent tutorial.
Maybe this will interest Sara and she can add a modification for this 90 ° rotation function, that would be very interesting? …
Hello Gérard,
I read your previous e-mail about rotating the image.
After the command on the original scrip:
window.onload = document.getElementById(“photo”).src = Window.location.href.slice(0, -1) + “:81/stream”;
Add this 2 lines:
var deg = -90;
window.onload = document.getElementById(“photo”).style.transform = ‘rotate(‘ + deg + ‘deg)’;
Changing the “var deg” you can rotate the image to 180º
Hope it helps.
Hello Arlvaro Henriques,
Great (by changing -90 to 90), it’s great.
I just have to go down the image to be below the Title
ESP32-CAM Pan and Tilt
Then move down the buttons to be below the image
I’ll do some testing so as not to make a mistake.
thank you so much
Hello Arlvaro Henriques,
Ok to go down the image under the title, and go down the buttons under the image.
I added :
h2> & nbsp </ h2 under h1> ESP32-CAM Pan and Tilt </ h1 to lower the position of the image
Then:
h2> & nbsp </ h2 under img src = “” id = “photo” to lower the position of the buttons
it works very well, thanks again, it’s great !!!
Hello can you port the complete script for me?
Hi Sara ,
Thank you for your job !
I try to add a button to turn on the lamp but I can not! Can you help me, thank you?
Has anyone figured this out yet?
Hi Sara,
Found this a very interesting tutorial.
However I ordered pan & tilt mechanism from your link, but it needs a 5V signal to operate. Had to use 2 level shifters & 2 power supplies (1 for each servo), to achieve the desired effect) . Using same power supply for both servo’s resulted in interfarance between the 2.
Bonjour,
Excellent tuto!
Pour moi j’ai bien l’image sur mon PC mais rien sur mon telephone portable, je ne vois que les boutons.
Pouvez vous m’aider?
Merci
Hi
You can only watch the video streaming in one place at a time.
Please close your computer web browser window before opening it on the smartphone.
Regards,
Sara
Merci pour votre réponse rapide!
OK effectivement c’était bien mon pb…. sorry.
Par contre si je change le port 80 par un autre port dans le PGM
je n’ai plus l’image, j’ai contrôlé dans la boxe et le port concerné est bien activé.
Voici ou j’ai modifié:
void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 49161; //port validé dans la boxe
et à quoi servent ces 2 lignes:
config.server_port += 1;
config.ctrl_port += 1;
Grand merci pour votre aide et vos tutos géniaux.
To avoid problems with the servos, you need to put a 10 uf , and a 0.1 uf condenser between + and – and the source is 5V /1Amp
Hello. Can you post a circuit diagram?
Hello,
Great your program, thank you.
I’m in the middle of testing, but there must be some problem with my setup, but I don’t know what …
My low servo (to go from left to right or vice versa) does not stop, it seems that it is still looking for a position because it is continually panicking.
Do you have an opinion on my problem please?
(By the way, I posted a suggestion to rotate the image 90 °, if that helps …)
Please let me know about my panicking servo problem.
I answer myself …
version 1.0.4 must be installed. of the esp32 card
it works well…
I thought I had solved my pan-tilt problem which trembles as soon as I plug it in, but no, it starts again.
it might be necessary to put capacitors, but which ones and where, I am zero in electronics …
Anyone have an idea, and if so can I refer me to a tutorial, please? I searched but could not find anything regarding this problem …
I continue my research regarding servomotor shaking, so the esp32-cam and pan-tilt servomotors all connected to 5v, the pan-tilt shakes and is uncontrollable from the power on 5v.
With a 3.3v / 5v power supply module (https://fr.aliexpress.com/item/1722852745.html?detailNewVersion=&categoryId=400103), the esp32-cam connected in 5v, and the pan-tilt servomotors connected in 3.3v, it works, the servomotors no longer shake.
That’s good, but how do you make a mini board like you suggest, putting 5v for the esp32-com and 3.3v for the servos?
Can you help me, I’m lost and I’m really bad at electronics, please?
Hello from France,
For other people who have the same pan-tilt shaking problem, I follow up: my problem is solved, I definitely hope.
I had changed several usb cables for the 5v power supply, unfortunately with the same problem.
And this morning, finding yet another usb cable, I tried it on the off chance, and it works perfectly!
The esp32-cam AND the Pan-Tilt, all connected to the 5v.
So this problem was simply the power supply, it will have made me waste a lot of time, but it works very well now with this cable found at the bottom of a drawer …
This project and tutorial is great, thank you Sara, and well done …
Great!
I’m glad you made it work!
Regards,
Sara
Good day and thanks for posting this article. I was hoping to please ask for some assistance with the esp32-cam.
I have been attempting to enable face detection on the ESP32-Cam however it has failed on multiple boards. The boards flash ok and the webserver example runs but when I turn on face detection on the webserver web interface, the esp32-cam reboots or shows a memory heap error in Arduino serial monitor (baud rate 115200). I have tried six units and all have failed. I tried powering the esp32-cam directly to a power supply (5V), it still failed. I have flashed using various methods, ESP32-CAM-MB USB Programming Adapter, UNO and a FT232RL FTDI USB to TTL Serial Adapter; they all flash the board but face detection still crashes it.
Thanks for any ideas or suggestions.
Hi.
Please check the version of the ESP32 Boards Installation. It should be 1.0.4. (recent versions have some sort of bug that crashes face recognition).
In your Arduino IDE, go to Tools > Board > Boards Manager and search for ESP32. Make sure you have version 1.0.4.
Regards,
Sara
Thank you for that tip.
So, I tried that, changed board to 1.0.4, still no luck. A bunch of gibberish in serial monitor then it says connected to webserver but crashes when face detection is selected using the example webserver code. I tried downgrading Arduino IDE to 1.8.12 as well, but still no luck on the face detection. I have 5 of these left, I did have 6 but one met an untimely demise with a hammer (it felt sooooo good), the rest are destined to this fate soon.
What’s the board that you’re using?
Are you using an external antenna?
Make sure it can catch a good wi-fi signal from your router.
Regards,
Sara
Hello again and thank you for your assistance.
I am using this board (esp32S chip) and have tried others: https://www.amazon.ca/gp/product/B08XYLSH15/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1
No external antenna. Wi-fi Router is right beside me.
The part that is strange, is that directly after a successful flash with Arduino IDE and before any testing, I open serial monitor where it shows a bunch of garbage characters, as if the baud rate is wrong (it’s 115200), right after the garbage it says connecting…, it connects and says successfully connected and gives me the IP of the webserver. I browse to the IP and the Webserver works until I select Face Detection.
In Arduino IDE, I am choosing the AI THINKER board, should I be choosing Wrover?
Thanks,
Norton
Hi.
Try selecting the Wrover module with the following settings and see if it works.
In Tools > Board select ESP32 Wrover Module.
In Tools > Partition Scheme select Huge App 3MB No OTA.
Regards,
Sara
Thanks so much for all the help.
So here is what worked for me:
Board: “ESP32 Wrover Module”
Upload Speed: “115200”
Flash Frequency: “40MHz”
Flash Mode: “QIO”
Partition Scheme: “Huge APP (3MB No OTA/1MB SPIFFS)”
Cored Debug Level: “None”
Port: the CH340 port
Programmer: “AVR ISP”
Arduino IDE version 1.8.12
Board: esp32 version 1.0.4
I did have to push the reset button on the esp32-Cam and timing sometimes was hit and miss however when it worked, it worked successfully.
The part I’m not getting is that in Arduino IDE the board selected is ESP32 Wrover Module whereas the board in the code is AI_THINKER.
Thanks again, you guys rock!
Hi.
I’m also not sure why that happens.
But, I’m glad it is working now.
Regards,
Sara
Hello Rui & Sara
It works!
One question: I was using 2 Wifi analyzer apps (Netspot on Windows / WIFI Analyzer on Android) in order to measure the signal strength of the ESP32.
On both apps the ESP32 does not show up.
Strange because the camera was working.
What is going on here?
Regards
Chris
Hi, this project is working in lovalhost, but when I tried to use port forward, using ngrok, the video is not loading (sreaming), but the servos works fine. Could you explain me why it is happening?
Hello from France,
Always to learn, and going further to put your excellent tutorial to my taste, I would like to mark, on the web page, the current position of the servomotors at each change of position, therefore the value of servo1Pos and servo2Pos.
Do you think this is possible, and if so, can you help me do it, please?
Hello,
To have the current position, or the requested position of the servomotor, on the WEB page, I try to take inspiration from your excellent tutorial:
https://randomnerdtutorials.com/esp32-servo-motor-web-server-arduino-ide/
But I am very afraid of doing anything stupid to do so.
Could you help me please, to have the same possibility in the web page of the tutorial with the pan-tilt, I would be really grateful to you, I am not very good at programming, and I really have need to know.
Hello,
Nobody has an idea to write the current position, OR the requested position, of the servomotors (servo1Pos and servo2Pos) on the WEB page, at each rotation of the servomotors?
I really try, but I can’t, help
Great project. Question: any hints on how to add a slider for the LED light?
When I used the verify/compile command of Arduino 1.8.13 on this project I got an error on line 299. The variable “s” was not defined. I corrected the error by un-commenting the “flip the camera vertically” setting. Did I miss that in the instructions or is it unique to my installation? Once that error was cleaned up my servos started acting correctly–before that I had some jerky motion and random movements and I would lose connection to the video stream.
One other thing I noticed is that my up and down servo is opposite–when I click on the down button it goes up and vice versa. I’m using Tower Pro SG92R actuators. I swapped the up and down variables and it seems to do what it should.
Thanks and as always, a well done, great tutorial.
Hi
First of all, thanks for sharing the project.
I want to do external led control (on/off) as the video stream of this project, but it doesn’t work.
So when the video stream of this project comes out
https://randomnerdtutorials.com/esp32-relay-module-ac-web-server/
Here I want the result of merging the led control.
Can you help?
Good Day,
Would you happen to have any tutorials using the esp32-cam with object tracking using pan/tilt servos?
Thanks!
N.
Hi.
We don’t have that specific project.
But here’s another tutorial that might help: https://randomnerdtutorials.com/esp32-cam-opencv-js-color-detection-tracking/
Regards,
Sara
Hello,
Thanks for the reply, yes, there is some helpful information in that tutorial.
Would you consider doing such a project?
Thanks,
N.
Hi.
Maybe in the future.
But, at the moment, we’re dedicating time to other projects.
Regards,
Sara
Hello,
Really good and helpful project.
I am just facing problem in adding new variable to display on webpage such as Temperature etc.
Can you please help me to display such variable on Webpage in the same project
Thank You,
Hi.
You just need to add the needed HTML to display the temperature in the PROGMEM INDEX_HTML and concatenate with a variable that saves the temperature reading.
Regards,
Sara
Hello,
Thank you for the reply,
Yes i can make the changes in the Program INDEX_HTML but not able to concatenate.
Means how to link the temperature data from the main loop to the INDEX_HTML
Please if possible share some example to understand.
Thank you,
Saurabh
Hi again.
When you say you are not able to concatenate, what happens exactly?
Regards,
Sara
Hi, Thanks again
As in this code below function is added for the buttons in HTML
function toggleCheckbox(x) {
var xhr = new XMLHttpRequest();
xhr.open(“GET”, “/action?go=” + x, true);
xhr.send();
}
and then below code is used to detect buttons from HTML
if (httpd_query_key_value(buf, “go”, variable, sizeof(variable)) == ESP_OK)
So how to use such thing for temperature data to display in the HTML page. Means what to add in the HTML and what in the loop
I might sound stupid but i am really confused and not able to figure out the solution so please let me how can i do this
Thank you,
Saurabh
If the LED can be turned on and off from a button on the webpage, this would be excellent.
Has anyone managed it?
Leon
Hello Leon,
Yes, but with the non-simplified program, i.e. with the menu, see this link: https://www.esp32.com/viewtopic.php?f=19&t=11190
it works very well
cordially
Bonjour,
Apres de nombreux tests et essais et controls de la conf des routages sur la boxe je constate que ça ne fonctionne pas sur un port différent de 80 ?!
Si on ouvre une connexion sur PC -> impossible sur smartphone, et vice versa.
Apparemment il ne peut y avoir qu’une seule connexion à la fois possible.
Pourquoi? et Comment faire?
Quelqu’un a t-il la solution?
encore bravo pour vos travaux!!!!
Merci
Hi.
Yes, with this example, you can only have one client connected at a time to the ESP32.
Regards,
Sara
Hello Sara,
With your simplified program, it’s really great.
But I would also like to use the Pan-Tilt with the version of the program which is with its menu (original program for example).
There are 4 tabs:
The .ino sctech
app_httpd.cpp
camera_index.h
camera_pins.h
I added the direction buttons in the camera_index.h html file, but for the rest, ie to operate the servomotors, I admit that I am lost, I do not know where to put the different commands. ..
I tried a lot of hypotheses, but failed …
Could you please help me, to tell me where to put the different controls in the original program, to get the Pan-Tilt to work, I’m quite a novice …
Hi Sara,
Thanks for the excellent project!
One of my servos seems to be going backwards… Clicking ‘Up’ makes the tilt go ‘Down’ and clicking ‘Down’ makes it go ‘Up’. ‘Left’ & ‘Right’ appear to be working properly as viewed through the camera.
What could make this happen?
I have triple checked my wiring and it looks correct to me…
Kind regards,
Mark
Hello Sara,
If I upload the software without CamWebServerTilt It works coorectly. But with the Pan and tilt i have one error: ‘httpd_req_t’ was not declared in this scope.
Could you help me, please?
Beleljam
I have the same issue, where is this declaration?
I would like to add a voltage meter to this project. And I would like the measurements to be shown on the web server. Do you have any tutorial on how I can attach this meter to this code?
this is my voltage meter;
ptrobotics.com/sensor-de-corrente/5099-funduino-voltage-sensor-for-arduino.html?gclid=CjwKCAjwlcaRBhBYEiwAK341jSQk_DlqQ4X-XGamn14BqkWpHKG34_utJKG8pTVRcsei1DSVfOMGWRoCna8QAvD_BwE
Hi.
I’m sorry, but unfortunately, we don’t have any tutorials about that subject.
Regards,
Sara
Hi Sara!
That’s great project. By the way I have try this and it’s happened that the servo motor wouldn’d work (but while I’m press the up, right, left, bottom it shows just find in arduino monitor) I’ve also check the Vin from batteries and it definitely 5 V.
Please help. Thanks !
Hi.
Check that your servo is working properly with a servo example sketch.
Also, make sure you’re powering the servo correctly and that it is wired properly on the right pins.
You can also try to check with an oscilloscope (if you have one) if the GPIOs are outputting the corresponding PWM signals.
Regards,
Sara
i’ve issue my adapter was blinking when plugging to esp32 cam. So i try to press the reset button in my AI Thinker it’s blinking too.
My adapter 5v 2A just normally no problem in other. Then i test the servos is was good and work normally.
i confused in this, where’s the problem..
Hello Sara,
Thanks for this project
Nice tutorial and easy to understand
I’ve one issue
The esp32 cam doesn’t connected with adapter.
Even though when uploading the code esp32 cam is fine and i can access the webserver normally. The problem came after I connected to some wire, servos pin, then to the adapter.
My adapter was blinking when plugging to esp32 cam that’s mean it doesn’t connected. From there i confused what happen actually. I try to press the RESET button in my AI Thinker it’s blinking too.
My adapter 5v 2A just normally no problem in other. Then i test the servos is was good and work normally. The wiring like pins and other everything is correct.
Please help this problem
Thanks!
Hi. What’s exactly the adapter you’re using?
Regards,
Sara
Many thanks for another great project. Is there a way of using AsyncElegantOTA with this video streaming. When I try I get the compile error redefinition of HTTP_GET.
Also interested in ElegantOTA integration
Hi! Thank you very much for this wonderful tutorial!
I also would like to ask about pin used for the servo.
Can i use other pin beside 14 and 15 for the servo? For example pin 2 and 13, and should i change Servo1N and Servo2N pin attach?
Thanks!
Hi, I am a new learner to ESP32 cam. I use your code and my pre-writing code in my project to let pan tilt automatically track the human face. However, when I open the website, the stream JPG does not show up. It was quite weird because all the code seem to be the same except for other fuction in my pre-writing code for face recognition and drawing detecting box for human face. Could I send email to you with my code? I have difficulty to figure out which place is the problem for error. Thank you very much
Hello Sara, great project. I recreated it and it works fine so far.
I have only one problem:
The left<>right servo can only be moved within a range of approx. 90 degrees. But I want 180 degrees.
How can I implement this?
Greetings Ulli
Answered here: https://rntlab.com/question/esp32-cam-pan-and-tilt-video-streaming-web-server/
Problem solved.
servo1.attach(SERVO_1, 650, 2000); // up – down
servo2.attach(SERVO_2, 600, 2400); // left – right
Hello,
Love the external antenna on this ESP32 CAM. Do you have any photos or instructions on how to make that happen?
https://randomnerdtutorials.com/esp32-cam-connect-external-antenna/
Hi Sara, Great project! I did a similiar project with your code, the camera is working fine, but the 2 servo is not responding! when i press the up down left right button on the web page it hanged! could you pls advise, thanks.
Hi Sara,
I had tested both servos with AI thinker board and its working fine, supply the 2 servos with separate 5V and update ESP32Servo.h with version 0.7. But it still hang when button UP was pressed, tough video seems to be working fine. Could you pls advise thanks.
Had the same issue here, even if the servo weren’t wired.
Thanks for the hint!
I was using the ESP32Servo.h with version 0.12.1
I downgraded to version 0.4.0 and the code worked when button UP was pressed.
Something was changed between version 0.4.2 and 0.5.0 that interfere with the camera.
I have uploaded this code to ESP32-CAM. When I start the webserver and click the UP button the stream stops and everything freezes. Other buttons are OK.
Note: I do not have servos attached, just testing code with serial monitor.
For now, you need downgrade ESP32Servo.h to version 0.4.2
Thanks. That fixed it.
I made a couple builds of this project along with 3d printed enclosures. It has been a while but the files are available at
https://github.com/trentbrown13/ESP32_Cam_Pan_Tilt
Thank you to the Santos’s for such great inspiration and also thank you to ‘the man with the Swedish accent’ as well as to the person who posted a link on how to rotate the images but is not longer available.
Sorry Andreas, I meant the man with the Swiss Accent.
That’s great!
Thanks for sharing your work.
Regards,
Sara
Installed Trent Brown’s of esp32-CAM Pan & Tilt Sweep and having problems. Been working on it for a couple of days.
The web page comes up but image disappears immediately with Serial Monitor displaying ‘Camera capture failed’. I can see responses from button pushes but servos do not respond.
Any help is appreciated.
I had the same problem. Uninstalling servo library and reinstalling again but 4.0 version worked for me.
Use ESP32Servo library version 0.4.2.
Regards,
Sara
hey! thanks a lot!
can I use two 28 BYJ steppers?
i think there are not enough digital pins on espcam or is there a way?
Hi.
You can use a GPIO expander to have more available GPIOS, but I haven’t tested it with the ESP32-CAM.
Regards,
Sara
can we change camera pwm channel to the last, or set servo channel directly without creating dummy servoN ?
I think you can try changing the PWM channel for camera on the following line:
config.ledc_channel = LEDC_CHANNEL_0;
Try it out and see if it works.
Regards,
Sara
I have been refining this code for some time. I have the pan and tilt sevos working with sliders. It is much smoother than buttons.
Anyway, I would like to move the html code outside of the sketch, to clean up the code, and to learn how to do that. I have tried to imitate such code from other projects but just can’t get it to work.
Any help is greatly appreciated.
Hi, could you please post the code to make the sliders work?
It would be very helpful to everyone…
Thanks
Hi Sara,
I copied your original code. The program works except for one problem. If I press the up button, the camera stream stops and the message “Camera capture failed” appears in the serial monitor. The problem also occurred with other users and your recommendation was to reset the ESP32-Servo.h to version 0.4.2. But I use the latest version 0.12.1.
I found a solution with this version too. After the servo objects ServoN1 and ServoN2, I have added another servo object, ServoN3. Servo1 and Servo2 now use channels 4 and 5 and the camera is no longer disturbed.
Thanks for the solution.
I didn’t know about that.
Regards,
Sara
Hi Hajo, I have the same problem: camera hanged when up button was pressed, I have been stuck at this issue for months, wonder if you can share your code? thanks in advance.
Hi cosgrove. Send me an email to [email protected]. I will then send them back with the code.
OK, this pan & tilt project is becoming a career. I have made many improvements (in my opinion) to the code. It’s running perfectly.
So, I have now added a function to send a capture frame to a folder on Google drive. This works fine if run by itself. I have added a capture button to the the web page and when pressed it runs the Capture_Handler. I have added the SendToGDrive function on the end of the Capture_Handler.
Problem is this stops the Stream_Handler and causes an exception and ESP32 reboot.
I want this system as a security camera so it will be mounted outside. Saving images to SD card makes things complicated when I need to get the image. Also saving to SPIFFS is not a good plan.
I am wondering if I can run the Stream_Handler as vTask so it would be run on a separate thread (maybe) and would not be interrupted.
I have tried various methods such as delays to no avail.
Any suggestions are appreciated.
Hi.
I don’t think you can run both tasks simultaneously.
When you need a picture, you need to stop the streaming.
You can return to the streaming right after taking the picture.
I think this is the best strategy so that the board doesn’t crash.
Regards,
Sara
Thanks. I can’t figure out how to pause/stop the stream and restart it. Do you have any ideas on that.
Re: ESP32-CAM watchdog timeout when sending a photo to Google Drive while video streaming.
I managed to get the Pan & Tilt app to send a photo to Google Drive. After creating a Google Drive app script, I created RTOS task, sendToGDrive, and pinned it to core 0 in the ESP32-CAM. It works like a charm. I put a Capture button on the web page and when pressed a single frame is captured and sent to Google Drive.
So now I can mount the ESP32-CAM fixture outside and can manage everything, including OTA updates, from my computer.
I figured out another solution to the problem of ‘camera capture failed ‘ error when activating one of the servo motors. Most people are solving it with the work around of using an older version of the esp32Servo library. One comment above adds a 3rd dummy, servoN3. What I found was that sometime between version 0.4 (which most people report works) and 0.13 (current as of April 6, 2023) the issue of PWM interfering with the camera was changed. In this example 2 dummy servo instances are created servoN1 and servoN2. In the setup(void) function they are attached to pin 2 and 13, The explanation is that PWM channels interfere with the camera, so they have to be set up as dummies.
What I suspected was that it was the dummies that were actually interfering with the camera, since it is the camera that locked up when the servos were activated.
I commented out the dummy servo entries:
//Servo servoN1;
//Servo servoN2;
Servo servo1;
Servo servo2;
//servoN1.attach(2, 1000, 2000);
//servoN2.attach(13, 1000, 2000);
servo1.attach(SERVO_1, 1000, 2000);
servo2.attach(SERVO_2, 1000, 2000);
Now the ESP32-CAM behaves correctly with ESP32Servo.h version 0.13. So it seems like PWM channel 3 is what conflicts with the camera now, since 1 and 2 work in my case and 4 and 5 work in the previous comment. Added bonus, is that you can use GPIO 2 and 13 for other things.
Hi.
Thanks for sharing that information.
I’ll need to try this example again with the latest version of the library and sww which PWM channels I can use.
Regards,
Sara
Picture perfect result thanks to your comment. Thankyou, thankyou, thankyou.
Rui & Sara … your tutorials and post tutorial assistance is great work. Thank you
I confirm David results. I am using a Freenove ES32-WRover board with esp32servo 0.13.0.
Activating servos locks video stream, no matter the pins you use. Commenting out ServoN1/ServoN2 lines works a treat.
Currently using pines 32 and 33 for servos (for a minirobot, not for pan tilt mechanism)
Hi! thanks a lot for this!
I still have a problem on something i am working on.
I am trying to create an python script on my pc which tries to videocapture from the stream hosted by the esp32CAM on the webserver. because i want to use opencv on the videostream. When i use your code for the esp32Cam and run this python code below on my pc with the correct ip adress it crashes. But when i use the example CameraWebServer code in arduino for the esp32Cam and run this python code below on my pc it works just fine.
Do you know what the problem is?
when i go to http://:81/stream i am able to see the stream.
import cv2
stream_url = “http://:81/stream”
cap = cv2.VideoCapture(stream_url)
while True:
ret, frame = cap.read()
if not ret:
break
cv2.imshow("Video", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Good Day,
Thanks for sharing this, I have gotten it to work however I was wondering if it would be possible to also make the device an access point at the same time?
Thanks,
Norton
Ok, I think I figured it out…
// Wi-Fi connection
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print(“AP IP address: “);
Serial.println(IP);
startCameraServer();
// WiFi.begin(ssid, password);
// while (WiFi.status() != WL_CONNECTED) {
// delay(500);
// Serial.print(“.”);
// }
// Serial.println(“”);
// Serial.println(“WiFi connected”);
//
// Serial.print(“Camera Stream Ready! Go to: http://“);
// Serial.println(WiFi.localIP());
//
// // Start streaming web server
// startCameraServer();
}
Hi.
Yes.
You can set it as an access point.
Regards,
Sara
Hi
Great project an well explained. I’m going to implement it for monitoring my 3D printer, and also add small relay from GPIO4 LED to activate existing enclosure light. It’s a LED light strip so relay be overkill, but it uses 12V plug pack and is already installed so inserting relay inline is straightforward
Thanks again
rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
i am facing this error when uploading the code to esp32 cam and pressing the reset button please help!
Hi Sara, I am currently working on an antenna tracker project with 2 servos. In the process, I became aware of the great project with PanTilt.
Since I would like to use an ESP32 WROOM 32, I have a question:
Is it possible to shorten the code so that I can use it for my project without a camera? What do I have to remove from the code or comment out in order to flash it to ESP32?
Sorry I am still a beginner with ESP32.
greetings Georg
Translated with http://www.DeepL.com/Translator (free version)
Hello to the users,
can someone help me with code for 2 servos without the camera.
greetings Georg
Hello from Scotland.
I have been working on this project for a couple of days and have enjoyed doing it. I have however got an issue with the image. I currently have the ESP32 Cam connected to the ESP32 MB, connecting using USB. I have no servos connected as yet.
On first load the image from the camera appears but after about 30 seconds the image disappears. I’m using Chrome browser on Windows 10. Inspecting the web page as soon as the image disappears the following error appears “Failed to load resource: net::ERR_INCOMPLETE_CHUNKED_ENCODING” followed by a link to “stream:1”.
I have done a line by line comparison of my code against the code in the article and also checked the streaming element of the robot car and can’t find any difference.
I’m sure it’s something obvious but I’ve checked all I can think of, What am I missing?
Thanks.
Hello, unfortunately I never encountered that issue before.
Make sure you are using a good power source that supplies enough current to make the board work reliably.
You also need to keep in mind that the ESP32-CAM can’t have more than 1 client accessing the web server at the same time.
Regards,
Rui
Hello Rui
Thank you for the reply.
I did try using a 5 volt 2 amp power supply but that made no difference.
I then wondered about the strength of the wi-fi signal and as soon as I moved the camera to a different location it all worked perfectly. I am currently using the internal aerial, I’ve ordered an external one but it hasn’t arrived as yet, but will fit the new one as soon as it arrives.
Hopefully this might help if anyone else has this problem in the future. Wi-fi strength is worth checking.
Thank you for your help.
Bill
I finished the esp cam pan tilt tutorial, it worked without any problem. Thank you for creating this easy is to follow tutorial.
I ran into an odd problem with the video stream, and hope you can help me find a solution.
I am able to stream video via the LAN and control the servos okay. When i port forward the stream, I don’t get the video stream, i only get the text. I am able to control the servos from the forwarded text but never get any video.
I tried a different browser, and changing the image size but this did not help,
Thank you.
Larry
Good morning Sara and Rui, thank you for your projects and your availability. I created this project but I have a problem, when I go to manage the camera, the image is seen in the browser, but when I press a button for the direction of the servos the program goes haywire and the image disappears. I have to press reset to restart it. The servos don’t move. You can help me . Thank you very much.
Hi Paolo, I have the same problem. Did you find a solution?
Good evening Sara E Rui, I would like to add a Flash on/off button, can you kindly give me some instructions to do so. Thanks in advance
Hi,
Code worked well for some months.
Yesterday I made a adaption, since then I get an error message (see below) while compiling. Very strange, as I have not changed anything and I have checked the libraries, – all correct.
Here the error message:
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp: In member function ‘double ESP32PWM::setup(double, uint8_t)’:
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp:70:30: error: ‘ledcSetup’ was not declared in this scope
70 | double val = ledcSetup(getChannel(), freq, resolution_bits);
| ^~~~~~~~~
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp:74:16: error: ‘ledcSetup’ was not declared in this scope
74 | return ledcSetup(getChannel(), freq, resolution_bits);
| ^~~~~~~~~
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp: In member function ‘void ESP32PWM::attachPin(uint8_t)’:
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp:113:17: error: ‘ledcAttachPin’ was not declared in this scope; did you mean ‘ledcAttach’?
113 | ledcAttachPin(pin, getChannel());
| ^~~~~~~~~~~~~
| ledcAttach
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp: In member function ‘void ESP32PWM::detachPin(uint8_t)’:
c:\Users\Boss\Documents\Arduino\libraries\ESP32Servo\src\ESP32PWM.cpp:169:16: error: ‘ledcDetachPin’ was not declared in this scope; did you mean ‘ledcDetach’?
169 | return ledcDetachPin(pin);
| ^~~~~~~~~~~~~
| ledcDetach
exit status 1
Compilation error: exit status 1
Any idea?
Konrad
In order to follow most ESP32 projects available online at the moment, we recommend using the ESP32 board add-on version 2.
If you update to version 3.0 (which was the case), there are a few changes required to make the code compile. We’ll be updating all our guides in the upcoming weeks.
Previously for version 2 ESP32 board add-on inside the setup function:
pinMode(LED_PIN, OUTPUT);
// configure LED PWM functionalities
ledcSetup(ledChannel, freq, resolution);
// attach the channel to the GPIO to be controlled
ledcAttachPin(LED_PIN, ledChannel);
ledcWrite(ledChannel, 0);
For the NEW version 3 ESP32 board add-on inside the setup function:
ledcAttachChannel(LED_PIN , freq, resolution, ledChannel);
ledcWrite(LED_PIN, 0);
More information here: https://docs.espressif.com/projects/arduino-esp32/en/latest/migration_guides/2.x_to_3.0.html
I hope this helps.
Regards,
Sara
Hi Sara,
yep; – just saw same problems with other ESP32 scripts!
Changed to 2.xx Version and the problem was solved.
Thanks
We’ll try to migrate all our previous projects to version 3 in the upcoming days.
Regards,
Sara
This is a great project!
I have tried to smooth the movement of the servos by putting a for loops in place in each of the servowrite sequences, I set it to 1 degree increments followed by a delay 15 milliseconds over 10 cycles. The unit freezes. Please see code below.
I know that delay is not a great option as it is blocking. I also expect that the commands via web server for one degree movement at 15ms intervals is totally swamping things.
Does anyone have a solution for this? I will probably try millis instead of delay but expect it will still swamp.
Thank You
Code
if(!strcmp(variable, “up”)) {
if(servo1Pos >= 11) {
for (int i=1; i=10; i++) {
servo1Pos -= 1;
servo1.write(servo1Pos);
delay(15);
}
}
Serial.println(servo1Pos);
Serial.println(“Up”);
}
Is the ESP01 powered with 3.3V or 5V?
Hi.
Usually it’s 3V3. But you should check the specs for your specific board.
Regards,
Sara
Hi sara
When I enter the following request, it does not respond
192.168.1.5/stream
Nothing matches the given URI
Hi sara
In my project, I convert the grayscale image to jpeg with the img_converters.h library. This Apache 2 license library wants, can you tell me where this license should be added to the program and how?
hi,Sara,
Sorry for my english, Ican’t upload my sketch . I have this mistake .
fatal error occurred: Failed to connect to ESP32: No serial data received.
Please how procede this ? thank you very much for helping. Have a good day. Jean-Charles.
Sara,
I’sorry ,
I have upload the code no prob but , message is
load:0x40078000,len:16460
load:0x40080400,len:4
load:0x40080404,len:3504
entry 0x400805cc
E (53) camera: Detected camera not supported.
E (53) camera: Camera probe failed with error 0x106(ESP_ERR_NOT_SUPPORTED)
Camera init failed with error 0x106 can you help me please .JCD
Which camera are you using?