Pilotare un motore passo-passo con un server web

In questo post realizzeremo insieme un sistema per pilotare, tramite un server, la  rotazione di un motore da remoto.

Introduzione

Grazie ad Internet e alla disponibilità di microcontrollori  a basso costo, realizzare sistemi di controllo da remoto, definiti anche IOT (Internet of Things), sono alla portata di tutti.

In questo post realizzeremo insieme un sistema per pilotare, tramite un server, la  rotazione di un motore da remoto.

Questo progetto  può avere diverse applicazioni pratiche, per esempio la rotazione di una telecamera, l’apertura  di una  porta, un distributore  d’alimenti per animali ecc.

Suggeritemi  nei commenti altre possibili soluzioni d’uso di questo progetto, potrebbe essere  argomento di un altro post.

Anche in questo progetto, utilizzeremo il sistema ESP32.

Da italiano dovrei  promuovere l’utilizzo di Arduino, ottimo progetto e con numerosissime  soluzioni molto valide, ma quello che mi spinge ad usare l’ESP32 è il costo d’acquisto molto basso insieme alle ottime caratteristiche.

Prima di iniziare la lettura del post vi consiglio di leggere prima l’articolo  sul mio sito   in cui descrivo le caratteristiche  e  il processo di funzionamento del motore passo passo link

Comunque ho in “cantiere” diversi progetti in cui utilizzerò dei sistemi con Arduino.

Come ruotare un motore a distanza con l’ESP32

Implementeremo un server connesso ad un motore passo passo.

Il server mostrerà una pagina HTML, con un form per l’inserimento dei comandi da  far eseguire al motore, che sono la direzione di rotazione e il numero di  passi e quindi l’angolo di rotazione.

Sul microcontrollore ESP32  verrà installato un server connesso alla rete Internet , tramite un wi-fi domestico oppure tramite una SIM di un operatore mobile.

Utilizzeremo il motore passo passo 28BYJ-48 , con il relativo driver ULN2003, che solitamente è venduto  abbinato con il motore.

Figura 1

Come collegare un motore 28BYJ-48  al driver ULN2003

Il motore 28BYJ-48  ha due bobine e ciascuna di esse ha una presa centrale.

Le due prese centrali sono collegate internamente e pertanto in uscita ci sono  5 fili, l’alimentazione è il filo rosso.

Nella figura di seguito è riportata l’immagine del motore con i collegamenti interni degli induttori e la sua pin function.

Figura 2

Il motore esegue uno step completo di 11,25°, ma al suo interno c’è un riduttore di 64, pertanto, un singolo passo può eseguire una rotazione di:

Il numero di passi per effettuare una rotazione completa è dato dalla seguente relazione:

Per effettuare un giro completo il motore deve eseguire 2048 passi.

La corrente massima d’uscita dell’ESP32 non  può pilotare direttamente gli induttori del motore, per questo motivo è necessario introdurre un driver  tra i due dispositivi.

Il motore è solitamente venduto in abbinamento al driver ULN2003, prodotto dalla Texas Instruments.

Il circuito integrato ULN200A  è  formato da sette di transistor Darlington e la corrente massima d’uscita è  500 mA, idoneo per pilotare il nostro motore.

Schema elettrico  

Lo schema elettrico è molto semplice:

Figura 3

Possiamo osservare che in questo progetto l’alimentazione è fornita tramite un alimentatore esterno, ma è anche possibile, sui modelli che hanno anche la tensione 5v disponibile, prelevarla direttamente dalla scheda.

Codice

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>
 
// Impstazioni del motore passo passo
const int NumeroMaxGiro = 2048;  // Il numero di step del motore, per un angolo giro
#define IN1 17
#define IN2 16
#define IN3 4
#define IN4 0 
Stepper myStepper(NumeroMaxGiro, IN1, IN3, IN2, IN4);
 
// le credenziali della tua rete wifi
const char* ssid = "--------";
const char* password = "-------";
 
// Creamo un ogegtto server sulla porta 80
AsyncWebServer server(80);
 
//  I parametri di impostazione della rotazione 
const char* Parametro_direzione = "direzione";
const char* Parametro_numero_passi = "psssi";
 
// Le variabili per salvare i valori impostati nel form HTML
String direzione;
String psssi;
 
// Variabile per il controllo di una nuova richiesta
bool NuovaRichiesta = false;
 
// Pagina HTML del server
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html> 
<html>
<head>
  <title>Motore Passo Passo </title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <h1> Controllo del Motore Passo Passo</h1>
    <form action="/" method="POST">
      <input type="radio" name="direzione" value="CW" checked>
      <label for="CW"> Direzione orario </label>
      <input type="radio" name="direzione" value="CCW">
      <label for="CW">Direzione antiorario</label><br><br><br>
      <label for="psssi">Numero di psssi:</label>
      <input type="number" name="psssi">
      <input type="submit" value="Vai!">
    </form>
</body>
</html>
)rawliteral";
 
// connessione alla tua rete wifi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("mi sto connetendo al WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
		Serial.print('.');
		delay(1000);
  }
  Serial.println(WiFi.localIP());
}
 
 
void setup() {
  Serial.begin(115200);
 
  initWiFi();
 
  myStepper.setSpeed(5);
 
  // Root URL  del web server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(200, "text/html", index_html);
  });
   
  // gestire le richieste dal form
  server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
    int params = request->params();
    for(int i=0;i<params;i++){
      AsyncWebParameter* p = request->getParam(i);
      Serial.println(HTTP_POST);
      if(p->isPost()){
        // HTTP POST  (direzione)
        if (p->name() == Parametro_direzione) {
          direzione = p->value().c_str();
          Serial.print("direzione set to: ");
          Serial.println(direzione);
        }
        // HTTP POST (passi)
        if (p->name() == Parametro_numero_passi) {
          psssi = p->value().c_str();
          Serial.print("Numero di passi: ");
          Serial.println(psssi);
        }
      }
    }
    request->send(200, "text/html", index_html);
    NuovaRichiesta = true;
  });
 
  server.begin();
}
 
