Construisez un robot de voiture télécommandé Wi-Fi avec l’ESP32-CAM. Vous pourrez contrôler le robot à l’aide d’un serveur Web qui affiche un streaming vidéo de ce que le robot « voit ». Vous pouvez contrôler votre robot à distance même s’il est hors de votre vue. L’ESP32-CAM sera programmé à l’aide d’Arduino IDE.
Compatibilité des cartes: ce projet nécessite 4 GPIO pour contrôler les moteurs à courant continu. Ainsi, vous pouvez utiliser n’importe quelle carte de caméra ESP32 avec 4 GPIO disponibles comme le Carte ESP32-CAM Ai-Thinker ou la TTGO T-Journal.
Aperçu du projet
Avant de commencer le projet, nous mettrons en évidence les fonctionnalités et les composants les plus importants utilisés pour construire le robot.
Wifi
Le robot sera contrôlé via Wi-Fi à l’aide de votre ESP32-CAM. Nous allons créer une interface Web pour contrôler le robot, accessible depuis n’importe quel appareil de votre réseau local.
La page Web montre également un streaming vidéo de ce que le robot « voit ». Pour de bons résultats avec le streaming vidéo, nous vous recommandons d’utiliser un ESP32-CAM avec antenne externe.
Important: sans antenne externe, le flux vidéo est à la traîne et le serveur Web est extrêmement lent à contrôler le robot.
Commandes de robots
Le serveur web dispose de 5 contrôles : Effronté, En arrière, À gauche, À droite, et Arrêter.
Le robot bouge tant que vous appuyez sur les boutons. Lorsque vous relâchez un bouton, le robot s’arrête. Cependant, nous avons inclus le Arrêter bouton qui peut être utile dans le cas où l’ESP32 ne reçoit pas la commande d’arrêt lorsque vous relâchez un bouton.
Kit de châssis de robot intelligent
Nous allons utiliser le Kit de châssis de robot intelligent. Vous pouvez le trouver dans la plupart des magasins en ligne. Le kit coûte environ 10 $ et il est facile à assembler – regardez cette vidéo pour voir comment assembler le kit de châssis de robot.
Vous pouvez utiliser n’importe quel autre kit de châssis à condition qu’il soit livré avec deux moteurs à courant continu.
Pilote de moteur L298N
Il existe de nombreuses façons de contrôler les moteurs à courant continu. Nous utiliserons le pilote de moteur L298N qui permet de contrôler facilement la vitesse et la direction de 2 moteurs à courant continu.
Nous n’expliquerons pas comment fonctionne le pilote de moteur L298N. Vous pouvez lire l’article suivant pour un didacticiel détaillé sur le pilote de moteur L298N :
Pouvoir
Pour que le circuit reste simple, nous alimenterons le robot (les moteurs) et l’ESP32 en utilisant la même source d’alimentation. Nous avons utilisé une banque d’alimentation/un chargeur portable (comme ceux utilisés pour charger votre smartphone) et cela a bien fonctionné.
Noter: les moteurs consomment beaucoup de courant, donc si vous sentez que votre robot ne bouge pas correctement, vous devrez peut-être utiliser une alimentation externe pour les moteurs. Cela signifie que vous avez besoin de deux sources d’alimentation différentes. L’un pour alimenter les moteurs à courant continu et l’autre pour alimenter l’ESP32.
Pièces requises
Pour ce projet, nous utiliserons les pièces suivantes :
Vous pouvez utiliser les liens précédents ou aller directement sur MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !
Code
Copiez le code suivant dans votre IDE Arduino.
/*********
Rui Santos
Complete instructions at https://Raspberryme.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"
// 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 MOTOR_1_PIN_1 14
#define MOTOR_1_PIN_2 15
#define MOTOR_2_PIN_1 13
#define MOTOR_2_PIN_2 12
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "rn--" PART_BOUNDARY "rn";
static const char* _STREAM_PART = "Content-Type: image/jpegrnContent-Length: %urnrn";
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 Robot</h1>
<img src="" id="photo" >
<table>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('forward');" ontouchstart="toggleCheckbox('forward');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Forward</button></td></tr>
<tr><td align="center"><button class="button" onmousedown="toggleCheckbox('left');" ontouchstart="toggleCheckbox('left');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Left</button></td><td align="center"><button class="button" onmousedown="toggleCheckbox('stop');" ontouchstart="toggleCheckbox('stop');">Stop</button></td><td align="center"><button class="button" onmousedown="toggleCheckbox('right');" ontouchstart="toggleCheckbox('right');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Right</button></td></tr>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('backward');" ontouchstart="toggleCheckbox('backward');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Backward</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: %uBn",(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();
int res = 0;
if(!strcmp(variable, "forward")) {
Serial.println("Forward");
digitalWrite(MOTOR_1_PIN_1, 1);
digitalWrite(MOTOR_1_PIN_2, 0);
digitalWrite(MOTOR_2_PIN_1, 1);
digitalWrite(MOTOR_2_PIN_2, 0);
}
else if(!strcmp(variable, "left")) {
Serial.println("Left");
digitalWrite(MOTOR_1_PIN_1, 0);
digitalWrite(MOTOR_1_PIN_2, 1);
digitalWrite(MOTOR_2_PIN_1, 1);
digitalWrite(MOTOR_2_PIN_2, 0);
}
else if(!strcmp(variable, "right")) {
Serial.println("Right");
digitalWrite(MOTOR_1_PIN_1, 1);
digitalWrite(MOTOR_1_PIN_2, 0);
digitalWrite(MOTOR_2_PIN_1, 0);
digitalWrite(MOTOR_2_PIN_2, 1);
}
else if(!strcmp(variable, "backward")) {
Serial.println("Backward");
digitalWrite(MOTOR_1_PIN_1, 0);
digitalWrite(MOTOR_1_PIN_2, 1);
digitalWrite(MOTOR_2_PIN_1, 0);
digitalWrite(MOTOR_2_PIN_2, 1);
}
else if(!strcmp(variable, "stop")) {
Serial.println("Stop");
digitalWrite(MOTOR_1_PIN_1, 0);
digitalWrite(MOTOR_1_PIN_2, 0);
digitalWrite(MOTOR_2_PIN_1, 0);
digitalWrite(MOTOR_2_PIN_2, 0);
}
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
pinMode(MOTOR_1_PIN_1, OUTPUT);
pinMode(MOTOR_1_PIN_2, OUTPUT);
pinMode(MOTOR_2_PIN_1, OUTPUT);
pinMode(MOTOR_2_PIN_2, OUTPUT);
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_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_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() {
}
Insérez vos informations d’identification réseau et le code devrait fonctionner immédiatement.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Comment fonctionne le code
Jetons un coup d’œil aux pièces pertinentes pour contrôler le robot. Définissez les GPIO qui contrôleront les moteurs. Chaque moteur est contrôlé par deux broches.
#define MOTOR_1_PIN_1 14
#define MOTOR_1_PIN_2 15
#define MOTOR_2_PIN_1 13
#define MOTOR_2_PIN_2 12
Lorsque vous cliquez sur les boutons, vous effectuez une demande sur une URL différente.
<table>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('forward');" ontouchstart="toggleCheckbox('forward');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Forward</button></td></tr>
<tr><td align="center"><button class="button" onmousedown="toggleCheckbox('left');" ontouchstart="toggleCheckbox('left');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Left</button></td><td align="center"><button class="button" onmousedown="toggleCheckbox('stop');" ontouchstart="toggleCheckbox('stop');">Stop</button></td><td align="center"><button class="button" onmousedown="toggleCheckbox('right');" ontouchstart="toggleCheckbox('right');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Right</button></td></tr>
<tr><td colspan="3" align="center"><button class="button" onmousedown="toggleCheckbox('backward');" ontouchstart="toggleCheckbox('backward');" onmouseup="toggleCheckbox('stop');" ontouchend="toggleCheckbox('stop');">Backward</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>
Voici les requêtes effectuées en fonction du bouton sur lequel on appuie :
Effronté:
<ESP_IP_ADDRESS>/action?go=forward
En arrière :
/action?go=backward
À gauche:
/action?go=left
À droite:
/action?go=right
Arrêter:
/action?go=stop
Lorsque vous relâchez le bouton, une demande est faite sur le /action?go=stop URL. Le robot ne bouge que tant que vous appuyez sur les boutons.
Traiter les demandes
Pour gérer ce qui se passe lorsque nous recevons des requêtes sur ces URL, nous utilisons ces instructions if… else :
if(!strcmp(variable, "forward")) {
Serial.println("Forward");
digitalWrite(MOTOR_1_PIN_1, 1);
digitalWrite(MOTOR_1_PIN_2, 0);
digitalWrite(MOTOR_2_PIN_1, 1);
digitalWrite(MOTOR_2_PIN_2, 0);
}
else if(!strcmp(variable, "left")) {
Serial.println("Left");
digitalWrite(MOTOR_1_PIN_1, 0);
digitalWrite(MOTOR_1_PIN_2, 1);
digitalWrite(MOTOR_2_PIN_1, 1);
digitalWrite(MOTOR_2_PIN_2, 0);
}
else if(!strcmp(variable, "right")) {
Serial.println("Right");
digitalWrite(MOTOR_1_PIN_1, 1);
digitalWrite(MOTOR_1_PIN_2, 0);
digitalWrite(MOTOR_2_PIN_1, 0);
digitalWrite(MOTOR_2_PIN_2, 1);
}
else if(!strcmp(variable, "backward")) {
Serial.println("Backward");
digitalWrite(MOTOR_1_PIN_1, 0);
digitalWrite(MOTOR_1_PIN_2, 1);
digitalWrite(MOTOR_2_PIN_1, 0);
digitalWrite(MOTOR_2_PIN_2, 1);
}
else if(!strcmp(variable, "stop")) {
Serial.println("Stop");
digitalWrite(MOTOR_1_PIN_1, 0);
digitalWrite(MOTOR_1_PIN_2, 0);
digitalWrite(MOTOR_2_PIN_1, 0);
digitalWrite(MOTOR_2_PIN_2, 0);
}
Tester le code
Après avoir inséré vos informations d’identification réseau, vous pouvez télécharger le code sur votre carte ESP32-CAM. Si vous ne savez pas comment télécharger du code sur le tableau, suivez le tutoriel suivant :
Après le téléchargement, ouvrez le moniteur série pour obtenir son adresse IP.
Ouvrez un navigateur et saisissez l’adresse IP ESP. Une page Web similaire devrait se charger :
Appuyez sur les boutons et jetez un œil au Serial Monitor pour voir s’il diffuse sans décalage et s’il reçoit les commandes sans planter.
Si tout fonctionne correctement, il est temps d’assembler le circuit.
Circuit
Après avoir assemblé le châssis du robot, vous pouvez câbler le circuit en suivant le schéma suivant.
Commencez par connecter l’ESP32-CAM au pilote de moteur comme indiqué dans le schéma de principe. Vous pouvez utiliser une mini planche à pain ou un stripboard pour placer votre ESP32-CAM et construire le circuit.
Le tableau suivant montre les connexions entre l’ESP32-CAM et le pilote de moteur L298N.
Pilote de moteur L298N | ESP32-CAM |
EN 1 | GPIO 14 |
EN 2 | GPIO 15 |
IN3 | GPIO 13 |
IN4 | GPIO 12 |
Nous avons assemblé toutes les connexions sur un mini stripboard comme indiqué ci-dessous.
Après cela, câblez chaque moteur à son bornier.
Noter: nous suggérons de souder un condensateur céramique de 0,1 uF aux bornes positive et négative de chaque moteur, comme indiqué sur le schéma pour aider à atténuer les pics de tension. De plus, vous pouvez souder un interrupteur coulissant au fil rouge provenant de la banque d’alimentation. De cette façon, vous pouvez allumer et éteindre l’appareil.
Enfin, appliquez l’alimentation avec une banque d’alimentation comme indiqué dans le diagramme schématique. Vous devez dénuder un câble USB. Dans cet exemple, l’ESP32-CAM et les moteurs sont alimentés en utilisant la même source d’alimentation et cela fonctionne bien.
Noter: les moteurs consomment beaucoup de courant, donc si vous pensez que votre robot ne se déplace pas assez vite, vous devrez peut-être utiliser une alimentation externe pour les moteurs. Cela signifie que vous avez besoin de deux sources d’alimentation différentes. L’un pour alimenter les moteurs à courant continu et l’autre pour alimenter l’ESP32. Vous pouvez utiliser un pack de 4 piles AA pour alimenter les moteurs. Lorsque vous obtenez votre kit de châssis de robot, vous obtenez généralement un support de batterie pour 4 piles AA.
Votre robot devrait ressembler à la figure suivante :
N’oubliez pas que vous devez utiliser une antenne externe avec l’ESP32-CAM, sinon le serveur Web pourrait être extrêmement lent.
Manifestation
Ouvrez un navigateur sur l’adresse IP ESP32-CAM et vous devriez pouvoir contrôler votre robot. Le serveur Web fonctionne bien sur un ordinateur portable ou un smartphone.
Vous ne pouvez ouvrir le serveur Web que sur un seul appareil/onglet à la fois.
Emballer
Dans ce didacticiel, vous avez appris à construire un robot télécommandé à l’aide de l’ESP32-CAM et à le contrôler à l’aide d’un serveur Web.
Contrôler les moteurs à courant continu avec l’ESP32-CAM revient à les contrôler à l’aide d’un ESP32 « régulier ». Lisez ce didacticiel pour en savoir plus : ESP32 avec moteur à courant continu et pilote de moteur L298N – Contrôle de la vitesse et de la direction.
Si vous souhaitez contrôler votre robot en dehors de la portée de votre réseau local, vous pouvez envisager de configurer l’ESP32-CAM comme point d’accès. De cette façon, l’ESP32-CAM n’a pas besoin de se connecter à votre routeur, il crée son propre réseau wi-fi et les appareils wi-fi à proximité comme votre smartphone peuvent s’y connecter.
Pour plus de projets et de tutoriels avec l’ESP32-CAM :