El ESP32 AC MotorShield es una placa de extensión que permite a un ESP32 NodeMCU controlar dos motores de corriente continua o un motor paso a paso. Hemos visto cómo accionar un motor de corriente continua utilizando un puente en H, que puede requerir mucho cableado cuando sólo se utiliza el circuito integrado. Para una aplicación a bordo, como un robot Willy, necesitarás accionar varios motores en paralelo. Existen escudos para simplificar el montaje.
Hardware
- Ordenador
- NodoMCU ESP32
- Cable USB A macho
- AC Motor Shield ESP32
- Motor CC x2 o motor paso a paso x1
- Fuente de alimentación externa de 9 V
Principio de funcionamiento
El ESP32 AC MotorShield utiliza el doble puente en H SN751044NE. Puede accionar motores en dirección y velocidad con una tensión nominal de entre 4,5 y 36V y una corriente de 1A con una fuente de tensión externa:
- hasta dos motores de corriente continua o un motor paso a paso bipolar
- GPIOs disponibles
- Buses I2C y UART
Diagrama
Compatible avec la carte NodoMCU ESP32, le shield se place directement sur le microcontrôleur. L’alimentation des moteurs se branche au bornier VM/GND et celle de la carte au bornier VIN/GND. Les moteurs se branchent sur les borniers A+,A-,B+,B-.
- 0,4 (motor A
- 15, 2 (motor B
- GPIOs disponibles en otros pines
En el caso de un escudo, las conexiones están predefinidas. Las conexiones del motor se detallan en los siguientes diagramas.
En los dos ejemplos siguientes, añadimos una interfaz web que permite probar los motores en ambos sentidos de giro.
Código de gestión de un motor de corriente continua
Para interactuar con MotorShield ESP32 y accionar motores DC, no utilizamos ninguna librería en particular. Siempre puedes crear tu propia librería para simplificar tu código.
#include <WiFi.h> #include <WebServer.h> #include <Arduino.h> #include <analogWrite.h> #define IN1 34 //sensor #define OUT1 0 //A+ - Black #define OUT2 4 //A- - Green #define OUT3 15 //B+ - Red #define OUT4 2 //B- - Blue //Motor param int Steps = 0; int Direction = 0; int speedMotor = 150; //Wifi const char *ssid = "****"; const char *password = "*****"; WebServer server(80); const int led = 2; int stateMotorA = 0,stateMotorB = 0; char stateMotorTextA[3][10] = {"STOP","CCW!","CW!"}; char stateMotorTextB[3][10] = {"STOP","CCW!","CW!"}; String sensorValue; /********************************************************************************************* * HANDLE FUNCTIONS *********************************************************************************************/ void handleRoot() { String page = "<!DOCTYPE html>"; page += "<html lang='fr'>"; page += "<head>"; page += " <title>ESP32MotorShieldV1</title>"; page += " <meta http-equiv='refresh' content='60' name='viewport' content='width=device-width, initial-scale=1' charset='UTF-8' />"; page += " <link rel='stylesheet' href='https://www.w3schools.com/w3css/4/w3.css'>"; page += "<script>"; page += "function getData() {"; page += " var xhttp = new XMLHttpRequest();"; page += " xhttp.onreadystatechange = function() {"; page += " if (this.readyState == 4 && this.status == 200) {"; page += " document.getElementById('SensorValue').innerHTML =this.responseText;"; page += " console.log(this.responseText);"; page += " }"; page += " };"; page += " xhttp.open('GET', 'readSensor', true);"; page += " xhttp.send();"; page += "}"; page += "setInterval(function() {getData();}, 2000); // Call a function repetatively with 2s interval"; page += "</script>"; page += "</head>"; page += "<body>"; page += " <div class='w3-card w3-padding-small w3-jumbo w3-center' style='color:#fff; background-color:#3aaa35;'>"; page += " <p>Motor State A: "; page += stateMotorTextA[stateMotorA]; + "</p>"; page += " </div>"; page += " <div class='w3-bar'>"; page += " <a href='/lefta' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>GAUCHE</a>"; page += " <a href='/stopa' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>STOP</a>"; page += " <a href='/righta' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>DROITE</a>"; page += " </div>"; page += " <div class='w3-card w3-padding-small w3-jumbo w3-center' style='color:#fff; background-color:#3aaa35;'>"; page += " <p>Motor State B: "; page += stateMotorTextB[stateMotorB]; + "</p>"; page += " </div>"; page += " <div class='w3-bar'>"; page += " <a href='/leftb' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>GAUCHE</a>"; page += " <a href='/stopb' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>STOP</a>"; page += " <a href='/rightb' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>DROITE</a>"; page += " </div>"; page += " <div class='w3-card w3-padding-small w3-jumbo w3-center' style='color:#fff; background-color:#3aaa35;'>"; page += " <p>Sensor value: <span id='SensorValue'>0</span></p>"; page += " </div>"; page += " <div class='w3-center w3-padding-16'>"; page += " <p>Server hosted on NodoMCU ESP32 - <i>Made by <a href='https://www.aranacorp.com' style='color:#3aaa35;'>AranaCorp</a></i></p>"; page += " "; page += " </div>"; page += "</body>"; page += "</html>"; server.setContentLength(page.length()); server.send(200, "text/html", page); } void handleLeftA(){ stateMotorA = 2; digitalWrite(led, HIGH); server.sendHeader("Location","/"); server.send(303); } void handleRightA(){ stateMotorA = 1; digitalWrite(led, LOW); server.sendHeader("Location","/"); server.send(303); } void handleStopA(){ stateMotorA = 0; digitalWrite(led, HIGH); server.sendHeader("Location","/"); server.send(303); } void handleLeftB(){ stateMotorB = 2; digitalWrite(led, HIGH); server.sendHeader("Location","/"); server.send(303); } void handleRightB(){ stateMotorB = 1; digitalWrite(led, LOW); server.sendHeader("Location","/"); server.send(303); } void handleStopB(){ stateMotorB = 0; digitalWrite(led, HIGH); server.sendHeader("Location","/"); server.send(303); } void handleInput() { sensorValue = String(analogRead(IN1)); server.send(200, "text/plain", sensorValue); //Send ADC value only to client ajax request } void handleNotFound(){ digitalWrite(led, HIGH); stateMotorA = 0; stateMotorB = 0; server.send(404, "text/plain", "404: Not found"); } /********************************************************************************************* * MAIN *********************************************************************************************/ void setup() { pinMode(IN1, INPUT); pinMode(OUT1, OUTPUT); pinMode(OUT2, OUTPUT); pinMode(OUT3, OUTPUT); pinMode(OUT4, OUTPUT); Serial.begin(115200); delay(1000); Serial.println("\n"); pinMode(led, OUTPUT); digitalWrite(led, HIGH); WiFi.persistent(false); WiFi.begin(ssid, password); Serial.print("Tentative de connexion..."); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); } Serial.println("\n"); Serial.println("Connexion etablie!"); Serial.print("Adresse IP: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/lefta", handleLeftA); server.on("/righta", handleRightA); server.on("/stopa", handleStopA); server.on("/leftb", handleLeftB); server.on("/rightb", handleRightB); server.on("/stopb", handleStopB); server.on("/readSensor", handleInput);//To get sensor value update server.onNotFound(handleNotFound); server.begin(); Serial.println("Serveur web actif!"); } void loop() { server.handleClient(); //Handle motor A switch(stateMotorA) { case 0: analogWrite(OUT1, 0); analogWrite(OUT2, 0); break; case 1: analogWrite(OUT1, speedMotor); analogWrite(OUT2, 0); break; case 2: analogWrite(OUT1, 0); analogWrite(OUT2, speedMotor); break; } //Handle motor B switch(stateMotorB) { case 0: analogWrite(OUT3, 0); analogWrite(OUT4, 0); break; case 1: analogWrite(OUT3, speedMotor); analogWrite(OUT4, 0); break; case 2: analogWrite(OUT3, 0); analogWrite(OUT4, speedMotor); break; } }
Código de gestión del motor paso a paso
Para accionar un motor paso a paso, las bobinas del motor deben activarse en una secuencia precisa. Esta secuencia se describe en la función step de la librería stepper.h
/* Nema | Board pin | NodeMCU GPIO | Arduino IDE black A+ 0 0 green A- 4 4 red B+ 15 15 blue B- 2 2 */ #include <WiFi.h> #include <WebServer.h> #include <Arduino.h> #include <analogWrite.h> #include <Stepper.h> #define IN1 34 //sensor #define OUT1 0 //A+ - Black #define OUT2 4 //A- - Green #define OUT3 15 //B+ - Red #define OUT4 2 //B- - Blue //Stepper param const int stepsPerRevolution = 200; int speedMotor = 20; Stepper myStepper(stepsPerRevolution, OUT1, OUT2, OUT3, OUT4); //Wifi const char *ssid = "*****"; const char *password = "********"; WebServer server(80); const int led = 2; int stateStepper = 0,stateStepperB = 0; char stateStepperText[3][10] = {"STOP","CCW!","CW!"}; String sensorValue; /********************************************************************************************* * HANDLE FUNCTIONS *********************************************************************************************/ void handleRoot() { String page = "<!DOCTYPE html>"; page += "<html lang='fr'>"; page += "<head>"; page += " <title>ESP32MotorShieldV1</title>"; page += " <meta http-equiv='refresh' content='60' name='viewport' content='width=device-width, initial-scale=1' charset='UTF-8' />"; page += " <link rel='stylesheet' href='https://www.w3schools.com/w3css/4/w3.css'>"; page += "<script>"; page += "function getData() {"; page += " var xhttp = new XMLHttpRequest();"; page += " xhttp.onreadystatechange = function() {"; page += " if (this.readyState == 4 && this.status == 200) {"; page += " document.getElementById('SensorValue').innerHTML =this.responseText;"; page += " console.log(this.responseText);"; page += " }"; page += " };"; page += " xhttp.open('GET', 'readSensor', true);"; page += " xhttp.send();"; page += "}"; page += "setInterval(function() {getData();}, 2000); // Call a function repetatively with 2s interval"; page += "</script>"; page += "</head>"; page += "<body>"; page += " <div class='w3-card w3-padding-small w3-jumbo w3-center' style='color:#fff; background-color:#3aaa35;'>"; page += " <p>Stepper State: "; page += stateStepperText[stateStepper]; + "</p>"; page += " </div>"; page += " <div class='w3-bar'>"; page += " <a href='/left' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>GAUCHE</a>"; page += " <a href='/stop' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>STOP</a>"; page += " <a href='/right' class='w3-bar-item w3-button w3-border w3-jumbo' style='width:33%; height:50%;'>DROITE</a>"; page += " </div>"; page += " <div class='w3-card w3-padding-small w3-jumbo w3-center' style='color:#fff; background-color:#3aaa35;'>"; page += " <p>Sensor value: <span id='SensorValue'>0</span></p>"; page += " </div>"; page += " <div class='w3-center w3-padding-16'>"; page += " <p>Server hosted on NodoMCU ESP32 - <i>Made by <a href='https://www.aranacorp.com' style='color:#3aaa35;'>AranaCorp</a></i></p>"; page += " "; page += " </div>"; page += "</body>"; page += "</html>"; server.setContentLength(page.length()); server.send(200, "text/html", page); } void handleLeft(){ stateStepper = 2; digitalWrite(led, HIGH); server.sendHeader("Location","/"); server.send(303); } void handleRight(){ stateStepper = 1; digitalWrite(led, LOW); server.sendHeader("Location","/"); server.send(303); } void handleStop(){ stateStepper = 0; digitalWrite(led, HIGH); server.sendHeader("Location","/"); server.send(303); } void handleInput() { sensorValue = String(analogRead(IN1)); server.send(200, "text/plain", sensorValue); //Send ADC value only to client ajax request } void handleNotFound(){ digitalWrite(led, HIGH); stateStepper = 0; server.send(404, "text/plain", "404: Not found"); } /********************************************************************************************* * MAIN *********************************************************************************************/ void setup() { pinMode(IN1, INPUT); Serial.begin(115200); delay(1000); Serial.println("\n"); pinMode(led, OUTPUT); digitalWrite(led, HIGH); myStepper.setSpeed(speedMotor); WiFi.persistent(false); WiFi.begin(ssid, password); Serial.print("Tentative de connexion..."); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); } Serial.println("\n"); Serial.println("Connexion etablie!"); Serial.print("Adresse IP: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/left", handleLeft); server.on("/right", handleRight); server.on("/stop", handleStop); server.on("/readSensor", handleInput);//To get sensor value update server.onNotFound(handleNotFound); server.begin(); Serial.println("Serveur web actif!"); } void loop() { server.handleClient(); //Handle Stepper switch(stateStepper) { case 0: //stop break; case 1: myStepper.step(1); break; case 2: myStepper.step(-1); break; } }
Aplicaciones
- Controla un robot de dos ruedas como Willy mediante una conexión WiFi o Bluetooth