Licence CC BY

Semaine 13 : Internet des Objets (2/2)

Toutes les bonnes choses ont une fin…

Et oui, après 13 semaines intenses : l'aventure "La Fabrication Numérique" touche à sa fin. On ne se quitte pas encore puisque nous vous avons encore réservé du contenu sur l'Internet des Objets cette semaine. Laurent Toutain de Télécom Bretagne nous expose les bases des protocoles réseaux en nous parlant de container de bananes :)

Je profite de cette dernière semaine pour remercier l'équipe pédagogique qui a fait tout le boulot :

  • Glenn : notre génie de l'électronique à la motivation infinie. Il a énormément apporté dans le forum et les cours ! Merci merci merci !
  • Simon (Eskimon) : pointure de l'Arduino, il est venu compléter, enrichir cette seconde édition avec une pédagogie sans faille. je vous invite à dévorer son site qui est une mine d'or. MERCI !
  • Laurent Mattlé : notre modeleur fou qui a carrément révolutionné la partie modélisation 3D. Ces vidéos sont parmi les plus regardées et viennent de dépasser les 10 000 vues ! Merciiiiiiii !

Et on continue avec les acteurs de ce MOOC : vous !

Corrigé du TP 10 : Pilotage de LED par Internet

Voici la correction du TP de la semaine dernière qui reprend des éléments du cours sur l'internet des objets.

Code Arduino
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
  Pilotage de LED par Internet
 
 TP de la semaine 12 du MOOC "La Fabrication Numérique" 
 
 Le montage :
 * Un shield Ethernet branché sur les broches 10, 11, 12, 13
 * Une LED branché sur la broche 2
 
 créé le 20 Juin 2014
 par Théophile Paimparay
 
 Ce code est en CC0 1.0 Universal
 
 https://www.france-universite-numerique-mooc.fr/courses/MinesTelecom/04002/Trimestre_1_2014/about
 
 */

#include <SPI.h>
#include <Ethernet.h>
#include <String.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);

// Initialize the LED pin
const int led = 2;

// Initialize the message sent by the client
String cmdString = "";

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  // Start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  Serial.print("Server is at ");
  Serial.println(Ethernet.localIP());

  // Setup as output the pin where the LED is connected
  pinMode(led, OUTPUT);
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");

    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //store characters to string 
        cmdString.concat(c);  



        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          //Parse the cmdString to obtain the command
          if(cmdString.substring(6,13)== "led=on "){
            // display LED ON in the web browser
            client.print("LED ON");
            // OPEN the LED
            digitalWrite(led, HIGH);
          }
          if(cmdString.substring(6,14)=="led=off "){
            // display LED OFF in the web browser
            client.print("LED OFF");
            // SHUTDOWN the LED
            digitalWrite(led, LOW);
          }

          client.println("<br />");       

          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    //   Serial.println("client disonnected");
    //clear the command Line
    cmdString="";
  }
}

Correction du TP 10

Ce code Arduino est disponible ici.

Montage

Montage - Correction du TP 10

Schéma

Schéma - Correction du TP 10

Pour réaliser ce montage, vous avez besoin de :

  • Un Arduino
  • Une platine de prototypage
  • Un câble USB branché à votre ordinateur
  • Une LED de votre couleur préférée
  • Des fils de prototypage
  • Une résistance de 220Ω
  • Du temps :)

Notre correction s'arrête là. Pour des éclaircissements, nous vous invitons à poser vos questions sur le forum et à reparcourir le cours.

Internet des objets

Arduino et Internet

Merci d'avoir regardé cette vidéo. Celle-ci vous permettra, nous l'espérons de mieux comprendre ce qui se passe lorsqu'un Arduino équipé d'un shield Ethernet est branché sur une box Internet. Nous vous invitons maintenant à réaliser votre second montage connecté. Aussi, il est (vraiment) recommandé de lire les références proposées ici :

Références

Merci à Laurent Toutain pour ce cours

Qu'est ce qu'une API ?

Récupérer un flux RSS avec Arduino

Nous vous en parlions la semaine passée : Internet se propage dans nos objets. Cela permet aux équipements autour de nous de récupérer toute sorte d'informations comme les conditions météos, les actualités, l'état du trafic routier…

À la différence de l'homme, les machines n'ont pas besoin d'avoir des pages avec des images, des menus, une police agréable à lire, une structure de page… Ce qui compte, c'est l'information !

Nous souhaitons cette semaine vous montrer comment les machines peuvent récupérer des données météo à l'aide d'une API (une interface de récupération de données dediée aux machines).

Grâce à l’API de Yahoo Weather Forecast, nous allons pouvoir récupérer la température en degré celsius de pratiquement n’importe quelle ville du globe. Les données récupérées serviront pour changer la couleur d’une LED RGB sur une gamme de couleur représentant la température. En d’autres termes, nous allons faire un thermomètre lumineux !

Les données sont fournies au format XML (Extensible Markup Language) qui est un langage de balisage, il est couramment utilisé afin de structurer des données.

L’URL du flux XML que nous allons utiliser est la suivante http://weather.yahooapis.com/forecastrss?w=619163&u=c

