Quantcast
Channel: Tuto Arduino – Le blog d'Eskimon
Viewing all 11 articles
Browse latest View live

1000 Telechargements !!

$
0
0

Et oui, nous avons aujourd’hui passé la barre des 1000 téléchargements de l’ebook en seulement 2 semaines !

Bravo à tous ! Ça nous fait du 70 téléchargements par jour (tout confondu). Voici les détails pour ceux que cela intéresse !

J’en profite pour vous poser une question :

  • J’ai le sentiment (partagé par certains lecteurs) que le format « articles de blog » n’est pas le plus confortable pour la lecture comparé au pdf/epub. Je ne compte pas changer de CMS (WordPress) mais je peux essayer de faire des améliorations par ci par là.
    Avez-vous une idée de ce qui cloche et comment le confort de lecture en ligne pourrait-être amélioré ?

1000 Téléchargements !

A bientôt pour les 10 000 j’espère !

Et n’oubliez pas, un sondage est en cours pour m’aider à améliorer et préparer le prochain tutoriel… Si vous ne l’avez pas encore rempli cela ne devrais vous prendre que 2 minutes en suivant ce lien ! Je ferais une synthèse des réponses à la fin du mois d’avril 🙂 .

A bientôt et bon week-end à tous !


[ Arduino annexe E ] Utiliser Sublime Text comme IDE

$
0
0
Utiliser un vrai IDE change complètement la donne quand il s’agit de faire du développement de projet un peu conséquent… Personnellement j’utilise quotidiennement l’éditeur Sublime Text pour de nombreuses raisons (Vitesse, personnalisation, beauté de l’interface, j’ai dit vitesse ?).
Je vous propose du coup d’en profiter pour l’utiliser avec notre compagnon de bricolage : la carte Arduino !

Sublime Text

Sublime Text est un éditeur de texte. Autrement dit, son boulot consiste à ouvrir des fichiers contenant du texte pour vous permettre de le modifier. Dit comme ça, rien de bien sexy… Mais Sublime Text ce n’est pas que cela, c’est bien plus. En effet, c’est un logiciel que l’on qualifie d’Environnement de Développement (IDE en anglais). Il est optimisé pour le traitement de fichier de type « code source » en proposant une coloration syntaxique puissante, personnalisable et d’autres atouts divers et variés comme la complétion automatique de code, la fermeture de balise, l’indentation intelligente et bien plus encore !
Logo Sublime Text
Dans le monde du développement, Sublime Text est assez à la mode en ce moment. Il s’est fait remarquer grâce à sa charte graphique élégante ainsi que sa rapidité même contre de gros fichiers / projets. De plus, son moteur de plugin est très bien fait ce qui en permet une personnalisation très avancée.
Comparé au petit IDE Arduino natif, c’est le jour et la nuit. Sublime Text brille de toute sa splendeur et sa puissance devant Arduino dont l’environnement laisse quelque peu à désirer quand on est habitué à plus « gros ». Nous allons voir comment installer un plugin sur ST qui, je pense, ne vous ferra pas revenir en arrière de sitôt…
Mais avant toute chose, installons le logiciel !

Installer Sublime Text

Si ce n’est pas encore fait, je vous invite à vous rendre sur le site officiel pour un aperçu rapide (qui fait peur) et plus particulièrement allez dans la section « Download ». À partir de là choisissez la version adaptée à votre système d’exploitation puis installez le logiciel comme vous le feriez d’habitude. Rien de réellement compliqué ! Personnellement, au moment d’écrire ces lignes j’utilise la version « Beta » (sans bug pour autant !) 3059. Je vous la recommande (ou une version plus récente si cela a été mis à jour depuis !).

Petite information importante, Sublime Text est distribué gratuitement et de manière complète mais vous invitera régulièrement à acheter une licence. Si vous aimez le logiciel et voulez soutenir les développeurs, n’hésitez pas à vous en offrir une !

Des plugins bien utiles !

Maintenant que le logiciel est installé, passons en revue quelques plug-ins bien utiles au quotidien et qui vont nous permettre de voir comment leurs installations fonctionnent (c’est très simple vous allez voir !).

Package Control

On commence par le plus compliqué (pour une fois) mais indispensable : Package Control ! Ce plugin est LE plugin à installer en premier. En effet, il permet de centraliser les extensions existantes dans le monde et ainsi de les installer en deux clics ! C’est donc bien pratique !
Pour l’installer, il faudra faire une manipulation un peu bizarre que l’on ne fera que pour ce dernier. Le reste sera simple, promis !
Commencez par ouvrir la console du logiciel en appuyant sur la combinaison de touche Ctrl + ~. La console devrait apparaître en bas.
Dans celle-ci, collez le texte suivant :

import urllib.request,os,hashlib; h = '7183a2d3e96f11eeadd761d777e62404' + 'e330c659d4bb41d3bdf022e94cab3cd0'; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)

