Archives Mensuelles: mai 2012

ArduGate ou le pilotage d’un Arduino en manuel via une interface web

Un rapide petit billet pour vous parler d’un projet que je viens de découvrir : ArduGate.

ArduGate permet de contrôler son arduino à partir d’une page web.

Un programme est à charger sur l’arduino et un agent tourne sur l’ordinateur auquel il est connecté en USB. Une fois ce dernier lancé on a accès au serveur web sur http://127.0.0.1:8880/.

L’écran d’ArduGate

1) Paramétrage du port série à utiliser et du baudrate. A noter que sous Linux le port série est en /dev/ttyACM0 et que les ports énumérés ici sont les /dev/ttySXX. En attendant une correction de la part de l’auteur, j’ai donc fait un lien symbolique entre /dev/ttyS33 (un port inexistant) et /dev/ttyACM0.

sudo ln -s /dev/ttyACM0 /dev/ttyS33

2) Connexion à l’Arduino. L’Arduino doit avoir été préchargé avec le programme de l’ArduGate et bien sûr être connecté à l’ordinateur ^^

Une fois connecté il est possible d’accéder aux entrées/sortie digitales (3) et analogique (4).

Le sens des E/S Digitales est paramétrable dans les boites boites de sélection. Il est aussi possible de choisir de piloter un servo, un switch, une lumière ou un relais .

Je pense que ce programme me sera très utile dans les phases de développement et de test d’un montage électronique. Cependant je me vois mal l’utiliser pour piloter mes créations de façon pérenne, l’interface web étant à paramétrer lors de l’utilisation. Par contre pourquoi ne pas réemployer le protocole de communication entre l’ordinateur et l’arduino pour en faire un protocole universelle, mais cela revient à déplacer l’intelligence de l’Arduino vers l’ordinateur, l’Arduino n’étant plus que l’esclave de ce qu’il reçoit par son port série.

Passer un Arduino en wifi avec un WR703N

Le problème dans un appartement c’est bien souvent de faire passer des câbles et je trouve les shields réseau pour Arduino horriblement couteux. Rien que le shield ethernet coute une trentaine d’euro, et le wifi, si mes souvenirs sont bons est au moins une cinquantaine.

Possédant un WR703N qui allie le wifi et l’ethernet pour un prixé dérisoire, j’avais déjà pris le pari dans les articles précédents de lire les données de l’arduino depuis celui-ci. La connexion était en filaire, j’ai un peu cherché dans différents tutoriels pour activer le  mode client en WPA sur openwrt.

J’ai failli m’arreter sur celui-ci , utilisant wpa_supplicant, mais il n’est pas intégré aux outils de configuration d’OpenWRT ce que je trouvais dommage.

Apres quelques tâtonnements j’ai trouvé la configuration suivante :

  • /etc/config/network
config interface 'wan'
 option ifname 'wlan0'
 option 'proto' 'static'
 option 'ipaddr' '192.168.2.99'
 option 'netmask' '255.255.255.0'
  • /etc/config/wireless
config wifi-iface
 option device 'radio0'
 option mode 'sta'
 option ssid 'ssid de votre réseau Wifi'
 option encryption 'psk'
 option key 'mot de passe du wifi'

Il suffit alors de rebooter ou tout simplement de lancer la commande

wifi up

Reste à le passer en mode dhcp pour coller à la topologie du réseau de la maison, mais l’essentiel est fait.

Actuellement je mesure 0.5W en consommation pour l’Arduino (avec le programmes d’acquisition des températures et de la luminosité) et le WR70N avec Wifi et LAN activé. Je serais curieux de comparer avec un shield wifi, si quelqu’un à l’info …

D’ailleurs je cherche un câble USB « court » A mâle vers B mâle pour alimenter l’arduino depuis le WR703N, le plus court que j’ai fait son mètre et c’est un peu ridicule pour relier deux petites machines qui sont cote a cote. Alors si quelqu’un sait ou s’en procurer des pas cher (ou des connecteurs USB pas cher pour faire un câblage maison …)