Elle est composée du chemin d’accès à l’API Yahoo http://weather.yahooapis.com/forecastrss puis comporte ensuite deux arguments séparés par le caractère & :

  • w=619163 correspond à l’ID de la ville sur laquelle on souhaite se baser (ici, Rennes), pour rechercher l’ID d’une ville, cliquez-ici
  • u=c est relatif aux unités utilisées, ici le degré celsius à l’instar du fahrenheit

Le flux XML

Comme on le constate sur l’image précédente, le fichier XML est organisé grâce à des balises possédant des attributs. Par exemple, temp est un attribut de la balise yweather:condition.

Notre but est donc de récupérer ce flux XML depuis notre carte Arduino mais surtout cibler correctement l’information dont nous avons besoin. C’est l’étape de parsing (parser des données revient à extraire une ou plusieurs informations ciblées dans un ensemble de données).

Il existe plusieurs méthodes afin d’arriver au bon résultat. On peut parser des données manuellement ou bien, ce que nous allons faire ici, utiliser une librairie qui nous simplifiera la tâche. L’une des grandes forces du langage Arduino et son extrême polyvalence et son extensibilité à l’aide de librairies écrites par la communauté, qui consistent en un ensemble de fonctions exécutants des tâches spécifiques. En d’autres termes, une librairie est un pack de Lego supplémentaire qui trouvera sa place sans aucun mal dans votre coffre à jouets informatique.

TextFinder nous aidera à extraire simplement l’information dont nous avons besoin dans le flux XML.

Téléchargez la librairie et copiez le dossier dans le répertoire des librairies d’Arduino.

Préparation du montage

Branchement d'une led RGB

Le montage ci-dessus représente une LED à anode commune reliée aux pins digitaux 3, 5, 6 de la carte Arduino. La résistance de 220 Ohms sur la masse permet de ne pas suralimenter la LED. Enfin, on notera l’utilisation de pins digitaux PWM (symbolisés par le signe \~ à côté de leur numéro).

Ces pins sont particuliers puisqu’ils permettent la Power Width Modulation utilisée par la fonction analogWrite d’Arduino. Nous verrons leur utilité par la suite.

Test de la LED

Un programme Arduino comporte deux blocs principaux. La fonction setup exécutée une seule fois lors de la mise sous tension de la carte et la fonction loop dont le contenu est exécuté tant que la carte est sous tension.

Le programme que nous allons écrire permet de tester notre montage. Créez un nouveau sketch Arduino. La première étape consiste à déclarer les pins utilisés par notre LED, nous utilisons des variables afin de pouvoir changer par la suite ces pins si besoin, sans avoir à rectifier manuellement dans tout le programme les endroits où ils sont mentionnés.

1
2
3
4
//Déclaration des pins utilisés par la LED
int ledR = 6;
int ledG = 5;
int ledB = 3;

Il n’y a pas besoin de déclarer ces pins comme étant des sorties (OUTPUT).

1
2
3
void setup(){
  // les pins utilisant analogWrite n'ont pas besoin d’être déclarés en sorties
}

Nous pouvons désormais écrire des valeurs de courant sur notre LED. Nous utilisons ici la fonction analogWrite, qui permettra par la suite de mixer les différentes intensités de Rouge Vert ou Bleu de notre LED afin d’en changer sa couleur.

1
2
3
4
void loop(){
  //Ecriture sur les pins de la LED
  analogWrite(ledR, 64);
}

La LED est allumée en rouge à un quart de son intensité maximale. Les valeurs utilisées par la fonction analogWrite s’échelonnent de 0 à 255. Un premier exercice pourrait consister à mélanger les couleurs entre elles, par exemple :

1
2
3
4
 //Ecriture sur les pins de la LED
  analogWrite(ledR, 180);
  analogWrite(ledG, 200);
  analogWrite(ledB, 0);

Ces valeurs me donnent du orange avec la LED que j’ai utilisée.

Déclaration d’une nouvelle fonction changement de couleur

Notre objectif principal et de colorer la LED en fonction de la température extérieure. Plutôt que d’écrire à chaque fois les couleurs manuellement, nous allons simplifier le processus à l’aide d’une fonction qui regroupera l’attribution des différentes intensités de rouge, vert, bleu en une seule ligne :

1
2
3
4
5
6
//Définition de la couleur grace à son code RGB
void setColor(int red, int green, int blue){
 analogWrite(ledR, red);
 analogWrite(ledG, green);
 analogWrite(ledB, blue);
}
Connexion à l’API Yahoo weather

Récupérer les informations météo est très simple. En effet, il s’agit d’une simple requête HTTP GET permettant de récupérer le contenu d’une page. L’API de Yahoo ne nécessite pas de s’authentifier afin de pouvoir accéder aux données. En revanche, c’est le cas de certaines API comme celle de Twitter par exemple.

La suite du programme consiste à implémenter la récupération de la température en plusieurs étapes :

  • Établir une connexion entre Arduino et Internet
  • Récupérer une page
  • Parcourir la page et récupérer l’information dont on a besoin
  • Stocker cette information
  • Tester cette donnée et choisir la couleur de LED appropriée
  • Recommencer