On redémarre Sublime Text et on laisse la magie opérer ! Maintenant quand vous ouvrirez la palette de commande (raccourci Ctrl + Alt + P vous pourrez trouver l’option « Install Package ». Lorsque vous la sélectionnez, vous pourrez alors installer les plug-ins suivants…

Sidebar Enhancement

Et on commence tout de suite avec un ajout permettant d’améliorer la fonctionnalité de la side bar (panneau latéral gauche listant les fichiers ouverts). Ce plugin permet de rajouter une poignée de fonctions supplémentaires bien pratiques. Vous pouvez découvrir le projet sur le github de l’auteur.
Pour l’installer : Ctrl + Alt + P puis « Install Package » et enfin « SideBarEnhancements ».

Avez vous remarqué la rapidité/simplicité de la recherche ? Même pas besoin de taper « Install » que vous êtes déjà arrivé sur la bonne fonction 😀

Git et GitGutter

Étant un grand fan du gestionnaire de code source git, les extensions git et gitgutter sont les bienvenues ! La première permet d’utiliser les commandes git dans le logiciel et la deuxième vous indique à côté de votre code où sont les modifications avec le fichier actuel.
On refait pareil ! Ctrl + Alt + P puis « Install Package » et « Git » puis rebelote avec « GitGutter ». Rapide non ?

Theme Soda

Enfin, Sublime Text ce n’est pas que des plug-ins, c’est aussi des zolis thèmes. Il en existe de très nombreux. Parmi tous, j’aime beaucoup le thème « Soda » en version Dark (à régler dans vos paramètres perso). Je le trouve très reposant lors d’une utilisation prolongée.

Le plugin Arduino

Vous l’attendiez ? Eh bien le voilà ! Le fameux plugin Arduino qui nous intéresse tant ici. Histoire de faire un peu les présentations, voici les fonctionnalités qu’il propose : LES MÊMES QUE L’ÉDITEUR D’ORIGINE ! Et oui, avec ce plugin vous avez un environnement de développement complet pour Arduino, avec toutes les fonctions au rendez-vous (compilation, terminal série etc…)
La seule contrainte, c’est qu’il y a une petite étape de paramétrage à faire pour le faire fonctionner correctement. Mais rien de bien méchant ! (ah et il n’y a pas de petites icônes mais un joli menu, c’est peut-être moins pratique mais vous pouvez toujours ajouter des raccourcis clavier perso !).

Installation

Avant toute chose, il faut bien sûr que vous ayez une installation du logiciel Arduino qui fonctionne. En effet, le plugin va se reposer sur les composants/outils installés pour fonctionner. Mais si vous suivez le tuto je suppose que c’est déjà fait 😀 (sinon allez ici pour voir comment faire !)
Je pense que vous avez compris la routine maintenant, il suffit d’aller dans le gestionnaire d’installation des packages et de trouver le paquet nommé : « Arduino-like IDE ». Une fois installé, un menu « Arduino » a du être rajouté dans la barre d’outils. Nous allons pouvoir faire la dernière étape avant de jouer : la configuration !
J’en profite pour vous donner le lien vers le GitHub du plugin : https://github.com/Robot-Will/Stino.

Menu Arduino

Un nouveau menu voit le jour

Configuration

Et oui, il ne reste plus qu’une chose à faire avant de jouer avec le plugin, lui indiquer où l’on veut ranger nos nouveaux projets et où se trouve les exécutables et autres fichiers sources du framework Arduino.
1ère étape : Nous allons commencer par définir le dossier où doivent être enregistrés les nouveaux projets. Ce dossier correspond au « sketchbook » dans l’IDE classique. Pour cela, allez dans le menu Arduino puis sélectionnez « Preferences » et « Change sketchbook folder ». Maintenant, sélectionnez à l’aide des flèches de votre clavier (ou votre souris) le dossier où vous souhaitez enregistrer vos nouveaux projets.
2ème étape : Dire à Sublime Text où se trouve le dossier d’origine du Framework Arduino pour que la compilation se passe correctement. Pour cela, la procédure est très similaire à l’étape précédente : Menu Arduino -> Preferences -> « Select Arduino Application Folder ». Il ne reste plus qu’à entrer le bon dossier.

  • Sous Windows : C:/Program Files/Arduino/
  • Sous Linux : /usr/share/arduino/
  • Sous Mac : /Applications/Arduino.app (non vérifié)

La configuration de base est maintenant prête ! Découvrons notre nouveau jouet !

Utilisation

Blink ST

Un blink de toute beauté !

Puisque tout est prêt à être utilisé, commençons à découvrir ce nouveau menu et prendre nos marques avec cet environnement.

Le nouveau menu

Créer un projet

La première chose qui va sûrement vous intéresser sera de pouvoir commencer un nouveau projet ou « Sketch » dans le langage Arduino. Pour cela les choses sont simples, il suffira d’aller sur la première ligne du menu : « New Sketch ». L’application se chargera elle-même de créer le dossier du projet dans le « Sketchbook » décidé plus tôt et de préparer un fichier .ino avec la fonction setup et loop n’attendant plus que vos instructions. Sympa !

Le squelette de base est automatiquement proposé

Le squelette de base est automatiquement proposé

Vérifier / Compiler

Une fois que vous avez codé, vous avez sûrement envie de vérifier tout cela et de compiler votre projet. Il faudra alors aller dans le menu et chercher l’option « Verify/Compile » pour lancer la compilation. Vous verrez alors la console s’afficher en bas pour vous donner une idée de la progression et vous indiquer si votre code contient des erreurs.
Pour aller plus vite, vous pouvez utiliser le raccourci clavier Ctrl+Alt+V.

Un code avec une erreur de compilation (led non déclarée)

Un code avec une erreur de compilation (led non déclarée)

Envoyer le programme

Si votre programme compile et que vous êtes satisfait, il ne reste plus qu’à l’envoyer dans la carte. Pour cela, deux étapes sont nécessaires. En premier, il faut s’assurer que la carte est branchée et bien sélectionnée dans le menu Arduino.
Ensuite, vous pouvez envoyer le code dans la carte via le menu (option « Upload ») ou le raccourci clavier Ctrl+Alt+U.

Un nouveau terminal

Enfin, parlons un peu du terminal pour utiliser la voie série. Ce dernier se trouve à la ligne « Serial Monitor ». Cette ligne propose plusieurs options pour démarrer/fermer la voie série mais aussi quelques réglages tels que la vitesse ou le caractère de fin de chaîne (quand vous appuyez sur Entrée). Pour la vitesse, sélectionnez celle requise par votre application. Pour le caractère de fin de chaîne je vous conseille de sélectionner la dernière option : « Both CR & NL » afin que la touche Entrée soit bien prise en compte.
Sorti de ces deux options, tout se passe comme d’habitude. Les caractères reçus s’affichent au milieu et ceux à envoyer sont à taper dans la zone en bas.

J’espère que ce tutoriel vous aura plu et que vous allez vous amuser avec ce nouvel environnement de développement.
C’est vrai que le changement est un peu radical au début, mais croyez moi il vaut très franchement le coup de passer quelques minutes/heures difficiles à prendre en main le logiciel, ses particularités et raccourcis clavier tellement ce dernier est puissant, personnalisable et agréable à utiliser !
Ah au fait, vous avez remarqué que le plug-in était aussi en Français :-° !

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !

[ Arduino Annexe F ] Organisez votre code en fichiers

$
0
0
Lorsque vous commencez à faire de gros projets, il devient utile voire indispensable de (très) bien organiser son code. Cela commence par séparer son code en différents fichiers afin d’avoir des entités logiques séparées les unes des autres.
Voyons cela !

Séparer en fichiers

Une opération simple à faire et qui permet de gagner beaucoup en organisation de son code est de séparer ce dernier en différents fichiers. Généralement, on fait un fichier par unités « logiques ». Par exemple, imaginons que nous utilisions un composant un peu compliqué qui sert d’horloge. Ce composant peut renvoyer une date en entier, juste le jour, mois, année ou encore juste l’heure, la minute ou la seconde courante. Pour bien faire, il nous faudrait une fonction par unité de temps. On aurait ainsi au moins 6 fonctions pour récupérer heure/minutes/secondes/jour/mois/année et 6 fonctions pour les régler dans le composant. 12 fonctions + la loop et le setup et vous voilà avec un fichier original bien encombré 😀 .
Pour créer un nouveau fichier dans l’IDE Arduino, il suffit de cliquer sur la petite flèche en haut de l’espace d’édition du code puis ensuite de cliquer sur « Nouvel Onglet » ou « New Tab » comme mis en évidence sur la capture d’écran ci-dessous :
Ajout de fichiers

Le fichier .h

lorsque l’on veut séparer son code en plusieurs fichiers, il y a certaines choses à respecter. Ainsi, à chaque fois que l’on veut créer un nouveau fichier de code on ne vas pas en créer un mais deux ! Le premier fichier aura l’extension .h signifiant header, c’est ce que nous allons voir maintenant.
Ce fichier va regrouper les prototypes des fonctions ainsi que les définitions de structures ou de classes mais nous verrons cela après.
Le prototype d’une fonction représente un peu un contrat. Il va définir le nom de la fonction, ce qui rentre à l’intérieur (les paramètres) et ce qui en sort (la variable de retour). Ainsi, votre programme principal aura une idée de comment fonctionne extérieurement votre fonction. Un peu comme s’il s’adressait à une boîte noire.
Si l’on devait écrire l’exemple ci-dessus on pourrait avoir le contenu de fichier suivant :
horloge.h

/* fichier horloge.h */

char getHeure();
char getMinute();
char getSeconde();
char getJour();
char getMois();
char getAnnee();

void setHeure(char val);
void setMinute(char val);
void setSeconde(char val);
void setJour(char val);
void setMois(char val);
void setAnnee(char val);

void afficherDate();
void afficherHeure();
void afficherDateHeure();

Comme vous pouvez le voir, avec ces définitions on peut savoir ce qu’est supposé faire la fonction grâce à son nom et le type de variable qu’elle manipule en entrée et en sortie.
Bien, maintenant passons à la suite pour voir où et comment implémenter ces fonctions.

Le second fichier .cpp

Le second fichier que nous allons créer sera avec une extension .cpp (pour C plus plus ou C++). Il regroupera le code à proprement parler, l’implémentation de vos fonctions. C’est ici que vous allez écrire le contenu de vos fonctions, ce qui est censé se passer à l’intérieur de ces dernières.
Pour faire cela, la première étape sera d’inclure le fichier de prototypes via la commande de préprocesseur #include :

#include "horloge.h" //horloge.h pour notre exemple

Cette ligne doit être la première de votre fichier .cpp et elle ne prend pas de ; à la fin.

Une fois cela fait, il va falloir taper le code de vos fonctions.
Pour le besoin de l’exercice, je vais me contenter d’écrire des instructions bidons. Dans la vraie vie de tous les jours, vous auriez bien sûr fait un joli code pour communiquer avec un module où je ne sais quoi encore bien sûr 🙂 .
horloge.cpp

/* fichier horloge.cpp */
#include "horloge.h"

char getHeure() {
   Serial.println("getHeure");
   return 0;
}

char getMinute() {
   Serial.println("getHeure");
   return 0;
}

char getSeconde() {
   Serial.println("getHeure");
   return 0;
}

char getJour() {
   Serial.println("getHeure");
   return 0;
}

char getMois() {
   Serial.println("getHeure");
   return 0;
}

char getAnnee() {
   Serial.println("getHeure");
   return 0;
}


void setHeure(char val) {
   Serial.print("setHeure : ");
   Serial.println(val, DEC);
}

void setMinute(char val) {
   Serial.print("setMinute : ");
   Serial.println(val, DEC);
}

void setSeconde(char val) {
   Serial.print("setSeconde : ");
   Serial.println(val, DEC);
}

void setJour(char val) {
   Serial.print("setJour : ");
   Serial.println(val, DEC);
}

void setMois(char val) {
   Serial.print("setMois : ");
   Serial.println(val, DEC);
}

void setAnnee(char val) {
   Serial.print("setAnnee : ");
   Serial.println(val, DEC);
}


void afficherDate() {
   Serial.println("afficherDate");
}

void afficherHeure() {
   Serial.println("afficherHeure");
}

void afficherDateHeure() {
   Serial.println("afficherDateHeure");
}

Lier nos fichiers au programme principal

Vos définitions sont écrites et vos fonctions sont implémentées ? Il ne reste plus qu’à les ajouter à votre programme principal ! C’est en fait très simple vous aller voir.
Tout d’abord, il va falloir s’assurer que vos fichiers .h et .cpp sont dans le même dossier que votre .ino où se trouve votre fichier de programme Arduino. Comme ceci :
Emplacement des fichiers
C’est bon ?
Bien, il ne reste qu’une seule chose à faire, l’inclure dans le programme. Pour cela c’est tout bête, il suffit d’ajouter la ligne #include "horloge.h" en haut de votre fichier.
Et voilà ! Il ne vous reste plus qu’à faire des appels tout simples à vos fonctions perso dans le programme (setup ou loop ou où vous voulez !).
Maintenant, quand vous allez compiler, le compilateur va aller chercher le fichier pointé par le include, le compiler puis le lier dans votre programme principal.

Il peut arriver que le lien avec les symboles/librairies Arduino ne se fasse pas correctement. Dans ce cas là, rajoutez l’include suivant au début de votre .h ou .cpp : #include "Arduino.h"

Séparer son code en fichiers est important pour facilement s’y retrouver, j’espère que vous l’avez bien compris. Une fois cette étape faite, vous devriez y voir plus clair dans vos gros programmes.
Les plus aguerris d’entre vous qui connaissent le C++ peuvent même coder en C++ pour créer des classes et ainsi pousser l’organisation encore plus loin !

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !

Retour sur le sondage sur le tutoriel Arduino

$
0
0

Il y a quelques semaines je vous proposais de répondre à un petit sondage pour m’aider à préparer un nouveau tutoriel et faire un petit bilan sur ce qui avait été appliqué dans celui sur Arduino.
Je vous propose sans plus attendre de partir à l’analyse des résultats !

Petit mot sur les participants

Déjà merci à tous d’avoir participé ! Cela m’a été très utile et m’a permis de confirmer pas mal de choses et de lever certains doutes (mais pas tous).
Vous avez été plus d’une cinquantaine à répondre, ce qui est plutôt pas mal vu quand plus des réponses vous avez presque tous écris un commentaire pour étayer vos réflexions 🙂 ! Plutôt pratique pour compléter les résultats !

Attaquons maintenant les questions une par une dans l’ordre et la discipline !!

Note pour la suite : L’échelle sur 5 signifie 1->Bof, 5->Super !

Impressions sur le tuto Arduino

Bon déjà, c’est rassurant, on ne c’est pas complètement trompé sur le tutoriel Arduino 😀 .
Les retours sont très positifs et sont très encourageants pour écrire un nouveau tuto dans la même ligne…
Je pense que les graphiques se passent de commentaires, vous avez l’air d’être un public satisfait !
Comment avez vous trouvé le tuto
A propos du ton

Cependant, il est bon de nuancer grâce aux commentaires que vous avez pu émettre. En effet, certains sont moins fan du ton trop « léger » et parfois des « raccourcis » qui peuvent être pris vis-à-vis de la rigueur scientifique.
Pour ce qui est du ton, c’est un exercice assez délicat, on aime ou pas, comme pour les goûts et les couleurs, difficile de plaire à tout le monde 😉 .
Pour ce qui est de la rigueur, c’est vrai qu’il pourrait être bon de rentrer plus en profondeur sur certains points. Cependant, il y a alors un risque de décrochage pour des plus débutants. Il est souvent assez difficile de jauger « où s’arrêter » dans une explication. Pas assez et c’est dommage on passe trop au dessus des choses et manque de curiosité, trop et on perd une partie des lecteurs n’ayant pas forcément le recul (ou juste l’envie) pour se frotter à des problématiques plus épineuses (essentiel ou non).
Bref, j’essaierai d’être encore plus vigilant pour la suite et de votre côté vous me ferez des retours si vous êtes en manque de profondeur dans les explications 😀

La méthode pédagogique

Exercices et TP

Exercices et TP
Vous êtes unanimes sur un point : il faut pratiquer pour apprendre ! En effet, c’est ce que pense 94% d’entres vous en plaçant les exercices et les TP comme des « must have » dans les tutoriels.
Je pense aussi comme vous.
Il me semble important d’avoir des situations de mise en pratique afin de confronter ses nouvelles connaissances avec des cas « presque réels ».
Cependant, cela demande du temps à être mis en place et il sera donc difficile de répondre positivement aux personnes qui m’ont demandé « encore plus d’exercices » 😀 . Entre la recherche d’idée, la rédaction, la vidéo, les schémas et l’écriture de la correction dans un format pédagogique c’est loin d’être simple 😉 .
De plus, j’ai essayé de proposer des exercices indépendants au tuto sur la page des bricolages. Cependant ce dernier n’a pas rassemblé des foules donc je reste mitigé sur le besoin d’en faire « encore plus » (ou alors il y a un gros manque de communication à ce sujet de ma part, ce qui est possible aussi).
Enfin, l’idée d’un TP « Fil rouge » repris au fur et à mesure des chapitres a été émise. Je suis très partisan de ce concept, mais il est assez difficile à mettre en place. Je vais donc étudier cela mais ne peut rien promettre pour le moment.

QCM

QCM
Viennent ensuite les QCM. Bien que paraissant moins important que les exercices, vous semblez y être attaché tout de même…
…Et pourtant, j’en ai rajouté sur l’ensemble des parties du tutoriels (puisqu’ils avaient disparu après le SdZ) mais ces derniers ne semble pas vraiment être visité. J’ai quelques idées pourquoi notamment un manque de communication à ce sujet là encore et certains m’ont fait remarqué certaines ambiguité dans ces derniers. Je ne sais pas encore si je poursuivrais ces derniers puisqu’ils demandent pas mal de temps pour peu de résultat (dommage Sandhose avait fait de super badges pour vous récompenser…)

Le format vidéo

Les vidéos d’illustrations

Vidéos d'illustrations
Les vidéos de types « illustrations » permettant de mettre en image un comportement physique tombe à mon sens dans la catégorie des « il n’y en a jamais de trop » 😀 et apparemment vous pensez pareil. En effet, une petite vidéo vaut souvent mieux qu’un long paragraphe pour illustrer un comportement ou un programme. C’est là une particularité des systèmes embarqués par rapport à l’informatique classique : Il y a une interaction avec le monde extérieur !
Bonne nouvelle, depuis la fin du tuto Arduino j’ai investi dans du matériel photo (pour le loisir). Les prochaines vidéos/photos auront donc une bien meilleure qualité !

Les vidéos MOOCs

Vidéos MOOC
C’est à la mode en ce moment dans le monde de l’éducation, les MOOCs sont partout ! Je ne pouvais donc pas passer à côté.
Chose qui me rassure, ce n’est pas une demande massive. C’est globalement un « oui c’est chouette » qui se dégage mais pas un « C’est indispensable » comme pour les points précédents. Ca me rassure car c’est une chose qui est loin d’être simple (à l’échelle individuelle) à mettre en place… Ca demande du temps (filmer/monter/diffuser) et je ne suis pas sur que cela soit d’un si grand intérêt en terme de pédagogie (ce n’est que mon opinion).
J’espère donc que ce « oui » mitigé n’est qu’une cause d’un effet de mode :-° .
Vous l’aurez compris, je ne vais probablement pas succomber à ce format, mais pourquoi pas le revisiter pour autre chose… (plein d’idée pour plus tard 😉 ).


Conclusion

Voilà, j’ai fait le tour des différentes questions et essayé d’analyser si possible et d’émettre mon avis par rapport aux résultats. Ces derniers m’ont donné de nouvelles idées et du baume au coeur pour continuer à écrire et essayer de toujours vous surprendre avec de nouvelles choses à apprendre 🙂 !
Je vais maintenant reprendre certains commentaires qui soulèvent des points n’ayant pas des réponses dans les paragraphes précédents… (Je ne citerais pas les messages de remerciements mais le coeur y est, merci à vous tous pour vos petits mots 🙂 !!!).

je rajouterai la possibilité de lire le tuto en entier sur une seule page sans avoir à changer de page entre chaque partie. Ou au moins la possibilité d’afficher plusieurs chapitre sur la même page. C’est un peu pénible de pas pouvoir faire une recherche car on n’est pas sur la bonne partie. Pour ça l’ebook est vraiment cool.

Pour des raisons techniques, ca ne va pas être possible. La structure WordPress n’est pas vraiment prévu pour et ca me demanderait trop de temps pour essayer d’y remédier.
Pour ce qui est de la recherche, il y a une boite de recherche en haut à droite qui devrait marcher 😉 .

C’est malheureusement inhérent à WP, mais je ne suis pas fan des tutos sous formes d’article, du coup me suis penché sur les versions pdf/ebook où la lecture est plus aisée.

Et bien moi non plus je ne suis pas fan. J’ai l’impression qu’il manque quelque chose mais je ne sais pas quoi… Du coup si vous trouvez, faites moi signe 😀

Beaucoup de fautes d’orthographe malheureusement 🙂

J’essaie de faire attention, mais en tapant c’est souvent difficile d’être vigilant sur tout. Cependant des correcteurs se relient dorénavant pour donner un coup de main pour que le contenu soit le plus agréable possible !

peu de choses « vraiment microcontroleur » abordées. on est plus dans l’utilisation de l’arduino que dans la compréhension de comment ça marche dedans, et ça fait pêcher un peu je trouve

C’est vrai mais c’est inhérent à Arduino. Le framework se veut simple d’approche et d’usage donc le tuto l’est aussi… Le tutoriel que je sortirais bientôt sera d’un niveau supérieur, un peu différent mais moins « débutant » (vous voila prévenu ^^ ).

Un aspect interactif en direct live , c’est vrai que ce serait un plus , mais faut pouvoir le réaliser .
La difficulté de ce type d’apprentissage est que si un moment tu ne comprends pas…:( hé ben ,t’es un peu tout seul ….:)

J’espère pouvoir revenir bientôt sur cette idée 😉 .

Je pense qu’il faudrait terminer le tuto par une suite de projets plus approfondis et qui reprends les différents chapitres (seul ou par groupes) pour des montages plus complexes. Par exemples, le mini projet LCD est un bon début. Est-il possible de faire un projet qui englobe l’arduino, des servomoteurs, une webcam, un PC sous linux… ou autres pour la découverte et l’utilisation d’autres circuits.

Idem j’espère pouvoir revenir sur cela bientôt !

UN VOYAGE A LA MER POUR CEUX QUI ONT SUIVI LE TUTO 😉

OK, c’est parti on fait ca ! Je te nomme responsable de l’organisation ! 😉

Des repères qui permettraient de retrouver très vite une partie qui nous intéresse à l’instant T.

Un nouveau menu « sticky » est dorénavant disponible sur toutes les pages du tuto 🙂 .

Que le sujet traité soit revu succinctement par une approche différente. / Le fait de savoir au début du tutoriel ce que l’on saura faire à la fin de celui-ci est important, il permet d’avoir une motivation, mais aussi de connaître le but et le résultat de celui-ci.

Je vais essayer de mettre ca en place à l’avenir, d’une part dans l’introduction et d’autres part dans un espace « résumé » à la fin des chapitres.


Voila un petit bilan de ce sondage. Pour ceux qui n’y ont pas participé, il est toujours actif si vous souhaitez donner votre avis (lien donnée en début d’article) !
Je sais maintenant à quoi me tenir et que faire pour progresser 🙂 . Parce que bon, écrire un tuto c’est avant tout pour qu’il soit lu, alors autant faire en sorte qu’il vous plaise !

Si vous avez des idées d’améliorations ou des choses à me dire, j’ai mis en place une boîte à idées disponible à l’adresse suivante : suggestions [arobase] eskimon.fr . (Inutile de m’y envoyer des demandes d’aides aux devoirs ou autre, je n’y répondrais pas, ce n’est pas le but de cette adresse). Bien sur la zone de commentaires est aussi là pour ça !
A bientôt tout le monde !!

Du nouveau chez Arduino !

$
0
0
Ça bouge pas mal en ce moment dans les bureaux d’Arduino ! Je ne sais pas si c’est l’été qui fait cela mais de nouveaux produits plus musclés arrivent sur les étals…
Faisons un peu le tour de cela en regardant le cas de trois nouvelles cartes, la Zero, la Yun et la Tre.

L’Arduino Zero

On commence gentiment avec une petite évolution, l’Arduino Zero. Pourquoi petite ? Eh bien parce que comparée aux autres cartes dans la suite de cet article, la Zero reste « juste un microcontrôleur ». Cette carte est la première à être faite avec le fondeur Atmel. On y retrouve un microcontrôleur 32 bits de type Cortex M-0 (SAMD21). Gros atout comparé aux autres Arduino : un debugguer sera disponible sur la carte ! Il sera enfin possible de faire du vrai debugguage de code sans passer par des envois sur la voie série ou d’autres techniques un peu cheap.
Par contre certains risquent de grincer des dents : ce genre de carte tourne en 3.3V, bye bye les shields 5V du fond du tiroir… Mais il faut s’y faire, le 5V est une ère révolue de moins en moins courante (comparé au 3.3V voire même 1.8V).
Un des avantages de cette carte est bien sûr la puissance de calcul rehaussée par le microcontrôleur 32 bits. Pour rappel, là où une Arduino doit découper les int et autres float pour faire des opérations dessus, une architecture 32 bits permet de faire le traitement en une seule fois.

L’Arduino Yun

Si on monte en gamme, on trouve l’Arduino Yun. À quoi sert-elle ? Quel est son but ?
La Yun vise la mobilité. Elle se découpe en deux parties. C’est un microcontrôleur 8 bits classique (similaire à celui de l’Arduino) et ce dernier est épaulé par un processeur bien plus costaud qui embarque un système Linux. Ce système, qui tournera dans son coin, sert à gérer toutes les interfaces de type Ethernet et Wi-Fi présentes sur la carte. Une liaison série entre les deux systèmes permet de faire de l’échange de données.

La connexion entre le Linux et le microcontrôleur


Il est apparemment aussi possible d’installer des (petites) applications sur le Linux embarqué.
Bref, vous l’avez compris, cette carte a pour objectif d’améliorer la connectivité de vos projets en embarquant la couche Wi-Fi et Ethernet.

L’Arduino Tre

Manifestement chatouillé par les initiatives RaspberryPi, BeagleBone et autres « singe-board computer », Arduino a décidé d’aller jouer dans cette cour aussi ! C’est ainsi qu’est en train de naître la dernière de la série qui s’appellera « Tre ». Pour ceux qui suivent le blog, j’avais eu l’occasion d’en parler il y a quelques mois dans un article où je m’interrogeais sur la pertinence de tel choix.
C’est ainsi qu’Arduino s’est allié avec Texas Instrument pour produire un combo « Beagle Bone + Leonardo ». On est ainsi censé retrouve le meilleur des deux mondes, avec la puissance de calcul d’une BeagleBone (1 GHz, 512 Mo de RAM) d’un côté et la simplicité d’utilisation qui a fait la renommée d’Arduino…
Mais est-ce vraiment une bonne idée ? En effet, tant que l’on a pas pu jouer avec difficile de savoir de quoi il retourne vraiment… Est-ce que le pont entre les deux cartes sera simple, est-ce que le côté Arduino n’agira pas comme un boulet au pied de la BeagleBone qui en elle même est déjà très performante et a de nombreux atouts (plein de GPIO par exemple, en fait tout ce que fait une Arduino mais en plus poussé…).
Pour l’instant, difficile de répondre. Une centaine de cartes (à 150 euros l’unité quand même) ont été vendue en tant que version Beta à une sélection de personnes/développeurs. Attendons leur retour pour en savoir plus… Affaire à suivre donc !

Réaliser un télémètre à ultrasons

$
0
0
Comme nous avons pu en parler dans un des chapitres sur les capteurs, il est possible de mesurer une distance via l’utilisation d’un télémètre à ultrasons. Bien que peu précis à l’échelle des centimètres, ces derniers sont relativement fiables à l’échelle de la dizaine de centimètres et utiles. Comme ils balayent un cône (ils sont peu directifs), ils font de très bons détecteurs d’obstacles.
Nous allons donc aujourd’hui nous lancer dans la réalisation d’un petit télémètre à ultrasons avec affichage intégré (parce que la voie série c’est un peu pénible pour se promener 😀 ).

Rappel sur les ultrasons

Faisons un peu de sciences et rappelons ce que sont des ultrasons.
Un ultrason est une onde sonore à haute fréquence. Par haute fréquence j’entends toutes les fréquences sonores inaudibles pour l’oreille humaine, soit celles au-delà de 20 kHz. Elles sont l’opposé des infrasons qui sont les ondes sonores dont la fréquence est inférieure à la plus faible audible pour l’Homme et qui est de 20 Hz.
Bon, c’est bien beau mais cette histoire de fréquence ça ne nous en dit pas beaucoup plus !

Une onde sonore c’est quoi ?

Une onde sonore est un phénomène physique/mécanique de compression/décompression. Lorsqu’une vibration est produite (par n’importe quel objet qui vibre), l’air subit alors une onde de choc qui se traduit en mouvement des atomes. Il y a alors ce phénomène de compression/décompression que des récepteurs dans nos oreilles convertissent en bruit.
Plus les compressions sont proches et plus la fréquence est élevée. On parle alors de son aigu. Au contraire, plus les compressions sont éloignées et plus la fréquence est faible, on parle d’un son grave.
Une fréquence s’exprime en Hertz et traduit la répétition d’un motif d’un phénomène durant une seconde. Par exemple si je cligne des yeux trois fois par seconde, on peut dire que je cligne des yeux à 3 Hz.

Dans le cas des ultrasons, les compressions/décompressions sont très courtes. En effet, le motif se répète plus de 20 000 fois par seconde, donc à plus de 20 kHz. En général, en électronique on utilise un transducteur piézo pour générer cela. C’est une sorte de petit buzzer capable de vibrer très vite. Très souvent, les télémètres à ultrasons vibrent à une fréquence de 40 kHz.

Une dernière caractéristique des ondes sonores est leur capacité à être réfléchie par les obstacles. En effet, les ondes sonores ont tendance à « rebondir » sur les obstacles. On entend alors l’onde de départ et un peu plus tard la même avec un retard et une plus faible intensité. En général, dans le domaine de l’acoustique et de la musique, on cherche à supprimer cette caractéristique en recouvrant les murs de matériaux spéciaux. Cependant, dans le cas d’une mesure de distance, on va exploiter cet effet.

Principe de la mesure

Comme je le disais juste avant, on va tirer parti du fait que l’onde sonore rebondit sur les obstacles et revient souvent vers l’expéditeur. On va aussi exploiter une autre chose connue, sa vitesse !
En effet, la vitesse de déplacement d’une onde sonore dans l’air est connue depuis longtemps. Elle est d’environ 340 mètres par secondes à 25 degrés Celsius (plutôt lent comparé à la lumière et ses 300 000 km/s 😀 ).
À partir de là, si on sait quand l’onde est partie et quand on la reçoit de nouveau (après le rebond), on est en mesure de calculer un temps de vol de l’onde. On a alors une durée, une vitesse, et on peut en déduire une distance !
Comme l’onde fait un aller-retour (le voyage depuis l’émission de l’onde, le rebond, puis le retour sur le récepteur), il faudra diviser le temps de vol par deux pour ne considérer qu’un trajet (l’aller ou le retour).
Le calcul sera alors simple. Une vitesse s’exprime par une distance divisée par un temps \( v = d/t \) donc la distance sera la vitesse multipliée par le temps \( d = v \times t \).

Passons un peu à la pratique pour mieux comprendre !

IMG_4456

Mise en œuvre du télémètre

Le télémètre que nous allons utiliser est assez simple. Son nom est HC-SR04 et existe en différentes variations. Découvrons-le et voyons comment le faire fonctionner avec notre Arduino.

Le HC-SR04

Présentation du composant

Le HC-SR04 est ce que l’on appelle communément un « Télémètre à ultrasons ». Il est trouvable relativement facilement sur de nombreux sites de fournisseurs de composants électroniques. Les sites livrant depuis la Chine proposent des prix inférieurs à 5 euros en général.
Ce composant possède plusieurs petites choses. Tout d’abord, sur la face avant on peux voir l’émetteur US et son récepteur. Ce sont des petites cellules piézo-électriques qui vont soit vibrer lorsqu’une tension est appliquée (émetteur) soit au contraire produire une tension lorsque une vibration est reçue (récepteur).
Sur la face arrière on trouve plusieurs petits circuits permettant la génération du signal et le traitement de ce dernier. Ainsi, un composant va générer une onde de 40 kHz lors d’un « top départ » et la partie restante s’occupera de la mise en forme de la réception (amplification et filtrage) et de mettre en forme cela proprement sur une broche de sortie.
Parlons d’ailleurs des broches.
On en trouve 4. Les premières sont bien sûr VCC et GND qui vont accueillir l’alimentation (respectivement 5V et masse). On trouve ensuite une broche nommée « Trig ». Cela signifie « Trigger » soit « déclencheur ». En mettant cette broche à l’état haut pendant 10µs vous allez déclencher le ping pour la mesure. Enfin, on trouve la broche « echo » sur laquelle sera présent le signal de sortie.
Ce signal de sortie est assez simple à exploiter. Il est initialement à 0, puis passe à 1 lorsque le ping est envoyé. Il repasse ensuite à 0 quand l’écho est revenu au récepteur OU s’il n’y a pas de retour durant les 30ms après l’envoi (l’onde est considérée perdue)

Branchement

Les branchements sont eux-même assez simples. Il suffira de relier 5V et GND à leurs broches respectives sur Arduino et mettre « Trig » et « Echo » sur des I/O numériques (8 et 9 par exemple). Pas la peine d’un schéma pour cela !

Avec Arduino

Passons maintenant à la pratique avec Arduino. Le but ici sera d’être capable de faire une mesure de distance puis de l’afficher en millimètres dans la console de la voie série.

Setup

On va comme toujours commencer par le setup. Pour une fois, pas de bibliothèque externe à rajouter, tout sera fait « à la main ». Comme vu plus tôt, nous allons utiliser deux broches que je vais très justement nommer « USTrig » et « USEcho », pour le déclencheur (une sortie numérique) et le retour d’informations (une entrée numérique).
Je vais ensuite préparer la voie série pour afficher les mesures.

const int USTrig = 8; // Déclencheur sur la broche 8
const int USEcho = 9; // Réception sur la broche 9

void setup() {
    pinMode(USTrig, OUTPUT);
    pinMode(USEcho, INPUT);

    digitalWrite(USTrig, LOW);

    Serial.begin(9600);
}

Et c’est tout pour le setup !!

Loop

Les choses faciles sont réglées, passons aux choses amusantes et faisons des mesures !
Comme je le disais dans la présentation du composant, il y a une suite d’actions à faire pour mesurer la distance. Schématiquement cela se traduirait par la liste suivante :

  1. Un état haut de 10 microsecondes est mis sur la broche « Trig »
  2. On remet à l’état bas la broche Trig
  3. On lit la durée d’état haut sur la broche « Echo »
  4. On divise cette durée par deux pour n’avoir qu’un trajet
  5. On calcule la distance avec la formule \( d = v \times t \)
  6. On affiche la distance

Tout ces étapes sont en fait assez simples, à part peut-être la mesure de la durée. Heureusement, une fonction nommée pulseIn() est la pour ça 🙂 . Cette dernière, qui est bloquante, se chargera de mesurer combien de temps une broche reste dans un état (HIGH or LOW). Elle prend en paramètre le numéro de la broche et l’état à observer.

Voici alors un exemple de programme que l’on obtient :

#define VITESSE 340 //vitesse du son 340 m/s

// setup()

void loop()
{
   // 1. Un état haut de 10 microsecondes est mis sur la broche "Trig"
   digitalWrite(USTrig, HIGH);
   delayMicroseconds(10); //on attend 10 µs
   // 2. On remet à l’état bas la broche Trig
   digitalWrite(USTrig, LOW);

   // 3. On lit la durée d’état haut sur la broche "Echo"
   unsigned long duree = pulseIn(USEcho, HIGH);

   if(duree > 30000)
   {
      // si la durée est supérieure à 30ms, l'onde est perdue
      Serial.println("Onde perdue, mesure échouée !");
   }
   else
   {
      // 4. On divise cette durée par deux pour n'avoir qu'un trajet
      duree = duree/2;

      // 5. On calcule la distance avec la formule d=v*t
      float temps = duree/1000000.0; //on met en secondes
      float distance = temps*VITESSE; //on multiplie par la vitesse, d=t*v

      // 6. On affiche la distance
      Serial.print("Duree = ");
      Serial.println(temps); //affiche le temps de vol d'un trajet en secondes
      Serial.print("Distance = ");
      Serial.println(distance); //affiche la distance mesurée (en mètre)
   }

   // petite pause
   delay(250);
}

Si vous voulez obtenir la distance en millimètres, il suffira de multiplier par 1000. Mais soyons malins, nous pouvons aussi optimiser en évitant une opération. Pour cela c’est simple, la ligne calculant le temps en seconde passe de :

float temps = duree/1000000.0;

à

float temps = duree/1000.0;

puisque multiplier la distance par 1000 dans notre situation revient exactement à avoir un temps divisé par le même facteur (pour avoir l’information en centimètres, il aurait fallu utiliser un facteur 100 plutôt que 1000).
Je vous laisse poser les maths si vous voulez me croire sur parole 😉 .

Si les mesures ne sont pas ultra-précises, essayez de modifier la constante de vitesse. Les ondes sont sensibles à la température ce qui influe sur leur vitesse. Nous verrons cela plus tard 😉 .

Ajout de l’écran et montage final

Tout va bien ? Les échos reviennent ? Alors place à la portabilité ! Dans cette dernière étape nous allons rajouter l’écran à notre nouvel outil.

Pour rajouter l’écran, commençons par vérifier le câblage nécessaire. Comme vu dans la partie 7, l’écran nécessite 4 fils de données (+ 2 de contrôle) et une alimentation.
L’alimentation sera prise sur les broches 5V et GND de l’Arduino et les fils de données seront sur les broches 2 à 5. Les fils de contrôle EN et R/W seront sur les broches 6 et 7.

Faire fonctionner l’écran seul

En science, lorsque l’on veut tester quelque chose on l’isole du reste. Ici c’est pareil ! Nous avons pu constater que notre télémètre fonctionne bien en le faisant marcher seul, nous allons faire de même en utilisant l’écran seul.
Pour cela, nous allons simplement afficher une ligne de caractères.
On commence logiquement par le setup et ce qui va avec, notamment la bibliothèque LiquidCrystal et un objet du même nom.

#include "LiquidCrystal.h"

// VÉRIFIEZ AVEC VOS PROPRES BROCHES
LiquidCrystal lcd(6,7,2,3,4,5); //liaison 4 bits de données

void setup() {
    lcd.begin(2, 16); // Initialisation de l’écran (2 lignes 16 caractères pour ma part)
}

Une fois cela fait, on va afficher une simple ligne dans notre programme principal :

void loop() {
    lcd.clear();
    lcd.home(); // Replace le curseur en haut a gauche
    lcd.print("-+ Eskimetre +-");
    delay(10000); //pause de 10 secondes inutile, juste pour éviter de rafraîchir sans arrêt
}

Si le message s’affiche correctement comme sur la capture ci-dessous, alors tout va bien et vous pouvez continuer !

L’écran avec le télémètre

Nous y voilà ! Le moment tant attendu ou nous allons afficher les mesures sur l’écran ! Pour cela, commencez par rajouter sur votre montage le télémètre (broche 8 et 9) et fusionner les setup pour n’en faire qu’un sans la voie série. Vous devriez obtenir quelque chose comme ça :

#include "LiquidCrystal.h"
#define VITESSE 340

// VÉRIFIEZ AVEC VOS PROPRES BROCHES
LiquidCrystal lcd(6,7,2,3,4,5); //liaison 4 bits de données
const int USTrig = 8; // Déclencheur sur la broche 8
const int USEcho = 9; // Réception sur la broche 9

void setup() {
    lcd.begin(2, 16); // Initialisation de l’écran (2 lignes 16 caractères pour ma part)

    pinMode(USTrig, OUTPUT);
    pinMode(USEcho, INPUT);

    lcd.print("-+ Eskimetre +-");
}

Il faut ensuite fusionner le tout pour faire un affichage sur le LCD. Je vous propose d’exploiter les deux lignes pour afficher :

  • En haut : la distance en millimètres (int)
  • En bas : le temps en millisecondes (int)

void loop() {
    // 1. Un etat haut de 10 microsecondes est mis sur la broche "Trig"
   digitalWrite(USTrig, HIGH);
   delayMicroseconds(10); //on attend 10 µs
   // 2. On remet a l'etat bas la broche Trig
   digitalWrite(USTrig, LOW);

   // 3. On lit la duree d'etat haut sur la broche "Echo"
   unsigned long duree = pulseIn(USEcho, HIGH);

   if(duree > 30000)
   {
      //si la durée est supérieure à 30ms, l'onde est perdue
      lcd.clear();
      lcd.home(); // Replace le curseur en haut a gauche
      lcd.print("Onde perdue :(");
      lcd.setCursor(0,1);
      lcd.print("Mesure echouee !");
   }
   else
   {
      // 4. On divise cette duree par deux pour n'avoir qu'un trajet
      duree = duree/2;

      // 5. On calcul la distance avec la formule d=v*t
      unsigned int distance = duree*(VITESSE/1000.0); //on multiplie par la vitesse, d=t*v
      
      // 6. On affiche !
      lcd.clear();
      lcd.home(); // Replace le curseur en haut a gauche
      char message[16] = "";
      sprintf(message, " Dist : %4d mm", distance);
      lcd.print(message);
      sprintf(message, "Temps : %4d us", duree);
      lcd.setCursor(0,1);
      lcd.print(message);
   }
   delay(250); //petite pause
}

Il est pas beau ce télémètre 😀 ? Voici ce que ça donne chez moi :

Aller plus loin

Comme je l’ai brièvement mentionné plus tôt, la température a un impact sur la vitesse des ondes (ainsi que la pression et d’autres choses). Une amélioration de notre télémètre serait donc d’avoir une correction de la vitesse via une mesure de la température !
Pour débuter, prenons connaissance des données. Wikipédia nous dit que la vitesse de propagation du son dans l’air suit à peu près le tableau suivant :

Table temperature

Table temperature

Si l’on fait un graphique avec ce tableau, on obtient une relation \( V = f(t) \) (vitesse en fonction de la température) presque linéaire et donc modélisable par une fonction affine.
En faisant le calcul de la variation via les deux points les plus extrêmes du bout de droite, on obtient un coefficient de 0.6 m/s par degrés Celsius (\( \frac{325.4-349.2}{-10-30} \)). On observe aussi une ordonnée à l’origine (soit à 0 degrés) de 331.5 mètres par seconde.
Tout cela donne la relation : \( V = at+b \) (avec \( V \) la vitesse en mètres par secondes et \( t \) la température en degrés Celsius). \( a \) vaudra ainsi 0.6 et \( b \) vaudra 331.5.

Je ne donnerais pas le détail du montage ni le code ici cependant. Je vous le laisse en tant qu’évolution si vous le souhaitez. Voici cependant la logique de code qu’il faudrait suivre pour implémenter cela :

void loop() {
    // On fait la mesure de température

    // On stocke la température en degrés Celsius dans "degres".
    float degres;

    // puis on ajuste la vitesse en fonction de la température
    float vitesse = 0.6*degres + 331.5;

    // et enfin, on fait tout le reste comme avant (mesure + affichage)
    // La seule différence sera que l'on utilisera la variable "vitesse" ...
    // ... au lieu de la constante VITESSE
}

Vous avez maintenant un outil de mesure complètement fonctionnel. Il suffit de fabriquer un boîtier et de rajouter une batterie ou quelques piles pour avoir un module complètement autonome ! On pourrait aussi pousser le vice en utilisant une Arduino mini ou micro pour réduire encore un peu plus la taille du produit final !

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !

[ Arduino Annexe G ] Utiliser un module bluetooth HC-05 avec Arduino

$
0
0
Un fil USB pour communiquer c’est contraignant ! On est limité en distance et on ne peut pas mettre en boîte notre carte, une vraie laisse ! Heureusement, ce ne sont pas les solutions sans fil qui manquent ! Je vous propose dans cette annexe du tutoriel Arduino de découvrir, utiliser et paramétrer un module bluetooth qui coûte une poignée d’euros : le HC-05.

Le bluetooth et le module HC-05

Afin de bien débuter, voyons d’abord à quoi ressemble le bluetooth et découvrons de quoi est composé le nouveau module que nous allons utiliser.

Qu’est ce que le bluetooth ?

Le bluetooth est un protocole de communication sans fil. Il a vu le jour à la fin des années 1990 et n’a vraiment percé que dans les années 2000. Il a subi de nombreuses révisions et évolutions pour atteindre aujourd’hui la version 4.1 depuis la fin 2013.
À l’origine, la société Ericsson cherchait à développer un moyen d’utiliser une voie série sans passer par un fil. Petit à petit, ses utilisations se sont étendues pour atteindre ce que l’on connais aujourd’hui, un moyen de connecter sans fil de nombreux appareils, allant d’une Arduino et sa voie série à un ordinateur, ou pour utiliser un casque audio ou encore une manette de jeu sur une console de salon.

Rentrons un peu dans le détail. Ce protocole est un cousin du Wi-Fi. En effet, ils respectent tous deux une même spécification IEEE et utilisent la même gamme de fréquences : 2.4 GHz (tout comme les téléphones portables et le zigbee par exemple). C’est une communication bidirectionnelle, deux modules peuvent communiquer ensemble en même temps. Le comportement utilisé est « maître/esclave ». Un esclave pourra parler avec un seul maître, mais un maître pourra dialoguer avec plusieurs esclaves.
Pour son utilisation, elle se passe en plusieurs étapes :

  1. Le maître se met en mode « reconnaissable »
  2. L’esclave trouve le maître et demande à s’y connecter
  3. Le maître accepte la connexion
  4. Les périphériques sont alors appairés (ou associés)
  5. La communication peut commencer

Ensuite, selon le type de composant que vous utilisez (une oreillette bluetooth, une manette de jeu-vidéo etc) la communication pourra se faire selon un protocole ou un autre. Dans notre cas cela consistera simplement en une liaison série. Au final, nous aurons donc le même fonctionnement qu’une liaison série habituelle (partie 3 du tuto Arduino) mais toute la partie « filaire » de la communication sera englobée dans des trames bluetooth gérées par le module. C’est totalement transparent pour nous (ou presque). Faisons donc un peu plus connaissance avec « HC-05 », le petit module bluetooth si pratique.

Présentation du module bluetooth HC-05

Comme expliqué plus tôt, le module utilisé se nomme HC-05 et est trouvable assez facilement pour quelques euros (via des sites d’import de Chine). Il est aussi gros que le pouce et est en fait un montage d’un module bluetooth sur un petit PCB. Cela permet de s’affranchir de certaines contraintes comme la soudure du module (qui est très délicate), la conversion 5V -> 3.3V, la régulation de l’alimentation (3.3V de nouveau) ou encore l’ajout de LEDs de signal. Tout cela est déjà intégré !
Alors que trouvons nous sur ce petit module ?
Tout d’abord, un ensemble de broches. VCC et GND pour l’alimentation (5V), Rx/Tx pour la communication. On y voit aussi une broche « Key » qui servira à envoyer des commandes de configuration au module (nous y reviendrons plus tard). La dernière broche nommée « Led » permet de brancher une LED pour obtenir un signal sur l’état du module.

HC-05

Le module bluetooth HC-05

Brancher le module à l’Arduino

Voyons comment brancher tout ça. Tout d’abord, l’alimentation. C’est assez habituel, le VCC sera relié au 5V de l’Arduino et le GND à la masse. Ensuite, viennent les broches de transmission de données, Rx et Tx. Vous pourrez au choix les connecter aux broches de liaison série de l’Arduino (0 et 1) pour utiliser la voie série native, ou alors les brancher sur n’importe quelle autre pin afin de garder la voie série disponible pour du debug avec l’ordinateur (ce que je conseille). Nous reviendrons sur ce point. Il ne reste alors plus que les broches Key et Led. Led sert à connecter une LED de statut, vous pouvez la laisser déconnectée cela n’influencera pas le comportement du module. Key sert à utiliser le mode « commande » du module. Avec cette dernière vous pourrez reconfigurer la voie série (vitesse, parité etc…) et d’autres options liées au bluetooth (nom du module, mot de passe d’appairage, mode esclave/maître…). Cette broche est à connecter à n’importe quelle sortie numérique de l’Arduino.

Communication entre HC-05 et Arduino

Maintenant que le module est connecté, il est temps de le mettre en œuvre avec notre Arduino ! Pour garder les choses simples, nous allons simplement faire une connexion qui permet de renvoyer tout sur la voie série de l’ordinateur. Tout le long de ce tutoriel, seul le mode « esclave » sera utilisé mais le mode « maître » n’est pas beaucoup plus compliqué à atteindre 😉 .

Une question de voie série

Comme il a été dit et répété tout au long de la présentation, le module fonctionne via une voie série. Sur une Arduino Uno nous pouvons en trouver seulement une que nous allons garder pour faire du debugging avec l’ordinateur le temps de mettre en œuvre le module. Il y a donc un problème, comment allons nous faire pour communiquer avec le module si la voie série est déjà prise ?
La réponse est assez simple, nous allons émuler une voie série ! Ainsi, nous allons pouvoir utiliser deux broches numériques classiques pour créer une voie série par dessus. C’est une méthode assez habituelle de contournement, c’est équivalent à trouver une solution logicielle à un problème matériel.
Pour mettre en œuvre cela il y a deux écoles : Coder la nouvelle voie série soi-même ou utiliser une librairie existante. Si vous avez du temps, la première solution est réellement intéressante et formatrice. Pour ma part, le temps est une denrée ce faisant rare, je vais donc utiliser une bibliothèque existante qui a été codée par des professionnels et testée par des milliers de personnes à travers le monde : SoftwareSerial.

Utiliser la bibliothèque

Pour mettre en œuvre cette bibliothèque c’est assez simple. Il va tout d’abord falloir l’inclure dans vos projet. Au choix, soit en cliquant sur « Library/Import/SoftwareSerial » dans l’IDE Arduino (inclus de base) ou alors en ajoutant la ligne suivante en haut de votre programme :

#include <SoftwareSerial.h>

Une fois que la bibliothèque est là, il nous faudra l’utiliser. Cette bibliothèque nous donne l’accès à un objet nommé…SoftwareSerial (quelle coïncidence 😛 ). On peut donc créer une instance de cette objet en écrivant :

SoftwareSerial mavoieserie(Rx, Tx);

Rx et Tx seront les numéros des broches sur lesquelles sont connectées les broches d’émission/réception de votre module bluetooth. Par exemple j’ai pour ma part la broche Rx du module branchée sur la pin 10 de l’Arduino et la broche Tx reliée a 11. J’ai donc dans mon programme :

SoftwareSerial mavoieserie(10, 11);

Une fois cela fait, tout est prêt ! En effet, cette bibliothèque offre les mêmes fonctions que la voie série habituelle, la seule différence sera qu’au lieu d’utiliser Serial on utilisera mavoieserie, comme on peut le voir dans le listing ci-dessous :

mavoiserie.begin(speed);// démarre la voie série à la vitesse speed
mavoiserie.available(); // retourne le nombre de caractère à lire
mavoieserie.read();     // retourne le prochain caractère reçu
mavoiserie.write(val);  // envoie le char "val" sur la voie série

Notre module fonctionnant par défaut en 9600 bauds, nous allons pouvoir le préparer en écrivant :

#include <SoftwareSerial.h>

SoftwareSerial mavoieserie(10, 11);

void setup() {
    mavoiserie.begin(9600);
}

Puis afin de tester tout cela, nous allons faire un petit code qui se contentera de faire un « echo » entre la voie série liée à l’ordinateur et celle liée au module bluetooth. Ainsi, chaque fois qu’un caractère/texte sera reçu sur la voie série de l’un, il sera renvoyé sur la voie série de l’autre. Notre Arduino servira alors de relais/adaptateur entre l’USB de l’ordinateur et le module bluetooth 😉 . Ce petit programme vous donne alors tout ce qu’il faut savoir pour faire vos premières applications avec 🙂 . Juste une chose : branchez la broche « Key » à la masse pour que le module soit en mode « communication » et non pas en mode commande.

#include <SoftwareSerial.h>

SoftwareSerial mavoieserie(11, 10); // (RX, TX) (pin Rx BT, pin Tx BT)

void setup()
{
    // Ouvre la voie série avec l'ordinateur
    Serial.begin(9600);
    // Ouvre la voie série avec le module BT
    mavoieserie.begin(9600);
}

void loop() // run over and over
{
    if (mavoieserie.available()) {
        Serial.write(mavoieserie.read());
    }
    if (Serial.available()) {
        mavoieserie.write(Serial.read());
    }
}

https://www.youtube.com/watch?v=Ory5NlvQF3s

Aller plus loin, la configuration (AT)

Si vous voulez pouvoir utiliser plus de fonctionnalités avec votre module, il va falloir modifier ses paramètres internes. Pour pouvoir être configuré, le module utilise un jeu de commandes plus ou moins standards que l’on appelle « commande AT » (ATtention) ou Commande Hayes du nom de leur inventeur. Pour les utiliser, il faudra que le module soit placé dans un mode particulier, le mode « commande ». Dans ce mode, toutes les informations envoyées au module seront interprétées pour faire de la configuration, rien ne sera envoyé en bluetooth à un autre appareil.

Les commandes AT portent plutôt bien leur nom. En effet, tous les ordres de configuration commencent par les caractères « AT+ » suivis de l’ordre en question puis un retour à la ligne via les caractères « \r\n ». Voyons cela plus en détail.

Passer en « mode commande »

Pour que le module décide que ce qu’il reçoit doit être traité comme un ordre de configuration et non comme un bout de texte à transmettre, il faudra le placer en mode « commande ». Dans ce mode, plus aucun texte ne sera transmis.
Afin d’établir cette communication, il existe deux méthodes.
La première consiste à démarrer le module avec sa broche « Key » à l’état HAUT (reliée au 5V). La LED présente sur le module devrait alors clignoter rapidement, signalant que le module est prêt à recevoir des ordres AT. Dans cette configuration, tous les messages envoyés seront interprétés comme des commandes et le seul moyen d’en sortir sera de redémarrer le module (en supprimant son alimentation). Attention, dans ce mode la connexion s’effectue à une vitesse de 38400 bauds ! N’oubliez pas de le prendre en compte dans votre programme. Je déconseille cette première méthode qui est finalement assez contraignante.

Une deuxième méthode, plus souple, sera d’utiliser la broche « Key » dans notre programme. Il faut donc dans un premiers temps déclarer cette dernière en sortie et la mettre à l’état bas par défaut. Elle sera connectée à la pin 12 pour ma part. Dans cette situation, la vitesse restera à 9600 bauds.

const int key = 12;

void setup() {
    pinMode(key, OUTPUT);
    pinMode(key, LOW);
}

Maintenant, chaque fois que vous souhaiterez passer dans le mode « commande » vous devrez mettre cette broche à l’état haut et la maintenir dans cet état tant que vous envoyez des commandes.

Envoyer des commandes

Comme je l’écrivais plus tôt, chaque commande envoyée doit commencer par « AT+… » et finir par un retour à la ligne « \r\n ». Il existe plusieurs commandes que l’on trouve en général dans les documents fournis par le constructeur. Vous pourrez trouver ce jeu de commande en faisant une recherche du type « HC-05 AT commandes » dans votre moteur de recherche préféré ou en téléchargeant ce fichier (en anglais of course).
Que voyons nous ici ? À partir de la page 3, on peut voir une série de commandes et leur retour. Essayons tout cela.
Pour cela, passez tout d’abord votre module en mode commande en mettant sa broche Key à 1.
Maintenant, en reprenant le programme vu plus haut faisant un echo dans la voie série, envoyons la chaîne suivante « AT+NAME ». Cette commande passée sans paramètre donne le nom visible du module. Par défaut vous devriez obtenir « HC-05 » en retour. Si maintenant nous voulions changer ce nom, nous ferions « AT+NAME=TEST » pour l’appeler « TEST » par exemple. Si tout se passe bien, le module doit vous répondre « OK ». C’est aussi simple que ça !
D’une manière générale, pour lire un paramètre on fera « AT+[paramètre] » et pour le changer on fera AT+[paramètre]=[valeur].
Lorsque vous utiliserez le module sans aucune liaison série externe pour vérifier, il peut être bon de s’assurer que tout se passe bien en vérifiant que le module renvoie bien « OK » lorsque vous changez un paramètre. Si au début du mode commande vous voulez vérifier que le module est bien présent et prêt à répondre, vous pouvez envoyer simplement « AT » et il vous répondra « OK » !

Vous devriez maintenant être en mesure d’utiliser votre module bluetooth HC-05. Il ne reste plus qu’a coder une petite application sur votre PC ou un téléphone et vous pourrez faire du pilotage à distance complètement autonome, sans fil relié à un ordinateur pour recevoir les ordres !

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !

[ Arduino 801 ] Découverte de l’Ethernet sur Arduino

$
0
0
Pour accéder à internet et connecter notre Arduino au monde extérieur, nous allons utiliser le shield Ethernet. Ce dernier repose sur le protocole éponyme dont nous allons voir les fondements dans ce chapitre.
Vous allez donc pouvoir découvrir comment les choses fonctionnent au niveau du réseau puis nous finirons par une présentation du shield Ethernet que nous allons utiliser.
Ce chapitre sera principalement composé de théorie et de culture générale, mais ça ne fait jamais de mal ! Je vous conseille de le lire pour que nous soyons bien sur la même longueur d’onde pour la suite. Les chapitres suivants permettront de rentrer un peu plus dans le cœur des choses avec la mise en pratique.

Un réseau informatique c’est quoi ?

Internet, qu’est ce que c’est au juste ? On en entend parler tout le temps et vous vous en servez probablement tous les jours, mais seriez-vous capable de le définir pour autant ? Essayons d’y voir plus clair…

Internet est un réseau de réseaux. C’est un support de transfert d’informations dans un sens le plus large possible. Afin d’organiser ces échanges, on utilise des **protocoles** spécifiques pour chaque type de transfert. Ces protocoles sont ainsi adaptés à une tache en particulier. Le plus connu est certainement *http*, soit *HyperText Transfert Protocol* qui sert à naviguer sur des pages en se promenant via des liens. Ceux d’entre vous qui font du développement web connaissent aussi sûrement le *ftp*, *File Transfert Protocol* (Protocole d’échanges de fichiers) qui permet de faire du transfert de fichiers uniquement.

Si l’on descend dans des considérations plus techniques, on peut s’intéresser au support de l’information, comment cette dernière voyage-t-elle. On découvrira alors les différents vecteurs de communication comme le WiFi ou l’Ethernet.

Chaque partie du réseau, que ce soit le medium de transfert de l’information ou le protocole final utilisé, peut être retrouvé dans ce que l’on appelle le modèle OSI (Open Systems Interconnection). Ce modèle possède 7 couches servant à définir le rôle de chacun des composants importants du réseau :

Les couches OSI

Les couches OSI (source Wikipédia)

L’Ethernet, que nous allons voir dans ce cours agit sur les couches 1 et 2, physique et liaison de données puisqu’il transforme et transporte les données dans un « format » électronique qui lui est spécifique.

Le shield Ethernet

Toute la documentation officielle du shield Ethernet peut être trouvée ici : http://arduino.cc/en/Main/ArduinoEthernetShield

Maintenant que nous y voyons plus clair dans ce qu’est un réseau, voyons un peu les caractéristiques du matériel que nous allons utiliser pour relier notre carte Arduino.
Il faut tout d’abord savoir que l’Arduino seule n’est PAS DU TOUT faite pour utiliser une liaison réseau comme l’Ethernet. Nous venons de le découvrir, il y a de nombreuses couches à respecter, protocoles à utiliser et paquets à réaliser. Le pauvre petit microcontrôleur de l’Arduino en serait bien incapable dans de bons délais, ce qui rendrait l’utilisation de la carte impossible.
C’est pourquoi l’Arduino va être épaulée par un shield qui se nomme très justement « shield Ethernet ». Il est relativement simple à trouver et coûte moins d’une trentaine d’euros, comme sur le site de Farnell. Ce shield permettra alors de décharger l’Arduino de tout le traitement des couches réseau pour ne donner que les informations utiles à cette dernière.
Commençons l’autopsie…

Le cœur du traitement : Le Wiznet 510

Tout le traitement ou presque va être géré par la puce que vous pouvez voir sur le dessus de la carte. Ce circuit intégré possède la référence Wiznet 5100. C’est un composant qui est dédié au traitement par Ethernet. Une fois configuré, il se chargera de faire toute la communication. C’est à dire que vous n’aurez qu’à envoyer vos données au shield (via SPI, nous y reviendrons) et le shield se chargera de les encapsuler dans des trames et de les transmettre à l’adresse que vous souhaitez. De la même façon, si des données sont reçues il se chargera de les récupérer et les transmettre à l’Arduino pour que votre programme puisse les exploiter.

Ce composant possède une mémoire *buffer* de 16 KB. C’est-à-dire que dans le cas d’un échange de données (téléchargement d’une page web par exemple) les données seront stockées ici le temps que l’Arduino les lise et les traite.

Le shield possède aussi plusieurs leds reliées au Wiznet dont voici le nom et le rôle :

  • PWR: indique que la carte est alimentée
  • LINK: indique que la carte est connectée à un réseau. Cette led clignote lors de l’émission/réception de données ;
  • FULLD: cette led est allumée dans le cas d’une connexion full-duplex (émission et réception simultanées)
  • 100M: allumée si le réseau peut aller à 100 Mb/s (vitesse max. du composant), éteinte dans le cas d’un réseau a 10 Mb/s ;
  • RX: clignote lors de la réception de données ;
  • TX: clignote lors de l’envoi de données ;
  • COLL: clignote si des collisions de données sont détectées.

De la communication à droite à gauche…

Le shield Ethernet, on s’en doute, communique principalement par … Ethernet ! Mais ce n’est pas tout. Il lui faut aussi échanger avec l’Arduino pour pouvoir recevoir une configuration, savoir quelle page aller chercher ou encore transmettre des informations reçues. Pour toutes ces opérations, la transmission se fera par une liaison que nous ne connaissons pas encore : SPI (Serial Protocol Interface).

Cette transmission, nous allons découvrir comment l’utiliser via la librairie Ethernet dans cette partie. Nous n’allons cependant pas rentrer dans les détails puisque ce n’est pas le but de cette partie.

Carte SD

Sur le shield vous avez sûrement vu l’emplacement pour la carte SD. Cette dernière servira à stocker/charger des pages ou des données quelconques. Cette carte se sert elle aussi de la connexion SPI que je viens d’évoquer. On devra donc utiliser une broche comme « Slave Select » (sélection de cible) pour déclarer au système à quel composant on s’adresse, soit l’Ethernet, soit la SD.

L’Ethernet Shield Arduino officiel

Un peu de vocabulaire

Architecture Serveur/Client

Dans le monde magique d’internet, des ordinateurs se parlent entre eux. Cependant, on retrouve deux rôles particuliers : les clients et les serveurs. Bien que souvent exclusif, il peut cependant arriver qu’une machine serve aux deux. Mais voyons plus en détail ces rôles.

Le Serveur

Le travail du serveur est de … servir une information. Cette dernière peut être une page web ou un service quelconque. Par exemple, quand vous allez sur un site web, c’est un « serveur http » (serveur web) qui sera chargé de vous répondre en vous renvoyant la bonne page. Autre exemple, dans votre établissement (scolaire ou professionnel), si une imprimante est branchée sur le réseau alors c’est un serveur d’impression qui sera utilisé pour convertir votre demande « imprime moi la page 42 du pdf Arduino d’Eskimon » en une tâche dans le monde réel.

Vous vous en doutez sûrement, des serveurs il en existe pour plein de choses différentes ! Web, e-mail, impression… Quand nous utiliserons notre Arduino pour offrir/servir une donnée, on dira alors qu’elle est en fonctionnement de « serveur ». On aura donc un « Serveur Arduino » en quelque sorte (qui pourra être un simple serveur web par exemple).

Le Client

Si vous avez compris les paragraphes précédents, alors vous avez sûrement deviné le rôle du client. Comme dans la vie réelle, le client est celui qui va demander une information ou un service. Dans la vie de tout les jours, vous utilisez sûrement au quotidien un navigateur internet. Eh bien ce dernier est un client pour un serveur web. Il fera alors des demandes au serveur, ce dernier les renverra et le client les interprétera.

Il existe autant de types de clients qu’il y a de types de serveurs. À chaque service sa tâche !

Des adresses pour tout !

Dans ce tutoriel, nous allons rencontrer deux types d’adresses, l’IP et la MAC. voyons de quoi il s’agit.

IP

L’adresse IP, Internet Protocol, représente l’adresse à l’échelle du réseau, qu’il soit global ou local. Dans le monde physique, vous possédez une adresse pour recevoir du courrier. Dans le monde de l’internet c’est pareil. Quand des paquets de données sont échangés entre serveur et client, ces derniers possèdent une adresse pour savoir où les délivrer.

À l’échelle globale, votre connexion possède une adresse IP dite publique. C’est cette dernière qui sert à échanger avec le monde extérieur. En revanche, quand vous êtes connecté à votre box internet ou un routeur quelconque, vous possédez alors une adresse IP locale. Cette dernière est très souvent de la forme 192.168.0.xxx. C’est votre box/routeur qui servira d’aiguillage entre les paquets qui sont destinés à votre ordinateur ou votre Arduino (ou n’importe quel autre équipement sur le même réseau).

MAC

L’adresse MAC, Media Access Control, représente une adresse physique, matérielle, de votre matériel. Elle est propre à votre ordinateur/carte réseau. Elle est normalement unique à n’importe quel matériel réseau. Mais elle est aussi falsifiable, donc l’unicité ne peux être garantie globalement.

D’autres notions utiles

Ports

Comme on le voyait un peu plus tôt, différentes applications serveur peuvent fonctionner sur une même machine. MAIS, ils sont tous cachés derrière la même adresse IP. Comment donc séparer les paquets qui vont au serveur web de ceux qui vont au serveur e-mail par exemple ? Une solution pourrait être d’ajouter une information dans le paquet pour préciser l’application de destination. Et bien c’est presque ça. En effet, chaque paquet se verra attribuer un *port* de destination qui est celui sur lequel l’application fonctionne.

Pour imager, essayez d’imaginer la liaison Internet comme une autoroute avec de très nombreuses voies. Les paquets sont les voitures circulant sur cette autoroute. Chaque port sera alors une voie dédiée. Ainsi, le serveur web serait la voie de droite, le serveur mail celle du milieu et le serveur Arduino la voie de gauche. Et comme ça tout le monde arrive à bon port, le serveur au bout de la voie a juste à s’occuper de ses paquets et non pas ceux des autres applications !

Maintenant que les bases sont posées, nous allons pouvoir partir à l’aventure et la conquête du monde par l’Internet ! Place à la grande mode de « L’Internet des objets » !

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !


[ Arduino 802 ] Arduino et Ethernet : client

$
0
0
Commençons doucement à découvrir ce shield en utilisant notre Arduino comme client.
Dans ce chapitre, nous allons découvrir comment faire en sorte que notre Arduino aille interroger un site internet pour obtenir une information de sa part.

Ici nous allons interroger un site internet, mais cela aurait très bien pu être un autre service, sur un autre port (vous allez comprendre)

Afin de bien comprendre, je vous propose tout d’abord quelques explications sur le protocole HTTP et comment se passe un échange de données (requête + réponse).
Ensuite, nous verrons comment mettre en œuvre le shield et faire en sorte qu’il puisse accéder au monde extérieur.
Enfin, nous mettrons tout en œuvre pour faire une simple requête sur un moteur de recherche.
Pour terminer, je vous propose un petit exercice qui permettra de voir un cas d’utilisation : le « monitoring » d’un serveur.

Client et requêtes HTTP

Faisons un petit retour étendu sur la notion de client et surtout découvrons plus en détail en quoi consiste exactement une requête http.

Un client, ça fait quoi ?

Le rôle du client est finalement assez simple. Son but sera d’aller chercher des informations pour les afficher à un utilisateur ou effectuer une action particulière. D’une manière générale, le client sera celui qui traite l’information que le serveur envoie.

Prenons l’exemple du navigateur web. C’est un client. Lorsque vous l’utilisez, vous allez générer des requêtes vers des serveurs et ces derniers vont ensuite renvoyer un tas d’informations (la page web). Le navigateur va alors les traiter pour vous les afficher sous une forme agréable et prévue par le développeur web.

Finalement, c’est simple d’être client, ça consiste juste à demander des choses et attendre qu’elles arrivent 🙂 !

Les termes « client » et « serveur » (et même « requête ») sont d’ailleurs très bien choisis car ils illustrent très bien les mêmes rôles que leur équivalent « dans la vraie vie ».

Une requête HTTP, c’est quoi

Des requêtes HTTP il en existe de plusieurs types. Les plus classiques sont sûrement les GET et les POST, mais on retrouve aussi les PUT, DELETE, HEAD… Pour faire simple, nous allons uniquement nous intéresser à la première car c’est celle qui est utilisée la plupart du temps !

Émission

Dans la spécification du protocole HTTP, on apprend que GET nous permet de demander une ressource en lecture seule. On aura simplement besoin de spécifier une page cible et ensuite le serveur http de cette page nous renverra la ressource ou un code d’erreur en cas de problème. On peut passer des arguments/options à la fin de l’adresse que l’on interroge pour demander des choses plus particulières au serveur.

Par exemple, si vous êtes sur la page d’accueil de Google et que vous faites une recherche sur « Arduino », votre navigateur fera la requête suivante : GET /search?q=arduino HTTP/1.0. Il interroge donc la page principale « / » (racine) et envoie l’argument « search?q=arduino ». Le reste définit le protocole utilisé.

Réception

Une fois la requête faite, le serveur interrogé va vous renvoyer une réponse. Cette réponse peut être découpée en deux choses : l’en-tête (header) et le contenu. On pourrait comparer cela à un envoi de colis. L’en-tête possèderait les informations sur le colis (destinataires etc) et le contenu est ce qui est à l’intérieur du colis.

Typiquement, dans un réponse minimaliste on lira les informations suivantes :

  • Le code de réponse de la requête (200 si tout s’est bien passé)
  • Le type MIME du contenu renvoyé (text/html dans le cas d’une page web)
  • Une ligne blanche
  • Le contenu

Les deux premières lignes font partie du header, puis après viendra le contenu.

Si on veut chercher des informations, en général on le fera dans le contenu.

Utilisation du shield comme client

Maintenant que l’on en sait un peu plus, on va pouvoir faire des requêtes et aller interroger le monde…

Préparation minimale

Pour commencer, il va falloir configurer notre module Ethernet pour qu’il puisse travailler correctement. Pour cela, il va falloir lui donner une adresse MAC et une adresse IP (qui peut être automatique, nous y reviendrons). On va utiliser 4 variables différentes :

  • Un tableau de byte (ou char) pour les 6 octets de l’adresse MAC ;
  • Un objet IPAddress avec l’adresse IP que l’on assigne au module ;
  • Un objet EthernetClient qui nous servira à faire la communication ;
  • Une chaîne de caractères représentant le nom du serveur à interroger.

L’adresse MAC doit normalement être écrite sur un autocollant au dos de votre shield (sinon inventez en une !)

De manière programmatoire, on aura les variables ci-dessous.

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);
// L'objet qui nous servira à la communication
EthernetClient client;
// Le serveur à interroger
char serveur[] = "leserveur.com"