EDIT : A lire la procédure de Andy Brown qui part dans le même sens que moi, mais à une autre approche que moi pour la lecture des données venant de l’arduino (je l’avais détaillée ). Comme on dit en perl : tmtowtdi.

Mise en graphique des données

Dans les billets précédents j’ai donc détaillé comment récupérer des température depuis l’Arduino, comment les véhiculer sur le réseau à travers un modèle client/serveur et comment les insérer dans une base de données.

Tout cela est bien beau mais des données non exploitées ne servent à rien.

Deux écrans de consultation me viennent naturellement à l’esprit :

Une consultation de la dernière valeur (un peu comme le ferait un thermomètre accroché au mur), cet écran est trivial donc pas la peine d’en parler.

Graphique de la station météo

Graphique de la station météo

Une visualisation d’un historique, cet historique sera constitué des moyennes sur chaque heure et restitués sur un graphique a deux axes (d’un coté les températures et de l’autre les mesures de lumière).  J’ai utilisé une librairie de chez Google dont la documentation se trouve ici .Je vous encourage a vous balader dans la doc, il y a des fonctionnalités assez intéressante d’autant plus que son utilisation est assez aisée. La génération du graphique que je souhaite rendre est fait coté client par du JavaScript.

En moins d’une heure j’ai donc codé un graphique, ce n’est peut être pas très « sexy » mais les données sont restituées et c’était là mon but.

Comme d’habitude le code est dans mon répository Google Code

Avec des Plugins c’est plus festif

Il y a deux semaines je vous avais parlé de mon Bus Arduino (qu’entre temps j’ai nommé ARV, comme Arduino Rendez-Vous). J’ai décidé de le faire évoluer pour que le collector puisse faire d’autres choses.

J’ai imaginé plusieurs architectures pour pouvoir évoluer facilement suivant les besoins et j’en suis arrivé à développer des plugins pour le collector.

Un plugin c’est quoi ?

Un plugin c’est une librairie partagée (dll ou .so suivant votre plateforme) ayant des noms de fonction normalisée.

Tous les plugins pour une même application auront donc des fonctions et des variables en communs : celles qui seront appelées par le programme « maitre ».

Ce programme va donc ouvrir chaque plugin à charger et récupérer un pointeur sur chaque fonction/variable qu’il compte utiliser.

Comment ça s’implémente ?

On commence par « ouvrir » le plugin

void * plugin = dlopen (fileName, RTLD_NOW);
 if (!plugin)
 {
  printf ("Cannot load %s: %s\n", fileName, dlerror ());
  return 1;
 }

et après on peu « lier » une variable  (par exemple la variable pluginName contenu dans le plugin)

char * pPluginName = dlsym (plugin, "pluginName");
result = dlerror ();
if (result)
[...] traitement des cas d'erreur

ou une fonction

typedef int (*init_f) ( char * _subject, sirElement * config );
init_f init = dlsym (plugin, "init");
 result = dlerror ();

Notez bien le typedef du prototype de fonction.

Pour chaque plugin chargé je stocke un pointeur vers une fonction d’initialisation du plugin (init), qui va me permettre d’ouvrir des fichiers ou de me connecter à une base de donnée, et une fonction de traitement du message reçu (parse).

Le chargement ? quel chargement ?

Oui, car il faut charger tous les plugins qu’on compte utiliser, j’ai opté pour un fichier de paramétrage (collector.ini dont un exemple est reproduit ici) qui va définir les plugins à charger et quand les utiliser.

[base]
pluginDir=plugins
[plugins]
arduinoTP.StationMeteo=stationMeteo.so
arduino.StationMeteo=stationMeteo.so
arduinoTP.StationMeteo=toFile.so
[stationMeteo]
DBHost=127.0.0.1
DBName=BaseArduino
DBUser=UserArduino
DBPassword=MotDePasseArduino
[toFile]
#Par défaut le plugin prends "toFile.csv", on peut aussi le fixer par configuration
fileOut=
[toFile:arduinoTP.StationMeteo]
#On peu aussi définir des paramétrage pour un couple plugin/sujet
fileOut=fichierOut.csv

