PI & ARDUINO via USB

mariage de raison ou comment faire communiquer un RASPBERRY PI et un ARDUINO UNO via port USB et un software .

ARDUINO et RASPBERRY sont très complémentaires en utilisation. l’ ARDUINO pour commander et communiquer avec des capteurs et globalement pour tout traitment de signal évolué , RASPBERRY PI lui est adapté pour les traitements et les calculs complexes nécessitant de la puissance, pour les affichages haute definition et les traitements grapiques evolués, pour les connexions wifi et inthernet et pour l’utilisation de software gourmants en memoire ou necessitant de la puissance de processeur .

il est donc intéressant de pouvoir les faire communiquer ensemble . partant du fait qu’ils ont tous les deux un port USB , alors autant en profiter . nous allons voir ici comment.

pour traiter la question au travers d’un exemple pratique, nous allons utiliser le montage a base d’un u capteur DHT11 pour mesurer la temperature et l’humidité) utilisé dans la rubrique ARDUINO-TUTOS:

l’idée est tout simplement de lire les données avec l’ARDUINO et de les envoyer au RASPBERRY PI via le port USB pour les afficher en clair soit via une interface graphique simple développée sous TKINTER soit via une interface graphique développée avec PROCESSING.

NOTA: tous les développements expliqués ci dessous peuvent être entièrement réalisés sous RASPBERRY PI 4 ( de preference avec mini 4Go de RAM) à condition d’installer l’IDE ARDUINO et PROCESSING sur le RPI . pour cela voir la partie “RASPBERRY – generalités / utilitaires divers”

PREPARATION DE L’ARDUINO UNO:

rappel des connexions:

programme a télécharger dans l’Arduino UNO:

#include <dht_nonblocking.h>
#define DHT_SENSOR_TYPE DHT_TYPE_11
static const int DHT_SENSOR_PIN = 2;
DHT_nonblocking dht_sensor( DHT_SENSOR_PIN, DHT_SENSOR_TYPE );

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

static bool measure_environment( float *temperature, float *humidity ) {
  static unsigned long measurement_timestamp = millis( );
  /* Measure once every four seconds. */
  if( millis( ) - measurement_timestamp > 3000ul )   {
    if( dht_sensor.measure( temperature, humidity ) == true )
    {
      measurement_timestamp = millis( );
      return( true );
    }
  }
  return( false );
}

void loop( ) {
  float temperature;
  float humidity;
  if( measure_environment( &temperature, &humidity ) == true )
  {
    Serial.print( temperature );
    Serial.print( "," );
    Serial.print( humidity);
    Serial.print( "\n" );
  }
}

GESTION DE LA COMMUNICATION USB avec PYTHON:

avant de continuer , dans un premier temps il faut connecter l’ARDUINO UNO et le RPI via USB ( si pas deja fait pour telecharger l’ARDUINO) puis determiner la dénomination du port USB connecté a l’ARDUINO .

pour cela ouvrir le mode de commande en ligne puis taper la ligne de commande suivante:

dmesg -s 1024

apres avoir validé , un tas de lignes defilent a l’ecran et vers la fin ou trouve l’identifiant du port USB de connexion de l’ARDUINO:

ouvrir Thonny Python et copier/coller dedans le programme ci dessous ( lien du pgme version zip) en verifiant de bien mettre la designation correste du port USB ( ligne 9 partie rouge du pgme ci dessous), bien respecter egalement l’indentation des lignes:

import serial
import tkinter as tk
import datetime

root= tk.Tk()
canvas1 = tk.Canvas(root, width = 400, height = 200)
canvas1.pack()

label11 = tk.Label(root, text= "METEO")
canvas1.create_window(200, 40, window=label11)

ser = serial.Serial(port='/dev/ttyACM0',baudrate = 9600,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,bytesize=serial.EIGHTBITS,timeout=1)
 
while 1:
    x= str(ser.readline())
    now = datetime.datetime.now().strftime('%d/%m/%Y - %H:%M:%S')
    temp = x[2:7]
    humi = x[8:12]
    if x != "b''" :
        label12 = tk.Label(root, text= now )      
        label21 = tk.Label(root, text= "TEMPERATURE")
        label22 = tk.Label(root, text= temp +' °C')
        label31 = tk.Label(root, text= "HUMIDITE")
        label32 = tk.Label(root, text= humi + ' %')
        canvas1.create_window(200, 80, window=label12)
        canvas1.create_window(120, 120, window=label21)
        canvas1.create_window(120, 150, window=label22)
        canvas1.create_window(300, 120, window=label31)
        canvas1.create_window(300, 150, window=label32)
        label12.update()
        label22.update()
        label31.update()