Démarrer le shield

Maintenant que nous avons nos variables, nous allons pouvoir démarrer notre shield dans le setup(). Pour cela, il suffira d’appeler une fonction bien nommée : begin(), et oui, comme pour la voie série ! Cette fonction prendra deux paramètres, l’adresse MAC et l’adresse IP à utiliser. C’est aussi simple que cela !

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);
// L'objet qui nous servira à la communication
EthernetClient client;
// Le serveur à interroger
char serveur[] = "perdu.com"

void setup() {
  // On demarre la voie série pour déboguer
  Serial.begin(9600);

  // On démarre le shield Ethernet
  Ethernet.begin(mac, ip);
  // Donne une seconde au shield pour s'initialiser
  delay(1000);
}

Simple non ?

le DHCP

Si vous bricolez à domicile, il est fort probable que vous soyez en train d’utiliser un routeur ou votre box internet. Bien souvent ces derniers ont par défaut la fonction DHCP activée. Cette technologie permet de donner une adresse IP automatiquement à tout les équipements qui se connectent au réseau. Ainsi, plus besoin de le faire manuellement !

Du coup, on peut faire évoluer notre script d’initialisation pour prendre en compte cela.

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);
// L'objet qui nous servira a la communication
EthernetClient client;
// Le serveur à interroger
char serveur[] = "perdu.com";

