Aller au contenu


Path

Inscrit(e) (le) 06 févr. 2016
Déconnecté Dernière activité févr. 26 2023 08:44
*****

Introduction à Node JS sur PI

Publié Path le 24 mars 2016 - 10:55 in Programmation

nodejs-logo.png raspberry_pi_logo.png

 
C'est quoi Nodejs ?
 
Nodejs, c'est un portage open source en C++ du moteur d'interpretation et d'exécution javascript que l'on trouve habituellement dans les navigateurs (chrome) : le V8 de google. Nodejs permet de sortir le javascript des navigateurs pour l'exécuter sur une machine windows, mac ou linux en standalone (desktop, serveur ou embarqué). 
 
Les navigateurs étant sécurisés, par exemple, on ne peut pas accéder aux fichiers, à la ligne de commande ou écouter un port. Nodejs ajoute au javascript les fonctions  d'accès au système qui lui faisaient défaut. Nodejs suis les évolutions de la norme ECMAScript (spécifications du langaue) et est devenu une plateforme à la fois simple, léger et mature. Surtout depuis ES6. La doc de l'API exposée par NodeJS en plus du Javascript : https://nodejs.org/d...-v6.x/docs/api/
 
NodeJS est maintenant couramment utilisé dans le monde de l'IT pour des middleware, des web services temps-réel ou en full-stack (coté serveur et coté client) pour des applications web. On le voit aussi beaucoup dans le monde des objets connectés. Il arrive naturellement sur le raspberry PI pour piloter un robot. 
 
Le langage javascript n'est pas un langage simple contrairement à ce qu'on pense généralement. Ce tuto ne couvre pas le javascript. Il faudra pour cela voir de ce coté : http://javascript.de...ppez.com/cours/. C'est faux de croire que l'on connait javascript si on a affiché un bouton dans une page web. En effet le navigateur masque toute la partie interessante de javascript : sa boucle d'évènements. Le code javascript est exécuté dans un seul thread. Mais derrière tous les appels asynchrones, la mécanique du V8 est parallélisée. Mieux que des mots, la meilleure video que je connaisse pour expliquer comment fonctionne javascript.
 

 
Par exemple, hello.js

// attends 1s et affiche le texte
setTimeout (function() {
  console.log("les makers");
},1000);
console.log ("Hello");

$node hello.js (ou C:\node.exe hello.js)

hello.js affiche :
Hello
​les makers
(et pas "les makers Hello")
 
Avertissement
 
Le tuto qui suit montre comment piloter un robot avec NodeJS. Vous l'aurez compris, NodeJS devient intéressant quand on connait javascript.
 
Ce tuto pré-suppose que le raspberry est installé avec la raspbian : https://www.raspberr.../documentation/
 
Ce tuto est destiné aux débutants en robotique. Il est réalisé dans le cadre de la conception du robot Ash : http://www.robot-mak...alancing-robot/
 
Pourquoi PAS NodeJS ?
 
Javascript n'est pas un langage temps-réel.
Javascript n'est pas compilé. Il n'y a pas de vérification du code avant l'exécution.
Javascript est faiblement typé. Il demande un peu d'attention.
 
Alors, plus concrètement,
 
Pourquoi NodeJS ?

  • javascript n'attend pas

Il continue à exécuter le code pendant qu'une instruction asynchrone est en attente. Une lecture de ficher, d'un port série ou réseau. Cela le rend bien plus efficace et performant qu'un système multi-threadé.

  • javascript est un langage à évènements.

Ce n'est pas avec une librairie ou un addon. C'est au coeur du langage.

  • Les streams

L'API stream de NodeJS combine la puissance des évènements avec celle des pipes d'unix. Si vous connaissez les pipes entre les commandes unix, vous savez que c'est une aide précieuse et facile à mettre en place.

  • javascript est full stack

Un seul langage pour le serveur, pour le client et pour les middlewares orienté messages (évènements). 

 
Si on connait son langage, NodeJS est un pont facile à mettre en place entre arduino et une interface de contrôle web. Et disposer d'une interface web permet de ne rien installer sur le terminal de commande (sauf un navigateur) et il est compatible avec tous les smartphone et sur toutes les machines desktop habituels.
 
 
tutorials-9452-0-82260000-1462831177.png
 
NodeJS ouvre le raspberry (et donc le robot qui en est doté) à tout l'Internet domestique ou extérieur.
 
Enfin, Nodejs bénéficie d'une très large communauté. Il est accompagné d'un gestionnaire de packages (librairies) npm. Pour vous faire une idée, voilà ce qu'on trouve déjà concernant le port gpio chez nodejs : https://www.npmjs.com/search?q=gpio
  
  
NPM
 
