Aller au contenu


Photo
- - - - -

[Test] Plotter les données venant d'un Arduino

plot processing arduino python

  • Veuillez vous connecter pour répondre
11 réponses à ce sujet

#1 R1D1

R1D1

    Modérateur et Membre passionné

  • Modérateur
  • PipPipPipPipPip
  • 1 148 messages
  • Gender:Male
  • Location:Autriche

Posté 03 mai 2017 - 10:31

Aujourd'hui, on plotte.

Quand je teste des trucs avec Arduino, je suis régulièrement frustré par la difficulté à visualiser mes données, particulièrement quand il s'agit de capteurs. Le retour texte par le moniteur série, c'est pas mal, mais rien ne vaut un beau plot temporel (désolé, j'utiliserai l'anglicisme "plot" de to plot, déformation professionnelle :)).
Dans cette optique, j'ai regardé ce qui se faisait en termes d'outils pour afficher les données du port série. Mon propre essai d'il y a deux ou trois ans était assez décevant, donc j'ai cette fois repéré trois librairies pour répondre à mon problème :

  • ArduinoPlot de gregpinero (github ArduinoPlot) : ce qui m'a plu dans ce projet, c'est que le code est en python et utilise wxWidgets, dont je me sers également en ce moment pour des projets de logiciel avec GUI. L'utilisation est simple, l'interface propre, et visiblement configurable.
  • arduino-plotter de devinaconley (github arduino-plotter) : plot en temps ou en XY, configuration de l'affichage du plot à partir de l'Arduino, possibilité de changer le layout facilement.
  • RealTimePlotter de sebnil (github RealtimePlotter) : il expose exactement la problématique qui me préoccupe dans sa description (Yay!), le format de message série est explicitement simple, l'interface a l'air simple et on peut la modifier en live.

Principe
Avant de rentrer dans mon retour d'expérience, un petit mot sur le principe très général des plotters et de leur mise en oeuvre ici.
Il faut distinguer deux programmes : celui qui tourne sur l'Arduino (et qui est chargé de collecter les données et de les envoyer sur le port série), et celui qui tourne sur le PC (et qui lit le port et affiche le graphe). On définit un port pour la communication (COMx ou /dev/ttyX), puis le programme côté Arduino envoie des données à une certaine fréquence, tandis que le programme côté PC met à jour son affichage périodiquement ou à réception des données. Les trois librairies sont je parle respectent ce principe, vous devrez donc d'une part, uploader un code sur l'Arduino, d'autre part lancer le programme de visualisation sur votre PC.
Pour tester tout ça, j'ai utilisé un montage basique avec un capteur DHT 22 branché sur le port 2 de mon Arduino Uno et alimenté en 3.3V.

Résultats
Le principal critère dans cette évaluation est d'abord la facilité de mise en oeuvre : je n'ai pas envie de passer des heures à adapter le système à mon problème pour visualiser mes données ou à chercher quel script lancer. Si ça ne marche pas, out. Ensuite viennent les aspects simplicité du code (et donc "hackabilité" pour mes propres systèmes) et configuration de l'interface (pour différences échelles de temps, amplitudes des données, etc.). Je n'ai pas vraiment regardé ces derniers points ici, mais je poursuivrai sûrement ça bientôt.

ArduinoPlot
Première déception, le code qui va lire le port série utilise une méthode (read_all) qui n'existe pas dans ma version de la librairie. J'ai également galéré à installer wxWidgets sur la machine où je teste (je l'utilse sur un autre ordi sans problème), même avec un virtualenv. Bon, trop d'efforts, pas de réconfort, on laisse tomber.

arduino-plotter
Lors de mon premier test, j'ai laissé tomber assez rapidement, parce que je trouvais le code peut clair à mettre en oeuvre. Je viens de retester ce soir, et en fait, cette librairie est plutôt bien ! Déjà, le fait de configurer l'affichage à partir de l'Arduino est vraiment sympa, pour faire évoluer l'affichage dynamiquement (hop, je presse un bouton connecté à un pin et j'affiche tel ou tel signal). Le code côté Arduino est super simple (voir plus bas).
Quelques petits défauts quand même : l'affichage n'est pas continu (pas de ligne mais des points), ce qui fait qu'entre deux données qui ont un grand écart (par exemple, mon taux d'humidité qui passe de 15 à 10%), on a du vide. L'affichage en abscisse est aussi assez bizarre, mais je ne me suis pas trop penché sur le code côté plotter. Autre défaut, le graph se reset parfois, je pense quand l'Arduino reboot, ce qui n'est pas forcément génial, mais ne pose pas de problème si on ne touche pas au montage.









/*
  ===========================================================================================
  Example used in Quick-Start + DHT sensor (R1D1)
  -------------------------------------------------------------------------------------------
  Plotter
  v2.3.0
  https://github.com/devinaconley/arduino-plotter
  by Devin Conley
  ===========================================================================================
*/

// Includes and definitions for sensor :
#include <Adafruit_Sensor.h>
#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// Plotting lib
#include "Plotter.h"

// Containing variables
double x,t,h;

Plotter p;

void setup()
{
    h= 0.0;
    t= 0.0;
    p.Begin();
    dht.begin();

    p.AddTimeGraph( "R1D1 - test DHT 22", 500, "t (temp)", t , "h (hum)", h ); // for adding x : "x (sin)", x ,
}

void loop()
{
  // Reading temperature or humidity takes about 250 milliseconds!
  h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  t = dht.readTemperature();

    // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)){ return; }
  
  // The following value will not be sent actually (R1D1)
  x = 10*sin( 2.0*PI*( millis() / 5000.0 ) );

  delay(500);
  p.Plot(); // usually called within loop()

}

Fichier joint  Screen_arduino-plotter_DHT22.png   363,61 Ko   28 téléchargement(s)

RealTimePlotter
Le premier que j'ai réussi à faire fonctionner. J'ai passé un certain temps pour obtenir un affichage correct, et surtout à comprendre quel type de message envoyer à partir de l'Arduino (je suis pas sûr d'avoir tout compris). L'affichage est robuste aux erreurs dans la communication. Le code côté Arduino n'est pas forcément super clair, il est probable que pas mal de parties pourraient être intégrées dans une classe et séparées du code principal.
 

