Serveur Web ESP32 : contrôle du moteur pas à pas (WebSocket)

Serveur Web ESP32 : contrôle du moteur pas à pas (WebSocket)

Dans ce guide, vous apprendrez à créer un serveur Web avec l’ESP32 qui affiche une page Web pour contrôler un moteur pas à pas. La page Web vous permet d’insérer le nombre d’étapes et de sélectionner le sens horaire ou antihoraire. De plus, il indique également si le moteur tourne actuellement ou s’il est arrêté. La communication entre le client et le serveur est réalisée via le protocole WebSocket. Tous les clients sont mis à jour avec l’état actuel du moteur.

Moteur pas à pas de contrôle de serveur Web ESP32 WebSocket Arduino IDE

Ce tutoriel est la deuxième partie de cet article ESP32 Web Server : Control Stepper Motor (HTML Form), mais il peut également être suivi en tant que tutoriel autonome.

Pour mieux comprendre le fonctionnement de ce projet, vous pouvez jeter un œil aux tutoriels suivants :

Table des matières

  1. Conditions préalables
  2. Aperçu du projet
  3. Organisation de vos fichiers :
    1. Fichier HTML
    2. Fichier CSS
    3. Fichier JavaScript
    4. Esquisse Arduino
  4. Télécharger le code et les fichiers
  5. Manifestation

Conditions préalables

Avant de poursuivre le didacticiel, assurez-vous de vérifier les prérequis suivants.

1) Pièces requises

Pour suivre ce tutoriel, vous avez besoin des pièces suivantes :

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

Serveur Web ESP32 controle du moteur pas a pas WebSocket

2) Complément pour les cartes Arduino IDE et ESP32

Nous allons programmer l’ESP32 à l’aide de l’IDE Arduino. Donc, vous devez avoir installé le module complémentaire ESP32. Suivez le tutoriel suivant si vous ne l’avez pas déjà fait :

Si vous souhaitez utiliser VS Code avec l’extension PlatformIO, suivez plutôt le tutoriel suivant pour apprendre à programmer l’ESP32 :

3) Plugin de téléchargement de système de fichiers

Pour télécharger les fichiers HTML, CSS et JavaScript nécessaires à la construction de ce projet sur le système de fichiers ESP32 (SPIFFS), nous utiliserons un plug-in pour Arduino IDE : SPIFFS Filesystem Uploader. Suivez le tutoriel suivant pour installer le plugin filesystem uploader si vous ne l’avez pas déjà fait :

Si vous utilisez VS Code avec l’extension PlatformIO, lisez le didacticiel suivant pour savoir comment télécharger des fichiers sur le système de fichiers :

4) Bibliothèques

Pour compiler ce projet, vous devez installer les bibliothèques suivantes :

Les bibliothèques ESPAsyncWebServer et AsynTCP ne peuvent pas être installées via le gestionnaire de bibliothèque Arduino. Vous devez cliquer sur les liens précédents pour télécharger les fichiers de la bibliothèque. Ensuite, dans votre IDE Arduino, allez dans Sketch> Inclure la bibliothèque> Ajouter une bibliothèque .zip et sélectionnez les bibliothèques que vous venez de télécharger.

Installation de bibliothèques (VS Code + PlatformIO)

Si vous programmez l’ESP32 à l’aide de PlatformIO, vous devez ajouter les lignes suivantes au fichier platformio.ini pour inclure les bibliothèques (modifiez également la vitesse du moniteur série à 115200) :

monitor_speed=115200
lib_deps = ESP Async WebServer
    arduino-libraries/Stepper @ ^1.1.3

5) Diagramme schématique

Le schéma de principe suivant montre les connexions entre le moteur pas à pas et l’ESP32.

ESP32 avec moteur pas à pas 28BYJ-48 et schéma de câblage ULN2003A

Remarque : Vous devez alimenter le pilote de moteur ULN2003APG à l’aide d’une alimentation externe de 5 V.

Pilote de moteur ESP32
EN 1 GPIO 19
EN 2 GPIO 18
IN3 GPIO 5
IN4 GPIO 17

Aperçu du projet

La vidéo suivante montre une démonstration rapide de ce que vous obtiendrez à la fin de ce didacticiel.

L’image suivante montre la page Web que vous allez créer pour ce projet.

