N.B. Ce tutoriel a été mis à jour le 2 août 2019 (ajout d'informations concernant l'ESP32).
Il y a quelques semaines, nous nous sommes amusés à contrôler un moteur à courant continu par WiFi grâce à un ESP8266 ou un ESP32.
L'expérience d'aujourd'hui est dans le même ordre d'idées, sauf que nous contrôlerons cette fois-ci un moteur pas à pas.
Une page web nous permettra de choisir le nombre de pas effectués par le moteur, la direction de sa rotation (horaire ou antihoraire) ainsi que le temps écoulé entre deux pas consécutifs (ce qui influencera évidemment la vitesse de rotation du moteur).
Matériel nécessaire
Un moteur pas à pas (j'ai utilisé un moteur bipolaire provenant d'une vieille imprimante), une carte de développement munie d'un ESP8266 ou d'un ESP32, un double pont en H (j'ai utilisé un module L298N), et un accès à un réseau WiFi.
Préparation de l'IDE Arduino
L'IDE Arduino ne dispose pas par défaut des fichiers nécessaires pour programmer l'ESP8266 ou l'ESP32: si ce n'est pas déjà fait, vous pouvez consulter une marche à suivre détaillée pour l'ESP8266 ou pour l'ESP32.
Le circuit
Sans trop de surprise, le circuit est très similaire à celui que nous avions utilisé pour le contrôle d'un moteur électrique conventionnel, sauf que le moteur pas à pas accapare toutes les sorties du module L298N.
Dans le sketch (disponible un peu plus loin), j'ai supposé que le moteur pas à pas allait être contrôlé par les broches GPIO 4, GPIO5, GPIO 14 et GPIO 16.
Voici le schéma du circuit pour le module ESP32 que j'utilise (sur cette carte, la broche GPIO 16 est identifiée par "RX2"):
Avec une petite carte Wemos D1 Mini, ça donne ça (la numérotation sur la carte n'est pas le numéro de GPIO: on utilise D2, D1, D5 et D0):
Et voici sur le schéma et les instructions pour un module ESP-12 programmé au moyen d'un convertisseur USB-TTL:
L'ESP8266 nécessite une alimentation de 3,3 V, ce qui est trop faible pour la plupart des moteurs pas à pas, d'où les deux alimentations distinctes.
- 3 broches de l'ESP8266 sont connectées à 3,3 V: VCC, RST et CH_PD (aussi appelée "EN" sur certains modèles).
- 2 broches de l'ESP8266 sont connectées à la masse: GND et GPIO0.
- La broche RXD de l'ESP8266 est reliée à la broche TX du convertisseur USB-TTL, et la broche TXD de l'ESP8266 est reliée à la broche RX du convertisseur USB-TTL.
- Les broches GPIO4, GPIO5, GPIO14 et GPIO16 de l'ESP8266 sont branchées à IN1, IN2, IN3 et IN4 du module 298N, puisqu'elles sont responsables de contrôler le moteur.
- Toutes les masses sont reliées ensemble (GND de l'ESP8266, du convertisseur USB-TTL et du module L298N).
Le sketch
La fonction "construitPage()" retourne une chaîne de caractères contenant la totalité de la page web, en langage html. Cette page web contient un champ qui permettra à l'utilisateur de déterminer de combien de pas il veut faire tourner le moteur, une paire de boutons radio permettant de choisir le sens de rotation, un champ permettant de choisir le délai en millisecondes entre deux pas consécutifs, et finalement un bouton "appliquer" qu'on clique pour que les nouveaux paramètres soient pris en compte par le microcontrôleur.
La fonction "gestionPage()" est appelée lors d'un clic sur le bouton "Appliquer". Elle met à jour quelques variables globales en fonction des choix faits par l'utilisateur de la page web, et indique les paramètres choisis dans le moniteur série (ce qui sera surtout utile pour le débogage).
prochainStep() et gestionMoteur() sont responsable de faire tourner le moteur avec les paramètres spécifiés (j'ai choisi de ne pas utiliser la bibliothèque Stepper).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************************************************** | |
ESP8266 Pas à pas | |
Contrôle d'un moteur pas à pas au moyen d'une page Web. | |
Compatible ESP8266 et ESP32. | |
https://electroniqueamateur.blogspot.com/2018/08/moteur-pas-pas-controle-par-wifi-esp8266.html | |
***********************************************************************/ | |
// inclusion des bibliothèques utiles | |
#if defined ARDUINO_ARCH_ESP8266 // s'il s'agit d'un ESP8266 | |
#include <ESP8266WiFi.h> | |
#include <ESP8266WebServer.h> | |
#elif defined ARDUINO_ARCH_ESP32 // s'il s'agit d'un ESP32 | |
#include "WiFi.h" | |
#include <WebServer.h> | |
#endif | |
// modifiez ces deux constantes pour qu'elles contiennent les caractéristiques de | |
// votre réseau Wifi | |
#define ssid "**********" // le nom (SSID) de votre réseau WiFi | |
#define password "**********" // votre mot de passe WiFi | |
// le moteur est contrôlé par les GPIO 4, 5, 14 ete 16 de l'ESP8266 | |
#define pinMoteur1a 4 | |
#define pinMoteur1b 5 | |
#define pinMoteur2a 14 | |
#define pinMoteur2b 16 | |
#if defined ARDUINO_ARCH_ESP8266 // s'il s'agit d'un ESP8266 | |
ESP8266WebServer server(80); | |
#elif defined ARDUINO_ARCH_ESP32 // s'il s'agit d'un ESP32 | |
WebServer server(80); | |
#endif | |
// Les trois variables indiquant le sens, le nombre de pas et le delai entre chaque pas | |
// ce sont des strings, puisque leur contenu provient des champs de texte de la page web | |
String sensSTR = "1"; // peut prendre les valeurs 0 (horaire) ou 1 (antihoraire) | |
String nombrePasSTR = "10"; // nombre de pas | |
String delaiSTR = "100"; | |
/* La fonction construitPage retourne un string qui contient toute notre page web */ | |
String construitPage() { | |
String bouton1Str, bouton2Str; | |
// pour que le bon bouton demeure coché: | |
if (sensSTR == "1") { | |
bouton1Str = "checked"; | |
} | |
if (sensSTR == "2") { | |
bouton2Str = "checked"; | |
} | |
String page = "<html lang=fr-FR><head>"; | |
page += "<title>ESP8266 / ESP32 Moteur pas à pas</title>"; | |
page += "<style> body { background-color: #fffff; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }</style>"; | |
page += "</head><body><h1>Moteur pas à pas</h1>"; | |
page += "<form action='/' method='POST'>"; | |
page += "<h3>Nombre de pas:</h3>"; | |
page += "<p><INPUT type='text' name='pas' value='" + nombrePasSTR + "'></p>"; | |
page += "<h3>Sens de rotation:</h3>"; | |
page += "<p><INPUT type='radio' name='sens' value='1' " + bouton1Str + ">horaire"; | |
page += "<INPUT type='radio' name='sens' value='2' " + bouton2Str + ">antihoraire</p>"; | |
page += "<h3>Délai (en millisecondes):</h3>"; | |
page += "<p><INPUT type='text' name='delai' value='" + delaiSTR + "'></p>"; | |
page += "<INPUT type='submit' value='Appliquer'><br><br>"; | |
page += "</body></html>"; | |
return page; | |
} | |
/* La fonction gestionPage modifie les caractéristiques du moteur si le bouton | |
Appliquer a été cliqué. */ | |
void gestionPage() { | |
if ( server.hasArg("sens") ) { | |
sensSTR = server.arg("sens"); | |
nombrePasSTR = server.arg("pas"); | |
delaiSTR = server.arg("delai"); | |
Serial.print("Commande recue. Sens: "); | |
Serial.print(sensSTR); | |
Serial.print(" Nombre de pas: "); | |
Serial.print(nombrePasSTR); | |
Serial.print(" Delai: "); | |
Serial.println(delaiSTR); | |
gestionMoteur(); | |
} | |
server.send ( 200, "text/html", construitPage() ); | |
} | |
void prochainStep(int numero) { | |
if (numero == 0) { | |
digitalWrite(pinMoteur1a, true); | |
digitalWrite(pinMoteur1b, false); | |
digitalWrite(pinMoteur2a, true); | |
digitalWrite(pinMoteur2b, false); | |
} | |
if (numero == 1) { | |
digitalWrite(pinMoteur1a, false); | |
digitalWrite(pinMoteur1b, true); | |
digitalWrite(pinMoteur2a, true); | |
digitalWrite(pinMoteur2b, false); | |
} | |
if (numero == 2) { | |
digitalWrite(pinMoteur1a, false); | |
digitalWrite(pinMoteur1b, true); | |
digitalWrite(pinMoteur2a, false); | |
digitalWrite(pinMoteur2b, true); | |
} | |
if (numero == 3) { | |
digitalWrite(pinMoteur1a, true); | |
digitalWrite(pinMoteur1b, false); | |
digitalWrite(pinMoteur2a, false); | |
digitalWrite(pinMoteur2b, true); | |
} | |
} | |
/* Contrôle du moteur par les broches GPIO4 et GPIO5 */ | |
void gestionMoteur() { | |
for (int i = 0; i <= nombrePasSTR.toInt(); i++) { | |
if (sensSTR == "1") { // sens horaire | |
prochainStep(i % 4); | |
} | |
if (sensSTR == "2") { // sens antihoraire | |
prochainStep(3 - (i % 4)); | |
} | |
delay(delaiSTR.toInt()); | |
} | |
} | |
void setup() { | |
// broches qui contrôlent le moteur | |
pinMode(pinMoteur1a, OUTPUT); | |
pinMode(pinMoteur1b, OUTPUT); | |
pinMode(pinMoteur2a, OUTPUT); | |
pinMode(pinMoteur2b, OUTPUT); | |
// pour affichage dans le moniteur série | |
Serial.begin ( 115200 ); | |
// initialisation de la communication WiFi | |
WiFi.begin ( ssid, password ); | |
while ( WiFi.status() != WL_CONNECTED ) { | |
delay ( 500 ); Serial.print ( "." ); | |
} | |
Serial.println ( "" ); | |
Serial.print ( "Maintenant connecte a " ); | |
Serial.println ( ssid ); | |
Serial.print ( "Adresse IP: " ); | |
Serial.println ( WiFi.localIP() ); | |
// On indique le nom de la fonction qui gère l'interraction avec la page web | |
server.on ( "/", gestionPage ); | |
server.begin(); | |
Serial.println ( "Serveur HTTP en fonction" ); | |
} | |
void loop() { | |
server.handleClient(); | |
} |
Le résultat
Au démarrage du programme, l'adresse de la page web construite par l'ESP8266 ou l'ESP32 est affichée dans le moniteur série. Il suffit de coller cette adresse dans un navigateur web pour accéder à la page.
La page web vous permet de choisir le nombre de pas de la prochaine rotation du moteur, le sens de cette rotation, et le délai en millisecondes entre chaque pas. Le moteur devrait se mettre à tourner lorsque vous cliquez sur le bouton "Appliquer".