void loop() {
  //  verifica di una nuova richiesta
  if (NuovaRichiesta){
    if (direzione == "CW"){
      // rotazione del motore in senso orario
      myStepper.step(psssi.toInt());
    }
    else{
      // rotazione del motore in senso anti orario
      myStepper.step(-psssi.toInt());
    }
    NuovaRichiesta = false;
  }
}

Descrizione

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>

Come quasi tutte le applicazioni si inserisco le librerie.

La libreria WiFI, per la  connessione alla rete domestica, mentre le librerie AsyncTCP e ESPAsyncWebServer  per  il server e in ultimo la libreria Stepper per il motore passo passo.

const int NumeroMaxGiro = 2048;

Questo il numero massimo di passi che può effettuare il motore, nel nostro caso corrisponde a 2048, come spiegato nel paragrafo precedente.

#define IN1 17
#define IN2 16
#define IN3 4
#define IN4 0 

Assegnazione dei pins  per il collegamento al motore tramite il driver ULN2003.

Stepper myStepper(NumeroMaxGiro, IN1, IN3, IN2, IN4);

Inizializziamo la libreria myStepper indicando il numero massimo di passi  e i pins usati sull’ESP32.

// le credenziali della tua rete wifi
const char* ssid = "--------";
const char* password = "-------";
 
// Creamo un ogegtto server sulla porta 80
AsyncWebServer server(80);

Credenziali connessione  wifi.

//  I parametri di impostazione della rotazione 
const char* Parametro_direzione = "direzione";
const char* Parametro_numero_passi = "psssi";
 
// Le variabili per salvare i valori impostati nel form HTML
String direzione;
String psssi;
 

Inizializziamo le variabili che devono essere visualizzate sul nostro server.

In questa applicazione selezioneremo il senso di rotazione e numero di passi che deve eseguire il motore.

// Variabile per il controllo di una nuova richiesta
bool NuovaRichiesta = false;

Questa variabile sarà usata per memorizzare una nuova richiesta sul server.

// Pagina HTML del server
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html> 
<html>
<head>
  <title>Motore Passo Passo </title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <h1> Controllo del Motore Passo Passo</h1>
    <form action="/" method="POST">
      <input type="radio" name="direzione" value="CW" checked>
      <label for="CW"> Direzione orario </label>
      <input type="radio" name="direzione" value="CCW">
      <label for="CW">Direzione antiorario</label><br><br><br>
      <label for="psssi">Numero di psssi:</label>
      <input type="number" name="psssi">
      <input type="submit" value="Vai!">
    </form>
</body>
</html>
)rawliteral";

Questa è la sezione  HTML  del form per la visualizzazione della pagina WEB.

L’elemento action,  è l’azione che deve eseguire il nostro sistema.

Quando l’utente preme il pulsante invio, i dati sono forniti al server (ESP32).

In questo caso il metodo d’invio è il POST.

Il metodo POST invia i dati al server nel corpo del messaggio, a differenza del metodo GET li  invia nell’indirizzo web che ritorna al server.

Con il comando “radio” inviamo al server ESP32 le indicazioni sulla direzione di rotazione del motore.

 // Root URL  del web server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(200, "text/html", index_html);
  });

Avviamo il server  e invia la risposta al client dopo la connessione, come da protocollo.

// gestire le richieste dal form
  server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
    int params = request->params();
    for(int i=0;i<params;i++){
      AsyncWebParameter* p = request->getParam(i);
      Serial.println(HTTP_POST);
      if(p->isPost()){
        // HTTP POST  (direzione)
        if (p->name() == Parametro_direzione) {
          direzione = p->value().c_str();
          Serial.print("direzione set to: ");
          Serial.println(direzione);
        }
        // HTTP POST (passi)
        if (p->name() == Parametro_numero_passi) {
          psssi = p->value().c_str();
          Serial.print("Numero di passi: ");
          Serial.println(psssi);
        }
      }
    }
    request->send(200, "text/html", index_html);
    NuovaRichiesta = true;
  });

Gestiamo le richieste e individuiamo le variabili per il comando che deve eseguire il motore (direzione e numero di passi).

void loop() {
  //  verifica di una nuova richiesta
  if (NuovaRichiesta){
    if (direzione == "CW"){
      // rotazione del motore in senso orario
      myStepper.step(psssi.toInt());
    }
    else{
      // rotazione del motore in senso anti orario
      myStepper.step(-psssi.toInt());
    }
    NuovaRichiesta = false;
  }
}

Questa parte di codice esegue il comando richiesto dal client sul server ad ogni nuova richiesta.

Conclusioni

Con questo progetto si possono realizzare innumerevoli progetti, se avete dei suggerimenti e/o dei quesiti non esitate a scrivere nel form di seguito.

BUON LAVORO!

Lascia una risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Ti sei iscritto alla newsletter

There was an error while trying to send your request. Please try again.

Quattrodispositivi utilizzerà le informazioni fornite in questo modulo per restare in contatto con te e fornire aggiornamenti del sito