void setup() {
  // On démarre la voie série pour déboguer
  Serial.begin(9600);

  char erreur = 0;
  // On démarre le shield Ethernet SANS adresse ip (donc donnée via DHCP)
  erreur = Ethernet.begin(mac);

  if (erreur == 0) {
    Serial.println("Parametrage avec ip fixe...");
    // si une erreur a eu lieu cela signifie que l'attribution DHCP
    // ne fonctionne pas. On initialise donc en forçant une IP
    Ethernet.begin(mac, ip);
  }
  Serial.println("Init...");
  // Donne une seconde au shield pour s'initialiser
  delay(1000);
  Serial.println("Pret !");
}

Envoyer une requête

Une fois que le shield est prêt, nous allons pouvoir commencer à l’utiliser ! Accrochez-vous, les choses amusantes commencent !

Requête simple

Pour débuter, il va falloir générer une requête pour interroger un serveur dans l’espoir d’obtenir une réponse. Je vous propose de commencer par une chose simple, récupérer une page web très sommaire, celle de http://perdu.com !

C’est là que notre variable « client » de type EthernetClient entre enfin en jeu. C’est cette dernière qui va s’occuper des interactions avec la page. Nous allons utiliser sa méthode connect() pour aller nous connecter à un site puis ensuite nous ferons appel à sa méthode println() pour construire notre requête et l’envoyer.

void setup() {
  // ... Initialisation précédente ...

  // On connecte notre Arduino sur "perdu.com" et le port 80 (defaut pour l'http)
  erreur = client.connect(serveur, 80);

  if(erreur == 1) {
      // Pas d'erreur ? on continu !
      Serial.println("Connexion OK, envoi en cours...");

      // On construit l'en-tete de la requete
      client.println("GET / HTTP/1.1");
      client.println("Host: perdu.com");
      client.println("Connection: close");
      client.println();
  } else {
    // La connexion a échoué :(
    Serial.println("Echec de la connexion");
    switch(erreur) {
      case(-1):
        Serial.println("Time out");
        break;
      case(-2):
        Serial.println("Serveur invalide");
        break;
      case(-3):
        Serial.println("Tronque");
        break;
      case(-4):
        Serial.println("Reponse invalide");
        break;
    }
    while(1); // Problème = on bloque
  }
}

Étudions un peu ces quelques lignes.

Tout d’abord, on va essayer de connecter notre client au serveur de « perdu.com » sur son port 80 qui est le port par défaut du protocole http :

client.connect("perdu.com", 80);

Ensuite, une fois que la connexion semble correcte, on va construire notre requête pas à pas.
Tout d’abord, on explique vouloir faire un GET sur la racine (« / ») du site et le tout sous le protocole HTTP version 1.1.

client.println("GET / HTTP/1.1");

Ensuite, on redéclare le site qui devra faire (héberger, « host » en anglais) la réponse. En l’occurrence on reste sur perdu.com.

client.println("Host: perdu.com");

Puis, on signale au serveur que la connexion sera fermée lorsque les données sont transférées.

client.println("Connection: close");

Enfin, pour prévenir que l’on vient de finir d’écrire notre en-tête (header), on envoie une ligne blanche.

client.println();

J’ai ensuite rajouté un traitement des erreurs pour savoir ce qui se passe en cas de problème.

Requête avec paramètre

Et si l’on voulait passer des informations complémentaires à la page ? Eh bien c’est simple, il suffira juste de modifier la requête GET en lui rajoutant les informations !
Par exemple, admettons que sur perdu.com il y ait une page de recherche « recherche.php » qui prenne un paramètre « m » comme mot-clé de recherche. On aurait alors :

client.println("GET /recherche.php?m=monmot HTTP/1.1");

Ce serait équivalent alors à aller demander la page « perdu.com/recherche.php?m=monmot », soit la page « recherche.php » avec comme argument de recherche « m » le mot « monmot ».

Lire une réponse

Lorsque la requête est envoyée (après le saut de ligne), le serveur va nous répondre en nous renvoyant la ressource demandée. En l’occurrence se sera la page d’accueil de perdu.com. Eh bien vous savez quoi ? On fera exactement comme avec une voie série. On commencera par regarder si des données sont arrivées, et si c’est le cas, on les lira une à une pour en faire ensuite ce que l’on veut (recomposer des lignes, chercher des choses dedans…)
Dans l’immédiat, contentons nous de tout afficher sur la voie série !
Première étape, vérifier que nous avons bien reçu quelque chose. Pour cela, comme avec Serial, on va utiliser la méthode available() qui nous retourne le nombre de caractères disponibles à la lecture.

client.available()

Si des choses sont disponibles, on les lit une par une (comment ? Avec « read() » bien sûr ! 😀 ) et les envoie en même temps à la voie série :

char carlu = 0;
// on lit les caracteres s'il y en a de disponibles
if(client.available()) {
  carlu = client.read();
  Serial.print(carlu);
}

Enfin, quand tout a été lu, on va vérifier l’état de notre connexion et fermer notre client si la connexion est terminée.

// Si on est bien deconnecte.
if (!client.connected()) {
  Serial.println();
  Serial.println("Deconnexion !");
  // On ferme le client
  client.stop();
  while(1); // On ne fait plus rien
}

Globalement, voici le code pour lire une réponse :

void loop()
{
  char carlu = 0;
  // on lit les caracteres s'il y en a de disponibles
  if(client.available()) {
    carlu = client.read();
    Serial.print(carlu);
  }

  // Si on est bien deconnecte.
  if (!client.connected()) {
    Serial.println();
    Serial.println("Deconnexion !");
    // On ferme le client
    client.stop();
    while(1); // On ne fait plus rien
  }
}

Avez-vous remarqué, plutôt que de lire tout les caractères avec un while, on n’en lira qu’un seul à la fois par tour dans loop(). C’est un choix de design, avec un while cela marcherait aussi !

Code complet

En résumé, voici le code complet de la lecture de la page « perdu.com »

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);
// L'objet qui nous servira a la communication
EthernetClient client;
// Le serveur à interroger
char serveur[] = "perdu.com";

void setup() {
  // On démarre la voie série pour déboguer
  Serial.begin(9600);

  char erreur = 0;
  // On démarre le shield Ethernet SANS adresse ip (donc donnée via DHCP)
  erreur = Ethernet.begin(mac);

  if (erreur == 0) {
    Serial.println("Parametrage avec ip fixe...");
    // si une erreur a eu lieu cela signifie que l'attribution DHCP
    // ne fonctionne pas. On initialise donc en forçant une IP
    Ethernet.begin(mac, ip);
  }
  Serial.println("Init...");
  // Donne une seconde au shield pour s'initialiser
  delay(1000);
  Serial.println("Pret !");

  // On connecte notre Arduino sur "perdu.com" et le port 80 (defaut pour l'http)
  erreur = client.connect(serveur, 80);

  if(erreur == 1) {
      // Pas d'erreur ? on continu !
      Serial.println("Connexion OK, envoi en cours...");

      // On construit l'en-tete de la requete
      client.println("GET / HTTP/1.1");
      client.println("Host: perdu.com");
      client.println("Connection: close");
      client.println();
  } else {
    // La connexion a échoué :(
    Serial.println("Echec de la connexion");
    switch(erreur) {
      case(-1):
        Serial.println("Time out");
        break;
      case(-2):
        Serial.println("Serveur invalide");
        break;
      case(-3):
        Serial.println("Tronque");
        break;
      case(-4):
        Serial.println("Reponse invalide");
        break;
    }
    while(1); // On bloque la suite
  }
}

