Un robot connecté avec NodeJS et Raspberry Pi
- Par
- Le 2015-10-25
- Dans Conférences
NodeJS est un langage de développement orienté serveur, qui permet de coder en Javascript dans un environnement léger et performant. Propulsé par l'interpréteur V8 de Google, il offre un large choix de librairies bas niveau, et bénéficie d'une communauté activé, qui publie régulièrement de nombreux modules additionnels.
Le (ou la) Raspberry Pi est un ordinateur de la taille d'une carte de crédit, embarquant un processeur 4 coeurs et 1Gb de RAM. Il exécute une distribution linux dédiée, et profite de nombreuses ressources logicielles et matérielles.
Comment exploiter le langage nodeJS sur une carte RaspberryPi dans le cadre de la fabrication d'un robot connecté ? Ce billet est une synthèse de la présentation proposée par Nicolas Giraud le 20 octobre 2015 dans le cadre des événements de la Tech Amiénoise.
Objectifs
Nous souhaitons réaliser un robot capable de se déplacer dans une pièce, de filmer et diffuser les images, le tout pilotable via internet. Le robot sera construit autour d'une carte Raspberry Pi connectée en Wifi, il exploitera une caméra, et pilotera deux servo moteurs via une carte arduino. Il devra respecter les contraintes suivantes :
- Disposer d'une caméra embarquée
- Etre accessible via Internet
- Fonctionner sur piles ou batterie
- Exploiter un maximum de briques open source
- Ne pas dépasser 150€ de budget
Raspberry Pi
Raspberry Pi est une petite carte électronique (de la taille d’une carte de credit) embarquant un ordinateur complet (Single Board Computer). Facile d’accès, peu onéreux et propulsé par une communauté très active, les ressources logicielles et pédagogiques autour de cette carte ne manquent pas. Ses principales caractéristiques :
- Processeur ARM Dual Core
- 1Gb de RAM
- 4 ports USB
- 1 port Ethernet
- 1 port HDMI
- 1 port CSI (Camera Serial Interface) pour exploiter une caméra
- 1 port DSI (Display Serial Interface) pour exploiter un écran LCD
- Fonctionne sous Linux ou Windows 10
- Alimentation 5V (via un chargeur de tablette ou une batterie mobile)
NodeJS
NodeJS est une solution de développement serveur fondée sur l’interpréteur de Javascript V8 édité par Google. En plus des fonctionnalités de base du JS, il propose nativement de nombreuses librairies “bas niveau”, qui permettent d’accéder à la couche réseau, au système de fichiers, à la gestion de processus…
De nombreux modules additionnels sont proposés par la communauté, via l’utilitaire NPM (Node Package Manager). Malgré sa relative jeunesse, le riche écosystème disponible permet de rivaliser avec les environnements les plus aboutis, en terme de performances et de temps de travail.
Configuration du Raspberry Pi
Système d'exploitation
Télécharger et installer l'image Raspbian (Jessie) sur une carte MicroSD 4Gb classe 10. Les images officielles sont disponibles à l'adresse https://www.raspberrypi.org/downloads/raspbian/ NB :Une carte de classe 10 garantit des débits suffisants et une durée de vie prolongée.
Brancher un clavier et une souris et un adaptateur wifi sur les ports USB, un écran sur le port HDMI.
Prévoir une alimentation 5V qui puisse fournir 1A au moins. Un chargeur de smartphone ou de tablette devrait faire l'affaire. Evitez les chargeurs low cost.
Premier démarrage
Lors du premier démarrage, l'écran suivant s'affiche. Cet utilitaire permet de configurer quelques paramètres de base.
Utilisez cet écran pour régler les paramètres suivants, puis redémarrez le raspberry pi.
- Configuration du clavier
- Démarrage par défaut sur le bureau
- Activation de la camera, du SSH, de l'I2C
Configuration du réseau
Dans un terminal, demandez l'édition du fichier de configuration des interfaces réseau :
sudo leafpad /etc/network/interfaces
Forcer l'obtention d'une adresse IP fixe sur le réseau local via le Wifi. Choisir une adresse compatibles avec la plage autorisée par le routeur (ex :192.168.1.120, 192.168.0.120)
auto lo iface lo inet loopback auto eth0 allow-hotplug eth0 iface eth0 inet manual auto wlan0 allow-hotplug wlan0 #iface wlan0 inet manual iface wlan0 inet static address 192.168.1.120 netmask 255.255.255.0 gateway 192.168.1.254 wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf auto wlan1 allow-hotplug wlan1 iface wlan1 inet manual wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
Configuration du WIFI
Dans un terminal, demandez l'édition du fichier de configuration du Wifi :
sudo lefpad /etc/wpa_supplicant/wpa_supplicant.conf
Fixer le mode d'authentification, le nom du réseau et la clé :
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="TNCAP66A0B5" psk="C466B3644A" proto=RSN key_mgmt=WPA-PSK pairwise=CCMP auth_alg=OPEN }
Puis redémarrez
sudo reboot
Mises à jour
Obtenir et installer les dernières mises à jour du système, installer quelques outils de développement.
sudo apt-get update sudo apt-get upgrade sudo apt-get install build-essential
Utilitaires I2C
Installer les outils I2C officiels, ils permettent d'exploiter la communication I2C via un terminal
sudo apt-get install i2c-tools
Demander à charger les modules i2c au démarrage
sudo leafpad /etc/modules
Ajouter les lignes relatives aux modules i2c
snd-bcm2835 i2c-bcm2708 i2c-dev
Redémarrer
sudo reboot
Connexion SSH
A partir de maintenant, votre raspberry pi peut être démarré sans écran ni clavier. Il est accessible via le réseau et le protocole SSH. A l'aide d'un client SSH (WinSCP, putty, Bivise SSH Client), établir une connexion vers le raspberry pi avec les paramètres suivants:
- Adresse : 192.168.1.120
- Port : 22
- Login : pi
- Mot de passe : raspberry
NodeJS sur Raspberry Pi
Installation de NodeJS
Pour obtenir une version de nodejs fonctionnelle sur raspberry pi et Raspbian Jessie, suivre les indications fournies par node-arm.herokuapp.com.
Télécharger les sources
wget http://node-arm.herokuapp.com/node_latest_armhf.deb
Installer nodejs
sudo dpkg -i node_latest_armhf.deb
Vérifier le bon déroulement de l'installation en demandant le numéro de version de nodejs
node -v v4.2.1
Hello World
Créer un dossier attribué à l'utilisateur "pi"
sudo mkdir /var/www sudo chown pi /var/www
Créer le fichier /var/www/hello.js
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(80); console.log('Server running');
Lancer le serveur
sudo node /var/www/hello.js
Accéder au serveur via un navigateur, le texte "Hello world" est correctement envoyé par le serveur.
Exploiter la camera du Raspberry pi
Un capteur CMOS dédié au raspberry pi est disponible dans le commerce. Il se connecte au port CSI (Camera Serial Interface) du raspberry pi, et permet de prendre des photos ou de filmer en haute définition. 2 Utilitaires permettent d'exploiter cette camera :
- raspistill pour les photos
- raspivid pour les vidéos
Il est possible d'exploiter ces utilitaires directement dans nodeJS.
Capturer une image avec NodeJS
Créer le fichier /var/www/camera.js
// on doit accéder au réseau var http = require('http'); // on doit exécuter des commandes system var child_process = require('child_process'); // on doit accéder aux fichiers var fs = require('fs'); // on créer un serveur qui répondra aux requêtes http.createServer(function (req, res) { // la commande à exécuter var cmd = '/opt/vc/bin/raspistill --output /var/www/image.jpg --timeout 100 --nopreview'; // on lance la commande child_process.exec(cmd, function(error, stdout, stderr){ if(error) { // on affiche l'erreur dans la console console.log(error); // on alerte le visiteur res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('execution impossible'); return; } fs.readFile('/var/www/image.jpg', function(error, data){ if(error) { console.log(error); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('lecture impossible'); return; } res.writeHead(200, {'Content-Type': 'image/jpeg'}); res.end(data); }); }); }).listen(80); console.log('Server running');
Lancer le serveur
sudo node /var/www/camera.js
Tester le serveur dans un navigateur
Créer un flux MJPG
Pour obtenir simplement une vidéo plutot qu'une image, on utilise le "format" mjpg. Il s'agit d'une suite d'images JPG affichées successivement par le navigateur. La majorité des navigateurs supporte nativement cette mode d'affichage. L'utilitaire raspistill est en outre capable de prendre des photos en continu.
Créer un dossier en RAM
Pour préserver la carte SD et éviter d'écrire continuellement dessus, on créer un dossier dans la mémoire vive.
Créer un dossier à la racine :
sudo mkdir /ram
Définir une partition en RAM pour ce dossier
tmpfs /ram tmpfs nodev,nosuid,size=1M 0 0
Monter cette partition
sudo mount -a
Capturer un flux mjpg avec NodeJS
Créer le fichier /var/www/mjpg.js
var http = require('http'); var CameraStream = require('./cameraStream'); // gestionnaire de camera raspistill var camera = new CameraStream(); camera.doStart(320,240,6); // on créer un serveur qui répondra (res) aux requêtes (req) http.createServer(function(req, res){ // entêtes HTTP indiquant un contenu non-fini res.writeHead(200, { 'Cache-Control': 'no-cache', 'Cache-Control': 'private', 'Pragma': 'no-cache', 'Content-Type': 'multipart/x-mixed-replace; boundary=myboundary', }); // envoyer les images à mesure qu'elles arrivent var consume = function(buffer) { res.write("--myboundary\r\n"); res.write("Content-Type: image/jpeg\r\n"); res.write("Content-Length: " + buffer.length + "\r\n"); res.write("\r\n"); res.write(buffer,'binary'); res.write("\r\n"); } // tenter d'envoyer chaque image dès qu'elle arrive camera.on('image', consume); // la connexion a été coupée res.connection.on('close', function(){ camera.removeListener('image', consume); }); }).listen(8080, function(){ console.log('mjpeg server started'); });
La gestion de la capture des images est assurée par la librairie cameraStream.js. Pour tester ce script, vous devez télécharger cette librairie et la placer dans le dossier /var/www.
Lancer le serveur
sudo node /var/www/mjpg.js
Tester dans un navigateur
Matériel & Composants
La plupart des composants du robot provient d'Europe, des USA et de Chine. En octobre 2015, le montant total de cette liste avoisine les 150€, hors frais de port.
Raspberry Pi 2 Héberge le serveur nodeJS 42€ |
|
Module Camera Capteur Full HD, se connecte au port CSI du Raspberry Pi 23€ |
|
Adaptateur WIFI Pas tous compatibles, privilégier les officiels 10€ |
|
Arduino Nano, Pro Mini, Pro Trinket... Microcontrolleur 5V pour piloter les moteurs 10€
|
|
Carte d'accueil Pour connecter plus facilement l'arduino 5€ |
|
Servomoteur 360° Modifiés pour tourner en continu 2 x 10€ |
|
Boîtier à piles Pour 6 piles AA 5€ |
|
6 piles NiMh 2500mAh ou +, privilégier les marques En grande surface : 25€ |
|
Convertisseur de tension Pour abaisser la tension du pack de piles à 5V 5€ |
|
Jumpers câbles de prototypage, longueur, couleur et connectique variées. disponible partout |
Cablage
Alimenter le Raspberry Pi
Attention : Il est impératif d'appliquer une tension d'EXACTEMENT 5V aux bornes GPIO du raspberry Pi, car le seul circuit de protection/régulation de la carte se trouve au niveau de la prise micro USB. Ce schema montre simplement les broches à utiliser pour alimenter la carte.
VCC (5V) : GPIO 6
GND (0V) : GPIO 4
Alimenter l'Arduino
GND (0V) : GND
VCC (5 - 12V) : VIN
Alimenter les servos
Les servos fonctionneront sans problème de 4.8 à 6V.
Raspberry Pi et Arduino en I2C
SDA : GPIO 3 > A4
SCL : GPIO 5 > A5
GND : GPIO 9 > GND
Pilloter les servos avec Arduino
Servo L > D9
Servo R > D10
Communication I2C entre Raspberry Pi et Arduino
Le raspberry Pi ne propose pas de sorties dites "PWM" indispensables pour piloter les servo moteurs. Cette tâche est donc déléguée à une carte Arduino. Voici un exemple simple de communication I2C Maître-Esclave entre un raspberry pi et un arduino.
Câblage I2C
Code Arduino
Dans cet exemple, l'arduino est configuré comme esclave I2C. Il attend d'être contacté à l'adresse 0x04, et pilote la led intégrée à la sortie 13 en fonction des instructions qu'il reçoit.
#include#define ADDRESS 0x04 void setup() { pinMode(13, OUTPUT); Wire.begin(ADDRESS); Wire.onReceive(onRecieve); } void onRecieve(int len) { while(Wire.available()) { int data = Wire.read(); if(data==1) { digitalWrite(13, HIGH); } else { digitalWrite(13, LOW); } } } void loop() { delay(100); }
Détecter les esclaves I2C
Dans un temrinal, lancer la commande suivante
sudo i2cdetect -y 1
Qui dévoilera la liste des appareils I2C connectés au port 1 du raspberry pi
L'arduino est bien visible à l'adresse 0x04
Lancer des commandes I2C
Allumer la diode de l'arduino :
sudo i2cset -y 1 0x04 0x01
Eteindre la led:
sudo i2cset -y 1 0x04 0x00
Design du châssis
A l'aide d'un logiciel de dessin vectoriel (inkscape est disponible gratuitement et en open source), dessiner chaque face du robot, en pensant aux encoches pour l'assemblage, et en prévoyant la place pour chaque composant (piles, raspberry pi, arduino, etc...) Utilisez une même couleur pour toutes les faces de chaque composant et reportez la sur chaque face du robot.
Quelques points de reflexion :
- Prévoir la place pour chaque composant
- Prévoir les trous de fixation des composants
- Prévoir les passages de cables
- Gérer le centre de gravité du robot
- Prévoir un design facilitant les montages/démontages successifs
Découpe laser
Une fois le design validé, préparer un fichier vectoriel adapté aux machines à commande numérique. Dans le cadre de la réalisation de ce robot, une découpe laser sera utilisée.
- Penser à vectorier toutes les lignes
- Penser à dédoubler les lignes
- Penser à espacer suffisament chaque pièce (de quelques mm)
Montage du robot
Une fois les pièces découpées, il ne reste qu'à visser/coller/ajuster les composants.
Le robot terminé
Voici à quoi ressemble notre robot, complètement assemblé et équipé.
Interface de pilotage du robot
Nous créeons un simple fichier HTML qui propose un écran de connexion, permettant à l'utilisateur de configurer la taille et la qualité de l'image. Cette page HTML communique en temps réel avec le raspberry pi via l'API Websocket des navigateurs récents. L'ensemble des fichiers est disponible dans le dernier chapitre.
Questions & Réponses
L'utilisation de l'I2C entre arduino et raspberry pi est-elle sans risque ?
Dans le cadre de ce robot, le Raspberry Pi s'adresse à l'Arduino, la tension maximale qui circule sur l'I2C est donc celle du raspberry pi, soit 3.3V. Par chance, l'arduino -qui fonctionne sous 5V- interprète le 3.3V comme un état haut. Le bus fonctionne donc normalement et sans dager, uniquement dans ce sens.
6 piles AA suffisent-elles pour alimenter le raspberry pi ?
Nous utilisons ici 6 piles rechargeables NIMH d'une capacité de 2500mAh. La tension nominales de ces piles est de 1.2V, le pack complet délivre donc 7.2V, ramenés à 5V par le convertisseur de tension. On peut calculer approximativement l'autonomie de la façon suivante :
En série, les tensions s'ajoutent, pas les capacités, on a donc une batterie de 7.2V capable de délivrer 2500 mA pendant une heure. En abaissant la tension a 5V, on multiplie la capacité par 7.2 / 5 = 1.4. La capacité du pack de batterie atteint donc 2500 x 1.44 = 3600 mAh sous 5V. En considérant une consommation globale de 600mA (mesurée grossièrement) sous 5V, le robot pourra en théorie fonctionner 3600 / 600 = 6 heures.
Peut on utiliser une version du Raspberry Pi plus ancienne ?
L'intérêt du Raspberry pi dans le cadre de ce robot est double : Il propose un port CSI pour piloter la camera, et il permet d'exécuter du code complexe et gourmand, tel que celui d'un petit serveur web. Les versions précédentes de la carte sont sensiblement identiques, à l'exception de la quantité de mémoire vive, et de la gestion de l'USB. Il est donc tout a fait possible de réaliser ce robot avec une version précédente.
La qualité de l'image peut-elle être améliorée ?
La qualité d'une image influe directement sur son poids, et dans notre cas, sur le débit sortant de l'adaptateur Wifi. Malheureusement, ces petits adaptateurs sont rarement performants. Il faudrait passer par une solution réseau plus aboutie, ethernet ou routeur WIFI, qui impacterait directement la consommation électrique.
Ressources et liens
Les fichiers réalisés dans cette présentation :
- hello.js Hello World node JS
- camera.js Prendre une photo avec NodeJS sur raspberry Pi
- mjpg.js Diffuser un flux mjpg avec NodeJS
- camerastream.js Une librairie de gestion de la caméra pour NodeJS
- i2c.zip Un arduino en esclave i2c
- server.js Le code NodeJS du robot
- index.html L'interface web complète du robot
Les liens relatifs à la présentation :
- www.raspberrypi.org Le site officiel de la communauté, propose de nombreuses ressources pédagogiques
- www.nodejs.org Le site officiel du projet nodejs, propose les packets d'installation et une documentation exhaustive
- www.npmjs.org La plus grosse collection de packets additionnels pour nodejs
- fr.rs-online.com Un magasin d'électronique proposant de nombreux produits de l'écosystème Raspberry pi
- www.adafruit.com Un magasin d'électronique pour les hackers, le DIY. Il propose de nombreus tutos et librairies
- node-arm.herokuapp.com Propose les dernières versions de nodejs compilées pour raspberry pi
- www.fritzing.org Un logiciel de conception électronique qui peremt de produire des schémas
- www.arduino.cc Le site de la communauté arduino
- inkscape.org Logiciel de dessin vectoriel open source
- lamachinerie.org Coworking, Fablab, et découpe laser à Amiens
- latechamienoise.com Association destinée à fédérer les acteurs du numérique amiénois
Nicolas Giraud
Développeur web, chef de projet technique. PHP, NodeJS, OSHW, Raspberry Pi, Arduino ...