Archives par étiquette : adafruit

GPIO – Servos moteurs, joypad et WiFi

IMG_5494

Nous allons voir dans cet article comment réaliser une station de pilotage à distance pour commander des servos moteurs, à l’aide d’un Raspberry Pi, d’un joypad et d’un lien WiFi. Dans cet exemple j’uitiliserai un eeePC 901 pour la station de pilotage, mais il est tout à fait possible d’utiliser un deuxième Raspberry Pi.

Voici un schéma global :

pi joystick servoLa construction de ce dispositif se fait en trois étapes :

  1. Contrôle des servos moteurs par le Pi
  2. Utilisation du joypad
  3. Envoi des commandes à distance par wifi

Liste du matériel utilisé dans cet article

 

1 – Contrôle des servos moteurs par le Pi

Pour piloter plusieurs servos moteurs avec un Pi, nous n’avons d’autre choix que de passer par une carte contrôleur. Le site Adafruit propose justement un circuit permettant de contrôler jusqu’à 16 servos moteurs en utilisant le bus I²C (disponible sur le GPIO du Pi comme expliqué dans cet article GPIO – Entrée en matière).

imageVous pouvez acheter ce circuit directement sur le site d’Adafruit : Adafruit 16-Channel 12-bit PWM/Servo Driver – I2C interface – PCA9685

imageVous devrez sortir votre fer et souder les broches sur le circuit imprimé 🙂 Un bornier est prévu pour connecter une source d’alimentation. J’utilise un bloc coupleur de pile avec 4 piles AA pour fournir une tension de 6V, parfait pour alimenter mes servos moteurs.

Côté servos, je dispose de deux gros FUTABA S3010 et d’un minuscule FUTABA S3114.

Le branchement de la carte sur le Pi peut se faire simplement à l’aide de wire jumpers. Il suffit de connecter l’alimentation (3,3V et la masse/ground) ainsi que les broches SCL et SDA comme sur le schéma ci-dessous :

branchement_16cUne fois les branchements effectués, il convient d’activer le support de l’I²C sur le Raspberry Pi. Ceci se fait en deux étapes :

1 – Editez le fichier /etc/modules et ajoutez les deux lignes suivantes :

i2c-bcm2708
i2c-dev