Détaillons ce fichier de configuration

La section [base] contient pour le moment le chemin vers le répertoire des plugins. Tous les plugins devront être dedans au risque de ne pas être chargés.

La section [plugins] détaille les plugins à charger. Attardons nous un peu plus sur cette syntaxe.

arduinoTP.StationMeteo=stationMeteo.so

Il y a donc une clef  (arduinoTP.StationMeteo) qui à une valeur (stationMeteo.so),par cette directive on définie quel plugin utiliser (stationMeteo.so) lors de la réception d’un message de type « arduinoTP.StationMeteo ». C’est la fonction parse() du plugin qui sera utilisée pour traiter le message.

Le plugin stationMeteo.so a pour mission de stocker dans une base MySQL les message reçus (deux photoresistances et 5 capteurs de température), dans le but d’être accessible sur mon site web personnel.

Il est possible de mettre plusieurs ligne ayant une même clef afin de multiplier les actions à réaliser sur réception d’un message (par exemple stocker un message en base ET faire agir un autre arduino en envoyant un autre message sur le bus)

Le plugin de type stationMeteo a droit à une section de paramétrage, j’y ai placé les paramètres d’accès à la base de donnée.

[stationMeteo]
DBHost=127.0.0.1
DBName=BaseArduino
DBUser=UserArduino
DBPassword=MotDePasseArduino
J’ai écrit un autre plugin : toFile.so qui se contente d’écrire ce qu’il reçoit dans un fichier. C’est aussi une bonne méthode pour illustrer une autre façon de paramètrer des plugins.
[toFile]
#Par défaut le plugin prends "toFile.csv", on peut aussi le fixer par configuration
fileOut=
[toFile:arduinoTP.StationMeteo]
#On peu aussi définir des paramétrage pour un couple plugin/sujet
fileOut=fichierOut.csv

toFile a deux sections de configuration : [toFile] et [toFile:arduinoTP.StationMeteo]. Dans le second cas vos pouvez reconnaître un nom de message qui a déjà été paramétré dans la section [plugins]. Cela implique qu’un message de type arduinoTP.StationMeteo utilisera un plugin initialisé grâce à la section [toFile:arduinoTP.StationMeteo] et [toFile] dans les autres cas.

Dans le cas présent cela influe sur le nom de fichier, mais cette méthode est applicable par tout les plugin installé pour avoir des particularité suivant le message reçu (base de donnée différente, fichier différent, …).

Concernant la lecture du fichier d’ini

Par défaut le C n’a pas de librairie d’accès standard pour ce genre de fichier alors j’en ai ré-implémenté une aux fonctions minimales (sir.c dans le repository). J’avais d’abord cherché à utiliser ce qui existe déjà mais j’avais la contrainte de la taille (n’oublions pas que je compile pour une machine ayant 1.5Mo de filesystem ^^) , dans mes pérégrinations je suis tombé sur iniParser qui fait le boulot de recherche dans un .ini mais qui n’accepte pas d’avoir plusieurs clefs identiques, et comme j’utilise cette fonction pour multiplier les actions sur réception d’un message … j’ai été contraint d’en réécrire un plus simple.
L’accès au code se trouve comme d’habitude : ici

Robocarton piloté par Nunchuk

Et non Robocarton n’est pas à la plage, meme s’il aimerait surement. Mais son dermatologue lui a déconseillé, il parrait que l’eau ne lui ferait pas du bien. Donc il est resté à la maison et j’ai pu le faire évoluer. Le but de la manœuvre a été de le faire piloter via un vieux Nunchuk dont le fil était coupé (je vous rassure il existe aussi des adaptateurs pour éviter de le massacrer).

Cela faisait un bout de temps que je tâtonnais mais je m’étais fait avoir par les code couleurs des fils qui ne correspondent à rien de censé (c’est un nunchuk « compatible », pas « officiel »).

Le nunchuk que je possede a ce cablage là :

  • Jaune : 3.3V
  • Rouge : Gnd
  • Bleu : A5 (clk)
  • Blanc : A4 (data)

D’autre part j’avais trouvé une Démo permettant de piloter un arduino à partir du nunchuk, mais la forme ne me plaisait pas (mettre du code dans un .h, j’entends encore certains professeurs hurler ^^).

Alors que j’étais parti pour en faire une librairie je suis tombé sur une implémentation par Gabriel Bianconi  dudit code.

Cette librairie est à déposer comme d’habitude dans le répertoire ~/sketchbook/libraries/.

Le code suivant une fois compilé  et envoyé il est  donc possible de :

  • faire lever/baisser les bras en bougeant le joystick vers le haut/bas
  • faire tourner la tête en bougeant le joystick vers la droite/gauche
  • allumer les leds en appuyant sur le bouton Z

(le code est aussi accessible sur google code)

#include <Servo.h> 
#include <Wire.h>
#include <ArduinoNunchuk.h>
Servo myServoTete;
Servo myServoBrasDroit;
Servo myServoBrasGauche;
#define BAUDRATE 19200
#define SERVO_BRAS_DROIT 7
#define SERVO_BRAS_GAUCHE 5
#define SERVO_TETE 6
#define LED_GAUCHE 9
#define LED_DROITE 8
#define LED_PECTORAL 10
ArduinoNunchuk nunchuk = ArduinoNunchuk();
#define MIN_JOY 0
#define MAX_JOY 255
#define MIN_SERVO 1
#define MAX_SERVO 181
int oldAngleTete = 0;
int oldAngleBrasDroit = 0;
int oldAngleBrasGauche = 0;
int oldStatusBoutonZ = 0;
void setup ()
{
 Serial.begin(BAUDRATE);
 nunchuk.init();
 myServoTete.attach( SERVO_TETE );
 myServoBrasDroit.attach( SERVO_BRAS_DROIT );
 myServoBrasGauche.attach( SERVO_BRAS_GAUCHE );

 pinMode( LED_GAUCHE, OUTPUT);
 pinMode( LED_DROITE, OUTPUT); 
 pinMode( LED_PECTORAL, OUTPUT); 
}
void loop ()
{
 nunchuk.update();
 int angleTete = (int) (( (float) nunchuk.analogX / ( MAX_JOY - MIN_JOY ) ) * ( MAX_SERVO - MIN_SERVO ) + MIN_SERVO);
if ( angleTete != oldAngleTete )
 {
 myServoTete.write( angleTete );
 oldAngleTete = angleTete;
 }

 int angleBrasGauche = (int) (( (float) nunchuk.analogY / ( MAX_JOY - MIN_JOY ) ) * ( MAX_SERVO - MIN_SERVO ) + MIN_SERVO);
 if ( angleBrasGauche != oldAngleBrasGauche )
 {
 myServoBrasGauche.write( angleBrasGauche );
 myServoBrasDroit.write( MAX_SERVO - angleBrasGauche );
 oldAngleBrasGauche = angleBrasGauche;
 }

 int statusBoutonZ = nunchuk.zButton;

 if ( oldStatusBoutonZ != statusBoutonZ )
 {
 digitalWrite( LED_GAUCHE, (statusBoutonZ == 1 ? HIGH : LOW ) );
 digitalWrite( LED_DROITE, (statusBoutonZ == 1 ? HIGH : LOW ) );
 digitalWrite( LED_PECTORAL, (statusBoutonZ == 1 ? HIGH : LOW ) ); 
 oldStatusBoutonZ = statusBoutonZ;
 }
}

Je laisse mon fils vous faire une démo (c’est dire si la robotique c’est un jeu d’enfant 😉 ) :


Robocarton piloté par un nunchuk

Installation d’OpenVPN sous Linux

Pendant que je suis en train d’y penser j’avais pris quelques notes quand j’avais installé openVPN server sur ma machine.

J’avais suivi une très bonne procédure ici, elle couvre l’installation d’openVPN « normalement » ET le fait que celui-ci partage son port avec apache  ce qui limite l’exposition de ports et permet d’utiliser certains proxy.

Je vis juste pointer du doigt les éléments coté client à reprendre.

La création du certificat pour le client :

cd /usr/share/doc/openvpn/examples/easy-rsa/2.0/
 source ./vars
 ./build-key InserezIciLeNomDuClient

Les fichiers nécessaire pour le client sont les suivants, ils seront donc à copier dans le répertoire d’installation d’OpenVPN duu client :

  • client.key
  • client.crt
  • client.csr (j’ai un doute sur la nécessité de celui-ci, l’installation sur la tablette n’en a pas eu besoin)
  • ca.crt
  • ta.key

Si vous souhaitez révoquer un certificat :

cd /usr/share/doc/openvpn/examples/easy-rsa/2.0/
 source ./vars
 ./revoke-full clientARevoquer
 cp keys/crl.pem /etc/openvpn/keys/
 ajouter dans le server.conf openvpn : crl-verify keys/crl.pem

Pour les curieux il est intéressant de voir le contenu d’un certificat avec cette commande (ou juste pour en vérifier le contenu)

openssl x509 -text -noout -in ps -fe

 

Capteur de température et de luminosité pour Arduino

WR703n

Arduino avec 5 sondes de température et deux de luminosité

A partir de code récupéré sur mon-club-elec.fr et la doc officielle de l’Arduino. J’ai réalisé il y a quelques mois un petit montage sur Arduino qui peut mesurer la température provenant de plusieurs capteurs DS18B20, ainsi que la luminosité ambiante à partir de photorésistances.

Pour ce qui est du montage, on utilise des entrées numérique pour les capteurs de température et des entrées analogique pour les photorésistances.  Les DS18B20 (températures) utilisent le protocole OneWire, heureusement la doc Arduino est là avec ses explications (la lib est téléchargeable ici).

Le Montage

Le montage est séparable en deux parties

  • les Sonde Thermo (à gauche)

Les sondes thermo sont toutes connectées sur le même port d’entrée numérique de l’Arduino. Je n’en ai représenté qu’une seule, mais en pratique toutes les sondes sont reliées au même bornier.

  • les photorésistances (à la droite)

Les photorésistances sont des résistances dont la valeur change avec la quantité de lumière reçue. Il existe des formules permettant de calculer la valeur en Lux correspondant, mais je n’ai pas les moyens de faire un étalonnage pour l’instant. La valeur mesurée sera donc relative (sur une échelle allant de 0 à 1023).

La collecte des données

Le code de l’arduino est hérité du travail de Xavier Hinault et se trouve ici. J’ai principalement apporté la gestion de plusieurs sondes Thermo, des photorésistances et mis en forme la trame remontée au PC via le port USB.

Les données en sortie sont écrites sur la sortie série (le classique Serial.println) et récupéré sur l’ordinateur par un programme dont j’ai déjà parlé ici , j’ai nommé log-avr (dont le code source est toujours lisible ici )

Oui je sais, j’écris les articles dans le désordre :p

Android et OpenVPN

J’ai un openVPN à la maison et depuis un moment je cherche à raccorder ma tablette dessus, histoire d’avoir un peu de sécurité quand je suis sur wifi « ouvert ».

Or Android ne supporte pas, à moins d’être rooté, openVPN, et je n’ai pas envie de rooter mes appareils, c’est trop facil !

Une Feature Request existe à ce sujet et je m’étais inscris dans la liste d’attente et là j’ai la surprise de recevoir un mail m’aiguillant sur : Openvpn for Android. Cela ne marche que sous Android 4 (Ice Cream Sandwich), mais comme j’ai eu la chance d’avoir droit à l’upgrade en début de semaine (Youpi ^^)…