Contrôle du moteur pas à pas Démonstration du serveur Web ESP32
  • La page Web affiche un formulaire dans lequel vous pouvez entrer le nombre de pas que vous souhaitez que le moteur déplace et sélectionner la direction : dans le sens des aiguilles d’une montre ou dans le sens inverse des aiguilles d’une montre.
  • Il indique également l’état du moteur : moteur qui tourne ou moteur arrêté. De plus, il y a une icône d’engrenage qui tourne tant que le moteur tourne. L’engrenage tourne dans le sens des aiguilles d’une montre ou dans le sens inverse des aiguilles d’une montre selon la direction choisie.
ESP32 ESP8266 Moteur pas à pas Serveur Web Websocket Comment ça marche
  • Le serveur et le client communiquent via le protocole WebSocket.
  • Lorsque vous cliquez sur GO! bouton, il appelle une fonction Javascript qui envoie un message via le protocole WebSocket avec toutes les informations : étapes et direction (3). Le message est au format suivant :
steps&direction

Ainsi, si vous soumettez 2000 pas et dans le sens des aiguilles d’une montre, le message suivant sera envoyé :

2000&CW
  • En même temps, cela changera l’état du moteur sur la page Web et l’engrenage commencera à tourner dans la bonne direction (2).
  • Ensuite, le serveur reçoit le message (4) et fait tourner le moteur en conséquence (5).
  • Lorsque le moteur s’arrête de tourner (6), l’ESP enverra un message au(x) client(s), également via le protocole WebSocket, informant que le moteur s’est arrêté (7).
  • Le ou les clients reçoivent ce message et mettent à jour l’état du moteur sur la page Web (8).

Organiser vos fichiers

Les fichiers que vous souhaitez télécharger sur le système de fichiers ESP doivent être placés dans un dossier appelé data sous le dossier du projet. Nous allons déplacer trois fichiers dans ce dossier :

  • index.html pour créer la page Web ;
  • style.css pour styliser la page Web ;
  • script.js pour gérer la communication websocket et démarrer/arrêter l’animation de l’engrenage.
Serveur Web ESP32 avec fichiers HTML CSS et JavaScript Structure des fichiers

Vous devez enregistrer les fichiers HTML, CSS et JavaScript dans un dossier appelé data dans le dossier d’esquisse Arduino, comme indiqué dans le diagramme précédent. Nous allons télécharger ces fichiers sur le système de fichiers ESP32 (SPIFFS).

Vous pouvez télécharger tous les fichiers du projet :

Fichier HTML

Créez un fichier appelé index.html avec le contenu suivant :

<!DOCTYPE html>
<html>
<head>
  <title>Stepper Motor</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type="text/css" href="https://www.raspberryme.com/stepper-motor-esp32-websocket/style.css">
  <link rel="icon" type="image/png" href="favicon.png">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>
<body>
  <div class="topnav">
    <h1>Stepper Motor Control <i class="fas fa-cogs"></i></h1>
  </div>
  <div class="content">
        <form>
          <input type="radio" id="CW" name="direction" value="CW" checked>
          <label for="CW">Clockwise</label>
          <input type="radio" id="CCW" name="direction" value="CCW">
          <label for="CW">Counterclockwise</label><br><br><br>
          <label for="steps">Number of steps:</label>
          <input type="number" id="steps" name="steps">
        </form>
        <button onclick="submitForm()">GO!</button>
        <p>Motor state: <span id="motor-state">Stopped</span></p>
        <p><i id="gear" class="fas fa-cog"></i> </p>

  </div>
</body>
<script src="https://www.raspberryme.com/stepper-motor-esp32-websocket/script.js"></script>
</html>

Afficher le code brut

Ce fichier HTML est très similaire à celui utilisé dans le tutoriel précédent. Vous pouvez cliquer ici pour une explication complète du fichier HTML.

Nous avons ajouté des identifiants aux éléments HTML que nous voulons manipuler à l’aide de JavaScript : les boutons radio et le champ de saisie :

  • bouton radio dans le sens des aiguilles d’une montre : id=”CW”
  • bouton radio dans le sens contraire : id=”CCW”
  • champ de saisie des étapes : id= »étapes »
<input type="radio" id="CW" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" id="CCW" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
<label for="steps">Number of steps:</label>
<input type="number" id="steps" name="steps">