root.mainloop()

lancer l’execution du programme ( fleche verte en haut dans la barre de commande de thonny python), vous devriez avoir quelque chose comme cela:

mis a part la partie affichage utilisant TKinter ( voir rubrique spécifique), la partie stratégique du programme est en ligne 9 ou l’on vient tout simplement lire le contenu de la chaine de caractère qui arrive sur le port série et la stocker dans une variable chaine “ser” puis ensuite en lignes 13 et 14 ou l’on vient récupérer les portions de chaines de caractère relatives a la température et a l’humidité dans des variables chaine “temp” et “humi” pour ensuite les afficher via l’interface TKinter ( partie dans la boucle “while 1”).

petite particularité , au passage , dans le programme on recupère la date et l’heure du RPI en ligne 12 du pgme pour la stocker dans une variable “now” pour affichage dans le GUI TKinter.

COMMUNICATION USB avec PROCESSING :

pour executer la communication avec processing , ne rien changer a la partie ARDUINO, Ouvrir l’IDE PROCESSING  et copier/coller le programme suivant puis lancer l’execution ( fleche en haut a gauche dans l’IDE processing).

// Import Meter library
import meter.*;
// Import serial library
import processing.serial.*;

Serial port; // Define a port
Meter m, m2;

void setup(){
  // First we need to create a empty window
  size(950, 400); // Size of the window (width, height)
  background(0, 0, 0); // Background color of window (R,G,B)  
  // Create new port
  port = new Serial(this, "/dev/ttyACM0", 9600); //name of the port would be different for linux  
  // Lets add a default meter to empty window
  // TEMPERATURE METER
  m = new Meter(this, 25, 80);  // here 25, 10 are x and y coordinates of meter's upper left corner  
  m.setTitleFontSize(20);
  m.setTitleFontName("Arial bold");
  m.setTitle("Temperature (C)");  
  // Change meter scale values
  String[] scaleLabels = {"0", "10", "20", "30", "40", "50", "60", "70", "80"};
  m.setScaleLabels(scaleLabels);
  m.setScaleFontSize(18);
  m.setScaleFontName("Times new roman bold");
  m.setScaleFontColor(color(200, 30, 70));  
  // We can also display the value of meter
  m.setDisplayDigitalMeterValue(true);  
  // Lets do some more modifications so our meter looks nice
  m.setArcColor(color(141, 113, 178));
  m.setArcThickness(15);  
  m.setMaxScaleValue(80);  
  m.setMinInputSignal(0);
  m.setMaxInputSignal(80);  
  m.setNeedleThickness(3);  
  // HUMIDITY METER
  // lets take some refference from first meter
  int mx = m.getMeterX(); // x coordinate of m
  int my = m.getMeterY(); // y coordinate of m
  int mw = m.getMeterWidth();  
  m2 = new Meter(this, mx + mw + 20, my);  
  m2.setTitleFontSize(20);
  m2.setTitleFontName("Arial bold");
  m2.setTitle("Humidity (%)");  
  // Change meter scale values
  String[] scaleLabels2 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m2.setScaleLabels(scaleLabels2);
  m2.setScaleFontSize(18);
  m2.setScaleFontName("Times new roman bold");
  m2.setScaleFontColor(color(200, 30, 70));  
  // We can also display the value of meter
  m2.setDisplayDigitalMeterValue(true);  
  // Lets do some more modifications so our meter looks nice
  m2.setArcColor(color(141, 113, 178));
  m2.setArcThickness(15);  
  m2.setMaxScaleValue(100);  
  m2.setMinInputSignal(0);
  m2.setMaxInputSignal(100);  
  m2.setNeedleThickness(3);
}

void draw(){
  // Lets give title to our window
  textSize(30);
  fill(0, 255, 0); // Font color , (r,g,b)
  text("Temperature and Humidity", 250, 40); // ("text", x, y)  
  if (port.available() > 0) {
      String val = port.readStringUntil(10);  // until \n => 10 in  ascii
      if(val!=null){
         String[] list = split(val, ',');
         if(list.length==2){
             float temp = float(trim(list[0]));
             float hum = float(trim(list[1]));
             m.updateMeter(int(temp)); // int is used due to updateMeter accepts only int values
             m2.updateMeter(int(hum)); 
             println("Temperature: " + temp + " C  " + "Humidity: " + hum + "%");
             // delay(1000);             
          } 
      }
  }
}

processing est developpé a la base pour de la gestion graphique poussée , ce que ne sait pas faire TKinter , vous obtiendrez donc un resultat au look bien plus “high tech” sous processing avec des indicateurs genre compteurs/afficheurs du type ci dessous: