Présentation
Ce petit robot a été réalisé à l’aide d’une carte « Raspberry PI », d’un châssis à chenille de chez « Pololu », et d’une webcam.
a connexion Wifi lui permet de diffuser les flux vidéo sur le réseau et d’être commandé à distance de façon très simple, depuis un ordinateur ou éventuellement un smartphone type Iphone ou Andoid.
Je vous propose de décrire, en quelques lignes, les différentes étapes de cette réalisation ; les aspects mécaniques, électroniques et informatiques.
Liste des pièces mécaniques et électroniques
Voici la liste des pièces utilisées lors de la réalisation du robot :
- Le chassis « Zumo » de chez Pololu.com
- Deux moteurs 6volt de chez Pololu.com
- Une carte Raspberry PI 512Mo Modèle B
- Une carte SD de 8Go
- Un module USB WIFI
- Une Webcam Logitech QuickCam Pro9000
- Une batterie ANKER de 3000mAh
- Un Circuit pont en H 1A SN754410
… et aussi :
- Un buzzer
- Une LED tricolore
- Un circuit imprimé type plaque pastille au pas 2,54mm
- Quelques fils de connexion à connecteur femelle
- Quelques entretoises, vis et écrous M3
Présentation rapide de carte Raspberry PI
La carte « Raspberry PI » est un nano-ordinateur de la taille d’une carte de crédit (ou presque : 86x54cm) équipé d’un processeur ARM à 700Mhz.
Elle dispose, dans ca dernière version, de 512Mo de Ram, d’une interface Ethernet 10/100, de 2 interfaces USB, d’une sortie audio 5.1 de type jack 3,5mm et de deux sorties vidéo (HDMI et composite).
Son processeur graphique embarqué permet un encodage/décodage de flux vidéo au format h264/Mpeg4.
Son support de carte SD lui permet d’accueillir l’élément de stockage principal où est installé le système d’exploitation.
Un connecteur de 2×13 broches fournit :
- 8 ports GPIO (entrée/sortie)
- 1 UART Rs232
- 2 bus SPI
- 1 bus I2C
- Une alimentation 5V
- Une alimentation 3,3V
La carte Raspberry PI est alimentée en 5V via son connecteur micro USB
Configuration de la Raspberry
Installation de la distribution
Même si 4 Go peuvent suffire, j’utilise une carte SD de 8 Go pour héberger le système d’exploitation, ce qui permet d’avoir une souplesse de stockage à des fins expérimental. Il est de plus intéressant d’opter pour une carte performante en termes de débit (30Mb/s par exemple).
Diverses distributions Linux ont été compilées pour le processeur ARM de la Raspberry. J’utilise « Raspbian », recommandé par la fondation Raspberry PI, qui est tout simplement une adaptation de la distribution Debian « wheezy ».
Il existe plusieurs méthodes pour installer le système, « Win32DiskImage » sous Windows, « dd » sous linux ou mac …
La toute dernière méthode proposée par la fondation Raspberry PI et fonctionnant sous Windows ou Mac est encore plus simple !!! :
Exemple d’installation de l’OS sous Windows :
- Formater la carte SD avec l’utilitaire « SD Formatter 4.0 for SD/SDHC/SDXC » disponible ici : https://www.sdcard.org/…
- Télécharger la dernière version « NOOBS » offline depuis le site officiel (~1,3Go) : http://www.raspberrypi.org/downloads
- Extraire le Zip et Copier l’intégralité des fichiers directement sur car SD
- Installer la carte SD dans le slot de carte Raspberry PI
- Démarrer la carte Raspberry en connectant écran, clavier, souris, interface réseau et alimentation
- Le mode « Recovery » de la raspberry fait le reste … !!!
Configuration système
Lors du premier démarrage, sélectionner l’installation de la distribution « Raspbian ».
Après quelques minutes d’installation et un premier reboot, l’utilitaire « raspi-config » se lance automatiquement. Il permet de définir :
- le mot de passe
- les locales (par exemple : fr_FR ISO-8859-1 et fr_FR.UTF-8 UTF-8)
- le fuseau horaire
- le type de clavier
- le nom de host
Première connexion avec le nom d’utilisateur « pi », et mise à jour du système :
1 2 |
# sudo -s # apt-get update |
Puis :
1 |
# apt-get upgrade |
Et pour le fun, un peu de couleur dans vi :
1 2 |
# apt-get install vim # echo syn on >> /etc/vim/vimrc.local |
Installation des packages nécessaire
Dans cette distribution, les environnements de développement (Python, C, …) ainsi que le module GPIO « python3-rpi.gpio » sont déjà installés, Il ne reste que peu de chose à installer.
La librairie « RPIO » sera nécessaire ; Elle permet de générer des signaux de type PWM.
1 2 |
# apt-get install python-setuptools # easy_install -u RPIO |
D’autres packages seront également utile, pour le wifi, la webcam … ils sont traités plus bas
Configuration du wifi
Dans sa configuration actuelle, le robot se connecte directement à la borne Wifi de mon domicile. Ce qui lui permet un accès complet aux diverses ressources du réseau local, et un accès à Internet.
Une autre solution (une évolution possible) pourrait être de configurer la carte Raspberry en Acces-Point Wifi (en « hotspot »), ce qui la rendrait entièrement autonome.
L’ajout de l’adaptateur Usb Wifi crée une interface réseau nommée « wlan0 », il suffit d’éditer le fichier /etc/network/interfaces pour configurer une adresse IP, le SSID et mot de passe wifi.
1 |
vi /etc/network/interfaces |
1 2 3 4 5 6 7 8 9 |
auto wlan0 iface wlan0 inet static address 192.168.21.61 netmask 255.255.255.0 network 192.168.21.0 broadcast 192.168.21.255 gateway 192.168.21.1 wpa-ssid "mon_wifi" wpa-psk "mon_mot_de_passe" |
Gestion de la webcam et du flux video
L’objectif est de diffuser le simplement possible, le flux vidéo de la webcam sur le réseau local.
Après plusieurs tentatives avec diverses solutions tel que Motion, ffmpeg, vlc ou autres, j’ai fini par adopter « MJPG-Streamer » qui pour avantages d’être peu consommateur en ressources, d’embarquer son propre serveur web pour la diffusion, et le tout avec une faible latence !
MJPG-Streamer n’est pas packagé pour Raspbian, il faut donc le compiler pour le processeur ARM de la Raspberry.
Les sources sont disponibles sur sourceforge : http://sourceforge.net/projects/mjpg-streamer/
Installation de MJPG-Streamer
1 2 3 4 5 6 7 8 9 10 11 |
# cd /home/pi # wget http://sourceforge.net/projects/mjpg-streamer/files/mjpg-streamer/Sourcecode/mjpg-streamer-r63.tar.gz # tar -zxvf mjpg-streamer-r63.tar.gz # ln -s mjpg-streamer-r63 mjpg-streamer # cd mjpg-streamer # ln -s /usr/include/linux/videodev2.h /usr/include/linux/videodev.h # apt-get install libjpeg8-dev libmath++-dev # make clean all |
Lancement du processus MJPG-Streamer
1 2 3 4 5 6 7 8 9 10 11 |
# /home/pi/mjpg-streamer/start.sh MJPG Streamer Version.: 2.0 i: Using V4L2 device.: /dev/video0 i: Desired Resolution: 640 x 480 i: Frames Per Second.: 5 i: Format............: MJPEG o: www-folder-path...: ./www/ o: HTTP TCP port.....: 8080 o: username:password.: disabled o: commands..........: enabled |
Reste à vérifier : http://Mon_Adresse_IP:8080
Schémas électroniques
Connecteur GPIO
Voici le détail du connecteur de 2×13 broches de Raspberry.
Les broches sont numérotées de 1 à 26 sont également identifiées par une référence GPIO qui est plus simple à utiliser lors de la programmation. Elles peuvent être configurées en entrée ou en sortie.
Le Robot « Raspberry Zumo » utilise (dans sa version actuelle) 8 sorties GPIO :
- GPIO 25 –> Moteur Droite, marche avant
- GPIO 24 –> Moteur Droite, marche arrière
- GPIO 23 –> Moteur Gauche, marche avant
- GPIO 18 –> Moteur Gauche, marche arrière
- GPIO 22 –> LED tricolore, rouge
- GPIO 27 –> LED tricolore, vert
- GPIO 17 –> LED tricolore, bleu
- GPIO 04 –> Buzzer
Précision sur l’alimentation
Le robot utilise deux sources d’énergie.
- La batterie ANKER de 3000mAh fournit 5volt à la Rasberry et ces interfaces USB, comprenant le module Wifi et la Webcam. Elle alimente également la LED externe et le circuit SN754410
- Quatre piles rechargeables placées dans le châssis à chenille fournissent environ 6Volt aux deux moteurs
Schéma du robot « Raspberry Zumo »
Les sorties GPIO fournissent 3.3Volt pour un courant maximum de 100mA. Il est donc très simple d’alimenter une LED ou un Buzzer.
En revanche pour commander les 2 moteurs 6volt à courant continu, et qui plus est, pour gérer leur sens de rotation, il est nécessaire d’utiliser un « circuit pont en H ». J’utilise un SN754410 (équivalant au L293D) qui permet de piloter deux moteurs CC de 4,5V à 36V provenant d’une source d’alimentation dédiée, pour un prix très économique.
Programmation
Descriptif des fonctions
L’objectif est de développer un petit programme permettant de piloter les deux moteurs, d’allumer la LED tricolor en mode « tout-ou-rien » pour chaque couleurs et d’envoyer un signal de type PWM au buzzer.
Pour faciliter l’envoie de commandes via le réseau et permettre de futurs évolutions, j’ai souhaité mettre en place une solution client/serveur. Le robot héberge un serveur IP qui crée un socket TCP sur le port 12345. Cela a comme principal avantage d’être complètement indépendant de la plate-forme cliente (Linux, MacOs, Windows, Smartphone..) et du langage utilisé (Java, C… ou autre). Telnet, peut par exemple, et dans un premier temps, être très bon client !
Les différentes librairies et exemples sont disponibles pour la Raspberry en langage Python. De plus l’environnement de développement est déjà préinstallé dans la distribution Raspbian Wheezy. Le serveur est donc développé en Python. Les principales commandes (marche avant, marche arrière, tourner à droite ou à gauche ….etc) ont été implémenté ainsi qu’un petit menu à la connexion.
Le code
Le fichier « robot-srv.py » est créé dans le répertoire /home/pi, l’attribut d’exécution doit être positionné sur ce fichier (chmod +x)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
#!/usr/bin/python # -*- coding:Utf-8 -*- from RPIO import PWM import RPIO import socket import RPi.GPIO as GPIO import time import sys HOST = "0.0.0.0" PORT = 12345 #-------------[ CABLAGE ]-------------------- My_LED = 22 Moteur_1_Forward = 25 Moteur_1_Reverse = 24 Moteur_2_Forward = 23 Moteur_2_Reverse = 18 LED_R = 22 LED_V = 27 LED_B = 17 BUZZER_PIN = 04 #-------------[ Initialisation ]-------------- GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(Moteur_1_Forward, GPIO.OUT) GPIO.setup(Moteur_1_Reverse, GPIO.OUT) GPIO.setup(Moteur_2_Forward, GPIO.OUT) GPIO.setup(Moteur_2_Reverse, GPIO.OUT) GPIO.setup(LED_R, GPIO.OUT) GPIO.setup(LED_V, GPIO.OUT) GPIO.setup(LED_B, GPIO.OUT) BUZZER = RPIO.PWM.Servo() #-------------------------------------------- def BIP() : BUZZER.set_servo(BUZZER_PIN,15000) time.sleep(.1) BUZZER.stop_servo(BUZZER_PIN) time.sleep(.01) BUZZER.set_servo(BUZZER_PIN,15000) time.sleep(.1) BUZZER.stop_servo(BUZZER_PIN) def AVANT() : print "Marche Avant" GPIO.output(Moteur_1_Forward, GPIO.HIGH) GPIO.output(Moteur_2_Forward, GPIO.HIGH) def ARRIERE() : print "Marche Arriere" GPIO.output(Moteur_1_Reverse, GPIO.HIGH) GPIO.output(Moteur_2_Reverse, GPIO.HIGH) time.sleep(0.5) STOP() def DROITE() : print "tourne a droite" GPIO.output(Moteur_1_Forward, GPIO.HIGH) GPIO.output(Moteur_2_Reverse, GPIO.HIGH) time.sleep(0.5) STOP() def DROITE_Toute() : print "tourne a droite" GPIO.output(Moteur_1_Forward, GPIO.HIGH) GPIO.output(Moteur_2_Reverse, GPIO.HIGH) def GAUCHE() : print "tourne a gauche" GPIO.output(Moteur_1_Reverse, GPIO.HIGH) GPIO.output(Moteur_2_Forward, GPIO.HIGH) time.sleep(0.5) STOP() def GAUCHE_Toute() : print "tourne a gauche" GPIO.output(Moteur_1_Reverse, GPIO.HIGH) GPIO.output(Moteur_2_Forward, GPIO.HIGH) def STOP () : print "stop" GPIO.output(Moteur_1_Forward, GPIO.LOW) GPIO.output(Moteur_2_Forward, GPIO.LOW) GPIO.output(Moteur_1_Reverse, GPIO.LOW) GPIO.output(Moteur_2_Reverse, GPIO.LOW) def LED_R_UP() : print "LED Rouge Marche" GPIO.output(LED_R, GPIO.HIGH) def LED_V_UP() : print "LED Vert Marche" GPIO.output(LED_V, GPIO.HIGH) def LED_B_UP() : print "LED Bleu Marche" GPIO.output(LED_B, GPIO.HIGH) def LED_DOWN() : print "LED Stop" GPIO.output(LED_R, GPIO.LOW) GPIO.output(LED_V, GPIO.LOW) GPIO.output(LED_B, GPIO.LOW) def MENU() : connexion.send( "\n\r" ) connexion.send( " A --> en Avant\n" ) connexion.send( " R --> en Arriere\n" ) connexion.send( " D --> a Droite\n" ) connexion.send( " DD --> a Droite (sans stop)\n" ) connexion.send( " G --> a Gauche\n" ) connexion.send( " GG --> a Gauche (sans stop)\n" ) connexion.send( " S --> STOP\n" ) connexion.send( " 1 --> LED Rouge ON\n" ) connexion.send( " 2 --> LED Vert ON\n" ) connexion.send( " 3 --> LED Bleu ON\n" ) connexion.send( " 0 --> LED OFF\n" ) connexion.send( " B --> BIP\n" ) connexion.send( " M --> MENU\n" ) connexion.send( "\n" ) print "GO" print "Start\n" # Creation du socket mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Liaison du socket avec l'interface try: mySocket.bind((HOST, PORT)) except socket.error: print "La liaison du socket à l'adresse choisie a échoué." sys.exit() BIP() # -------------------------------------- while 1: print "Serveur en attente ..." mySocket.listen(5) # Etablissement de la connexion : connexion, adresse = mySocket.accept() print "Client connecté, adresse IP %s, port %s" % (adresse[0], adresse[1]) # Envoi d'un message qu client : connexion.send("\nWelcome to Fred's Robot Server\n\n") MENU() # Reception des message client while 1: msgClient = connexion.recv(10).rstrip() print "C>"+msgClient+"<" if msgClient.lower() == "fin" or msgClient =="" or msgClient.lower() == "stop": print "Break !!!" break elif msgClient.upper() == "M" : MENU() # Commandes Robot elif msgClient.upper() == "A" : AVANT() elif msgClient.upper() == "R" : ARRIERE() elif msgClient.upper() == "D" : DROITE() elif msgClient.upper() == "DD" : DROITE_Toute() elif msgClient.upper() == "G" : GAUCHE() elif msgClient.upper() == "GG" : GAUCHE_Toute() elif msgClient.upper() == "S" : STOP() elif msgClient.upper() == "1" : LED_R_UP() elif msgClient.upper() == "2" : LED_V_UP() elif msgClient.upper() == "3" : LED_B_UP() elif msgClient.upper() == "0" : LED_DOWN() elif msgClient.upper() == "B" : BIP() # Fin de la session connexion.send("By By !") print "Connexion interrompue." connexion.close() # fin du programme if msgClient.lower() == "stop": break |
Tests
Et voilà !!! Il ne reste plus qu’à tester !
Donc sur la raspberry PI, heu … NON !!! à SUR LE ROBOT « Raspberry ZUMO », on lance la Webcam & le serveur :
1 2 3 |
# /home/pi/mjpg-streamer/start.sh # /home/pi/robot-srv.py |
Et on test, depuis un poste Windows par exemple :