Nous voulons envoyer les résultats du formulaire au serveur (ESP32) via le protocole WebSocket. Nous avons donc ajouté un bouton qui, lorsqu’il est cliqué (événement onclick), appelle la fonction javascript définie par l’utilisateur submitForm() qui envoie les résultats au serveur, comme vous le verrez plus tard dans le Rubrique JavaScript.

<button onclick="submitForm()">GO!</button>

De plus, nous avons également ajouté un paragraphe pour afficher l’état du moteur. Nous avons ajouté une balise avec l’identifiant de l’état du moteur afin de pouvoir manipuler le texte entre les balises à l’aide de Javascript.

<p>Motor state: <span id="motor-state">Stopped</span></p>

Enfin, il y a un paragraphe affichant une roue dentée avec l’id= »gear ». Nous avons besoin de cet identifiant pour faire bouger l’équipement.

<p><i id="gear" class="fas fa-cog"></i> </p>

N’oubliez pas que vous devez référencer le fichier JavaScript (scrip.js) dans le fichier HTML comme suit :

<script src="https://www.raspberryme.com/stepper-motor-esp32-websocket/script.js"></script>

Fichier CSS

Créez un fichier nommé style.css avec le contenu suivant :

html {
  font-family: Arial, Helvetica, sans-serif;
}

h1 {
  font-size: 1.8rem;
  color: white;
}

p{
  font-size: 20px;
  text-align: center;
}

.topnav {
  overflow: hidden;
  background-color: #0A1128;
  text-align: center;
}

body {
  margin: 0;
}

.content {
  padding: 20px;
  max-width: max-content;
  margin: 0 auto;
}

input[type=number], select {
  width: 100%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

form{
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}

button {
  background-color: #034078;
  border: none;
  padding: 14px 20px;
  text-align: center;
  font-size: 20px;
  border-radius: 4px;
  transition-duration: 0.4s;
  width: 100%;
  color: white;
  cursor: pointer;
}

button:hover {
    background-color: #1282A2;
}

input[type="radio"] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  border: 2px solid #999;
  transition: 0.2s all linear;
  margin-right: 5px;
  position: relative;
  top: 4px;
  }

input[type="radio"]:checked{
  border: 6px solid #1282A2;
}

#motor-state{
  font-weight: bold;
  color: red;
}

#gear{
  font-size:100px;
  color:#2d3031cb;
}

.spin {
  -webkit-animation:spin 4s linear infinite;
  -moz-animation:spin 4s linear infinite;
  animation:spin 4s linear infinite;
}

.spin-back {
  -webkit-animation:spin-back 4s linear infinite;
  -moz-animation:spin-back 4s linear infinite;
  animation:spin-back 4s linear infinite;
}

@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }

@-moz-keyframes spin-back { 100% { -moz-transform: rotate(-360deg); } }
@-webkit-keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); } }
@keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); } }

Afficher le code brut

Nous avons déjà couvert le fonctionnement du CSS pour le formulaire HTML. Vous pouvez cliquer ici pour une explication détaillée. Jetons un coup d’œil aux parties pertinentes de ce didacticiel.

Nous formatons le texte de l’état du moteur font-weight (gras) et couleur (rouge). Pour faire référence à un identifiant spécifique dans CSS, utilisez # suivi de l’identifiant (#motor-state).

#motor-state{
  font-weight: bold;
  color: red;
}

La ligne suivante formate la couleur et la taille de l’icône d’engrenage – rappelez-vous que son identifiant est gear, nous y faisons donc référence avec #gear :

#gear{
  font-size:100px;
  color:#2d3031cb;
}

Ensuite, nous formatons deux classes spin et spin-back qui ne sont encore attribuées à aucun élément HTML. Nous attribuerons les classes spin et spin-back à l’engrenage à l’aide de JavaScript lorsque le moteur commencera à bouger.

Ces classes utilisent la propriété animation pour faire pivoter l’engrenage. Pour en savoir plus sur le fonctionnement de la propriété d’animation, nous vous recommandons de consulter ce tutoriel rapide.

.spin {
  -webkit-animation:spin 4s linear infinite;
  -moz-animation:spin 4s linear infinite;
  animation:spin 4s linear infinite;
}