void loop()
{
  char carlu = 0;
  // on lit les caracteres s'il y en a de disponibles
  if(client.available()) {
    carlu = client.read();
    Serial.print(carlu);
  }

  // Si on est bien deconnecte.
  if (!client.connected()) {
    Serial.println();
    Serial.println("Deconnexion !");
    // On ferme le client
    client.stop();
    while(1); // On ne fait plus rien
  }
}

Et voici le résultat que vous devez obtenir dans votre terminal série. Remarquez la présence du header de la réponse que l’on reçoit.

HTTP/1.1 200 OK
Date: Thu, 26 Mar 2015 16:14:15 GMT
Server: Apache
Last-Modified: Tue, 02 Mar 2010 18:52:21 GMT
ETag: "cc-480d5dd98a340"
Accept-Ranges: bytes
Content-Length: 204
Vary: Accept-Encoding
Connection: close
Content-Type: text/html

<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1><h2>Pas de panique, on va vous aider</h2><strong><pre>    * <----- vous &ecirc;tes ici

[ Arduino 803 ] Arduino et Ethernet : serveur

$
0
0
Dans ce chapitre, l’Arduino sera maintenant responsable de l’envoi des données vers le monde extérieur. On dit qu’elle agit en serveur. Ce sera donc un outil externe (logiciel particulier, navigateur etc) qui viendra l’interroger et à ce moment-là elle renverra les informations demandées. On pourra aussi, via un site externe, lui envoyer des ordres pour faire des actions.

Préparer l’Arduino

L’utilisation de l’Arduino en mode serveur est sûrement plus courante que celle en client. Cette partie devrait donc particulièrement vous intéresser.
Deux grands rôles peuvent être accomplis :

  • L’envoi de données à la demande (l’utilisateur vient demander les données quand il les veut) :
  • La réception d’ordre pour effectuer des actions.

Ces deux rôles ne sont pas exclusifs, ils peuvent tout à fait cohabiter ensemble. Mais dans un premier temps, reparlons un peu de ce qu’est un serveur.

Nous l’avons vu dans le premier chapitre, un serveur est chargé de réceptionner du trafic, l’interpréter puis agir en conséquence. Pour cela, il possède un port particulier qui lui est dédié. Chaque octet arrivant sur ce port lui est donc destiné. On dit que le serveur écoute sur un port.

C’est donc à partir de cela que nous allons pouvoir mettre en place notre serveur !

Comme pour le client, il va falloir commencer par les options du shield (MAC, IP…) afin que ce dernier puisse se connecter à votre box/routeur.
On retrouve donc un setup similaire au chapitre précédent :

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);

void setup()
{
  // On démarre la voie série pour déboguer
  Serial.begin(9600);

  char erreur = 0;
  // On démarre le shield Ethernet SANS adresse ip (donc donnée via DHCP)
  erreur = Ethernet.begin(mac);

  if (erreur == 0) {
    Serial.println("Parametrage avec ip fixe...");
    // si une erreur a eu lieu cela signifie que l'attribution DHCP
    // ne fonctionne pas. On initialise donc en forçant une IP
    Ethernet.begin(mac, ip);
  }
  Serial.println("Init...");
  // Donne une seconde au shield pour s'initialiser
  delay(1000);
  Serial.print("Pret !");
}

Bien. Au chapitre précédent cependant nous avions des variables concernant le client. Ici, de manière similaire nous aurons donc des variables concernant le serveur.
La première et unique nouvelle chose sera donc une variable de type EthernetServer qui prendra un paramètre : le port d’écoute. J’ai choisi 4200 de manière un peu aléatoire, car je sais qu’il n’est pas utilisé sur mon réseau. Une liste des ports les plus souvent utilisés peut être trouvée sur Wikipédia.

// Initialise notre serveur
// Ce dernier écoutera sur le port 4200
EthernetServer serveur(4200);

Puis, à la fin de notre setup il faudra démarrer le serveur avec la commande suivante :

serveur.begin();

En résumé, on aura donc le code suivant pour l’initialisation :

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);

// Initialise notre serveur
// Ce dernier écoutera sur le port 4200
EthernetServer serveur(4200);

void setup()
{
  // On démarre la voie série pour déboguer
  Serial.begin(9600);

  char erreur = 0;
  // On démarre le shield Ethernet SANS adresse ip (donc donnée via DHCP)
  erreur = Ethernet.begin(mac);

  if (erreur == 0) {
    Serial.println("Parametrage avec ip fixe...");
    // si une erreur a eu lieu cela signifie que l'attribution DHCP
    // ne fonctionne pas. On initialise donc en forçant une IP
    Ethernet.begin(mac, ip);
  }
  Serial.println("Init...");
  // Donne une seconde au shield pour s'initialiser
  delay(1000);
  // On lance le serveur
  serveur.begin();
  Serial.print("Pret !");
}

Et voila, votre serveur Arduino est en train de surveiller ce qui se passe sur le réseau !

Répondre et servir des données

Maintenant que le serveur est prêt et attend qu’on lui parle, on va pouvoir coder la partie « communication avec le demandeur ».
La première étape va être de vérifier si un client attend une réponse de la part de notre serveur. On va donc retrouver notre objet EthernetClient vu au chapitre précédent et une fonction du serveur que l’on aurait presque pu deviner : available()

// Regarde si un client est connecté et attend une réponse
EthernetClient client = serveur.available();

Ensuite les choix sont simples. Soit un client (donc une application externe) est connecté avec l’Arduino et veut interagir, soit il n’y a personne et donc on ne fait… rien (ou autre chose). Pour cela, on va simplement regarder si client vaut autre chose que zéro. Si c’est le cas, alors on traite les données.

if (client) {
  // Quelqu'un est connecté !
}

Maintenant, on va faire au plus simple. On va considérer que l’on renvoie toujours les mêmes informations : la valeur de l’entrée analogique 0 et la variable millis(), quelque soit la requête du client. On va alors se retrouver dans le cas similaire au chapitre précédent ou il faudra simplement construire une requête pour renvoyer des données.
Comme j’aime les choses simples, j’ai décidé de ne pas renvoyer une page web (trop verbeux) mais juste du texte au format JSON qui est simple à lire et à fabriquer.

Le HTML demande BEAUCOUP trop de contenu texte à envoyer pour afficher une information utile. Soyons clair, un système embarqué comme Arduino n’est pas fait pour afficher des pages web, il faut pouvoir renvoyer des informations de manière simple et concise.

Il faudra comme pour le client commencer par renvoyer un header. Le notre sera simple et possèdera seulement deux informations : Le protocole utilisé avec le code de retour (encore http 1.1 et 200 pour dire que tout c’est bien passé) ainsi que le type mime du contenu renvoyé (en l’occurrence « application/json »). (Si vous renvoyez de l’html ce serait « text/html » par exemple).

// Tout d'abord le code de réponse 200 = réussite
client.println("HTTP/1.1 200 OK");
// Puis le type mime du contenu renvoyé, du json
client.println("Content-Type: application/json");
// Et c'est tout !
// On envoie une ligne vide pour signaler la fin du header
client.println();

Une fois le header envoyé, on construit et envoie notre réponse json. C’est assez simple, il suffit de bien former le texte en envoyant les données dans le bon ordre avec les bons marqueurs.

// Puis on commence notre JSON par une accolade ouvrante
client.println("{");
// On envoi la première clé : "uptime"
client.print("\t\"uptime (ms)\": ");
// Puis la valeur de l'uptime
client.print(millis());
//Une petite virgule pour séparer les deux clés
client.println(",");
// Et on envoie la seconde nommée "analog 0"
client.print("\t\"analog 0\": ");
client.println(analogRead(A0));
// Et enfin on termine notre JSON par une accolade fermante
client.println("}");

On a presque fini !

Une fois la réponse envoyée, on va faire une toute petite pause pour laisser le temps aux données de partir et enfin on fera le canal de communication avec le client.

// Donne le temps au client de prendre les données
delay(10);
// Ferme la connexion avec le client
client.stop();

Et voilà !

Il est maintenant temps de tester. Branchez votre Arduino, connectez-la au réseau et allez sur la page ip:port que vous avez paramétré avec votre navigateur (en l’occurrence http://192.168.0.143:4200/ pour moi). Si tout se passe bien, aux valeurs près vous obtiendrez quelque chose de similaire à ceci :

{
    "uptime (ms)": 18155,
    "analog 0": 386
}

Génial non ?

Voici le code complet pour faire tout cela :

// Ces deux bibliothèques sont indispensables pour le shield
#include <SPI.h>
#include <Ethernet.h>

// L'adresse MAC du shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E };
// L'adresse IP que prendra le shield
IPAddress ip(192,168,0,143);

// Initialise notre serveur
// Ce dernier écoutera sur le port 4200
EthernetServer serveur(4200);

void setup()
{
  // On démarre la voie série pour déboguer
  Serial.begin(9600);

  char erreur = 0;
  // On démarre le shield Ethernet SANS adresse ip (donc donnée via DHCP)
  erreur = Ethernet.begin(mac);

  if (erreur == 0) {
    Serial.println("Parametrage avec ip fixe...");
    // si une erreur a eu lieu cela signifie que l'attribution DHCP
    // ne fonctionne pas. On initialise donc en forçant une IP
    Ethernet.begin(mac, ip);
  }
  Serial.println("Init...");
  // Donne une seconde au shield pour s'initialiser
  delay(1000);
  // On lance le serveur
  serveur.begin();
  Serial.print("Pret !");
}

void loop()
{
  // Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) {
    // Quelqu'un est connecté !
    Serial.print("On envoi !");
    // On fait notre en-tete
    // Tout d'abord le code de réponse 200 = réussite
    client.println("HTTP/1.1 200 OK");
    // Puis le type mime du contenu renvoyé, du json
    client.println("Content-Type: application/json");
    // Et c'est tout !
    // On envoi une ligne vide pour signaler la fin du header
    client.println();

    // Puis on commence notre JSON par une accolade ouvrante
    client.println("{");
    // On envoie la première clé : "uptime"
    client.print("\t\"uptime (ms)\": ");
    // Puis la valeur de l'uptime
    client.print(millis());
    //Une petite virgule pour séparer les deux clés
    client.println(",");
    // Et on envoie la seconde nommée "analog 0"
    client.print("\t\"analog 0\": ");
    client.println(analogRead(A0));
    // Et enfin on termine notre JSON par une accolade fermante
    client.println("}");
    // Donne le temps au client de prendre les données
    delay(10);
    // Ferme la connexion avec le client
    client.stop();
  }
}

S’il faut encore vous convaincre, sachez que cet exemple affiche environ 50 caractères, donc 50 octets (plus le header) à envoyer. La même chose en html proprement formaté aurait demandé au grand minimum le double.

Agir sur une requête plus précise

Nous savons maintenant envoyer des données vers notre shield, mais il pourrait être sympa de pouvoir en interpréter et ainsi interagir avec le shield. Voyons voir comment, mais avant tout un petit avertissement :

On ne va pas se mentir, faire cela demande un peu de bidouille car il faut être à l’aise avec la manipulation de chaîne de caractères. Ce type de code est difficilement généralisable ce qui signifie qu’il faut bien souvent développer pour son cas précis. Ce qui sera exposé ici sera donc un « exemple d’application pour faire comprendre ».

Notre objectif va être simple, on doit être capable de recevoir et interpréter les choses suivantes :

  • Un premier paramètre sera « b » signifiant « broches ». Il indiquera l’état des broches 3, 4, 5. Si une broche est dans la liste, alors elle est à 1, sinon 0
  • Un second paramètre sera « p » et indiquera le rapport cyclique (entier entre 0 et 255) d’une pwm sur la broche 6.
  • Enfin, dans tous les cas on renvoie un json possédant les informations suivantes :
    • L’uptime de l’Arduino (millis)
    • L’état des broches 3, 4 et 5
    • La valeur de la PWM de la broche 6
    • La lecture analogique de la broche A0

Démarrons par la fin et avec les choses simples, une fonction pour renvoyer le json.

En cadeau voici le schéma !

Ethernet

Ethernet schema

Répondre à la requête

On l’a vu plus tôt, répondre à une requête n’est pas très compliqué et construire un json non plus. Je vais donc simplement vous poster le code de la fonction repondre() avec des commentaires en espérant que cela suffise. Rien de nouveau par rapport aux choses vues ci-dessus.

void repondre(EthernetClient client) {
  // La fonction prend un client en argument

  Serial.println("\nRepondre"); // debug
  // On fait notre en-tête
  // Tout d'abord le code de réponse 200 = réussite
  client.println("HTTP/1.1 200 OK");
  // Puis le type mime du contenu renvoyé, du json
  client.println("Content-Type: application/json");
  // Autorise le cross origin
  client.println("Access-Control-Allow-Origin: *");
  // Et c'est tout !
  // On envoi une ligne vide pour signaler la fin du header
  client.println();

  // Puis on commence notre JSON par une accolade ouvrante
  client.println("{");
  // On envoie la première clé : "uptime"
  client.print("\t\"uptime\": ");
  // Puis la valeur de l'uptime
  client.print(millis());
  //Une petite virgule pour séparer les deux clés
  client.println(",");
  // Et on envoie la seconde nommée "analog 0"
  client.print("\t\"A0\": ");
  client.print(analogRead(A0));
  client.println(",");
  // Puis la valeur de la PWM sur la broche 6
  client.print("\t\"pwm\": ");
  client.print(pwm, DEC);
  client.println(",");
  // Dernières valeurs, les broches (elles mêmes dans un tableau)
  client.println("\t\"broches\": {");
  // La broche 3
  client.print("\t\t\"3\": ");
  client.print(digitalRead(3));
  client.println(",");
  // La broche 4
  client.print("\t\t\"4\": ");
  client.print(digitalRead(4));
  client.println(",");
  // La broche 5
  client.print("\t\t\"5\": ");
  client.println(digitalRead(5));
  client.println("\t}");
  // Et enfin on termine notre JSON par une accolade fermante
  client.println("}");
}

Lire la requête

Lorsque l’on reçoit une requête, il faut la traiter. Avez-vous essayé de faire un Serial.print() des caractères reçus lors des demandes ? Vous pouvez remarquer que la première ligne est toujours « GET /… HTTP/1.1 ». Avec GET qui est « l’action », /... l’url demandée et HTTP/1.1 le protocole utilisé, on a tout ce qu’il faut pour (ré)agir ! Par exemple, si on reçoit la requête GET /?b=3,4&p=42 HTTP/1.1, on aura « juste » à traiter la demande pour extraire le numéro des broches à allumer (3 et 4 mais pas 5) et la valeur du rapport cyclique à appliquer pour la PWM (42).
Voyons comment faire.

Preparation

Tout d’abord, on va réserver un tableau de caractères pour le traitement des données. Dans notre cas, 100 caractères devraient largement faire l’affaire. On va aussi déclarer quelques variables pour stocker l’état des broches à changer.

char *url = (char *)malloc(100); // L'url reçue à stocker
//char url[100]; // équivalent à la ligne du dessus mais qui ne semble pas vouloir fonctionner
char index = 0; // index indiquant où l'on est rendu dans la chaine
boolean etats[3] = {LOW, LOW, LOW}; // L'état des 3 sorties
unsigned char pwm = 0; // La valeur de la pwm

Une fois cela fait, nous allons devoir passer à la récupération de la premiere chaîne envoyée par le client.

Récuperer l’URL

C’est parti, faisons notre loop ! On va commencer comme avant, en allant lire la présence d’un client.

void loop() {
  // Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) {
    url = ""; // on remet à zéro notre chaîne tampon
    index = 0;
    // traitement
  }
}

Si un client est présent, on va regarder s’il a des données à nous donner tant qu’il est connecté (car s’il se déconnecte pas la peine de perdre du temps avec lui !).

void loop() {
  // Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) { // Un client est là ?
    url = ""; // on remet à zéro notre chaîne tampon
    index = 0;
    while(client.connected()) { // Tant que le client est connecté
      if(client.available()) { // A-t-il des choses à dire ?
        // traitement des infos du client
      }
    }
  }
}

Maintenant que l’on sait que le client est là et nous parle, on va l’écouter en lisant les caractères reçus.

void loop() {
  // Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) { // Un client est là ?
    url = ""; // on remet à zéro notre chaîne tampon
    index = 0;
    while(client.connected()) { // Tant que le client est connecté
      if(client.available()) { // A-t-il des choses à dire ?
        // traitement des infos du client
        char carlu = client.read(); //on lit ce qu'il raconte
        if(carlu != '\n') { // On est en fin de chaîne ?
          // non ! alors on stocke le caractère
          url[index] = carlu;
          index++;
        } else {
          // on a fini de lire ce qui nous interesse
          // on marque la fin de l'url (caractère de fin de chaîne)
          url[index] = '';
          // + TRAITEMENT
          // on quitte le while
          break;
        }
      }
    }
    // Donne le temps au client de prendre les données
    delay(10);
    // Ferme la connexion avec le client
    client.stop();
  }
}

Interpréter l’URL

Maintenant que nous avons la chaîne du client, il faut l’interpreter pour lire les valeurs des paramètres.
Tout d’abord, on commencera par remettre les anciens paramètres à zéro. Ensuite, on va parcourir les caractères à la recherche de marqueur connu : b et p. Ce n’est pas ce qu’il y a de plus simple, mais vous allez voir avec un peu de méthode on y arrive !
Rappel : Nous cherchons à interpréter GET /?b=3,4&p=42 HTTP/1.1

PS : le code est « volontairement » un peu plus lourd car je fais des tests évitant les problèmes si quelqu’un écrit une URL un peu farfelue (sans le « b » ou le « p »).

boolean interpreter() {
  // On commence par mettre à zéro tous les états
  etats[0] = LOW;
  etats[1] = LOW;
  etats[2] = LOW;
  pwm = 0;

  // Puis maintenant on va chercher les caractères/marqueurs un par un.
  index = 0; // Index pour se promener dans la chaîne (commence à 4 pour enlever "GET "
  while(url[index-1] != 'b' && url[index] != '=') { // On commence par chercher le "b="
    index++; // Passe au caractère suivant
    if(index == 100) {
      // On est rendu trop loin !
      Serial.println("Oups, probleme dans la recherche de 'b='");
      return false;
    }
  }
  // Puis on lit jusqu’à trouver le '&' séparant les broches de pwm
  while(url[index] != '&') { // On cherche le '&'
    if(url[index] >= '3' && url[index] <= '5') {
      // On a trouvé un chiffre identifiant une broche
      char broche = url[index]-'0'; // On ramène ça au format décimal
      etats[broche-3] = HIGH; // Puis on met la broche dans un futur état haut
    }
    index++; // Passe au caractère suivant
    if(index == 100) {
      // On est rendu trop loin !
      Serial.println("Oups, probleme dans la lecture des broches");
      return false;
    }
    // NOTE : Les virgules séparatrices sont ignorées
  }
  // On a les broches, reste plus que la valeur de la PWM
  // On cherche le "p="
  while(url[index-1] != 'p' && url[index] != '=' && index= '0' && url[index] <= '9') {
      // On a trouvé un chiffre !
      char val = url[index]-'0'; // On ramène ça au format décimal
      pwm = (pwm*10) + val; // On stocke dans la pwm
    }
    index++; // Passe au caractère suivant
    if(index == 100) {
      // On est rendu trop loin !
      Serial.println("Oups, probleme dans la lecture de la pwm");
      return false;
    }
    // NOTE : Les virgules séparatrices sont ignorées
  }
  // Rendu ici, on a trouvé toutes les informations utiles !
  return true;
}

Agir sur les broches

Lorsque toutes les valeurs sont reçues et interprétées, il ne reste plus qu’à les appliquer à nos broches. Vu ce que l’on vient de faire, c’est de loin le plus facile !

void action() {
  // On met à jour nos broches
  digitalWrite(3, etats[0]);
  digitalWrite(4, etats[1]);
  digitalWrite(5, etats[2]);
  // Et la PWM
  analogWrite(6, pwm);
}

On assemble !!

Il ne reste plus qu’à enchaîner toutes nos fonctions pour avoir un code complet !!

void loop() {
  // Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) { // Un client est là ?
    Serial.println("Ping !");
    url = ""; // on remet à zéro notre chaîne tampon
    index = 0;
    while(client.connected()) { // Tant que le client est connecté
      if(client.available()) { // A-t-il des choses à dire ?
        // traitement des infos du client
        char carlu = client.read(); //on lit ce qu'il raconte
        if(carlu != '\n') { // On est en fin de chaîne ?
          // non ! alors on stocke le caractère
          Serial.print(carlu);
          url[index] = carlu;
          index++;
        } else {
          // on a fini de lire ce qui nous interesse
          // on marque la fin de l'url (caractère de fin de chaîne)
          url[index] = '';
          boolean ok = interpreter(); // essaie d'interpreter la chaîne
          if(ok) {
            // tout s'est bien passé = on met à jour les broches
            action();
          }
          // et dans tous les cas on repond au client
          repondre(client);
          // on quitte le while
          break;
        }
      }
    }
    // Donne le temps au client de prendre les données
    delay(10);
    // Ferme la connexion avec le client
    client.stop();
    Serial.println("Pong !");
  }
}

Code complet

Secret SelectionnerAfficher>

Sortir de son réseau privé

À ce stade, nous arrivons à récupérer des informations et donner des ordres à notre Arduino. Cependant, on est bloqué dans notre réseau local. En effet, si vous essayez d’y accéder depuis un autre ordinateur à l’autre bout du monde, il est fort probable que cela ne marche pas…

Pour palier à cela, il va falloir faire un peu d’administration réseau. Je vais couvrir la démarche ici mais ne rentrerai pas trop dans les détails car ce n’est pas non plus le but de ce tutoriel. Je partirai aussi du principe que vous êtes à votre domicile et utilisez une box ou un routeur que vous pouvez administrer.

L’opération que nous allons faire ici s’appelle une redirection NAT (Network address translation). Mais tout d’abord, essayons de comprendre le problème.

Le souci

Le problème dans l’état actuel c’est que votre box laisse passer le trafic vers l’extérieur, accepte les réponses, mais ne tolère pas trop qu’on accède directement à son adresse sur n’importe quel port. En effet, après tout c’est logique. Imaginez que vous avez plusieurs équipements connectés a votre routeur/box. Si vous essayez d’y accéder depuis l’extérieur, comment cette dernière saura à quel matériel vous souhaitez accéder ?

Dans votre réseau local, chaque appareil à sa propre adresse IP qui le représente localement. Cette adresse est très souvent de la forme 192.168.0.xyz. Vous pourriez avoir par exemple votre téléphone en 192.168.0.142, votre ordinateur en 192.168.0.158 et votre Arduino en 192.168.0.199. Votre box (qui gère ce réseau local) possède quant à elle une IP publique. C’est cette IP qui la représente aux yeux du monde. Admettons, pour l’exemple, que cette adresse soit 42.128.12.13 (trouvez la vôtre avec un service comme my-ip.com). Si vous cherchez à accéder à l’adresse publique avec le port 4200 en espérant atteindre votre Arduino vous serez déçus. En effet, vous allez bien atteindre votre box, mais cette dernière n’aura aucune idée de quel équipement doit être interrogé ! Est-ce votre ordinateur ? votre smartphone ? votre Arduino ?

Il va donc falloir lui expliquer…

Sa solution

Chaque constructeur de box/routeur possède sa propre interface. Je vais essayer d’être le plus générique possible pour que les explications parlent au plus grand nombre, mais ne m’en voulez pas si toutes les dénominations ne sont pas exactement comme chez vous !

Et cette explication s’appelle une redirection NAT, ou redirection de port. En faisant cela, vous expliquerez à votre box que « tout le trafic qui arrive sur ce port particulier doit être envoyé sur cet équipement local » (et vous pouvez même rerouter le trafic pour le changer de port si vous voulez).

Mettons cela en place. Pour cela, commencez par aller dans l’interface d’administration de votre box (souvent c’est à l’adresse 192.168.0.1). Vous devez être dans le réseau local de la box pour le faire ! Ensuite, il vous faudra trouver la partie parlant de « NAT » ou de « redirection de port ».
Une fois dans cette dernière, il va falloir demander à ce que tout ce qui rentre dans le port 4200 (ou la plage 4200-4200) soit redirigé vers l’équipement « Arduino » (Wiznet) ou son adresse IP locale si vous la connaissez et que vous l’avez déjà imposée au routeur comme fixe.

Vous aurez alors quelque chose comme ça :

Réglages NAT

Réglages NAT

Sauvegardez et éventuellement redémarrez votre box (normalement ce n’est pas nécessaire, mais sur du vieux matériel ça peut arriver…). Maintenant démarrez votre Arduino avec un des programmes ci-dessus et essayez d’accéder à votre adresse publique et le port 4200 avec un navigateur internet. Normalement, l’Arduino devrait répondre comme si vous l’interrogiez avec son adresse locale !

Faire une interface pour dialoguer avec son Arduino

Pour terminer ce tutoriel, je vous propose de réaliser une petite interface de pilotage de l’Arduino via internet. Pour cela, on va garder le programme que nous avions dans l’Arduino pour le paragraphe concernant les requêtes avancées, et nous nous contenterons de simplement faire de l’html et du javascript. L’html servira à faire l’interface et le javascript fera les interactions via des requêtes ajax.

Avant toute chose, je vous ai menti ! Il faut en fait rajouter une petite ligne dans notre code de la fonction repondre() faite plus tôt. En effet, pour des raisons de sécurité les requêtes ajax ne peuvent pas aller d’un domaine à un autre (donc de « n’importe où sur le web » à « votre Arduino »). Il faut donc rajouter une ligne dans le header renvoyé pour signaler que l’on autorise le « cross-domain ».
Rajoutez donc cette ligne juste après le « content-type » :

// Autorise le cross origin
client.println("Access-Control-Allow-Origin: *");

Maintenant que cela est fait, nous allons créer une structure html toute simple pour avoir nos boutons.

<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <title>Interface de pilotage Arduino</title>
  </head> 
  <body>
    <div class="main">
      <p>
        Adresse public du shield : <br />
        http://<input type="text" id="ip" value="123.123.123.123" size="15"/>
        : <input type="text" id="port" value="4200" size="5"/>
      </p>
      <hr />
      <p>
        <input type="checkbox" id="broche3" name="broche3" />
        <label for="broche3">Activer Broche 3.</label>
        Etat : <input type="radio" id="etat3" disabled />
      </p>
      <p>
        <input type="checkbox" id="broche4" name="broche4" />
        <label for="broche4">Activer Broche 4.</label>
        Etat : <input type="radio" id="etat4" disabled />
      </p>
      <p>
        <input type="checkbox" id="broche5" name="broche5" />
        <label for="broche5">Activer Broche 5.</label>
        Etat : <input type="radio" id="etat5" disabled />
      </p>
      <p>
        PWM : 0<input type="range" min="0" max="255" id="pwm" />255
      </p>
      <p>
        A0 : <meter min="0" max="1023" id="a0" />
      </p>
      <button id="envoyer">Executer !</button>
      <p>
        Millis : <span id="millis">0</span> ms
      </p>
    </div>
  </body>
</html>

Interface HTML

Interface HTML

Ensuite, un peu de javascript nous permettra les interactions. L’ensemble est grosso-modo divisé en deux fonctions importantes. setup() qui sera exécutée lorsque la page est prête puis executer() qui sera appelée à chaque fois que vous cliquez sur le bouton. Cette dernière fera alors une requête à votre Arduino et attendra la reponse json. La fonction afficher() utilisera alors les informations pour changer les composants html.
Comme vous pouvez le constater, toute la partie affichage est gérée de manière quasi-complètement indépendante de l’Arduino. Cela va nous permettre de transmettre un minimum de données et garder une souplesse maximale sur l’affichage. Si demain vous decidez de changer l’interface voire carrément de faire une application dans un autre langage, vous n’aurez pas besoin de toucher à votre Arduino car les données sont envoyées dans un format générique.

var broches = []; // Tableau de broches
var etats = []; // Tableau d'etat des broches
var pwm;
var a0;
var millis;
var adresse = "http://82.143.160.118:4200/"; // L'url+port de votre shield

document.addEventListener('DOMContentLoaded', setup, false);

function setup() {
    // fonction qui va lier les variables a leur conteneur html
    broches[3] = document.getElementById("broche3");
    broches[4] = document.getElementById("broche4");
    broches[5] = document.getElementById("broche5");
    etats[3] = document.getElementById("etat3");
    etats[4] = document.getElementById("etat4");
    etats[5] = document.getElementById("etat5");
    pwm = document.getElementById("pwm");
    a0 = document.getElementById("a0");
    millis = document.getElementById("millis");
    
    // La fonction concernant le bouton
    var bouton = document.getElementById("envoyer");
    bouton.addEventListener('click', executer, false);
}

function executer() {
    // Fonction qui va créer l'url avec les paramètres puis
    // envoyer la requête
    var requete = new XMLHttpRequest(); // créer un objet de requête
    var url = adresse;
    url += "?b=";
    for(i=3; i <= 5; i++) { // Pour les broches 3 à 5 de notre tableau
        if(broches[i].checked) // si la case est cochée
            url += i + ",";
    }
    // enlève la dernière virgule si elle existe
    if(url[url.length-1] === ',')
        url = url.substring(0, url.length-1);
    // Puis on ajoute la pwm
    url += "&p=" + pwm.value;
    console.log(url) // Pour debugguer l'url formée    
    requete.open("GET", url, true); // On construit la requête
    requete.send(null); // On envoie !
    requete.onreadystatechange = function() { // on attend le retour
        if (requete.readyState == 4) { // Revenu !
            if (requete.status == 200) {// Retour s'est bien passé !
                // fonction d'affichage (ci-dessous)
                afficher(requete.responseText);
            } else { // Retour s'est mal passé :(
                alert(requete.status, requete.statusText);
            }
        }
    };
}

function afficher(json) {
    // Affiche l'état des broches/pwm/millis revenu en json
    donnees = JSON.parse(json);
    console.log(donnees);
    
    for(i=3; i <= 5; i++) { // Pour les broches 3 à 5 de notre tableau
        etats[i].checked = donnees["broches"][i];
    }
    pwm.value = parseInt(donnees["pwm"]);
    a0.value = parseInt(donnees["A0"]);
    millis.textContent = donnees["uptime"];
}

En cadeau de fin, une version utilisable en ligne de cette interface peut être trouvée ici : http://jsfiddle.net/f6c2kc11/5/. Pour l’utiliser il suffit simplement de modifier l’url de base avec votre ip publique et le port utilisé par l’Arduino.

Une version légèrement améliorée (mise en paramètre de l’ip:port de la cible) est ici : http://jsfiddle.net/f6c2kc11/7/

Magie de l’internet, votre Arduino fait maintenant partie de la grande sphère de l’IoT, le phénomène très à la mode de l’Internet of Things. Qu’allez-vous bien pouvoir envoyer comme informations dorénavant ?

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !

Faites communiquer votre Arduino avec votre appareil Android

$
0
0

Cet article est un article « invité », rédigé par Sébastien (vous pourrez retrouver d’autres de ces réalisations à la fin de l’article).

Bonjour à tous !

Dans ce tutoriel porté sur Android et Arduino, nous allons connecter ces deux mondes géniaux (n’est-ce pas 😀 ?). Nous allons illustrer ce tutoriel par une application concrète ! A la fin, vous aurez une application Android avec deux boutons. Ces deux boutons permettront soit d’allumer une led connecté à l’Arduino, soit de l’éteindre. Pour cela, vous allez avoir besoin du matériel suivant :

  • Un Arduino avec un shield Ethernet (ou wifi) ainsi qu’une led et sa résistance
  • Un appareil sous Android
  • Un ordinateur

L’ordinateur jouera le rôle du serveur : il recevra les messages envoyés par l’application Android et les renverra ensuite à l’Arduino. Sachez qu’il est tout à fait possible d’envoyer des messages de l’Arduino à Android.

Au niveau des compétences requises, des connaissances basiques en programmation Android et en Arduino suffiront !

Si vous voulez voir le résultat que vous obtiendrez à la fin de ce tutoriel, je vous invite à vous rendre à la section « Résultat » où vous trouverez une vidéo !

Le protocole MQTT

Pour faire communiquer l’appareil Android avec l’Arduino, nous allons utiliser un langage commun : le protocole MQTT. L’avantage de ce protocole, c’est qu’il existe une librairie pour Android et une librairie pour Arduino. Ainsi nos deux mondes communiqueront de la même façon !

Le protocole MQTT est un protocole de messagerie de type Publish-Subscribe basé sur le protocole TCP/IP (d’où la nécessité du shield Ethernet). Le protocole se décompose donc en trois grandes parties :

  • Les « publishers » : ils envoient un ou des message(s) sur un ou plusieurs « Topic »
  • Le « broker » MQTT : il fait le lien entre les « publishers » et les « subscribers »
  • Les « subscribers » : ils s’abonnent à un ou plusieurs « Topic ». Lorsque qu’un message est publié sur un topic, tous les subscribers de ce topic reçoivent le message

Le broker MQTT permet de faire le lien entre le publisher (appareil Android) et le subscriber (Arduino). Dans notre exemple il n’y a qu’un seul publisher et qu’un seul subscriber, mais il pourrait y en avoir plus.

Le broker MQTT : le nœud central

Le broker MQTT est le cœur de notre architecture (voir image ci-dessous). Il va permettre de faire communiquer l’appareil Android avec l’Arduino.

Architecture

Architecture

Rassurez-vous, vous n’aurez pas besoin de développer votre propre broker, il en existe déjà. Mais si cela peut satisfaire votre soif de développement, ça fera un bon exercice !

Celui que je vais utiliser tout au long de ce tuto, et que je vous conseille, est le broker « Mosquitto ». C’est un broker open source. Il suffit de télécharger l’exécutable sur le site officiel (https://mosquitto.org/) et de l’installer. Pensez à lire le fichier readme.txt qui se trouve à la racine du dossier d’installation, car il vous précise les dépendances à installer. Il vous faudra notamment installer pthread, openSSL (les liens vous sont fournis dans le readme) ainsi que l’ajout de quelques dll. Pour information, il vous faudra placer les dll dans le dossier de l’installation.

Pour le lancer, une simple ligne de commande suffit. Dans mon cas ça donne (sachant que je suis sous Windows) :

"C:\Program Files (x86)\mosquitto\mosquitto.exe" -v -p 1883

Il suffit donc de lancer l’exécutable qui a été installé, avec les options :

  • -v : mode verbose
  • -p 1883 : on va utiliser le port de l’ordinateur 1883

Vous voilà avec un broker qui tourne et qui est prêt à recevoir et envoyer des messages !

Connectez votre appareil Android au broker MQTT

On va à présent créer notre application Android ! Elle sera composée de deux boutons : un pour allumer la LED connectée à notre Arduino, et l’autre pour l’éteindre.

Initialisez votre projet Android

On va dans un premier temps initialiser notre projet pour qu’il puisse communiquer avec le protocole MQTT. Pour cela, il faut :

– Ajouter les dépendances dans le fichier gradle:

– Au tout début de votre fichier gradle :

repositories {
        maven { url 'https://repo.eclipse.org/content/repositories/paho-snapshots/' }
    }

– Dans la partie dependencies de votre fichier gradle:

compile('org.eclipse.paho:org.eclipse.paho.android.service:1.0.3-SNAPSHOT') {
        exclude module: 'support-v4'
    }
    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.3-SNAPSHOT'

– Ajouter le service dans le Manifest entre les balises (si vous l’oubliez, vous n’aurez aucune erreur mais il vous sera impossible de vous connecter au broker et d’envoyer/recevoir des messages. Si je vous dis ça c’est que j’ai passé quelques heures à débogger mon application pour ce simple oublie) :

<service android:name="org.eclipse.paho.android.service.MqttService" ></service>

Ajouter les permissions dans le Manifest (en dessous de la balise fermante : ) :

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Connectez vous au broker MQTT

Votre projet est enfin prêt ! Nous allons maintenant créer la méthode qui va nous permettre de nous connecter au broker. Voici son prototype :

public void connect(String address, String port)

  • Le premier argument address, correspond à l’adresse IP où se situe le broker. Pour connaitre l’adresse IP de votre ordinateur (sous windows), ouvrez une console et tapez la commande ipconfig et cherchez la ligne Adresse IPv4. L’adresse est de la forme : 192.168.1.xxx
  • Le second argument port correspond au port utilisé par votre broker MQTT.

Dans la partie précédente, nous avons lancé notre broker MQTT sur le port 1883.

Le corps de la méthode est assez simple. Je vous laisse le découvrir par vous même. Si la connexion est réussi, la méthode onSuccess est appelée, sinon la méthode onFailure sera appelée. Attention ! Vous aurez une erreur sur la dernière ligne, quand on appelle la méthode setCallback, ainsi que sur la ligne subscribe(topic);. Commentez les, nous y reviendrons plus tard.

private MqttAndroidClient client = null;

public void connect(String address, String port) {
    String clientId = MqttClient.generateClientId(); // génère un ID
    client = new MqttAndroidClient(getApplicationContext(), "tcp://" + address + ":" + port, clientId);

    try {
        IMqttToken token = client.connect(); // on tente de se connecter
        token.setActionCallback(new IMqttActionListener() {
            @Override
            public void onSuccess(IMqttToken asyncActionToken) {
                // Nous sommes connecté
                System.out.println("On est connecté !");
                subscribe(topic); // ligne à commenter pour le moment
            }

            @Override
            public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                // Erreur de connexion : temps de connexion trop long ou problème de pare-feu
                System.err.println("Echec de connection !");
            }
        });
    } catch (MqttException e) {
        e.printStackTrace();
    }

    client.setCallback(new MqttCallbackHandler()); // ligne à commenter pour le moment
}

Il ne vous reste plus qu’à appeler cette méthode dans la méthode onResume et vous serez connecté à votre broker ! Pensez à mettre votre propre adresse IP et à avoir le broker qui tourne sur votre ordinateur pour que la connexion puisse se faire.

@Override
public void onResume() {
    super.onResume();
    connect("192.168.1.17", "1883");
}

Bien sûr, si vous vous connectez au broker dans la méthode onResume, il faut penser à vous déconnecter dans la méthode onPause. Je ne détaille pas le code mais je vous le donne (il est assez simple) :

@Override
public void onPause() {
    super.onPause();
    disconnect();
}

public void disconnect() {
    if (client == null) {
        return;
    }
    try {
        IMqttToken disconToken = client.disconnect();
        disconToken.setActionCallback(new IMqttActionListener() {
            @Override
            public void onSuccess(IMqttToken asyncActionToken) {
                // Nous nous sommes correctement déconnecté
            }

            @Override
            public void onFailure(IMqttToken asyncActionToken,
                                  Throwable exception) {
                // Quelque chose c'est mal passé, mais on est probablement déconnecté malgré tout
            }
        });
    } catch (MqttException e) {
        e.printStackTrace();
    }
}

Envoyez un message sur un topic

Pour envoyer un message, nous aurons besoin de deux choses : le topic sur lequel envoyer le message et le message lui-même. Pour ce faire, nous allons utiliser la méthode publish de notre client (de classe MqttAndroidClient). Cette méthode prend en paramètre un topic et un message, ça tombe bien ! Pour notre exemple, nous allons publier un message sur le topic LEDArduino. Ainsi, tous les subscribers abonnés à ce topic receveront le message. Voici le code :

private final String topic = "LEDArduino";

public void sendMsg(String msg) {
    MqttMessage message = new MqttMessage();
    message.setPayload(msg.getBytes());
    try {
        client.publish(topic, message);
    } catch (MqttException e) {
        e.printStackTrace();
    }
}

Recevoir un message

Pour notre exemple, notre application Android n’aura pas besoin de recevoir de message. Vous pouvez passer cette partie si vous le souhaitez. Sachez que c’est dans cette partie que nous allons pouvoir décommenter le code précédemment commenté dans notre méthode connect.

Nous allons avoir besoin de deux choses pour recevoir des messages : souscrire à des topics et avoir un callback qui sera appelé automatiquement quand un message aura été reçu par l’application.

Pour souscrire à un topic, nous allons faire appel à la méthode subscribe de notre client. Cette méthode prend deux arguments :

– topic : le topic sur lequel on veut s’abonner
– QOS (quality of service) : peut prendre trois valeurs :
– 0 : Le message sera délivré qu’une seule fois, sans confirmation
– 1 : Le message sera délivré au moins une fois, avec confirmation
– 2 : Le message sera délivré exactement une fois, avec vérification en quatre étapes

Voici ce que donne notre méthode subscribe. Une fois inséré dans votre code, vous pouvez décommenter le code qui l’appele dans la méthode connect.

private static int QOS = 0;

public void subscribe(final String topic) {
    try {
        IMqttToken subToken = client.subscribe(topic, QOS);
        subToken.setActionCallback(new IMqttActionListener() {
            @Override
            public void onSuccess(IMqttToken asyncActionToken) {
                // On a bien souscrit au topic
                System.out.println("onSuccess subscribe topic " + topic);
            }
            @Override
            public void onFailure(IMqttToken asyncActionToken,
                                  Throwable exception) {
                // La souscription n'a pas pu se faire, peut être que l'utilisateur n'a pas
                // l'autorisation de souscrire à ce topic
            }
        });
    } catch (MqttException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Passons maintenant à la classe qui va permettre d’avoir nos callback ! Elle doit implémenter l’interface MqttCallback. Une fois cette classe implémenter, vous allez pouvoir décommenter la méthode setCallback de la méthode connect. Dans notre exemple, la classe qui implémente cette interface se nomme MqttCallbackHandler. Je vous donne le code basique de la classe. Encore une fois, il est facile à comprendre :

import android.content.Context;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;

public class MqttCallbackHandler implements MqttCallback {

    /** {@link Context} for the application used to format and import external strings**/
    private Context context;
    /** Client handle to reference the connection that this handler is attached to**/
    private String clientHandle;

    public MqttCallbackHandler()
    {
    }

    /**
     * @see org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang.Throwable)
     */
    @Override
    public void connectionLost(Throwable cause) {
    }

    /**
     * @see org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String, |org.eclipse.paho.client.mqttv3.MqttMessage)
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        String message_str = new String(message.getPayload(), "UTF-8");
        System.out.println("message arrivé str " + topic + " " + message_str);
    }

    /**
     * @see |org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse.paho.client.mqttv3.IMqttDeliveryTok|en)
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        // Do nothing
    }
}

Créez votre application

Nous avons maintenant toutes les bases qu’il nous faut pour créer notre application qui va communiquer avec notre Arduino. Il ne nous reste plus qu’à créer deux boutons : un bouton qui va permettre d’allumer la LED et un bouton pour l’éteindre. Si on clique sur le bouton qui doit allumer la LED, on va envoyer le message « ON » en appelant simplement la méthode sendMsg précédemment écrite. Si on clique sur le bouton pour éteindre la LED, on va envoyer le message « OFF ». Simple non ? Je vous laisse le faire, et si besoin je vous donne mon code Java et XML :

public void AllumerLed(View v) {
    sendMsg("ON");
}
public void EteindreLed(View v) {
    sendMsg("OFF");
}

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="AllumerLed"
            android:text="Que la lumière soit !" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="EteindreLed"
            android:text="J'ai eu assez de lumière, merci !" />

    </LinearLayout>

</RelativeLayout>

Une fois votre application terminée, elle devrait pouvoir se connecter au broker MQTT (pensez à lancer le broker sur votre ordinateur et à avoir votre appareil Android en réseau local avec votre ordinateur, par exemple en étant sur le même réseau wifi, et envoyer des messages. Lorsque vous cliquez sur un bouton sur Android, vous devriez voir dans la console que le broker MQTT a reçu un message (voir image ci-dessous).

Console Mosquitto

Console Mosquitto

Le message reçu par le broker qui fait 2 bytes est le message « ON » et le message reçu qui fait 3 bytes est le message « OFF ».

Connectez votre Arduino au broker MQTT

Initialiser votre projet Arduino

Comme pour Android, il vous faut d’abord télécharger la librairie qui va vous permettre de communiquer avec le protocole MQTT. Rendez-vous à l’adresse suivante : https://eclipse.org/paho/clients/c/embedded/ et descendez jusqu’à la section Arduino. Vous allez avoir un lien pour télécharger la librairie. Pour rappel, pour ajouter la librairie dans Arduino (téléchargée au format ZIP), il vous faut cliquer (dans l’IDE d’Arduino) sur « Croquis->Inclure une bibliothèque->Ajouter la bibliothèque .ZIP ».

Une fois la librairie ajoutée, vous pouvez utiliser le protocole MQTT ! Sachez qu’un exemple très complet vous est fourni avec la librairie. Vous le trouverez dans votre dossier Arduino->libraries->MQTTClient->example. Vous ne devriez pas avoir de mal à le lire car il reprends ce que nous avons vu avec Android (connect, subscribe, …), mais façon Arduino. Sachez d’ailleurs que je me suis grandement inspiré de cet exemple pour écrire le code que nous allons voir ensemble.

Le câblage

Pour pouvoir utiliser le protocole MQTT sur votre Arduino, il vous faut un shield ethernet (ou wifi). En effet, le protocole MQTT étant basé sur le protocole TCP/IP, le shield ethernet (ou wifi) est requis. Il vous faudra également relier votre Arduino à votre réseau local en connectant le shield à votre box via un câble ethernet (ou via wifi). Une fois ceci fait, nous allons pouvoir brancher notre LED.

Concernant la LED, je l’ai connecté au PIN 2 de l’Arduino, en série avec sa résistance (ça serait bête de la griller !). J’ai connecté l’anode sur le pin 5V de l’Arduino et la cathode sur le PIN 2. Ainsi, quand le PIN 2 sera à 0V, la LED s’allumera, et quand le PIN sera à 5V, la LED s’éteindra.

Communiquez avec le protocole MQTT

Nous allons à présent passer au code pour connecter l’Arduino au broker MQTT et pour recevoir les messages. Je ne vous montrerai pas comment envoyer un message. Vous trouverez, si besoin, les quelques lignes qui le permettent dans la fonction loop() de l’exemple fourni avec la librairie.

Les includes nécessaires sont les suivants

#include <SPI.h>        // Pour communiquer avec le shield Ethernet
#include <Ethernet.h>   // Pour la partie Ethernet, evidemment !
#include <IPStack.h>    // Permet de gérer la couche IP
#include <Countdown.h>  // Timer utilisé par le protocole MQTT
#include <MQTTClient.h> // Permet de gérer le protocole MQTT

Les variables nécessaires

Dont le pin de la LED et le topic auquel on veut souscrire (qui sera le même que celui sur lequel on envoie les messages côté Android) :

const int led = 2; // pin de la LED

EthernetClient c; // remplacez par un YunClient si vous utilisez Yun
IPStack ipstack(c);
MQTT::Client<IPStack, Countdown, 50, 1> client = MQTT::Client<IPStack, Countdown, 50, 1>(ipstack);

byte mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };  // remplacer par l'adresse MAC de votre shield ethernet
const char* topic = "LEDArduino"; // le topic utilisé pour communiquer

Les fonctions connect et messageArrived

Nous allons créer la fonction qui sera appelée quand un message sera reçu. On indiquera plus tard au client MQTT que c’est cette fonction qu’il faudra qu’il appelle quand on recevra un message appartenant au topic LEDArduino. C’est dans cette fonction que nous gérons l’allumage et l’extinction de la LED en fonction du message reçu.

void messageArrived(MQTT::MessageData& md)
{
  MQTT::Message &message = md.message;
    
  char* msg = (char*) message.payload; // on recupere le message
  msg[message.payloadlen] = 0; // indique la fin du char*
  
  if (strcmp(msg, "ON") == 0) // on a reçu le message "ON"
    digitalWrite(led, LOW);   // on allume la LED
  else if (strcmp(msg, "OFF") == 0) // on a reçu le message "OFF"
    digitalWrite(led, HIGH);        // on éteint la LED
}

Maintenant il va falloir nous connecter au broker MQTT et souscrire au topic qui nous intéresse. Pour cela, nous allons créer la méthode connect, exactement de la même façon que nous avons fait pour Android. Pensez à remplacer la variable hostname par votre propre adresse IP (comme nous avons fait pour l’application Android).

void connect()
{
  char hostname[] = "192.168.1.17"; // IP où se trouve le broker MQTT
  int port = 1883; // port utilisé par le broker
 
  int rc = ipstack.connect(hostname, port);
  if (rc != 1)
  {
    Serial.print("rc from TCP connect is ");
    Serial.println(rc);
  }
 
  Serial.println("MQTT connecting");
  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
  data.MQTTVersion = 3;
  data.clientID.cstring = (char*)"arduino-id";
  rc = client.connect(data);
  if (rc != 0)
  {
    Serial.print("rc from MQTT connect is ");
    Serial.println(rc);
  }
  Serial.println("MQTT connected");
  
  rc = client.subscribe(topic, MQTT::QOS0, messageArrived);    // le client souscrit au topic
  if (rc != 0)
  {
    Serial.print("rc from MQTT subscribe is ");
    Serial.println(rc);
  }
  Serial.println("MQTT subscribed");
}

Finalisation du programme

Voilà ! Toutes nos fonctions sont prêtes, il ne nous reste plus qu’à implémenter les fonctions setup() et loop() ! Pensez à appeler client.yield(1000) dans la fonction loop() sinon votre Arduino ne recevra aucun message !

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH); // on initialise la LED en l'éteignant
  
  Serial.begin(9600);
  Ethernet.begin(mac);

  connect();
}

void loop() {
   if (!client.isConnected())
    connect();

   delay(500);
   client.yield(1000); // permet la reception des messages
}

Le résultat !

Nous allons à présent voir le résultat tant attendu après un travail acharné entre le monde d’Android, d’Arduino et sans oublier le protocole MQTT géré par le broker qui tourne sur votre ordinateur.

  • Lancez le broker sur votre ordinateur
  • Lancez l’application Android (soyez sûr que vous ayez toujours la bonne adresse IP pour le broker MQTT et que vous soyez connecté en réseau local avec le broker)
  • Démarrez votre Arduino connecté à votre réseau local

Amusez-vous à cliquer sur les boutons qui permettent d’allumer et d’éteindre la LED de votre Arduino !

Nous avons vu dans ce tutoriel comment faire communiquer un appareil Android avec un Arduino.

Nous nous sommes contenté, pour illustrer ce tuto, d’envoyer un message à l’Arduino pour qu’il allume ou éteigne une LED. Mais les possibilités sont infinies ! Vous pouvez envoyer des messages d’un Arduino à un appareil Android. Vous pouvez aussi faire communiquer autant d’Arduino et d’appareil d’Android que vous le voulez simultanément !

J’espère que ce tutoriel vous a plu ! Je vous laisse libre imagination pour intégrer la communication Android/Arduino dans vos futurs projets !

Si vous êtes intéressé par le développement Android, vous pouvez me retrouver :

A bientôt !

Sébastien

Viewing all 11 articles
Browse latest View live