Fort heureusement, le langage Arduino est très bien conçu. La plupart des méthodes liées à la connexion à un réseau sont implémentées au travers d’une classe cliente qui est native au langage Arduino. Il existera donc très peu de nuances dans le programme pour utiliser ou bien un shield ethernet ou WiFi. Un shield ethernet sera utilisé pour fournir les explications de la suite de cet article, en revanche, les sketchs pour le shield WiFi sont également téléchargeables.

Reprenons le programme que nous avons précédemment écrit. On ajoute au tout début de ce dernier les librairies nécessaires :

1
2
3
#include <SPI.h>
#include <Ethernet.h>
#include <TextFinder.h>

On ajoute ensuite les paramètres nécessaires à l’initialisation d’une connexion Ethernet :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//Adresse MAC de la carte
byte mac[] = {
  0xDE, 0xAF, 0xFF, 0xEF, 0xFE, 0xED};

EthernetClient client;

//Adresse du serveur
char server[] = "weather.yahooapis.com";

//Dernière connection au serveur en ms
unsigned long lastConnectionTime = 0;        

//Etat de la connection
boolean lastConnected = false;

//délai entre chaque connection en ms (1mn)
const unsigned long postingInterval = 60*1000;

Le bloc d’instructions suivant est à placer dans le setup et permet l’initialisation de la connexion

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
void setup() {
  //Initialisation du port série, utile au débuggage
  Serial.begin(9600);

  //Délai afin initialiser correctement le module ethernet
  delay(1000);

  //Initialisation de la connexion ethernet, attribution automatique d'une IP via DHCP
  Ethernet.begin(mac);

  //On affiche l'adresse IP du module
 Serial.print("IP address: ");
 Serial.println(Ethernet.localIP());
}

Passons maintenant au corps du programme :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
 void loop(){

  //Les données sont envoyées sur le port série pour affichage
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
 
    //Si il n'y a pas de connexion mais qu'il y en avait une lors de la dernière exécution du loop
  //on arrete le client
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  //si il n'y a pas de connexion mais que 10 secondes se sont écoulées depuis la dernière connexion
  //on essaye de nouveau
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    httpRequest();
  }
  //on stocke l'état de la connection
  lastConnected = client.connected();

}

Déclarons maintenant la fonction permettant de faire une requête HTTP :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//fonction permettant d'effectuer une requête HTTP
void httpRequest() {
  // si la connexion est réussie
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // on envoie le HTTP GET
    client.println("GET /forecastrss?w=12724564&u=c HTTP/1.0");
    client.println("Host: weather.yahooapis.com");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    //on stock le moment de la dernière connexion
    lastConnectionTime = millis();
  }
  else {
    //si la connexion échoue
    Serial.println("connection failed");
    Serial.println("disconnecting.");
    client.stop();
  }
}

A ce stade, si vous téléversez le programme, vous devriez voir, grâce au moniteur série, le contenu du fichier XML récupéré par la carte. Il reste à parser les données afin de récupérer uniquement la température, c’est là qu’intervient TextFinder. Cette librairie permet de parcourir la page en fonction des balises que nous lui aurons demandé de cibler. Nous allons donc cibler l’attribut temp pour récupérer la température

Au début du programme sous EthernetClient, rajoutons l’instruction suivante qui a pour but d’initialiser l’objet client utilisé par la librairie :

1
TextFinder finder(client);

La suite est un jeu d’enfant puisqu’elle tient en quelques lignes, c’est là qu’opère la magie d’Arduino, nous allons dans un premier temps déclarer une nouvelle variable globale (à la suite des déclarations de la LED par exemple) permettant de stocker la température

1
int temp;

On intègre ensuite à la fonction httpRequest le code magique permettant de récupérer la température, à placer en dessous de lastConnectionTime = millis();

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    // On cherche l'attribut temp
    if(finder.find("temp=") ){
      //On stocke la valeur voulue dans la variable temp
      temp = finder.getValue();
      //On affiche cette valeur à des fins de débuggage
      Serial.print("Temp C:  ");
      Serial.println(temp);
    }
    else {
      Serial.print("Pas de données");
    }

Nous allons commenter la portion de code suivant dans la boucle loop afin de ne pas être submergés d’informations dans le moniteur série :

1
2
3
4
5
6
7
/*
  //Les données sont envoyées sur le port série pour affichage
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
*/
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//Si la température est inférieure ou égale à 15 degrés...
if(temp <= 15){
  setColor(0, 0, 255); //Bleu
}
 
//Si la température est supérieure ou égale à 25 degrés...
else if(temp >= 25){
  setColor(255, 0, 0); //Rouge
}
 
//Si la température est supérieure à 15 degrés ou inférieure à 25 degrés...
else if(temp > 15 || temp < 25){
  setColor(0, 255, 0); //Vert
}

Compilez et uploadez le code sur la carte pour voir le résultat dans le moniteur série. Une précision IMPORTANTE, il faut changer le délai d’actualisation à 5 secondes pour obtenir un résultat immédiatement. En effet, les 60 secondes originales sont un délai plus qu’acceptable car la température ne change pas si rapidement. Cependant, lorsque la carte est mise sous tension, le programme attend 60 secondes avant d’effectuer la première requête !

Test de la température et changement de couleurs

Souvenons nous de la fonction que nous avons écrite précédemment, setColor… c’est le moment de l’utiliser ! Il va falloir tester la température pour voir si il fait chaud ou froid. Commençons avec nos trois couleurs, rouge pour chaud, vert pour tempéré et bleu pour froid. Placez le code suivant à la fin du loop :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//Si la température est inférieure ou égale à 15 degrés...
if(temp <= 15){
  setColor(0, 0, 255); //Bleu
}
 
//Si la température est supérieure ou égale à 25 degrés...
else if(temp >= 25){
  setColor(255, 0, 0); //Rouge
}
 
//Si la température est supérieure à 15 degrés ou inférieure à 25 degrés...
else if(temp > 15 || temp < 25){
  setColor(0, 255, 0); //Vert
}

Vous venez de visualiser une donnée de manière tangible grâce à un actionneur. A vous de définir votre propre couleur en nuançant les couleurs par exemple, effet de fading sur la LED…

Merci à Thomas Meghe pour ce cours !

Exemples d'objets connectés

Les objets connectés du FabLab de Lannion

Les objets connectés du FabLab de Lannion

Merci d'avoir regardé cette vidéo. Nous esperons que celle-ci vous donnera des idées pour vos futurs projets connectés. Aussi, nous vous invitons à jeter un coup d'oeil au projet laboîte de Baptiste : une petite horloge connectée à base d'Arduino qui va chercher de nombreuses informations sur Internet. En plus, comme c'est open-source (code Arduino et code serveur), ce projet peut servir de base à vos projets.

Merci au FabLab Lannion pour cette vidéo

Electronique et Arduino

Avant de commencer, un avertissement que j'ai ajouté au sujet de l'utilisation d'un microcontrôleur 'nu' pour vos projets (cours Arduino sans l'Arduino de la semaine dernière).

Le résultat de cette procédure de "flashage" c'est qu'un programme d'amorce (dit Bootloader en Anglais) se réveille chaque fois que le microcontrôleur est allumé ou réinitialisé (RESET). Entre autre, c'est ce programme qui nous permet le dialogue avec l'IDE Arduino et qui supervise le téléversement des Sketchs. Pour signaler sa présence, ce programme utilise le LED branché sur la sortie numérique 13 de l'Arduino : ce qui correspond à la broche 19 du microcontrôleur. Faites attention, donc, à ce que vous branchez sur cette broche 19 car, au démarrage, il sera configuré en tant que sortie (OUTPUT), et activé à l'état "haut" (HIGH) pendant quelques secondes. Si votre projet vous le permet, laissez un LED (avec sa résistance) branché sur la broche 19 pour éviter tout souci.

Arduinomètre connecté

Au fil des semaines nous avons amélioré notre montage de base, uniquement fait d'une simple diode.  L’étalonnage, l'ajout d'autres types de sonde, jusqu'à l'intégration d'un afficheur LCD pour le rendre autonome.  Nous avons dépensé beaucoup d'énergie récemment afin de libérer notre Arduinomètre de son cordon ombilical.  Allez comprendre pourquoi, mais cette semaine je vous propose d'y ajouter à nouveau un cordon !

Pour commencer avec le monde de l'internet, et les objets connectés, nous allons voir s'il est possible de lire la température de notre Arduinomètre comme si l'Arduino était un serveur web.

Comment ?

Vous avez peut-être déjà lu mes remarques au sujet de notre sur-exposition aux micro-ondes, donc je ne m'attarderai pas plus sur ce point, mais mes montages 'connectés' sont toujours… ben, connectés, quoi.  Pas de Wifi chez moi.  Je suis déjà limite Electro Hyper-Sensible et donc je ne m'amuse pas à travailler avec la tête dans une soupe de micro-ondes !  Ce montage se fait avec un Ethernet shield connecté avec le bon vieux câble RJ45.

Ce que j'ai en magasin chez moi c'est la version "budget serré" de cet interface, bâti sur le contrôleur ENC28J60.  Carte qui se trouve même en kit, ou à construire de A à Z.  L'autre variante de carte Ethernet qui utilise un contrôleur W5100, est plus chère mais beaucoup plus performante et moins gourmande en ressources.   Ici donc je parle de la version ENC28J60 mais, grâce à Baptiste qui m'a traduit le sketch pour une carte W5100 / Wiznet, vous pouvez aussi faire joujou si vous n'avez que cette dernière chez vous.

Voici à quoi ressemble la bête : 

EtherCard

Le câblage des Ethernet shields n'est pas difficile mais, à cause de leur communication avec l'Arduino sur une liaison série un peu spéciale, nous n'avons pas le choix des broches à câbler, mis à part le signal "CS".  Voici le câblage que je vous conseille :

Branchement du module Ethernet

ATTENTION : l'alimentation de la carte est du 3,3v, et non 5v.  Ne vous trompez pas de broche sur l'Arduino.  Le choix de la broche 8 pour CS est essentiellement pour être compatible avec la plupart des montages utilisant cette Shield.

Le Sketch

Je suis obligé de partir de l'hypothèse que vous savez un peu ce qu'est le html, et que vous savez un peu comment cette page, que vous lisez en ce moment, vous est transmise par un serveur web.  Nous allons faire abstraction de la plupart des protocoles utilisés (TCP/IP et al.), mais il faut soulever le capot un peu quand-même.  L'essentiel à garder en mémoire est que chaque dialogue entre un objet connecté (Arduino, serveur, PC…) et un autre se passe par l'envoi et la réception detrames (sortes de paquets cadeaux), et que chaque trame comporte un en-tête qui explique d'où il vient, où il est sensé aller, et quel type de message il porte.

Nous allons essayer d'envoyer des trames de html pour construire une page web, et nous allons afficher la température sur cette page.

A vos marques…

La bibliothèque se trouve ici : https://github.com/jcw/ethercard , et sa documentation ici : <http://jeelabs.net/pub/docs/ethercard/>.

(pour la W5100 il suffit de cliquer sur "Sketch" et "Incorporer librarie", "Ethernet".  Fastoche !)

Regardons ensemble les éléments majeurs du Sketch "Arduinomètre" modifié.

Déclarations
1
2
3
#include  <stdarg.h> // pour la fonction "format" #include <EtherCard.h>
#define Diode A0  // forward biased diode w/10K R to Vcc
#define Ether_CS 8 // Broche sur laquelle nous avons branché CS

La déclaration de <stdarg.h> nous permet d'accéder à quelques outils de l'environnement gcc - le compilateur qui mouline derrière l'interface Arduino.  Vous trouverez plus d'informations sur le Wiki.  Sinon, pas d'inquiétude particulière pour les "includes".

Variables

J'ai mis en surbrillance quelques mots ou structures que nous n'avons pas vu jusque-là.  A nouveau, je ne peux pas tout expliquer ici, mais vous trouverez plus d'informations sur le site Arduino ou sur mon-club-elec

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// il faut une adresse unique pour votre réseau 
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// Mettre une addr. IP valide et unique sur votre réseau
static byte myip[] = {192,168,0,80};
// Espace de mémoire utilisé pour contenir les trames TCP/IP entrantes et sortantes 
byte Ethernet::buffer[700];
// l'étoile définit un pointeur (adresse)
char* title = "Arduinomètre Website";
// pour contenir un message formaté ...
char tempString[32];

"Le mot-clé static est utilisé pour créer des variables qui sont visibles uniquement dans une fonction. A la différence des variables locales qui sont détruites et créées à chaque fois qu'une fonction est appelée, les variables static persistent au-delà de l'appel de la fonction, conservant leurs données entre deux appels de la fonction." (merci mon-club-elec)

Ethernet:: fait référence à un espace de mémoire réservé, avec le nom "Ethernet".  Cet espace est déclaré dans la bibliothèque EtherCard.

L'étoile après char nous fait soulever le couvercle de la boîte de Pandore : c'est pour indiquer que nous allons utiliser un pointeur.  Le compilateur va nous réserver une zone de mémoire pour loger le texte "Arduinomètre Website" mais la variable title ne contient pas le texte, mais un pointeur vers cette zone de mémoire.  C'est la bibliothèque EtherCard qui nous impose cette façon de faire - pour une fois, sur ce point, je vous demande de suivre sans essayer de comprendre.

La MAC adresse contient une valeur qui devrait bien fonctionner, sauf si vous êtes plusieurs à bricoler le même montage sur le même réseau local…

C'est un peu pareil pour l'adresse IP - mais déjà il faut vérifier que l'adresse soit compatible avec votre réseau.  Pour un grand nombre de 'box', la plage 192.168.0.xxx est compatible.  Regardez les paramètres réseau de votre PC pour avoir une idée.

Fonction 'format'

Voilà une astuce qui va aussi être documentée sur le Wiki.  Parfois nous avons besoin de formater (gérer la mise en page) l'information textuelle d'une façon plus évoluée que les simples instructions disponibles avec les commandes Serial.print.  Une bibliothèque très puissante existe pour cela, mais nous n'avons pas beaucoup de place pour 'caser' ces fonctionnalités.  Voici une façon d'accéder à un style de mise en forme assez sophistiqué mais pas trop gourmand. 

1
2
3
4
5
6
7
8
// Fonction utilitaire 'détournée' du compilateur gcc // Permet de créer un message formaté pour impression / inclusion 

void format(char *fmt, ... )
{
   va_list args;   va_start (args, fmt );  // allocation d'espace en mémoire
   vsnprintf(tempString, 32, fmt, args);  // formatage du message dans tempString
   va_end (args);  // libération des ressources.
}

Vous allez bientôt voir pourquoi j'ai déclaré cette fonction.

lecture_temp
1
2
3
4
5
6
7
void  lecture_temp() 
{
  // Lire la température
  DiodeValue = analogRead(Diode); // Lire la valeur
  // Traduire la valeur en degrés C 
  Temperature = map(DiodeValue, 595, 409, 0, 100);
}

Tiens, tiens - cela me dit quelque chose…  C'est l'algorithme pour convertir la tension lue par le convertisseur ADC en température.  J'avais presque oublié le but de l'Arduinomètre !

Le setup();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  // déclaration et initialisation de l'interface EtherCard avec "begin"
  if (! ether.begin(sizeof(Ethernet::buffer), mymac, Ether_CS))
     Serial.println("Erreur : carte contrôleur inaccessible");
  else
     Serial.println("Carte OK");

  #if STATIC
     if (! ether.staticSetup(myip))
        Serial.println("Erreur d'attribution d'adresse IP");
  #else
     Serial.println("Negociation DHCP...");
     if (! ether.dhcpSetup()) {
        Serial.println( "Erreur DHCP, j'essaie l'adresse fixe...");
        if (! ether.staticSetup(myip))
           Serial.println("Erreur d'attribution d'adresse IP");
     }
  #endif
     Serial.println();

Plusieurs nouveautés ici :

ether.begin est la déclaration proprement dite de la bibliothèque et de la carte.  Les paramètres ne posent pas de problèmes particuliers.  Notez l'utilisation de sizeof(); pour déclarer la taille de l'espace Ethernet::buffer - cela évite des erreurs difficiles à diagnostiquer dans le cas où on change la déclaration de cet espace.

#define STATIC 0, #if STATIC, #else, #endif : une astuce très pratique pour modifier le comportement du compilateur.  Ici on peut choisir de ne pas tenter la négociation DHCP si on sait d'avance que cela ne marche pas chez nous.  Pour cela, il suffit de changer #define STATIC 0 en #define STATIC 1.  Parfois il est utile d'apporter des changements sans en perdre la trace.  Avec quelques mots clefs au début du Sketch, il est possible de modifier le programme compilé.  Voir aussi #define ARDUINO_UNO et #define TRACES dans ce même Sketch pour d'autres utilisations des options de compilation.

C'était quoi, alors, tout ce charabia ?   En fait c'est ce que fait aussi votre ordinateur au démarrage : on demande une adresse IP pour qu'on puisse communiquer avec le protocole TCP/IP.  C'est comme notre adresse postale sur le web.  A partir de maintenant notre Arduino est connecté !

Page web

Pour une fois cela tombe bien que loop() soit appelé sans cesse, car nous avons besoin d'une boucle d'attente - il faut attendre que quelqu'un essaie de communiquer avec nous.  Quand nous voulons consulter une page web sur un serveur, nous mettons l'URL de la page dans le browser ou navigateur.  L'URL est converti en adresse IP, et une trame spéciale est envoyée à cette adresse qui dit : "Je me connecte chez vous en tant que client html, merci de me donner le contenu de cette page".  L'Arduino est désormais un webserveur, et nous attendons les clients.  Regardons comment c'est fait :

1
2
3
4
void loop() { 
    word len = ether.packetReceive();  // Récupère le message venant du client (len = longueur du msg.)    
    word pos = ether.packetLoop(len);  // position d'éventuels paramètres
}

La fonction ether.packetReceive(); regarde si nous avons reçu un message, et retourne la longueur du message reçu (ou "0" pour indiquer qu'il n'y a pas de message).  Si un message a été reçu, ether.packetLoop(len); nous donne l'endroit dans Ethernet::buffer à partir duquel on peut chercher des informations utiles.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if(pos) {
    // texte recherché dans les paramètres
    if(strstr((char *)Ethernet::buffer + pos, "GET /?temp=") != 0) {
        Serial.println("Recu commande.");
        // Lire la température
        lecture_temp();
        // Construire le message
        format("Valeur : %03d\t environ %02d°C", DiodeValue, Temperature);
    }
}

Si nous avons reçu un message du client, on regarde si ce message contient la commande ?temp=.  Si c'est le cas, un appel à lecture_temp();  permet la mise à jour des valeurs de température.  La fonction format (enfin !) nous aide à construire le texte à inclure dans le document html.  Si vous voulez en savoir plus sur les commandes de formatage, je vous conseille de regarder sprintf(); dans la documentation pour C ou C++.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Pour ne pas écraser l'en-tete du protocole TCP/IP
BufferFiller bfill = ether.tcpOffset();

/*
    Autre astuce pour ne pas consommer toute la memoire (RAM) de notre Arduino :
    la fonction PSTR.
    Ele force le stockage en memoire 'Flash' (espace program).
    Sur le UNO il n'y a que 2Ko de RAM, mais 32Ko de Flash.
*/

bfill.emit_p(PSTR("HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\nPragma: no-cache\r\n\r\n"
    "<html><head><meta http-equiv=\"content-type\" content=\"application/xhtml+xml; charset=utf-8\" />"
    "<title>$S</title></head>"
    "<body><h1>$S</h1><br />Derniere relevé de T° : $S<br />"
    "</body></html>"), title, title, &tempString);

// Page web en html.  Les "$S" seront remplacés par les valeurs passées
// en paramètres 2, 3 et ainsi de suite
ether.httpServerReply(bfill.position());

BufferFiller bfill = ether.tcpOffset(); initialise une trame vide, et nous positionne à l'endroit immédiatement après l'en-tête. bfill.emit_p est notre page web codée en html. Quelques détails intéressants : la fonction PSTR qui réserve la place pour ce texte en mémoire Flash (avec le code du programme) et non en mémoire RAM - car la RAM est très limitée sur l'Arduino UNO1bfill.emit_p copie notre texte vers le "buffer", et en même temps elle remplace les $S avec les valeurs passées en paramètres.  Vous souvenez-vous de l'étoile "pointeur" ?  C'est cette fonction bfill.emit_p qui exige qu'on lui passe des pointeurs au lieu des valeurs.  Parce que tempString n'était pas déclaré en tant que pointeur, on force le passage de son adresse au lieu de sa valeur en le précédant d'un &.

Lançons-nous

Télécharger le Sketch entier ici : ArduinometreWeb.ino (ou la version W5100 ArduinometreWebW5100.ino), et l'ouvrir dans l'environnement Arduino.  Vérifiez encore une fois les branchements, branchez le câble réseau.  Téléversez le code, et ouvrir le Serial Monitor : noter que la vitesse de liaison série est de "9600" pour laisser la priorité à l'interface EtherCard.  Dans la fenêtre du Serial Monitor vous devriez voir quelque chose comme suit :

Liaison série

Il peut y avoir un délai avant l'affichage des paramètres IP, à cause des temps de négociation souvent très longues sur les routeurs et autres "box".  Si maintenant on ouvre une fenêtre browser, et qu'on tape l'adresse de notre serveur ("My IP"), on devrait voir une page comme celle-ci :

Vue du serveur

Et pour voir la température, il faut ajouter ?temp= à la fin de l'adresse :

Vue du serveur avec la température

Dites-moi… qui a oublié de brancher sa diode, hein ?

Glenn Smith


  1. Vous voulez en savoir plus ? Voici un tutoriel sur les mémoires d'Arduino 

Gravure CNC avec Inkscape

Inkscape GCODE Extension

Nous avons beaucoup joué avec Inkscape pour la création d'images en 2D. Je vais vous montrer que Inkscape peut aussi directement générer du GCODE pour une fraiseuse numérique ou un graveur laser.

L'astuce se trouve dans une extension gratuite, le GCODETOOLS Extension. Très simple à installer, il suffit de télécharger le fichier ici et de dé-zipper le contenu sous Program Files\Inkscape\share\extensions\ (windows) ou /usr/share/inkscape/extensions/ (Linux). Avec cette extension, il est possible de convertir n'importe quel dessin en GCODE pourvu que les traces soient converties en chemin (path).

J'ai eu l'idée de me servir de ma fraiseuse pour faire des enseignes et écriteaux pour mes voisins. Mais il reste un souci de taille pour graver du texte…

Les polices de caractères TrueType et al. écrivent des symboles avec leurs contours. Les imprimantes savent remplir les contours pour faire des symboles gras. Mais pour graver, il nous faut des symboles exprimés par leur tracé, ou chemin. Les logiciels spécifiques pour la gestion des machines CNC fournissent de telles polices, mais pas Inskcape. Mais, là aussi, une extension existe.

L'extension s'appel Hershey text. Voici le lien pour le télécharger. L'installation est la même que pour les GCODE TOOLS.

Faire un carré en GCODE

Pour voir comment les GCODE TOOLS fonctionnent, nous allons dessiner un carré. Ouvrez Inkscape et vérifiez que les extensions sont bien présentes : regardez dans le menu "Extensions" et vous devez voir "GCodeTools". Sous "Extensions/Render", vous devez voir "Hershey text…". Allez, nous allons dessiner ce carré :

  • S'assurer que la feuille (page) est de taille A4 (dans "propriétés document");
  • Cliquez sur la croix en bas à gauche afin que le paramètre "remplissage" soit renseigné à "aucun".
  • Dessinez un carré ou rectangle au centre de la feuille

Carré Insckape

  • Avec l'outil de sélection (petite flèche noire en haut à gauche), cliquez sur une des lignes du carré pour le sélectionner.
  • Allez dans le menu "Chemins" (Paths) et cliquez sur "Objet -> Chemin". Vérifiez en bas de l'écran, vous devez voir le message "Chemin (4 … calque 1 …"
  • Nous allons maintenant utiliser les GCode Tools pour générer le fichier pour notre CNC.

D'abord, il faut fixer une référence de point zéro :

  • Dans le menu "Extensions/GCodeTools", sélectionnez l'option "Orientation points…". Une fenêtre s'ouvre. Remplissez les champs comme suit :

Menu

… et cliquez sur "Appliquer" puis "Fermer".

  • Le paramètre "Z depth" correspond à la profondeur de coupe finale de notre dessin.
  • Sur notre page, en bas à gauche, nous devrions avoir deux petites flèches de repère :

Flèches repère

  • Ne désolidarisez pas les composants de ce groupe. Sélectionnez l'ensemble des flèches et les faire glisser jusqu'à faire coïncider le point de la flèche "0.0" avec le coin inférieur gauche du carré :

Ajustement

Maintenant, nous allons définir notre outil de gravure :

  • Menu "Extensions/GCode Tools…", sélectionnez "Tools library". Une fenêtre s'ouvre. Laissez le choix "Defaut" et cliquez sur "Appliquer" puis, une fois cela fait, "Fermer".
  • Vous devez maintenant avoir un pavé vert au milieu de la page, avec pleins de paramètres. On peut le déplacer pour le positionner dans notre carré (cela fait moins désordre…) :

Paramètres

  • Si les paramètres dans votre 'pavé' correspondent à ceux-ci, tout va bien. Il est possible de les modifier avec l'outil de texte (A|). Ces paramètres seront éventuellement à modifier spécifiquement pour votre machine CNC.
  • Menu "Extensions/GCode Tools…", sélectionnez "Path to GCode", puis l'onglet "Préferences". Renseignez un nom de fichier et un dossier, "Carré.gcode", par exemple. Renseignez une valeur de quelques mm pour le paramètre "Z safe height…" : il s'agit de la hauteur de sécurité à laisser pour les mouvements de la fraise entre chaque coupe. Maintenant sélectionnez l'onglet "Path to GCODE" et vérifiez que le paramètre Depth function soit renseigné comme "d". Cliquez sur "Appliquer". Vous aurez probablement une fenêtre d'avertissement :

Warning GCODE

Pas de panique, tout va bien. Cliquer sur "OK". Puis "Fermer" de l'autre fenêtre.

  • Vous devez avoir un fichier GCODE dans le dossier spécifié dans l'étape précédente. Ouvrez le fichier avec un éditeur de texte. Vous devez avoir quelque chose comme ceci :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
%
(Header)
(Generated by gcodetools from Inkscape.)
(Using default header. To add your own header create file "header" in the output dir.)
M3
(Header end.)
G21 (All units in mm)
(Start cutting path id: rect2985)
(Change tool to Default tool)
G00 Z5.000000
G00 X-0.040318 Y120.508894

G01 Z-1.000000 F100.0(Penetrate)
G01 X141.070792 Y120.508894 Z-1.000000 F400.000000
G01 X141.070792 Y-0.040313 Z-1.000000
G01 X-0.040318 Y-0.040313 Z-1.000000
G01 X-0.040318 Y120.508894 Z-1.000000
G00 Z5.000000

(End cutting path id: rect2985)
(Start cutting path id: rect2985)
(Change tool to Default tool)
G00 Z5.000000
G00 X-0.040318 Y120.508894

G01 Z-2.000000 F100.0(Penetrate)
G01 X141.070792 Y120.508894 Z-2.000000 F400.000000
G01 X141.070792 Y-0.040313 Z-2.000000
G01 X-0.040318 Y-0.040313 Z-2.000000
G01 X-0.040318 Y120.508894 Z-2.000000
G00 Z5.000000
(End cutting path id: rect2985)

Ce sont les commandes en GCode pour dessiner le carré. Notez que le même dessin est répété 4 fois mais avec une profondeur (valeur de Z) qui augmente à chaque passe. Notre fraise et le moteur se portent mieux ainsi !

Hershey text

Pour faire l'écriteau le principe est le même. Recommencez avec une feuille A4 vierge et allez dans menu "Extensions/Render/Hershey text…" Une fenêtre (etc.)

Choix Hershey

  • A coté de "Action", sélectionnez "Write glyph table" puis choisissez une police dans le menu déroulant "Font face". Cliquez sur "Appliquer".
  • Dans notre dessin, nous voyons apparaître une table de correspondance ASCII et nos symboles. Supprimez l'ensemble des symboles chaque fois avant de choisir une autre police.
  • Si nous saisissons du texte, et si nous choisissons l'option "Typeset that text", notre message sera converti en chemins dans notre dessin. Exemple : "Fun MOOC", "Serif medium" cela donne :

Démonstration

  • Vous notez que le texte est rassemblé (group). Dés que vous avez rédimensionné et positionné le texte à votre convenance, il faut désolidariser cet ensemble.
  • Menu "Extensions/GCode Tools…", "Orientation points…". Faire comme avant, déplacez l'origine vers le coin inférieur gauche de notre texte.
  • Menu "Extensions/GCode Tools…", "Tools library". Déplacez le pavé pour que nous puissions toujours voir notre texte.
  • Sélectionnez l'ensemble du texte, mais EXCLURE les flèches d'origine (MAJ + clic).
  • Menu "Extensions/GCode Tools…", "Path to GCode", puis l'onglet "Préferences". Renseignez le nom du fichier. Revenez sur l'onglet "Path to GCODE" et "Appliquer"
  • Donnez le fichier GCODE à votre CNC préferé !

La bêta en œuvre

Glenn Smith