.spin-back {
  -webkit-animation:spin-back 4s linear infinite;
  -moz-animation:spin-back 4s linear infinite;
  animation:spin-back 4s linear infinite;
}

@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }

@-moz-keyframes spin-back { 100% { -moz-transform: rotate(-360deg); } }
@-webkit-keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); } }
@keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); } }

Fichier JavaScript

Créez un fichier appelé script.js avec le contenu suivant :

var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
window.addEventListener('load', onload);
var direction;

function onload(event) {
    initWebSocket();
}

function initWebSocket() {
    console.log('Trying to open a WebSocket connection…');
    websocket = new WebSocket(gateway);
    websocket.onopen = onOpen;
    websocket.onclose = onClose;
    websocket.onmessage = onMessage;
}

function onOpen(event) {
    console.log('Connection opened');
}

function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
}

function submitForm(){
    const rbs = document.querySelectorAll('input[name="direction"]');
    direction;
    for (const rb of rbs) {
        if (rb.checked) {
            direction = rb.value;
            break;
        }
    }

    document.getElementById("motor-state").innerHTML = "motor spinning...";
    document.getElementById("motor-state").style.color = "blue";
    if (direction=="CW"){
        document.getElementById("gear").classList.add("spin");
    }
    else{
        document.getElementById("gear").classList.add("spin-back");
    }
    
    var steps = document.getElementById("steps").value;
    websocket.send(steps+"&"+direction);
}

function onMessage(event) {
    console.log(event.data);
    direction = event.data;
    if (direction=="stop"){ 
      document.getElementById("motor-state").innerHTML = "motor stopped"
      document.getElementById("motor-state").style.color = "red";
      document.getElementById("gear").classList.remove("spin", "spin-back");
    }
    else if(direction=="CW" || direction=="CCW"){
        document.getElementById("motor-state").innerHTML = "motor spinning...";
        document.getElementById("motor-state").style.color = "blue";
        if (direction=="CW"){
            document.getElementById("gear").classList.add("spin");
        }
        else{
            document.getElementById("gear").classList.add("spin-back");
        }
    }
}

Afficher le code brut

Voyons comment fonctionne le JavaScript pour ce projet.

La passerelle est le point d’entrée de l’interface WebSocket. window.location.hostname obtient l’adresse de la page actuelle (l’adresse IP du serveur Web)

var gateway = `ws://${window.location.hostname}/ws`;

Créez une nouvelle variable globale appelée websocket.

var websocket;

Créez une autre variable globale appelée direction qui contiendra la direction actuelle du moteur : dans le sens des aiguilles d’une montre, dans le sens inverse ou à l’arrêt.

var direction;

Ajoutez un écouteur d’événement qui appellera la fonction onload lors du chargement de la page Web.

window.addEventListener('load',  onload);

La fonction onload() appelle la fonction initWebSocket() pour initialiser une connexion WebSocket avec le serveur.

function onload(event) {
  initWebSocket();
}

La fonction initWebSocket() initialise une connexion WebSocket sur la passerelle définie précédemment. Nous attribuons également plusieurs fonctions de rappel qui seront déclenchées lorsque la connexion WebSocket est ouverte, fermée ou lorsqu’un message est reçu.

function initWebSocket() {
  console.log('Trying to open a WebSocket connection…');
  websocket = new WebSocket(gateway);
  websocket.onopen = onOpen;
  websocket.onclose = onClose;
  websocket.onmessage = onMessage;
}

Lorsque la connexion est ouverte, imprimez un message dans la console à des fins de débogage.

function onOpen(event) {
  console.log('Connection opened');
}

Si, pour une raison quelconque, la connexion du socket Web est fermée, appelez à nouveau la fonction initWebSocket() après 2000 millisecondes (2 secondes).

function onClose(event) {
  console.log('Connection closed');
  setTimeout(initWebSocket, 2000);
}

Enfin, nous devons gérer ce qui se passe lorsque le formulaire est soumis et lorsque le client reçoit un nouveau message (événement onMessage).

Lorsque le formulaire est soumis, la fonction submitForm() est appelée :