#include <Adafruit_Sensor.h>
#include "DHT.h"

#define DHTPIN 2     // what digital pin we're connected to

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

uint8_t buffer[20]; //Buffer needed to store data packet for transmission
int16_t data1 = 1;
int16_t data2 = 2;
int16_t data3 = 3;
int16_t data4 = 4;
bool debug = false;

uint8_t buffer2[20];

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  dht.begin();
}

int16_t value = 0;
int8_t direction = 5;
void loop()
{
   // Reading temperature or humidity takes about 250 milliseconds!
  int16_t h = (int16_t)dht.readHumidity();
  // Read temperature as Celsius (the default)
  int16_t t = (int16_t)dht.readTemperature();

   // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t))
  { return; }
  // put your main code here, to run repeatedly: 
  //Serial.write(value);
  value = (value + direction);
  if (value > 100)
    direction = -10;
  else if (value < -50)
    direction = 10;
  //data3 = value;
  //plot(value, value/2, value/4, value/8);
  for (uint8_t i = 0; i<7; i++) {
    switch (i)
    {
      case 0:
      Serial.print(t);
      break;
      /*case 1:
      Serial.print(h);
      break;
      case 2:
      Serial.print(0);
      break;
      case 3:
      Serial.print(0);
      break;
      case 4:
      Serial.print(0);
      break;
      case 5:
      Serial.print(0);
      break;*/
    }
    if (i < 7)
      Serial.print(" ");
  }
  Serial.println("");
  delay(500);
}

uint8_t variableA = {0x00};