Node s'install avec son gestionnaire de packages. Voir : https://docs.npmjs.com/
On se contentera de faire des npm install pour obtenir des modules. 
 
Installation de NodeJS et NPM sur Raspberry PI
 
Ajouter le repository nodesource :

sudo curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -

Cette commande va aussi  mettre à jour le catalogue.
 
NB. Adafuit mets aussi node à disposition sur un repository similaire. Avec nodesource, on a une version plus à jour. 
NB. Quand la version 8 de NodeJS sera disponible, l'url ci-dessus devra être adaptée. Voir https://github.com/nodejs/LTS/.
 
Installer nodejs :

sudo apt-get install nodejs

NB. npm (le gestionnaire de package de node) est installé automatiquement avec nodejs.
 
Vérification :

pi@raspberrypi:~ $ nodejs -v
v6.2.1
pi@raspberrypi:~ $ npm -v
3.9.3

Source : https://nodejs.org/e...x-distributions

 

Installation d'un module NPM

$npm install <nom du module>

npm va alors créer un répertoire module dans le répertoire courant. Vous devez donc vous placer à la racine de votre projet pour lancer cette commande.

 

Pour plus d'infos sur NPM : https://docs.npmjs.com/

Interface avec Arduino
 
Le plus simple est de conserver le câble USB entre le raspberry et arduino dans le montage définitif du robot. 
 
Compilation
Cela permet de compiler le code arduino sur le raspberry directement et d'uploader le programme compilé sur l'arduino directement depuis le raspberry. Voir http://www.robot-mak...ne-de-commande/
 
Communication
Pour communiquer avec arduino, on utilise toujours le câble USB.
 
Coté raspberry, on utilise le module NPM "serialport" dans une classe utilitaire qui fait l'interface avec Arduino :

Spoiler

 
On utilise cette classe comme ceci :
 

var Arduino = require('./modules/arduino.js');

 
Pour envoyer un message à arduino :

arduino.writeSerial('COMMANDE:DONNEE:DONNEE:DONNEE');

 
Pour recevoir des messages de arduino :
 

arduino.on('ready', function() {
  console.log('Arduino ready');
});

arduino.on('CONSOLE', function(data) {
  console.log('[ARDUINO CONSOLE]'+data.args);
});

arduino.on('COUNTCODER', function(data) {
  console.log('Arduino COUNT left: '+data.args[0])
  console.log('Arduino COUNT right: '+data.args[1])
  (...)
})

 
Du coté Arduino, pour écrire un message à raspberry, on utilisera simplement 

Serial.print();

Pour lire les message envoyé par raspberry, il faut les dé-sérialiser et dispatcher les commandes. Par exemple :



Spoiler

 
Alimentation
Le raspberry peut alimenter l'aduino par le port USB donc dans la limite de 500mA.
 
Note
Le montage par câble USB sera remplacé par un branchement I2C ou SPI pour des besoins plus spécifiques communication en réseau. Arduino pourra être alimenté différemment s'il a besoin de plus de 500 mA.
 
Interface avec les programmes en python
 
Par exemple, on va intercepter les valeurs qui arrivent du capteur IMU du senseHAT. Le senseHAT est fourni avec une API en python. On va appeler la librairie du senseHAT et écrire une valeur sur la sortie standard.

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sense_hat import SenseHat
import time
sense = SenseHat()
sense.set_imu_config(False, True, True)  # compass_enabled, gyro_enabled, accel_enabled
while True:
	# Get orientation from hat
	orientation = sense.get_orientation_degrees()

	roll = orientation["roll"]
	roll = round(roll, 2)
        print(roll)
	time.sleep(.005)
 

Dans NodeJS, on va utiliser le module "python-shell" pour instancier ce programme en python et lire la sortie standard.
 

var PythonShell = require('python-shell');

var pyOptions = {
  mode: 'text',
  pythonPath: '/usr/bin/python',
  pythonOptions: ['-u'],
  scriptPath: '/home/pi/SBR'//,
  //args: ['value1', 'value2', 'value3']
};

var imu = new PythonShell('imu.py', pyOptions);

imu.on('message', function(data) {
    console.log(data); // data contient une ligne de la sortie standard données par imu.py
  });
 

 
 
Interface web
 
Pour servir une page static HTML avec node, c'est très simple. On va utiliser le module "express" pour créer un mini serveur web sur le raspberry. On y ajoutera tout de suite une websocket pour obtenir des informations du robot sur la page web en mode push (à l'initiative du serveur).
 

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);

io.on('connection', function(socket){

    socket.on('command', function(data) {
      // data contient les données envoyées depuis la page web
    });

    // Pour envoyer des données au navigateur
    io.sockets.emit("COMMAND", data);
});

// Pour servir la page static, on la place dans un répertoire dédié
app.use(express.static(__dirname + '/../static'));