function submitForm(){

Nous commençons par déterminer quel bouton radio est sélectionné. Nous enregistrons la valeur du bouton radio sélectionné dans la variable de direction.

const rbs = document.querySelectorAll('input[name="direction"]');
var direction;
for (const rb of rbs) {
  if (rb.checked) {
    direction = rb.value;
    break;
  }
}

Ensuite, nous changeons le texte de l’état du moteur en rotation du moteur… et sa couleur en bleu. Nous nous référons à cet élément HTML par son id motor-state.

document.getElementById("motor-state").innerHTML = "motor spinning...";
document.getElementById("motor-state").style.color = "blue";

Ensuite, nous vérifions si nous avons sélectionné le sens horaire ou antihoraire pour faire tourner l’engrenage dans la bonne direction. Pour ce faire, nous ajoutons la classe spin ou spin-back à l’élément avec l’identifiant de l’engrenage.

if (direction=="CW"){
  document.getElementById("gear").classList.add("spin");
}
else{
  document.getElementById("gear").classList.add("spin-back");
}

Nous obtenons le nombre d’étapes insérées et l’enregistrons dans la variable étapes.

var steps = document.getElementById("steps").value;

Ensuite, nous envoyons enfin un message via le protocole WebSocket au serveur (ESP32) avec le nombre d’étapes et la direction séparées par un &.

websocket.send(steps+"&"+direction);

Le serveur (votre carte ESP) enverra un message lorsqu’il sera temps de changer l’état du moteur. Lorsque cela se produit, nous enregistrons le message dans la variable de direction.

Nous vérifions le contenu du message et modifions l’état du moteur et l’animation des engrenages en conséquence.

function onMessage(event) {
  console.log(event.data);
  direction = event.data;
  if (direction=="stop"){ 
    document.getElementById("motor-state").innerHTML = "motor stopped"
    document.getElementById("motor-state").style.color = "red";
    document.getElementById("gear").classList.remove("spin", "spin-back");
  }
  else if(direction=="CW" || direction=="CCW"){
    document.getElementById("motor-state").innerHTML = "motor spinning...";
    document.getElementById("motor-state").style.color = "blue";
    if (direction=="CW"){
      document.getElementById("gear").classList.add("spin");
    }
    else{
      document.getElementById("gear").classList.add("spin-back");
    }
  }
}

Esquisse Arduino

Avant de télécharger, vous pouvez utiliser le lien suivant pour :

Copiez le code suivant dans l’IDE Arduino. Insérez vos informations d’identification réseau et cela fonctionnera immédiatement.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/stepper-motor-esp32-websocket/
  
  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 <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Stepper.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);

String message = "";

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Create a WebSocket object
AsyncWebSocket ws("/ws");

//Variables to save values from HTML form
String direction ="STOP";
String steps;

bool newRequest = false;

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else{
    Serial.println("SPIFFS mounted successfully");
  }
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void notifyClients(String state) {
  ws.textAll(state);
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    message = (char*)data;
    steps = message.substring(0, message.indexOf("&"));
    direction = message.substring(message.indexOf("&")+1, message.length());
    Serial.print("steps");
    Serial.println(steps);
    Serial.print("direction");
    Serial.println(direction);
    notifyClients(direction);
    newRequest = true;
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      //Notify client of motor current state when it first connects
      notifyClients(direction);
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
        handleWebSocketMessage(arg, data, len);
        break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
     break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

void setup() {
  // Serial port for debugging purposes

  Serial.begin(115200);
  initWiFi();
  initWebSocket();
  initSPIFFS();
  myStepper.setSpeed(5);

  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", "text/html");
  });
  
  server.serveStatic("/", SPIFFS, "/");

  server.begin();
}

void loop() {
  if (newRequest){
    if (direction == "CW"){
      myStepper.step(steps.toInt());
      Serial.print("CW");
    }
    else{
      myStepper.step(-steps.toInt());
    }
    newRequest = false;
    notifyClients("stop");
  }
  ws.cleanupClients();
}

Afficher le code brut

Le sketch Arduino est très similaire au tutoriel précédent, mais il gère la communication client-serveur en utilisant le protocole WebSocket. Voyons comment cela fonctionne ou passez à la section de démonstration.

Inclure les bibliothèques

Tout d’abord, incluez les bibliothèques requises. Le WiFi, AsyncTCP et ESPAsyncWebServer pour créer le serveur Web, la bibliothèque SPIFFS pour utiliser le système de fichiers ESP32 et la bibliothèque Stepper pour contrôler le moteur pas à pas.

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

Broches du moteur pas à pas et pas par révolution

