Marc Silanus

Structure d’un premier objet communicant

Posted on 24 février 2017

Le but de ce tutoriel est de mettre en œuvre une structure type d'un objet communicant basé sur l'utilisation d'une carte Arduino pour la partie acquisition/actionneurs et d'une carte PC embarqué (pcDuino, Raspberry Pi, ...) pour la partie traitement (script Python, programme C/C++, ...), connexion au réseau (filaire ou wifi), stockage local des données (serveur de bases de données SQLigth, MySQL, ...), mise à disposition des données (serveur web Apache2, lighttpd, ginx, ...). La connexion entre ces deux carte se fait naturellement par une liaison série sur USB. Le synoptique ci-dessous représente par exemple un système de surveillance de la hauteur et de la qualité de l'eau d'un cours d'eau. La température, le Ph et la hauteur de l'eau sont mesurés sur demande par la carte Arduino. Le pcDuino via un scritp Python dont l'exécution peut être planifiée avec Cron, effectue la demande puis lit les réponses et les stockent dans la base de données MySQL. Apache2, via une page web php, met à disposition des utilisateurs les informations.

Synoptique Sorgomètre - Carla ISN 2016

Pourquoi une liaison entre un PC embarqué et un Arduino?

Les PC embarqués disposent généralement de l'environnement matériel nécessaire à la mise en œuvre de la partie Acquisition. Nous pourrions donc parfaitement nous passer de la carte Arduino. Voici quelques raisons pour expliquer cette architecture entre une Raspberry pi et une Arduino citées sur le site  http://electroniqueamateur.blogspot.fr/2014/05/communication-par-usb-entre-raspberry.html :

  • Le Raspberry Pi n'est pas idéal pour accomplir des actions avec un timing précis, car  Linux pourrait décider de se consacrer temporairement à une autre tâche.   Par exemple, si vous contrôlez un moteur pas à pas avec le Raspberry Pi, le moteur pourrait s'arrêter momentanément, de temps à autres. L'Arduino est plus fiable dans ce genre de situation.

  • Vos capteurs peuvent se trouver sur un shield conçu pour être inséré sur un Arduino.  Évidemment, la disposition des pins GPIO du Raspberry Pi n'est pas la même.

  • Si vous êtes déjà un utilisateur expérimenté de l'Arduino mais un néophyte en Python/Linux/Raspberry Pi, il y a certaines choses que vous savez déjà faire très facilement avec l'Arduino, mais que vous ne savez pas encore comment faire avec le Raspberry Pi.

  • Vous désirez établir un réseau de plusieurs capteurs satellites qui se rapportent à une seule station centrale, et plusieurs Arduinos coûtent moins cher que plusieurs Raspberry Pi.

On peut ajouter dans le cas d'un PC embarqué type Raspberry pi que ce dernier ne dispose pas d'entrées Analogique, ce qui disqualifie d'office tous les capteurs de ce type, et ils sont nombreux ...!

Acquisition des données

Plaçons nous donc dans le cas où nous devons acquérir une donnée Analogique à la demande. Nous allons utiliser un potentiomètre connecté à l'entrée A0 qui nous fournira un nombre compris entre 0 et 1023 que nous transmettrons ensuite sur le port série. La réception sur ce même port d'un caractère de déclenchement démarrera le processus d'acquisition :

Chaque fois de le caractère "M" sera reçu, nous allons retourner le résultat de la conversion analogique/numérique de la tension présente sur A0 :

const int sensorPin = A0;    // select the input pin for the potentiometer
const int led = 13;          // select the output pin for led notification
int sensorValue = 0;  // variable to store the value coming from the sensor
char recu;            // variable to store the char from Serial via USB

void setup() {
  Serial.begin(9600);
  pinMode(led,OUTPUT);
  digitalWrite(led,LOW);
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);
  // Some char from Serial 
  if(Serial.available()>0)
  {
    recu = Serial.read();
    // Good char then send sensorValue and notify it with the led
    if(recu=='M')
    {
      digitalWrite(led,HIGH);
      Serial.println(sensorValue);
      delay(250);
    }
    digitalWrite(led,LOW);
  }
}
mesuresVersSerial.ino