2 – Editez ensuite le fichier /etc/modprobe.d/raspi-blacklist.conf et commentez les deux lignes suivantes (en ajoutant # au début de ces deux lignes) :

# blacklist spi-bcm2708
# blacklist i2c-bcm2708

Pour finir, installez l’outil i2c-tools et redémarrez le Pi :

apt-get install i2c-tools
shutdown -r now

Pour vérifer que la carte est bien reconnue par le Pi, lancez la commande suivante :

i2cdetect -y 1 # pour la révision 2 du Pi

ou

i2cdetect -y 0 # pour la première version du Pi

Vous devriez obtenir ce résultat :

root@raspberrypi:~# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --

Bien ! Nous allons maintenant écrire le programme en Python qui va nous permettre de piloter ces servos moteurs. Python est installé par défaut sur Raspbian, il ne manque que certains paquets :

apt-get install python-dev python-rpi.gpio python-smbus

Adafruit propose une librairie Python qui permet de dialoguer facilement avec les différents composants distribués par son site. Nous n’allons pas nous en priver 🙂 Pour télécharger la dernière version disponible de cette librairie, il suffit d’en récupérer les sources sur le dépôt GIT :

git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git

La partie qui nous intéresse ici se trouve dans le répertoire Adafruit-Raspberry-Pi-Python-Code/Adafruit_PWM_Servo_Driver.

Dans un premier temps, voici un petit script qui permet de tester les servos test_servo.py :

#!/usr/bin/python

from Adafruit_PWM_Servo_Driver import PWM
import sys

pwm = PWM(0x40, debug=True)
pwm.setPWMFreq(60)

pwm.setPWM(int(sys.argv[1]), 0, int(sys.argv[2]))

Pensez à rendre ce script exécutable grâce à la commande chmod 755 test_servo.py

Ce script prend deux paramètres :

  • l’id du port contrôlant un servo de 0 à 15
  • une valeur, généralement entre 150 et 600 qui détermine la position que doit prendre le servo

Exemples pour commander le servo branché sur le premier port (ayant pour id 0) :

./test_servo.py 0 480
./test_servo.py 0 240

Et voilà, si tout s’est bien passé, vous devriez pouvoir piloter vos servos de cette manière. Nous verrons plus loin dans cet article comment les piloter avec un joypad et à distance 🙂

Note : Je ne sais absolument pas pourquoi le troisième paramètre de la fonction setPWM() doit être entre 150 et 600… De même, je ne sais pas à quoi correspond le deuxième paramètre attendu par cette fonction. Si quelqu’un connaît la réponse, merci de nous expliquer cela en commentaire de cet article 🙂

2 – Utilisation du joypad

26-127-505-02Je dispose d’un magnifique joypad USB, modèle Saitek P990 munis de deux mini-joysticks ou « chapeaux chinois ». Nous allons utiliser ces deux joysticks pour piloter nos servos.

Un joystick qu’est ce que c’est ? En fait, c’est simplement un potentiomètre dont la valeur (la résistance) est interprétée et traduite en nombre. Sur ce modèle de joypad, les valeurs sont échantillonnées de 0 à 1023 (soit 1024 valeurs possibles). Pour obtenir deux axes, il y a deux potentiomètres par joystick. Avec deux joysticks, nous avons donc de quoi piloter indépendamment 4 servos 🙂

La librairie Python evdev permet d’interagir facilement avec les événements déclenchés par des périphériques USB. Pour l’installer :

apt-get install python-pip python-dev
pip install evdev

Avant d’écrire un script Python qui sache interpréter les actions de ces joysticks, vous devez connaître l’identifiant « event » attribué par le système au moment où vous branchez votre joypad USB.

lsusb
Bus 001 Device 003: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
Bus 001 Device 005: ID 05e3:0505 Genesys Logic, Inc.
Bus 002 Device 003: ID 06a3:040b Saitek PLC P990 Dual Analog Pad
Bus 005 Device 002: ID 0b05:b700 ASUSTek Computer, Inc. Broadcom Bluetooth 2.1
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 006: ID 11b0:6148 ATECH FLASH TECHNOLOGY
Bus 001 Device 007: ID 05af:3062 Jing-Mold Enterprise Co., Ltd Cordless Keyboard
Bus 001 Device 008: ID 046d:c016 Logitech, Inc. Optical Wheel Mouse

Mon joypad est bien reconnu par le système avec la dénomination : « Saitek PLC P990 Dual Analog Pad« .

cat /proc/bus/input/devices

Cherchez la référence à votre joypad et repérez l’identifiant « event », ici nous avons l’identifiant « event6« .

[...]

I: Bus=0003 Vendor=06a3 Product=040b Version=0100
N: Name="Saitek P990 Dual Analog Pad"
P: Phys=usb-0000:00:1d.0-2/input0
S: Sysfs=/devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input15
U: Uniq=
H: Handlers=event6 js0
B: PROP=0
B: EV=1b
B: KEY=3fff 0 0 0 0 0 0 0 0 0
B: ABS=30027
B: MSC=10

[...]

A chaque fois que l’on va presser un bouton sur le joypad, ou actionner un de ses joysticks, un événement sera déclenché. Il s’agit donc de surveiller en permanence les événements déclenchés et d’agir en fonction. Voici maintenant un petit script Python qui permet de tester votre joypad et d’identifier les différents événements liés à chaque joystick et chaque bouton : test_joypad.py

#!/usr/bin/python

from evdev import InputDevice, categorize, ecodes
from time import sleep
from datetime import date
import os, sys, socket

dev = InputDevice('/dev/input/event6') # reprendre le même identifiant "event"
print(dev)

for event in dev.read_loop(): # boucle qui surveille l'arrivée d'un événement
  e_code=event.code
  e_type=event.type
  e_value=event.value
  print(str(e_type)+' - '+str(e_code)+' - '+str(e_value))

A chaque fois que vous toucherez quelque chose sur votre joypad, ce script affichera trois variables, e_code, e_type et e_value :

./test_joystick.py
device /dev/input/event6, name "Saitek P990 Dual Analog Pad", phys "usb-0000:00:1d.0-2/input0"
3 - 0 - 508
3 - 0 - 412
3 - 0 - 347
3 - 0 - 391
3 - 0 - 457
3 - 0 - 511
3 - 1 - 602
3 - 1 - 701
3 - 1 - 771
3 - 1 - 659
3 - 1 - 561
3 - 1 - 511

Voilà ce que j’obtiens en actionnant le joystick gauche de mon joypad, identifié par l’e_code 3. Dans l’axes des X, j’obtiens un e_type 0, et un e_type 1 pour l’axe des Y. Lorsque je relâche le joystick en position centrale, les valeurs sont proches de 512 (valeur médiane entre 0 et 1023). Ces caractéristiques sont propres à ce modèle de joypad, mais le principe de fonctionnement est le même pour tous 🙂 Ce petit script vous permettra de noter l’e_code et l’e_type de chaque bouton et joystick que vous voulez utiliser.

Pour ma part, j’ai trois servos à piloter, et je dispose de deux joysticks avec chacun deux axes. J’utiliserai l’axe X du joystick gauche (e_code 3, e_type 0) pour piloter le servo 1. L’axe Y du joystick gauche (e_code 3, e_type 1) pour piloter le servo 2. Et enfin l’axe X joystick droit (e_code 3, e_type 5) pour piloter le servo 3 🙂

A partir de là, vous pouvez facilement imaginer associer le servo 1 au roulis d’un avion, le servo 2 au tangage et le servo 3 au lacet par exemple 🙂

La dernière étape consiste à envoyer les commandes du joypad, branché sur la station de pilotage, au Raspberry Pi qui répercutera les ordres sur ses servos 🙂

3 – Envoi des commandes à distance par wifi

Nous avons d’un côté un script Python qui tourne sur un Raspberry Pi qui a pour rôle de piloter des servos. De l’autre, nous avons un eeePC (ou autre machine…), qui exécute un second script Python dont le but est d’interpréter les commandes envoyées par un joypad. Il s’agit maintenant de faire communiquer ces deux scripts entre eux, ce que nous pouvons facilement faire grâce aux sockets 🙂

Sans trop rentrer dans les détails, il s’agit d’ouvrir une socket au niveau du script qui s’exécute sur le Pi afin qu’il soit à l’écoute de messages envoyés par le script côté « station de pilotage ». Le script côté « station de pilotage » se connecte à cette socket en passant par le réseau IP (via WiFi), et envoie les commandes déclenchées par le joypad.

Côté Raspberry Pi :

#!/usr/bin/python

from Adafruit_PWM_Servo_Driver import PWM
import sys, os, socket

listen_address = ('0.0.0.0', 12800) # écoute sur toutes les interface sur le port 12800

srv_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # protocole UDP
srv_socket.bind(listen_address)
print "server enabled"

pwm = PWM(0x40, debug=True) # initialisation de la carte contrôleur
pwm.setPWMFreq(60)

while True:
  query, clt_address = srv_socket.recvfrom(1024) # écoute les message
  order=query.split('_') # on découpe les messages reçus
  servo=order[0]
  pos=order[1]
  print str(query)+' - '+str(servo)+' - '+str(pos) # on affiche les infos
  pwm.setPWM(int(servo), 0, int(pos)) # on envoie la commande au servo
sys.exit(0)

Côté Station de pilotage :

#!/usr/bin/python

from evdev import InputDevice, categorize, ecodes
from time import sleep
from datetime import date
import os, sys, socket

now = date.today()
print(now)

clt_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # protocole UDP
srv_address = ('192.168.101.27', 12800) # on vise l'adresse IP du Pi sur le port 12800

dev = InputDevice('/dev/input/event6') # initialisation du joypad
print(dev)

def convertAxis (value, axis_max): # fonction qui convertie les valeurs des joystick
  facteur=axis_max/490
  new_value=int(round((value/facteur)+150, 0))
  return new_value

for event in dev.read_loop(): # pour chaque événement détecté
  e_code=event.code
  e_type=event.type
  e_value=event.value
  print(str(e_type)+' - '+str(e_code)+' - '+str(e_value))
  if e_type == 3:
    if e_code == 0: # à destination du servo 1
      servo_pos=str(convertAxis (e_value, 1024))
      clt_socket.sendto("0_"+servo_pos, srv_address)
    elif e_code == 1: # à destination du servo 2
      servo_pos=str(convertAxis (e_value, 1024))
      clt_socket.sendto("1_"+servo_pos, srv_address)
    elif e_code == 5: # à destination du servo 3
      servo_pos=str(convertAxis (e_value, 512))
      clt_socket.sendto("2_"+servo_pos, srv_address)

Conclusions

En déclinant ce principe, vous pouvez piloter de nombreux servos moteurs à distance et commencer à envisager la construction systèmes complexes comme des robots ou des drones 🙂

En parlant de drone, ces articles relatifs au GPIO me serviront à construire un drone avion, comme expliqué ici : Raspberry Pi BOA Drone 🙂

Cependant, certaines zones d’ombre persistes, notamment sur le pilotage de servos. L’utilisation de la lib distribuée par Adafruit évite de se poser de question, cela fonctionne immédiatement. La contre partie, c’est qu’on ne comprend pas forcément tout ce qui se passe. Aussi, j’invite les lecteurs de ce blog à intervenir en commentaire de cet article afin d’apporter des informations complémentaires, des idées ou simplement des remarques 🙂

Merci à vous 🙂

2 – Le choix du matériel

Raspberry Pi modèle B

205039Plus besoin de se poser la question entre le modèle A ou le modèle B, autant prendre le modèle le plus complet et le plus récent. Le Raspberry Pi Model B rev 2 doté de 512Mo de RAM et d’un port ethernet est désormais disponible chez beaucoup de revendeurs. J’ai trouvé celui-ci chez Amazon.

Commandé sur le site Amazon pour 39 €

Boîtier Adafruit

ID859angle_LRGJe reste très attaché à l’Adafruit Pi Box ! Ce boîtier transparent, livré en « kit », met en valeur la carte et permet de nombreuses personnalisations. Il permet notamment de faire passer une nappe branchée sur le GPIO du Pi grâce à une fente. Vous pouvez également retirer certaines parois pour faciliter l’accès à certaines parties de la carte tout en protégeant l’ensemble.

Commandé sur Amazon pour 10 € (livraison gratuite)

Carte SDHC 32Go

41i-JeRaW6L._SX385_Initialement, je souhaitais prendre une carte SD de 2Go ou 4Go pour l’OS puis stocker les musiques sur un disque dur externe. L’ennui, c’est qu’un disque externe dans une boite à gants de voiture, ça prend de la place, ça chauffe, ça risque de se détériorer, et ça occupe un port USB… Et ça coûte des sous… ‘Fin bref, j’ai rapidement laissé tomber cette option et ai choisi une carte SDHC de 32Go. Vous pouvez évidemment opter pour une carte de 64Go pour un peu plus de 50€.

Commandé sur Amazon pour 17 € (livraison gratuite)

Dongle WiFi USB

144267Il convient de choisir un dongle WiFi USB qui soit compact (inutile de s’encombrer d’une antenne), et surtout, qui supporte le mode « access point » !

Le site elinux.org nous informe que le dongle NetGear WNA1000M est parfaitement supporté par le Pi sans passer par un hub USB alimenté.

Commandé sur Amazon pour 12€

Carte son USB

plantronics_gamecom_777_para_jugones_418x241Je ne m’attends pas à obtenir une qualité de son extra-ordinaire, mais la qualité de la prise jack disponible sur le Pi n’est franchement pas suffisante pour une écoute de musique dans de bonnes conditions. J’ai retrouvé dans mes tiroirs une carte son USB Plantronics qui était fournis avec un casque (le Plantronics GameCom 777). Elle est très compacte, fonctionne très bien sous Raspbian, et m’évite d’en acheter une…

Alimentation

LD0000719626Dans une voiture, les différentes sources d’alimentations (allume-cigare, alimentation de l’autoradio, etc…) fournissent en général un courant en 12V. Nous avons besoin d’un transformateur qui fournis une tension en 5V pour alimenter correctement le Pi. Après avoir cherché des circuits convertisseurs ou régulateurs de tension 12V -> 5V, je me suis réveillé un jour en me disant qu’un chargeur allume-cigare pour smartphone devrait faire l’affaire… Bingo ! Très compact et peu onéreux, on peut en trouver un peu partout…

Le plus compliqué est d’en trouver un qui puisse délivrer un courant d’au moins 1A (La plupart des chargeur allume-cigare que l’on peut trouver dans le commerce ne dépassent pas les 500mA).

J’ai trouvé mon bonheur sur Amazon pour environ 15€

Mise à jour – 30 juillet 2013 :

imageL’immense majorité des chargeurs allume-cigare que l’on trouve dans le commerce ne sont pas blindé contre les variations de tension. C’est déjà problématique pour la durée de vie des batteries de téléphones, mais pour un Pi, c’est encore pire. De plus, lorsque la voiture démarre, la séquence « contact » puis « allumage du moteur » entraine des piques et des chutes de tensions importantes. Le Pi n’étant pas du tout protégé contre ce genre de parasitage et nécessitant une alimentation correctement régulée, j’ai préféré choisir un convertisseur de tension continue stabilisé  KEMO M015N.

  • Tension d’entrée 6-28V (idéal pour les 12V fournis par le circuit électrique de la voiture)
  • Tension de sortie 3-15V (parfait pour les 5V demandé par le Pi)

Il s’agira de faire un branchement parallèle sur le faisceau de l’allume cigare. En effet, c’est un circuit spécifiquement prévu pour tirer du courant et qui est géré par le système d’économie d’énergie qui coupera automatiquement l’alimentation du circuit si il consomme trop de courant sur la batterie lorsque le moteur est éteint. Ce qui nous évitera de mauvaises surprises 😉

Acheté chez Amazon pour moins de 15€

Interface entrée auxiliaire pour mon autoradio d’origine

IMG_4758La majeure partie des autoradios d’aujourd’hui disposent d’une entré auxiliaire. Dans mon cas, ma voiture datant de 2008 et souhaitant conserver l’autoradio d’origine (le très répandu RD4), je n’ai d’autre choix que d’utiliser une interface vendue par PSA pour environ 35€… A savoir qu’il faudra également faire activer une entrée auxiliaire dans un garage afin de pouvoir l’exploiter (Je ferai un article détaillé à ce sujet dans les prochains jours).

Commander dans un garage Citroën pour 35€ sous la référence faisceau auxiliaire autoradio RD4 réf. 9706.AG.

Vous pouvez également le commander ici sur Amazon.

 Note : Il est également possible de bricoler soit même ce faisceau auxiliaire. Voici un exemple de réalisation : http://www.forum-peugeot.com/Forum/forum-peugeot/Electronique-embarquee/Seconde-monte/auxiliaire-entree-maison-sujet_32999_1.htm

2 – Le choix des composants

Raspberry Pi

IMG_4469Souhaitant pouvoir réutiliser la bête plus tard pour d’autres choses, j’opte tout de suite pour le modèle le plus complet Raspberry Pi Model B rev 2 doté de 512Mo de RAM. Basiquement, j’utiliserai une Raspbian car je suis à l’aise avec Debian et que c’est une solution suffisamment fiable et robuste.

Commandé sur Amazon pour 30 € (frais de port inclus)

Le boitier pour le Raspberry Pi

IMG_4477Pour protéger le Raspberry Pi, j’ai choisi un boitier modulaire, facilement « customisable » créé par le site Adafruit spécialisé dans les kits électroniques, Adafruit Pi Box – Enclosure for Raspberry Pi Computers.

Commandé sur Amazon pour 10 € (livraison gratuite)

La carte mémoire SDHC

IMG_4476Afin de pouvoir stocker suffisamment de photos, j’ai choisi une carte SDHC Kingston SD10V/32GB Carte SD 10 Mo/s 32 Go Classe 10.

Commandé sur Amazon pour 21 € (livraison gratuite)

La caméra

IMG_4468J’ai opté pour une webcam USB standard. L’objectif est d’avoir une résolution suffisante et de ne pas avoir de problème de luminosité ni de mise au point. J’ai donc choisi un modèle de logitech Logitech C525 très bon marché, HD 720p avec autofocus :

Commandé sur Amazon pour 36 € (livraison gratuite)

La connexion réseau – dongle 3G

Dongle 3G + SIM FreeD’après ce que j’ai vu sur le net, le Huawei E220 est particulièrement bien supporté par le Raspberry Pi, et part Linux en général. J’utiliserai une carte SIM Free Mobile, avec l’abonnement à 2€ avec l’option 3G (20Mo inclus) pour 0,99€. Ce sera suffisant pour prendre la main sur le Raspberry Pi via SSH.

Commandé sur Amazon pour 40 € (livraison gratuite)

La batterie

batterie_5VLe Raspberry Pi doit être alimenté par un courant de 1 A (en prenant en compte les périphériques USB, webcam + dongle 3G) sur 5V.

Il existe de nombreux modèles de batterie 5V servant de batterie de secours pour téléphone mobile. De capacité, puissance, prix et qualité très variable, il est difficile de choisir.

En creusant le sujet, il apparait que les batteries de la marque TeckNet soient clairement au dessus du lot. Bonne durée de vie, puissance jusqu’à 2A avec des capacité de 7000 mAh à 12000 mAh. Pour rester dans un budget raisonnable, je choisi le modèle intermédiaire avec une capacité de 9000 mAh.

Commandé sur Amazon TeckNet iEP389 9000mAh  pour 39€ (livraison gratuite)

La boîte

IMG_4740Pour rester discret, je fais place le dispositif dans une boite en plastique (étanche de préférence), et enterrer le tout dans le sol, au fond du jardin. Seule la webcam sortira furtivement du sol, accrochée à une hauteur de un mètre environ, sur un poteau. La webcam sera renforcée pour résister à la pluie, et camouflée.

Prix environ 6 € (en grande surface)