void plot(int16_t data1, int16_t data2, int16_t data3, int16_t data4)
{
  int16_t pktSize;
  
  buffer[0] = 0xCDAB;             //SimPlot packet header. Indicates start of data packet
  //buffer[1] = 4*sizeof(int16_t);      //Size of data in bytes. Does not include the header and size fields
  buffer[1] = 1;
  buffer[2] = 5;
  buffer[3] = 6;
  buffer[4] = 7;
  buffer[5] = 8;
    
  pktSize = 2 + 2 + (4*sizeof(int16_t)); //Header bytes + size field bytes + data
  
  if (!debug) {
    Serial.print(data1);
    Serial.print(" ");
    Serial.print(data2);
    Serial.print(" ");
    Serial.print(data3);
    Serial.print(" ");
    Serial.print(data4);
    Serial.print('\r');
  }
  else {
    Serial.print("Size: ");
    Serial.println(pktSize, HEX);
    for (int i = 0; i<pktSize; i++) {
      Serial.print(buffer[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
}



Bonus stage : Graph (https://www.arduino..../tutorial/graph)
A posteriori, j'ai découvert Graph, qui fonctionne aussi avec Processing. L'affichage n'est pas top, mais le code est ultra simple, donc ouvert à évolutions.

Conclusion :
À première vue, j'ai commencé à écrire ce post dans l'idée de recommender RealTimePlotter. Après mes quelques essais supplémentaires, je pense que arduino-plotter est plus prometteur, et je vais sûrement creuser plus en détail ce que l'on peut faire avec. J'aime bien l'idée que l'Arduino envoie la config du plotter, changer le nombre de variables envoyé est enfantin, bref, c'est facile d'utilisation.
Pour ArduinoPlot, je vous invite à la tester si vous pouvez facilement installer les librairies requises dans leur bonne version. Vu que j'avais deux autres librairies à tester, je n'y ai consacré que le minimum de temps.


R1D1 - Calculo Sed Ergo Sum -- en ce moment, M.A.R.C.E.L.
Avatar tiré du site bottlebot

#2 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 03 mai 2017 - 11:13

Merci, super pratique !!


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#3 Telson

Telson

    Membre chevronné

  • Membres
  • PipPipPipPip
  • 975 messages
  • Gender:Male
  • Location:Punaauai - Tahiti

Posté 04 mai 2017 - 03:30

Ah punaise oui très pratique de pouvoir visualiser les données!

 

Merci.



#4 Melmet

Melmet

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 1 129 messages
  • Gender:Male
  • Location:Saint-Sozy (46200)

Posté 04 mai 2017 - 06:06

Bravo pour le tuto :) 

 

Merci.


Ne demande jamais à un robot de faire ce que tu peux faire toi même. :nono: :laugh1:


#5 R1D1

R1D1

    Modérateur et Membre passionné

  • Modérateur
  • PipPipPipPipPip
  • 1 148 messages
  • Gender:Male
  • Location:Autriche

Posté 04 mai 2017 - 09:18

Merci ! N'hésitez pas si vous avez des questions, des idées de quoi creuser sur le sujet. Je mettrais sûrement ce topic à jour en allant plus loin.


R1D1 - Calculo Sed Ergo Sum -- en ce moment, M.A.R.C.E.L.
Avatar tiré du site bottlebot

#6 macerobotics

macerobotics

    Membre occasionnel

  • Membres
  • Pip
  • 127 messages
  • Gender:Not Telling
  • Location:Bretagne

Posté 04 mai 2017 - 10:34

Bonjour,

 

Merci pour ces comparatifs de plot arduino, intéressant.


Mace Robotics - mobile platform for education makers and research.

www.macerobotics.com


#7 R1D1

R1D1

    Modérateur et Membre passionné

  • Modérateur
  • PipPipPipPipPip
  • 1 148 messages
  • Gender:Male
  • Location:Autriche

Posté 04 mars 2018 - 05:37

Bon, après discussion avec Path, si vous mettez votre IDE arduino à jour (pas comme moi), il y a un plotter intégré dans la dernière version. :D
Il suffit de faire un Serial.print des valeurs voulues séparées par une virgule et de finir par un saut de ligne (Serial.println).

Ci-après un exemple avec le DHT22. Enjoy !
 

Fichier joint  recordPlotterIDE-crop.png   46,53 Ko   0 téléchargement(s)


R1D1 - Calculo Sed Ergo Sum -- en ce moment, M.A.R.C.E.L.
Avatar tiré du site bottlebot

#8 zavatha

zavatha

    Membre occasionnel

  • Membres
  • Pip
  • 148 messages
  • Gender:Male

Posté 05 mars 2018 - 11:54

Salut a tous.

Le plot integre a l IDE se met a jour en teps reel (il cumule les fragments de courbe apres chaque println) ou est ce que le graph se reintialise a chaque nouveau signal de fin de ligne ?

@+
Zav

#9 R1D1

R1D1

    Modérateur et Membre passionné

  • Modérateur
  • PipPipPipPipPip
  • 1 148 messages
  • Gender:Male
  • Location:Autriche

Posté 05 mars 2018 - 12:24

Il se met à jour en temps réel : chaque point des deux courbes correspond à un envoi "humidité, température \n". Je mets le code que j'utilise pour envoyer les données depuis l'Arduino en dessous, c'est directement tiré de la libraire DHT.


#include <Adafruit_Sensor.h>

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"

#define DHTPIN 2     // what digital pin we're connected to

// Uncomment whatever type you're using!
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  //Serial.println("DHTxx test!");

  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  delay(1000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  //Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(",");
  Serial.print(t);
  Serial.println(",");
  //Serial.print(" %\t");
  //Serial.print("Temperature: ");
  //Serial.print(t);
  //Serial.print(" *C ");
  //Serial.print(f);
  //Serial.print(" *F\t");
  //Serial.print("Heat index: ");
  //Serial.print(hic);
  //Serial.print(" *C ");
  //Serial.print(hif);
  //Serial.println(" *F");
}

R1D1 - Calculo Sed Ergo Sum -- en ce moment, M.A.R.C.E.L.
Avatar tiré du site bottlebot

#10 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 4 486 messages
  • Gender:Male

Posté 05 mars 2018 - 02:10

Vous parlez bien du "Traceur série" de base, là ?
Ma chaine vidéo YouTube : https://www.youtube....wMz-IzZqyvqEUek

#11 R1D1

R1D1

    Modérateur et Membre passionné

  • Modérateur
  • PipPipPipPipPip
  • 1 148 messages
  • Gender:Male
  • Location:Autriche

Posté 05 mars 2018 - 10:02

Du traceur série inclus dans l'IDE, à côté du moniteur, oui.
J'ai découvert ça ce week-end, mon éditeur était toujours en v1.0.5.
R1D1 - Calculo Sed Ergo Sum -- en ce moment, M.A.R.C.E.L.
Avatar tiré du site bottlebot

#12 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 4 486 messages
  • Gender:Male

Posté 06 mars 2018 - 07:34

Ah oui ?! Mon IDE est en 1.8.2
Je ne me suis jamais posé de question. Effectivement c'est pas mal.
Ma chaine vidéo YouTube : https://www.youtube....wMz-IzZqyvqEUek





0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users