Télécharger le programme

Communication entre Arduino et Raspberry Pi

Pour faire communiquer les cartes Arduino et Raspberry pi ou une autre carte PC embarqué, rien de plus simple si cette dernière possède un pour USB. Il suffira de connecter la carte Arduino sur le port USB de la Raspberry comme on le fait pour un PC standard.

On peut installer l'IDE Arduino directement sur l'environnement Raspbian de la Raspberry pi pour développer sur Arduino, mais ce n'est pas nécessaire. Si vous souhaitez le faire : http://www.meccanismocomplesso.org/en/controlling-arduino-raspberry-pi/

Identifier le port série

La connexion de la carte Arduino sur un port USB de la Raspberry pi a entrainé l'apparition d'un nouveau périphérique matériel du type Serial Port over USB. Il est identifié par la dénomination tty* comme tous les autres ports de ce type sous linux. Pour l'identifier, il suffit de lister ces périphériques matériels. Ils sont situés dans le /dev :

pi@raspberrypi:~ $ ls /dev/tty*

La listes des périphériques apparait. Faire cette action Arduino déconnectée, puis Arduino connectée :

Note : Les périphériques de type Serial over USB sont souvent appelés ttyACMx ou ttyUSBx sous linux.

Maintenant, nous pouvons tester la communication entre les deux cartes en utilisant deux terminaux. Le premier nous servira à envoyer notre commande ("M") et le second à lire les données reçues :

A ce stade, il nous faut coder une application qui enverra le caractère "M" et lira les données reçues sur le port. Une telle application peut être codée simplement en shell à l'aide des commandes précédentes ou dans un autre langage de programmation. Nous utiliserons ici le langage Python mais il faut avant tout installer une librairie de gestion des communications séries :

Installation du module

Téléchargement : https://pypi.python.org/pypi/pyserial

pi@raspberrypi:~/Documents $ wget https://pypi.python.org/packages/1f/3b/ee6f354bcb1e28a7cd735be98f39ecf80554948284b41e9f7965951befa6/pyserial-3.2.1.tar.gz
pi@raspberrypi:~/Documents $ tar xzf pyserial-3.2.1.tar.gz
pi@raspberrypi:~/Documents $ cd pyserial-3.2.1
pi@raspberrypi:~/Documents/pyserial-3.2.1 $ sudo python setup.py install
 

Script Python

Dans le dossier Documents, créer le script suivant à l'aide de votre éditeur de texte préféré :

#!/usr/bin/python
# -*- coding: utf-8 -*-
#####################################################
# comArduino.py
#
# Communication serial entre Arduino et Raspberry
# Protocol :
#  - Emettre "M" pour demander les mesures
#  - Recevoir un entier entre 0 et 1023 suivit de \r\n
#  - 9600bps, 8, 1, n, n
######################################################

import serial
import time
    
ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(1)   #on attend un peu, pour que l'Arduino soit prêt.

ser.write('M')
print(ser.readline()) #on affiche la reponse

ser.close()
comArduino.py
 

Vérifier le fonctionnement

Télécharger le programme

Installation du serveur web

Nous choisissons ici d'installer Apache2 avec les modules php nécessaires qui nous permettrons de réaliser un site web dynamique pour accéder au données et pour les gérer au travers de l'outils phpMyAdmin :

pi@raspberrypi:~/Documents $ sudo apt-get update
pi@raspberrypi:~/Documents $ sudo apt-get install apache2 php5
 

Pour vérifier que tout s'est bien installé, ouvrez un navigateur et saisissez http://127.0.0.1 dans la barre d'adresse directement sur le PC embarqué ou http://ipDuPcEmbarque. La page suivante doit apparaitre :

Pour vérifier le fonction de php, nous allons écrire une page de test dans le dossier du serveur :

pi@raspberrypi:~/Documents $ cd /var/www/html/
pi@raspberrypi:/var/www/html $ sudo echo "<?php phpinfo(); ?>" > index.php
 

Dans un navigateur, saisissez l'url http://127.0.0.1/index.php :

Installation du serveur de bases de données

Nous choisirons ici d'installer MySQL server et phpMyAdmin pour gérer plus facilement les bases données :

pi@raspberrypi:~/Documents $ sudo apt-get install mysql-server php5-mysql
 

Au cours de l'installation, vous devrez définir un mot de passe pour l'utilisateur administrateur du serveur MySQL.

Pour testez le fonctionnement du serveur, nous allons juste nous y connecter puis en sortir aussitôt !

pi@raspberrypi:~/Documents $ mysql --user=root --password=monMotDePasseMySQL 
mysql > exit;
 

Nous allons maintenant installer phpMyAdmin :

pi@raspberrypi:~/Documents $ sudo apt-get install phpmyadmin

Lors de l'installation, il faudra indiquer le mot de passe root de MySQL configuré plus tôt, lors de l'installation du serveur.

L'installation de phpMyAdmin modifie les fichiers de configuration de php (php.ini). Ce fichier est chargé au démarrage d'Apache2, il est donc nécessaire de redémarrer ce serveur :

pi@raspberrypi:~/Documents $ sudo service apache2 restart

On accède à phpMyAdmin par l'intermédiaire d'un navigateur web. Seul le contenu du dossier du serveur est donc accessible (/var/www/html). Or, phpMyAdmin ne s'installe pas là. Il s'est installé dans le dossier /usr/share/phpmyadmin/. Nous allons donc créer un lien symbolique entre le dossier qui contient phpMyAdmin et le dossier du serveur :

pi@raspberrypi:/var/www/html $ sudo ln -s /usr/share/phpmyadmin/ phpmyadmin

Pour vérifier l'accès à phpMyAdmin, saisissez dans le navigateur l'url http://127.0.0.1/phpmyadmin

Base de données et tables

Pour sauvegarder les données des capteurs en provenance de la carte Arduino, nous avons besoin d'une base de données et d'au moins une table. Pour simplifier l'étude, nous nous limiterons ici à une table unique dans laquelle nous enregistrerons les grandeurs mesurées horodatées :

  • Base de données : myBDD
  • Tables : mesures
  • Champs :
    • Date : type datetime
    • Temperature : type float
    • Ph : type float
    • Distance : type float

Créer la base de données :

Créer la table :

Créer les champs :

Note : Le champs Date est une "clé primaire" (Index PRIMARY), cela signifie que les enregistrements de ce champs seront uniques (pas deux mesures à la même date).

Insertion de données :

Note : La date sera insérée automatiquement grace à l'usage de la fonction NOW( ). L'exécution de cette requête nous permettra de récupérer sa syntaxe SQL. Cela s'avérera intéressant lors de la rédaction du script Python qui devra alimenter la table en données.

 

Accéder aux données

 

Note : La syntaxe de la requête pour accéder aux données est SELECT * FROM 'Mesures'

Insérer des données à partir d'un script Python

Pour accéder au serveur MySQL, nous devons installer un module d'interfaçage entre Python et MySQL server : MySQL-python 1.2.5

Installation du module

téléchargement : https://pypi.python.org/pypi/MySQL-python/1.2.5

A partir des sources :

pi@raspberrypi:~/Documents $ wget https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip
pi@raspberrypi:~/Documents $ unzip MySQL-python-1.2.5.zip
pi@raspberrypi:~/Documents $ cd MySQL-python-1.2.5
pi@raspberrypi:~/Documents/MySQL-python-1.2.5 $ sudo apt-get install python-dev libmysqlclient-dev
pi@raspberrypi:~/Documents/MySQL-python-1.2.5 $ python setup.py build
pi@raspberrypi:~/Documents/MySQL-python-1.2.5 $ sudo python setup.py install
pi@raspberrypi:~/Documents/MySQL-python-1.2.5 $ service mysql restart

Script python d'insertion de données

Dans le dossier Documents, créer le script suivant à l'aide de votre éditeur de texte préféré :

#!/usr/bin/python
# -*- coding: utf-8 -*-
#####################################################
# mysqlPython.py
#
# Connexion au serveur MySQL et insertion de donnée
# Module : MySQLdb
#
######################################################

import MySQLdb as mysql

db = mysql.connect("localhost" , "root" , "monMotDePasseMySQL" , "myBDD")
cursor = db.cursor()
req="INSERT INTO Mesures (Date, Temperature, Ph, Distance) VALUES (NOW(), '25.7', '8.3', '124');"
cursor.execute(req)
db.commit()
mysqlPython.py

Excuter le script

pi@raspberrypi:~/Documents $ python mysqlPython.py
pi@raspberrypi:~/Documents $

Télécharger le programme

Vérifier l'insertion des données

Pour vérifier l'insertion des données, il suffit d'ouvrir phpmyadmin et constater l'ajout d'une ligne de données à la table Mesures de la base myBDD :

Script python complet

#!/usr/bin/python
# -*- coding: utf-8 -*-
#####################################################
# surveillanceRiviere.py
#
# Communication serial entre Arduino et Raspberry
# Module : serial
# Protocol :
#  - Emettre "M" pour demander les mesures
#  - Recevoir une chaine "temp;ph;dist;\r\n"
#  - 9600bps, 8, 1, n, n
# 
# Connexion au serveur MySQL et insertion de donnée 
# Module : MySQLdb
# Données :
#  - Date : date et heure de la mesure
#  - Temperature : DFRobot LM35 Linear Temperature Sensor
#  - Ph : Kit pH-mètre Analogique DFRobot Gravity
#  - Distance : Parallax Ping Ultrasonic Distance Sensor  
######################################################
import MySQLdb as mysql
import serial
import time
    
ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(1)   #on attend un peu, pour que l'Arduino soit prêt.

ser.write('M')
recu = ser.readline()) #on affiche la reponse
mesure=recu.split(";")
print(recu)
print(mesure[0])
print(mesure[1])
print(mesure[2]) 
ser.close()
db = mysql.connect("localhost" , "root" , "monMotDePasseMySQL" , "myBDD") 
cursor = db.cursor() 
req="INSERT INTO Mesures (Date, Temperature, Ph, Distance) VALUES (NOW(),%s, %s, %s);" % (mesure[0], mesure[1], mesure[2])
cursor.execute(req) 
db.commit()
surveillanceRiviere.py

Télécharger le programme

Affichage des données en php

On affiche les données de la table dans un tableau  après s'être connecté à la base de données :

<?php 
try
{
  mysql_connect ('127.0.0.1', 'root', 'monMotDePasseMySQL');
  mysql_select_db('myBDD');
  echo 'Connexion réussi a la base de donnée<br>';
}
catch (Exception $e)
{
  die('Erreur : ' . $e->getMessage());
}
?>

<table width="400px">
  <thead>
    <tr>
      <td with="40%"> Heure</td>
      <td with="20%"> Hauteur</td>
      <td with="20%"> pH</td>
      <td with="20%"> Température</td>
    </tr>
  </thead>
  <tbody>

    <?php
    $result = mysql_query('SELECT * FROM Mesures ORDER BY Date DESC');
      while ($row = mysql_fetch_array($result, MYSQL_NUM)) 
      {
            echo "<tr><td>".$row[0]."</td><td>".$row[3]."</td><td>".$row[2]."</td><td>".$row[1]."</td></tr>";
      }
    ?>
  </tbody>
</table>
affichage.php

L'utilisation de node.js en remplacement de php est parfaitement envisageable : https://codeforgeek.com/2015/01/nodejs-mysql-tutorial/

Exemple : Surveillance de la Sorgue

Un groupe d'élèves de terminal S ont mis en œuvre cette démarche dans le cadre de leur projet :

Fichiers du site.

Commentaires (0) Trackbacks (0)

Désolé, le formulaire de commentaire est fermé pour le moment

Trackbacks are disabled.