IMA3/IMA4 2020/2022 P10
Projet S6-S7 : Voiture radiocommandée autonome
POURRIER Matéo / AMOROS Paul / BLACK Baptiste / ROUSSEL Alexandre
L'objectif de ce wiki est de permettre (aux futurs personnes intéressées par ce projet) la pleine réalisation de cette voiture radiocommandée/autonome en suivant simplement les instructions expliquées et détaillées ci-dessous.
Sommaire
Configuration de la voiture et de la Raspberry
Dans un premier temps, il faut pouvoir paramétrer la direction et la vitesse de notre voiture. Pour se faire, il nous faut utiliser différents programmes sur Arduino. Le premier d'entre eux que nous avons choisi est le servomoteur.
Le servomoteur (code Arduino)
Nous avons utilisé l'interface d'Arduino (dont le langage est Python) afin de calibrer notre servomoteur. La configuration du spectre de rotation de ce dernier peut se faire via le code suivant :
#include <Servo.h>
Servo servo;
void setup() { Serial.begin(9600); //Serial.begin permet d'initialiser la communication série, ici à 9600 bauds servo.attach(9); //servo.attach permet de configurer le numéro du pin lié au servomoteur, ici 9 }
void loop() { Serial.println(60); //serial.println affiche la valeur passée en paramètre servo.write(60); //servo.write envoie la valeur passée en paramètre au servomoteur delay(500); Serial.println(120); servo.write(120); delay(500); servo.write(180); delay(500); servo.write(120); delay(500); servo.write(60); delay(500); servo.write(0); }
Une fois que la calibration du servomoteur est effectuée, nous pouvons passer au moteur.
Le moteur (code Arduino)
Le moteur brushless étant également dirigé par l'Arduino, il nous faut connaître la plage de valeurs à lui transmettre pour aller à une vitesse consigne.
Voici le code que nous avons utilisé :
#include <Servo.h>
Servo brushless; int mode = 0; boolean sent = false;
void setup() { Serial.begin(9600); brushless.attach(11); }
void loop() { if(!sent) { if(mode == 1) { brushless.write(90); Serial.println("Neutral point"); } else if(mode == 2) { brushless.write(180); Serial.println("Full throttle"); } else if(mode == 3) { brushless.write(0); Serial.println("Full brake"); } sent = true; } }
void serialEvent() { while(Serial.available()) { char inChar = (char)Serial.read();
if(inChar = '1') { mode++; sent = false; } } }
La Raspberry
Toute la partie de pré-configuration + configuration (paquets et prgm à installer).
Contrôle à distance
La première des 2 étapes de ce projet consiste à piloter la voiture à l'aide d'un site web hébergé par un serveur Node.js. Le principal atout de ce serveur est la possibilité de coder en Javascript, un langage de programmation déjà connu. On peut également utiliser Node.js pour faire des applications cross-plateforme.
Le server node js
Nous en arrivons à l’étape où nous allons devoir paramétrer la transmission de l’information. Pour cela nous nous sommes basés sur le travail d’étudiants ayant réalisé un projet similaire en tant que projet de fin d’étude, le projet 4xCar. En étudiant leur travail nous avons compris la nécessité de l’implantation d’un serveur faisant le lien entre l’application web, et la raspberry qui est en quelque sorte le client de l’information apportée par la page web et transmise par le serveur.
Ainsi, nous avons fait nos premiers tests sur les serveurs en faisant tourner le programme serveur.js depuis un ordinateur premièrement, puis directement sur la raspberry par la suite.
De ces essais nous avons pu déduire que les deux cas de figure sont fonctionnels et que l’on peut donc utiliser les deux configurations selon nos besoins.
Le serveur en lui même est codé dans le programme serveur.js, disur le git du projet 4xCar : https://github.com/EloiZalczer/4xCar/blob/master/server.js
Notre groupe étant composé d’étudiants connaissant le langage C, mais débutant dans le domaine de la programmation web, nous avons commencé par réutiliser le serveur fonctionnel proposé par le groupe de 4xCar. Celui basé son fonctionnement sur la transmission de requêtes http grâce à des websockets. Ainsi, il convient de définir le port que l’on souhaite écouter pour recevoir ces requêtes, qui correspond donc à la page web par laquelle on passe la commande souhaitée.
On défini également différentes sockets servant à la transmission d’une information telle que : le début de l’utilisation du véhicule la fin de l’utilisation une commande composée d’une valeur de vitesse et de direction
Enfin, les fonctions composées à l’aide de socket.emit.broadcast s’occupent d’envoyer les sockets transmises par la page web sur l’adresse de broadcast du serveur. C'est-à-dire que l'information est transmise à tous les clients connectés, sauf à l’envoyeur des sockets.
Cette étape nous amène à la réception et au traitement de ces sockets par la raspberry.
La RaspberryPi
Comme nous avons pu en parler précédemment, le premier travail réalisé au niveau de la raspberry pi à été l’installation de nombreux paquets/librairies/utilitaires nécessaires au bon fonctionnement de l’ensemble. Cette étape du travail a été la plus évolutive dans la mesure où nous avons dû nous adapter aux différents éléments ajoutés à l’ensemble, la réception des sockets du serveur, la transmission à l’arduino, c’est à dire le traitement côté “client” des informations envoyées par la page web.
Mais par la suite la partie la plus importante réalisée sur la rapsberry à été la partie programmation pour récupérer les websockets transmises par le serveur, en extraire l’information et enfin les transmettre à l’arduino par liaison série. Arduino qui, comme expliqué précédemment, est déjà prêt à recevoir l’information par liaison série.
Tout d’abord nous utilison le programme pilot.py : https://github.com/EloiZalczer/4xCar/blob/master/ironcar/pilot.py
Ce programme était initialement conçu par le groupe de projet dont nous nous sommes principalement inspirés pour faire fonctionner notre véhicule. Il contient toutefois des informations non nécessaires à l’application actuelle : En effet, nous n’avons pas encore traité la partie pilote automatique. Nous nous sommes donc principalement intéressés à la classe ManualPilot et à son fonctionnement.
Cette classe utilise des variables telles que self.commande[] le tableau des commandes transmises grâce au websockets du serveur mais aussi des variables telles que self.images[] un tableau qui servira par la suite du projet à récupérer les images transmises par la caméra.
L’utilisation de ce programme s’explicite par l’importation de la classe ManualPilot dans le main qui est disponible ici : https://github.com/EloiZalczer/4xCar/blob/master/ironcar/main.py
En effet on remarque dans ce programme:
- Https://upload.wikimedia.org/wikipedia/commons/1/1e/IpSerial.png
Cette adresse ip est passable en paramètre du main et doit donc également être modifiée selon la configuration réseau utilisée. Dans notre cas, nous utilisons ce programme exécuté avec l’option -m pour manual mode.
L’action combinée de ces 2 programmes permet donc à notre RaspberryPi d’établir le contact avec le serveur et donc la page web de commande, mais également de communiquer avec ces derniers. C’est ainsi que nous parvenons à transmettre les commandes speed et direction à l’arduino. En outre nous pourrons probablement continuer de les exploiter pour, dans le futur, récupérer les informations de la caméra ou d’autres appareil de mesures du véhicule pour ensuite les transmettre au serveur et les traiter (en affichant par exemple l’image mesurée par la caméra sur la page web, ou encore en stockant dans une base de donnée des mesures d’autres capteurs pour l’automatisation)
Évidemment, nous avons encore une fois dû appliquer quelques modifications aux programmes pour notre cas d’application, mais nous avons préféré citer le modèle original qui nous a permis d’en comprendre le fonctionnement.
L’application web de commande
En dernier lieu nous avons dû nous intéresser à la conception d’une page web, et plus précisément à celle d’une page web capable de transmettre l’information définie par ses boutons et autres entrées. En nous inspirant une nouvelle fois sur nos homologues de 4xCar nous avons pu établir notre application en réutilisant le dossier complet : https://github.com/EloiZalczer/4xCar/tree/master/public
Les différents boutons nécessaires sont implantés dans le fichier HTML, ainsi qu’un panneau de contrôle qui permet d’envoyer deux données en fonction de la position de la souris en x,y sur le panneau, ce qui permet dans notre cas d’énoncer les données speed (verticalement) et direction (horizontalement).
Le panneau est disposé sur la page dans la HTML file, mais est toutefois initialisé dans le fichier annexe qui lui est dédié nommé controller.js. En effet ce fichier définit les différentes variables dont le panneau de contrôle à besoin pour fonctionner, c'est-à-dire pour déchiffrer la donnée entrée par l’utilisateur, et ensuite la transmettre via une websocket de commande, comme expliqué dans les parties précédentes.
En outre pour le bon fonctionnement de l’application web il est nécessaire d’intégrer au projet un autre fichier dependencies qui contient simplement la librairie socket.io qui est encore une fois utilisée pour transmettre les websockets au serveur. A la fin de notre fichier HTML il convient donc d'intégrer ses lignes de code pour donner au site web les ressources nécessaires à son bon fonctionnement.
- Https://upload.wikimedia.org/wikipedia/commons/1/10/RessourcesWebProj.png
Le site web
- Https://upload.wikimedia.org/wikipedia/commons/9/97/SiteWebProj.png
Le code Arduino final
Nous avons, dans une précédente partie, calibrer notre servomoteur ainsi que notre moteur. Nous sommes donc prêt à concevoir, puis téléverser, le code final de notre Arduino. Ce dernier devra être en communication série avec la Raspberry. De plus, il devra appliquer les valeurs envoyées depuis la Raspberry et les affecter correctemetn entre le servomoteur et le moteur. Voici notre code final :
#include <Servo.h>
String command = ""; bool received = false; Servo servo; Servo brushless;
void setup() { Serial.begin(9600); command.reserve(3); servo.attach(9); brushless.attach(11); }
void loop() { if(received) { control_motors(command[0], command[1]); command = ""; received = false; } }
void serialEvent() { while(Serial.available()) { char inChar = (char)Serial.read(); // get the new byte command += inChar;
if(inChar == 0) received = true; } }
void control_motors(char direction, char speed) { servo.write(((unsigned int)direction)*5); brushless.write((unsigned int)speed); }
Autopilote
Cette étape permet à la voiture d'apprendre à piloter grâce à la reconnaissance d'images (cette partie pourra être réalisée avec un prolongement du projet au S8).