server.listen(3000);

Placez une un fichier nommé index.html dans le répertoire static.
 
Pour se connecter l'interface web, il faudra se connecter à l'IP du raspberry sur le port 3000 depuis un navigateur. (http://w.x.y.z:3000/). Votre navigateur affichera le contenu html de votre index.html.
A noter, socket.io sert son client websocket au navigateur de façon transparente.
 
Votre fichier html de commande peut ressembler à ceci :

 

Sans titre.png

 

Spoiler

 

Pour plus d'infos sur la websocket : https://github.com/socketio/socket.io
Pour plus d'infos sur express : http://expressjs.com/fr/

NB. Il s'agit d'un embryon de serveur web. Mais suffisant pour les besoins de pilotage d'un robot.

 
Pour aller plus loin
 
Le V8 de google : https://fr.wikipedia...eur_JavaScript)
NodeJS : https://nodejs.org/en/about/
Liens utiles NodeJS : https://github.com/s...NodeJS-Learning
Javascript : https://developer.mo.../Web/JavaScript

Thumbnail(s) attaché(s)

  • Ash suite.png



Compilation sur rPI et Upload sur arduino directement depuis le PI en ligne de commande.

Publié Path le 17 mars 2016 - 10:02 in Programmation

Testé sur un raspberry PI2B et arduino UNO.
OS Raspbian Jessie Lite à jour : apt-get update et apt-get upgrade voire un apt-get dist-upgrade.
Et comme on est sur un petit stockage, un dernier apt-get autoremove
 
Les 2 sont reliés en USB. Ils sont isolés du reste du robot. Le PI alimente l'arduino via USB.
 
post-9452-0-72697100-1458205262.png
 
Compilation
 
Pour modifier le sketch via ssh, depuis le PI vers l'arduino, sans passer par l'interface graphique (IDE)  :
 
(Préalable) Il faut installer 2 packages sur le PI :

sudo apt-get install arduino-core arduino-mk python-serial

Autoriser le user (pi) à utiliser les commandes arduino :

sudo usermod -a -G dialout pi

Pour chaque programme à uploader :
 
Il faut un répertoire dédié par programme. Il contient ces 2 fichiers : code.ino et le Makefile.
 
Par exemple, sur le PI, le contenu de ce répertoire donne :

pi@raspberrypi:~/SBR/arduino $ ls -la
total 24
drwxr-xr-x 4 pi pi 4096 mars  17 22:15 .
drwxr-xr-x 5 pi pi 4096 mars  17 17:46 ..
drwxr-xr-x 4 pi pi 4096 mars  17 22:18 build-uno
drwxr-xr-x 3 pi pi 4096 mars  17 21:43 libs
-rw-r--r-- 1 pi pi  176 mars  17 21:54 Makefile
-rw-r--r-- 1 pi pi 1697 mars  17 22:18 sbr.ino

NB. le répertoire build-uno est créé par le compilateur.
 
Code.ino (le nom importe peu mais l'extension doit être .ino) contient le code source arduino. On peut l'éditer via son éditeur de texte préféré, via ssh, via vi si on veut.

pi@raspberrypi:~/SBR/arduino $ vi sbr.ino

Makefile indique aux commandes arduino quelques paramètres. Il doit contenir ces lignes :

pi@raspberrypi:~/SBR/arduino $ cat Makefile
ARDUINO_DIR = /usr/share/arduino
BOARD_TAG = uno
ARDUINO_PORT = /dev/ttyACM*
ARDUINO_LIBS =
USER_LIB_PATH = /home/pi/SBR/arduino/libs
include /usr/share/arduino/Arduino.mk

Mon arduino est un uno , cela tombe bien. Je crois qu'il faut changer 'BOARD_TAG' si ce n'est pas le cas.
 
USER_LIB_PATH doit pointer vers le répertoire contenant vos librairies.
Par exemple, pour une lib Test.h et Test.cpp, ces 2 fichiers sont dans un sous répertoire du même nom. Chez moi : /home/pi/SBR/arduino/libs/Test/
 
 
 
Pour compiler, il faut se mettre dans le répertoire qui contient le .ino et le Makefile.
Lancer la commande make :

pi@raspberrypi:~/SBR/arduino $ make

Spoiler


Cela semble compiler ^^
 
Upload sur arduino
 
Pour uploader, toujours dans le même répertoire, lancer make upload.

pi@raspberrypi:~/SBR/arduino $ make upload

Spoiler

I thank you too Mr Duino.
 
 
Après la compilation et l'upload, comment le PI et l'arduino communiquent toujours via le câble USB, sans le débrancher : http://www.robot-mak...rduino-via-usb/
 
Tuto réalisé dans le cadre de la construction de Ash V1 : http://www.robot-mak...-robot/?p=67997