Icono del sitio AranaCorp

Uso de AC MotorShield ESP32

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

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:

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-.

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

Fuentes

Salir de la versión móvil