Définissez les pas par tour de votre moteur pas à pas – dans notre cas, c’est 2048 :

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution

Définissez les broches d’entrée du moteur. Dans cet exemple, nous nous connectons aux GPIO 19, 18, 5 et 17, mais vous pouvez utiliser tout autre GPIO approprié.

#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17

Initialisez une instance de la bibliothèque stepper appelée myStepper. Passez en arguments les pas par tour et les broches d’entrée. Dans le cas du moteur pas à pas 28BYJ-48, l’ordre des broches est IN1, IN3, IN2, IN4—il peut être différent pour votre moteur.

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

Informations d’identification réseau

Insérez vos informations d’identification réseau dans les lignes suivantes.

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

AsyncWebServer et AsyncWebSocket

Créez un objet AsyncWebServer appelé serveur sur le port 80.

AsyncWebServer server(80);

La bibliothèque ESPAsyncWebServer inclut un plugin WebSocket qui facilite la gestion des connexions WebSocket. Créez un objet AsyncWebSocket appelé ws pour gérer les connexions sur le chemin /ws.

AsyncWebSocket ws("/ws");

Initialisation des variables

Les variables suivantes enregistreront la direction et le nombre d’étapes reçues via le protocole WebSocket. Lorsque le programme démarre pour la première fois, le moteur est arrêté.

String direction ="stop";
String steps;

La variable newRequest sera utilisée pour vérifier si une nouvelle requête a eu lieu. Ensuite, dans la boucle (), nous allons faire tourner le moteur lorsqu’une nouvelle requête est reçue, lorsque la variable newRequest est vraie.

bool newRequest = false;

initSPIFFS()

La fonction initSPIFFS() initialise le système de fichiers ESP32.

void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else{
    Serial.println("SPIFFS mounted successfully");
  }
}

initWiFi()

La fonction initWiFi() initialise le WiFi.

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

Gestion des WebSockets – Serveur

Auparavant, vous avez vu comment gérer la connexion WebSocket côté client (navigateur). Voyons maintenant comment le gérer côté serveur.

Aviser tous les clients

La fonction notifyClients() notifie tous les clients avec un message contenant tout ce que vous transmettez comme argument. Dans ce cas, nous voudrons informer tous les clients de l’état actuel du moteur chaque fois qu’il y a un changement.

void notifyClients(String state) {
  ws.textAll(state);
}

La classe AsyncWebSocket fournit une méthode textAll() pour envoyer le même message à tous les clients connectés au serveur en même temps.

Gérer les messages WebSocket

La fonction handleWebSocketMessage() est une fonction de rappel qui s’exécute chaque fois que nous recevons de nouvelles données des clients via le protocole WebSocket.

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    message = (char*)data;
    steps = message.substring(0, message.indexOf("&"));
    direction = message.substring(message.indexOf("&")+1, message.length());
    Serial.print("steps");
    Serial.println(steps);
    Serial.print("direction");
    Serial.println(direction);
    notifyClients(direction);
    newRequest = true;
  }
}

Nous divisons le message pour obtenir le nombre d’étapes et la direction.

message = (char*)data;
steps = message.substring(0, message.indexOf("&"));
direction = message.substring(message.indexOf("&")+1, message.length());

Ensuite, nous informons tous les clients de la direction du moteur afin que tous les clients modifient l’état du moteur sur l’interface Web.

notifyClients(direction);

Enfin, définissez la variable newRequest sur true, afin que les moteurs commencent à tourner dans la boucle().

newRequest = true;

Configurer le serveur WebSocket

Nous devons maintenant configurer un écouteur d’événement pour gérer les différentes étapes asynchrones du protocole WebSocket. Ce gestionnaire d’événements peut être implémenté en définissant onEvent() comme suit :

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      //Notify client of motor current state when it first connects
      notifyClients(direction);
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
        handleWebSocketMessage(arg, data, len);
        break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
     break;
  }
}

L’argument type représente l’événement qui se produit. Il peut prendre les valeurs suivantes :

  • WS_EVT_CONNECT lorsqu’un client s’est connecté ;
  • WS_EVT_DISCONNECT lorsqu’un client s’est déconnecté ;
  • WS_EVT_DATA lorsqu’un paquet de données est reçu du client ;
  • WS_EVT_PONG en réponse à une requête ping ;
  • WS_EVT_ERROR lorsqu’une erreur est reçue du client.

Il y a une section pour informer n’importe quel client de l’état actuel du moteur lors de sa première connexion :

case WS_EVT_CONNECT:
  Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
  //Notify client of motor current state when it first connects
  notifyClients(direction);
  break;

Initialiser WebSocket

Enfin, la fonction initWebSocket() initialise le protocole WebSocket.

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

installation()

Dans setup(), initialisez le Serial Monitor.

Serial.begin(115200);

Appelez la fonction initWiFi() pour initialiser le WiFi.

initWiFi();

Appelez la fonction initSPIFFS() pour initialiser le système de fichiers.

initWebSocket();

Et réglez la vitesse du moteur pas à pas en tr/min.

myStepper.setSpeed(5);

Traiter les demandes

Ensuite, gérez le serveur Web. Lorsque vous recevez une requête sur l’URL root (/), c’est-à-dire lorsque vous accédez à l’adresse IP ESP, envoyez le texte HTML pour créer la page Web :

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

Lorsque le fichier HTML se charge sur votre navigateur, il fera une demande pour les fichiers CSS et JavaScript. Ce sont des fichiers statiques enregistrés dans le même répertoire (SPIFFS). Ainsi, nous pouvons simplement ajouter la ligne suivante pour servir les fichiers dans un répertoire à la demande de l’URL root. Il servira automatiquement les fichiers CSS et JavaScript.

server.serveStatic("/", SPIFFS, "/");

Enfin, démarrez le serveur.

server.begin();

boucle()

Jetons un coup d’œil à la section loop().

Si la variable newRequest est vraie, nous vérifierons quel est le sens de rotation : CW ou CCW. Si c’est CW, nous déplaçons le moteur du nombre de pas enregistrés dans la variable steps en utilisant la méthode step() sur l’objet myStepper. Pour déplacer le moteur dans le sens inverse des aiguilles d’une montre, il suffit de passer le nombre de pas mais avec un signe moins (–).

if (direction == "CW"){
  // Spin the stepper clockwise direction
  myStepper.step(steps.toInt());
}
else{
  // Spin the stepper counterclockwise direction
  myStepper.step(-steps.toInt());
}

Après avoir fait tourner le moteur, définissez la variable newRequest sur false, afin qu’elle puisse à nouveau détecter de nouvelles requêtes.

newRequest = false;

De plus, informez tous les clients que le moteur s’est arrêté.

notifyClients("stop");

Télécharger le code et les fichiers

Après avoir inséré vos informations d’identification réseau, enregistrez le code. Accédez à Sketch > Show Sketch Folder et créez un dossier appelé data.

afficher le dossier de données du dossier d'esquisse Arduino IDE

Dans ce dossier, vous devez enregistrer les fichiers HTML, CSS et JavaScript.

Ensuite, téléchargez le code sur votre carte ESP32. Assurez-vous d’avoir sélectionné la bonne carte et le bon port COM. Assurez-vous également d’avoir ajouté vos informations d’identification réseau.

Bouton de téléchargement Arduino 2.0

Après avoir téléchargé le code, vous devez télécharger les fichiers. Accédez à Outils> ESP32 Data Sketch Upload et attendez que les fichiers soient téléchargés.

Téléchargement de données d'esquisse ESP32 SPIFFS Arduino IDE

Lorsque tout est téléchargé avec succès, ouvrez le moniteur série à un débit en bauds de 115200. Appuyez sur le bouton ESP32 EN/RST, et il devrait imprimer l’adresse IP ESP32.

Manifestation

Ouvrez un navigateur Web ou plusieurs fenêtres de navigateur Web sur votre réseau local et vous accéderez à la page Web pour contrôler le moteur. Soumettez le formulaire pour contrôler le moteur.

Moteur pas à pas ESP32 Web Server Websocket Motor Spinning

L’engrenage sur la page Web commence à tourner dans la bonne direction et le moteur commence à fonctionner.

28BYJ-48 connecté au module ULN2003 Motor Driver 01

Lorsqu’il s’arrête, l’engrenage sur la page Web et l’état du moteur changent en conséquence.

Moteur pas à pas ESP32 Serveur Web Websocket Moteur arrêté

Notez que si vous avez plusieurs clients connectés, tous les clients mettent à jour l’état du moteur presque instantanément.

Regardez la vidéo ci-dessous pour une démonstration en direct.

Conclusion

Dans ce tutoriel, vous avez appris à contrôler un moteur pas à pas à l’aide d’un serveur Web construit avec l’ESP32. Le serveur Web fournit une page Web pour contrôler le moteur pas à pas à l’aide d’un formulaire dont les résultats sont envoyés à l’ESP32 via le protocole WebSocket.

Ceci est la partie 3 d’une série de tutoriels sur le contrôle d’un moteur pas à pas à l’aide d’un serveur Web. Vous pouvez suivre les parties 1 et 2 au lien suivant :

Si vous souhaitez en savoir plus sur les protocoles de communication HTML, CSS, JavaScript et client-serveur pour créer vos serveurs Web ESP32 et ESP8266 à partir de rien, comme nous l’avons fait dans ce didacticiel, assurez-vous de consulter notre eBook :

Nous espérons que vous trouverez ce tutoriel utile.

Merci d’avoir lu.

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video

  • Waveshare ESP32-S3 4.3inch Capacitive Touch Display Development Board, 800x480, 5-Point Capacitive Touch, 32-Bit LX7 Dual-Core Processor, Up to 240MHz Frequency, Support WiFi, with Onboard Antenna
    ESP32-S3-Touch-LCD-4.3 is a microcontroller development board with 2.4GHz WiFi and BLE 5 support, integrates high-capacity Flash and PSRAM. Onboard 4.3inch capacitive touch screen can smoothly run GUI programs such as LVGL Supports capacitive touch control via I2C interface, 5-point touch with interrupt support. Combined with various peripheral interfaces, suitable for the quick development of the HMI and other ESP32-S3 applications Equipped with Xtensa 32-bit LX7 dual-core processor, up to 240MHz main frequency. Supports 2.4GHz Wi-Fi (802.11 b/g/n) and BT5 BLE, with onboard antenna Built in 512KB of SRAM and 384KB ROM, with onboard 8MB PSRAM and 8MB Flash. Onboard 4.3inch capacitive touch display, 800×480 resolution, 65K color. Onboard CAN, RS485, I2C interface and TF card slot, integrates full-speed USB port Supports flexible clock, module power supply independent setting, and other controls to realize low power consumption in different scenarios
  • DollaTek ESP32-C3 Carte de développement WiFi + Bluetooth 5.0 équipée du module Internet des choses ESP32-C3-MINI-1 ESP32 WiFi pour Arduino
    ESP32C3-MINI-1 est un module double Wi-Fi universel et Bluetooth à faible puissance avec des fonctions puissantes. Le module adopte une antenne intégrée PCB et est équipé d'un flash SPI de 4 Mo. En-têtes de broches : toutes les broches GPIO disponibles ont été tirées vers les en-têtes de la carte de développement. 5 V vers 3 V3 LDO : convertisseur de puissance, entrée 5 V, éteint 3,3 V. Interface USB, peut être utilisée comme interface d'alimentation de la carte de développement, peut graver le micrologiciel sur la puce, et peut communiquer avec la puce via le protocole USB.
  • DollaTek ESP32 / ESP32-C3 WiFi + Bluetooth 5.0 Internet Of Things Dual Type-C Development Board Core Board ESP32-C3-DevKitM-1 pour Arduino
    La carte Core Link utilise une puce ESP32-C3FN4 et un module ESP32-C3-MINI intégré avec flash de 4 Mo. L'ESP32-C3-MINI-1 est un module Wi-Fi et Bluetooth à faible énergie (Bluetooth LE) à usage général avec des interfaces périphériques de petite taille et riches, qui peuvent être utilisés dans la maison intelligente, l'automatisation industrielle et d'autres domaines. ESP32-C3. Il est bon de l'utiliser comme un microcontrôleur avec fonctions Wi-Fi et Bluetooth. La plupart des applications n'utilisent pas le Wi-Fi et le Bluetooth. L'ESP32-C3 prend en charge le démarrage sécurisé basé sur l'algorithme RSA 3072 et le cryptage du flash basé sur l'algorithme AES-128-XTS pour garantir une connexion sécurisée des appareils. Module de signature numérique innovant et module HMAC pour garantir la sécurité de l'appareil.