Nous continuons notre série d’articles sur le pilotage à distance de servomoteur et plus particulièrement les systèmes articulés PTZ (Pan-Tilt). Dans les tutoriels précédents, nous avons vu comment faire pour piloter un servo depuis un smartphone à l’aide des librairies pour IoT Cayenne et Blynk. Dans ce nouveau tutoriel, nous allons en faire de même à l’aide de Node-RED. Pour communiquer avec l’ESP8266 en WiFi (ou depuis internet), nous utiliserons le protocole de communication MQTT (via le broker Mosquitto).
Sommaire
Comment ça marche ?
Le schéma ci-dessous montre comment on peut piloter le système articulé PTZ en Wi-Fi. Nous allons utiliser le module Dashboard UI de Node-RED pour créer 2 sliders (Pan, Tilt). A chaque modification d’un position, Node-RED publie un message sur le broker MQTT. Le message est transmis sur le réseau local (mais aussi via internet en utilisant un broker en ligne tel que cloudMQTT) en WiFi à l’ESP8266. La librairie PubSubClient permet de s’abonner à serveur (Broker) MQTT et de recevoir les messages. Après décodage du message, on déplacer le servomoteur concerné à la position angulaire demandée.
De quoi avez-vous besoin ?
Vous aurez donc besoin d’un ordinateur sur lequel est installé Node-RED. Si vous avez besoin de savoir comment faire, choisissez le tutoriel qui correspond à votre environnement :
Vous aurez également besoin d’un serveur (broker) MQTT. Il en existe plusieurs. Pour ce tutoril, nous utiliserons le broker Open Source Mosquitto développé par la fondation Eclipse. Suivez les instructions de ce tutoriel pour l’installer et le configurer sur Raspbian, Windows ou macOS.
Matériel utilisé pour piloter le bras robotique
Nous allons piloter en WiFi le mini kit Pan/Tilt. Vous pouvez utiliser n’importe quel ESP8266.
Kit robotique 4DOF (4 degrés de liberté)
Le circuit est identique aux tutoriels précédents.
Code Arduino
Pour recevoir (ou envoyer) des messages avec le protocole MQTT, nous allons utiliser la librairie PubSubClient (documentation officielle)
Installation des librairies dans l’IDE Arduino
Avant d’aller plus loin, ouvrez le gestionnaire de librairie et installez les librairies suivantes :
ESP8266
servo(esp8266)
PubSubClient
Comment fonctionne la librairie PubSubClient ?
Ici, nous ne rentrerons pas dans le détail de la connexion au réseau WiFi géré par la librairie ESP8266WiFi. Nous allons uniquement regarder comment s’abonner à plusieurs Topics MQTT et traiter les messages entrants.
La librairie PubSub a besoin d’un objet qui contient la connexion au réseau WiFi. On commence par créer un objet à l’aide de la classe WiFiClient comme ceci
WiFiClient espClient;
Ensuite, on créé un objet client
PubSubClient client(espClient);
Vous trouverez 3 variables au début du programme
- const char* mqtt_server = “xxx.xxx.xxx.xxx” : c’est l’adresse IP de votre serveur (Broker) MQTT
- const char* topic_pan = “servo/pan” : topic qui contient l’angle du servo Pan
- const char* topic_tilt = “servo/tilt” : Topic qui contient l’angle du servo Tilt
Dans la fonction setup(), on réalise les opérations suivantes
- On attache chaque servo sur le Pin qui lui correspond. Par exemple Pan sur D5 et Tilt sur D6
pan.attach(D5); tilt.attach(D6);
- On appel la fonction setupWiFi() qui s’occupe de connecter l’ESP8266 au réseau WiFi local
- On se connecte au broker MQTT sur le port 1883 (le port par défaut) client.setServer(mqtt_server, 1883)
- Enfin on définit une fonction callback qui sera appelée à chaque fois qu’un MQTT message est reçu client.setCallback(callback)
Réception des messages MQTT dans le programme Arduino
La fonction callback (documentation) permet donc de récupérer les messages entrants. Elle contient le topic, le message (payload) et la longueur du message. Avant de pouvoir traiter le message, il faut le convertir en string. Il n’y a aucun helper pour décoder les messages qui arrivent sous la forme d’un tableau de byte. Heureusement, on trouve beaucoup d’exemples sur internet. Voici comment décoder le message entrant
String string; for (int i = 0; i < length; i++) { string+=((char)payload[i]); }
La fonction servo.write(position) acceptant en entrée en entier, on devra convertir le message (payload)
int pos = string.toInt();
Pour déterminer si on doit déplacer le Pan ou le Tilt, on va utiliser la fonction de comparaison de chaînes strcmp. Il renvoi le nombre de caractères différents entre les 2 chaines. S’il n’y a aucune différence (retour = 0), c’est que les deux chaines sont identiques. Ce qui va par exemple nous donner pour le Topic Pan :
if ( strcmp(topic, topic_pan) == 0 ) { Serial.print("Move Pan to "); Serial.println(pos); pan.write(pos); }
Code Arduino complet
Voici le code Arduino complet. Créer un nouveau sketch et modifier les paramètres dans le code avant de téléverser :
- SSID, Password
- Adresse IP broker MQTT
- Broche servo Pan et tilt
/* * Node-RED + MQTT + ESP8266 + PTZ servo kit (Pan-Tilt) * How to move pan-tilt system with Node-RED - MQTT and ESP8266 * - Use Node-RED UI Dashboard to move Pan and Tilt servos * - Node-RED sequencer : scan Pan and tilt * - Node-RED reset position to 90°/90° * * Comment déplacer le système pan-tilt avec Node-RED - MQTT et ESP8266 * - Utilisez le tableau de bord Node-RED UI pour déplacer les servos Pan et Tilt * - Séquenceur Node-RED: balayage panoramique (Pan) et inclinaison (Tilt) * - Reset des positions depuis Node-RED (90°/90°) * - Tutoriel complet * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Licence : MIT * Copyright (C) 2017 : www.projetsdiy.fr and www.diyprojects.io */ #include #include #include Servo pan; Servo tilt; // Paramètre WiFi, MQTT - WiFi, MQTT parameters const char* ssid = "yourSSID"; // WiFi SSID const char* password = "yourPASSWORD"; // WiFi Password const char* mqtt_server = "xxx.xxx.xxx.xxx"; // IP Broker MQTT const char* topic_pan = "servo/pan"; // Topic MQTT pour servo Pan - Topic MQTT for Pan servor const char* topic_tilt = "servo/tilt"; // Topic MQTT pour servo Tilt - Topic MQTT for Tilt servor WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; void setup() { Serial.begin(115200); pan.attach(D5); tilt.attach(D6); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); } void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int length) { String string; // Affiche le topic entrant - display incoming Topic Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); // décode le message - decode payload message for (int i = 0; i < length; i++) { string+=((char)payload[i]); } // Affiche le message entrant - display incoming message Serial.print(string); Serial.print(" toInt "); // Conversion de la position en entier - convert position as an Integer int pos = string.toInt(); Serial.println(pos); // Détermine quel servo doit être bougé - Determines which servo should be moved if ( strcmp(topic, topic_pan) == 0 ) { Serial.print("Move Pan to "); Serial.println(pos); pan.write(pos); } if ( strcmp(topic, topic_tilt) == 0 ) { Serial.print("Move Tilt to "); Serial.println(pos); tilt.write(pos); } delay(15); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect("ESP8266Client")) { Serial.println("connected"); client.subscribe(topic_pan); client.subscribe(topic_tilt); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void loop() { if (!client.connected()) { reconnect(); } client.loop(); delay(100); }
Flow Node-RED
Pour ce flow Nod-RED, vous aurez besoin d’installer plusieurs modules. Ouvrez le gestionnaire de palette (tutoriel complet) et installez les modules suivants
Importez ce code Node-RED directement sur un flow
[{"id":"34545562.076d7a","type":"mqtt out","z":"2555341e.a5485c","name":"","topic":"servo/pan","qos":"1","retain":"false","broker":"ceed5755.206c58","x":680,"y":220,"wires":[]},{"id":"f9a85217.59893","type":"ui_slider","z":"2555341e.a5485c","name":"","label":"Pan","group":"9c59c1e2.8235f","order":4,"width":"6","height":"1","passthru":true,"topic":"","min":0,"max":"180","step":1,"x":510,"y":240,"wires":[["34545562.076d7a","d604bc1e.67691"]]},{"id":"d604bc1e.67691","type":"ui_gauge","z":"2555341e.a5485c","name":"","group":"9c59c1e2.8235f","order":5,"width":"6","height":"6","gtype":"donut","title":"Pan servo position ","label":"position ","format":"{{value}}","min":0,"max":"180","colors":["#00b500","#e6e600","#ca3838"],"x":680,"y":280,"wires":[]},{"id":"3a393dcd.afa272","type":"comment","z":"2555341e.a5485c","name":"ESP8266 MQTT Pan Tilt PTZ Control Servo","info":"","x":210,"y":680,"wires":[]},{"id":"4316c9.3c84a938","type":"mqtt out","z":"2555341e.a5485c","name":"","topic":"servo/tilt","qos":"1","retain":"false","broker":"ceed5755.206c58","x":680,"y":440,"wires":[]},{"id":"9087f6a0.b7e938","type":"ui_slider","z":"2555341e.a5485c","name":"","label":"Tilt","group":"9c59c1e2.8235f","order":4,"width":"6","height":"1","passthru":true,"topic":"","min":0,"max":"180","step":1,"x":410,"y":480,"wires":[["4316c9.3c84a938","584bfb6e.86a1d4"]]},{"id":"584bfb6e.86a1d4","type":"ui_gauge","z":"2555341e.a5485c","name":"","group":"9c59c1e2.8235f","order":5,"width":"6","height":"6","gtype":"donut","title":"Tilt servo position ","label":"position ","format":"{{value}}","min":0,"max":"180","colors":["#00b500","#e6e600","#ca3838"],"x":680,"y":500,"wires":[]},{"id":"6a8f2c2b.64bdb4","type":"ui_button","z":"2555341e.a5485c","name":"","group":"9c59c1e2.8235f","order":0,"width":0,"height":0,"label":"Reset","color":"","icon":"fa-undo","payload":"","payloadType":"str","topic":"","x":270,"y":620,"wires":[["743cd12b.d31b5"]]},{"id":"798e642.411779c","type":"mqtt out","z":"2555341e.a5485c","name":"","topic":"servo/tilt","qos":"1","retain":"false","broker":"ceed5755.206c58","x":640,"y":600,"wires":[]},{"id":"743cd12b.d31b5","type":"function","z":"2555341e.a5485c","name":"Pan (90°) - Tilt(90°)","func":"msg.payload = 90;\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":620,"wires":[["d604bc1e.67691","4336088.add08f8","798e642.411779c","d2553ca9.80fdd","584bfb6e.86a1d4"]]},{"id":"d2553ca9.80fdd","type":"mqtt out","z":"2555341e.a5485c","name":"","topic":"servo/pan","qos":"1","retain":"false","broker":"ceed5755.206c58","x":640,"y":660,"wires":[]},{"id":"3ba0147.632dcec","type":"link in","z":"2555341e.a5485c","name":"","links":["4336088.add08f8","56f0b2a7.b1c81c"],"x":415,"y":240,"wires":[["f9a85217.59893"]]},{"id":"4336088.add08f8","type":"link out","z":"2555341e.a5485c","name":"","links":["3ba0147.632dcec","8117306f.30c94"],"x":595,"y":720,"wires":[]},{"id":"8117306f.30c94","type":"link in","z":"2555341e.a5485c","name":"","links":["4336088.add08f8","56f0b2a7.b1c81c"],"x":315,"y":480,"wires":[["9087f6a0.b7e938"]]},{"id":"89f37cd6.f1a11","type":"comment","z":"2555341e.a5485c","name":"www.projetsdiy.fr | www.diyprojects.io","info":"# Version française \nwww.projetsdiy.fr\n\n# English version\nwww.diyprojects.io","x":190,"y":720,"wires":[]},{"id":"e5657f97.89ffd","type":"repeat","z":"2555341e.a5485c","name":"","repetitions":"18","elseOutput":false,"outputs":1,"x":460,"y":80,"wires":[["68869228.30d7fc"]]},{"id":"d4ee4d5e.0ffcd","type":"ui_button","z":"2555341e.a5485c","name":"","group":"9c59c1e2.8235f","order":0,"width":"6","height":"1","label":"Scan Pan","color":"","icon":"","payload":"-10","payloadType":"num","topic":"","x":180,"y":160,"wires":[["68869228.30d7fc"]]},{"id":"68869228.30d7fc","type":"function","z":"2555341e.a5485c","name":"+10°","func":"var pos = msg.payload;\npos += 10;\nmsg.payload = pos;\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":160,"wires":[["18dca8a0.64c977","f9a85217.59893"]]},{"id":"18dca8a0.64c977","type":"delay","z":"2555341e.a5485c","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":540,"y":160,"wires":[["e5657f97.89ffd"]]},{"id":"549400d6.d1279","type":"repeat","z":"2555341e.a5485c","name":"","repetitions":"18","elseOutput":false,"outputs":1,"x":360,"y":320,"wires":[["593953a.80dfbac"]]},{"id":"fe1eebc1.8d83c8","type":"ui_button","z":"2555341e.a5485c","name":"","group":"9c59c1e2.8235f","order":0,"width":"6","height":"1","label":"Scan Tilt","color":"","icon":"","payload":"-10","payloadType":"num","topic":"","x":100,"y":400,"wires":[["593953a.80dfbac"]]},{"id":"593953a.80dfbac","type":"function","z":"2555341e.a5485c","name":"+10°","func":"var pos = msg.payload;\npos += 10;\nmsg.payload = pos;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":400,"wires":[["4cfcf34c.3c7d3c","9087f6a0.b7e938"]]},{"id":"4cfcf34c.3c7d3c","type":"delay","z":"2555341e.a5485c","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":420,"y":400,"wires":[["549400d6.d1279"]]},{"id":"ceed5755.206c58","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"9c59c1e2.8235f","type":"ui_group","z":"","name":"PTZ Servo Control","tab":"84e11c13.a96e9","order":2,"disp":true,"width":"12"},{"id":"84e11c13.a96e9","type":"ui_tab","z":"","name":"ESP8266","icon":"dashboard","order":2}]
Que fait ce flow ?
On dispose de 2 sliders pour commander la position du servo Pan et du servo Tilt. Un bouton Reset permet de repositionner les 2 servos à 90°. Enfin une boucle repeat permet de faire un scan avec un pas de 10° dans chaque direction (Pan et Tilt).
Réception des messages MQTT
Vous pouvez écouter les messages qui transitent sur le réseau MQTT à l’aide d’un client. Vous pouvez par exemple utiliser MQTT.fx (disponible pour Linux, macOS et Windows, la page de téléchargement). Lancez MQTT.fx et connectez vous au Broker. Souscrivez (subscribe) au topic servo/#. Le # permet de récupérer tous les messages de l’arborescence. Ici pan et tilt.
Test en fonctionnement
Après avoir téléversez le programme dans l’ESP8266 et déployé le flow Node-RED, ouvrez le dashboard depuis n’importe quel navigateur internet. Vous pouvez également piloter le système articulé depuis le navigateur internet d’une tablette ou d’un smartphone. Ouvrez la page à l’adresse
http://IP_NODERED:1880/ui
Voici une petite vidéo de démonstration pour terminer l’article.
|
Avez-vous aimé cet article ?