L’application s’installe sans soucis via le market, il semblerait cependant que la disponibilité de l’application soit liée au pays dans lequel vous résidez (le chiffrement est considéré par certains comme une arme de guerre … no comment).

Effectivement après installation j’ai copié les fichiers que j’avais généré (ca.crt, tablette.key, tablette.crt et ta.key) via clef USB, renseigné deux-trois choses qui étaient dans la configuration initiale et pouf ça a marché !

Merci Android !

Usage Client/Serveur pour arduino

Afin de piloter mon arduino j’aimerais bien avoir accès simplement à une interface de pilotage.

Pour ce faire il me faut un comportement « réseau », moi ce qui me viens en premier c’est TCP/IP . J’ai donc commencé une implémentation d’un système client/serveur qui peut accepter plusieurs clients et plusieurs arduinos.

Je suis parti sur une architecture assez évolutive héritée de mon passé professionnel à utiliser Tibco Rendez-vous (« Middleware Orienté Message » comme on dit chez le Marketing) . J’ai donc implémenté un serveur sur lesquels peuvent se connecter des clients (jusque là rien de bien nouveau) . Ces clients peuvent être purement réseau (on les appellera client) ou avoir une patte sur le réseau et une sur le port série (on les appellera collecteur).

Le collecteur et le client sont presque identique, à la différence de l’implémentation de la lecture/écriture du port série pour le premier. Le code du client risque d’ailleurs de disparaitre au profit du collecteur que je trouve plus « puissant ».

Il est possible sur un client de taper du texte, il sera envoyé au serveur qui relayera le message à tous les clients connectés (sauf celui l’ayant envoyé), ça c’est le comportement d’un IRC. Le collecteur récupère des infos depuis la ligne série et peu aussi écrire des commandes vers cette derniere. Là on commence à avoir plus d’interet, non ?

Prenons un exemple d’utilisation.

Lançons le serveur (fenêtre du milieu)

./server

pour un test complet lançons un client « simple » (fenêtre du haut)

./collector 127.0.0.1 client
 et dans une autre fenêtre lançons le collecteur (fenêtre du bas)
./collector 127.0.0.1 collecteurMeteo /dev/ttyACM0 arduino.stationMeteo

Collecteur va écouter ce que l’arduino écrit sur sa liaison série et envoyer ça au serveur qui va répercuter ça à tous les autres clients. Ces clients peuvent les afficher, les stocker en base, faire agir d’autres arduino, … . Les possibilités sont infinies.

Afin de ne pas se mélanger les pinceaux chaque message envoyé est constitué de trois champs :

* la source : un nom identifiant l’émetteur du message

* le sujet : un texte décrivant le but du message . Par convention j’ai utilisé une série de mots séparés par des points : info.client.connect pour indiquer qu’un client s’est connecté.

* le message : champ  texte libre. A vous de vous définir un sous protocole pour communiquer avec vos créations

Le code source est accessible ici, bon c’est encore en travaux donc ne vous attendez pas à avoir un truc pil poil au top ^^. Je me suis basé sur l’exemple suivant pour l’implémentation du client/serveur, pas de fork, pas de thread , pas de haine. Il faut encore que je fasse du nettoyage pour permettre une plus grande clarté dans le code.

Tout est publié sous licence GPL v2, donc servez vous, mais tenez moi au courant de vos créations.

Arduino et le bluetooth – Acte 1

J’en ai marre, tout les jours je tombe sur des trucs intéressants !

Aujourd’hui c’est l’interfaçage d’un Arduino avec un PC via Bluetooth

Du coup j’ai commandé un module « Wireless Bluetooth Transceiver Module RS232 / TTL » sur ebay … 5€ frais de port compris, reste à voir ce que ça donne … d’ici un mois quand le colis sera arrivé de l’autre bout de la planète