IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Le blog de f-leb

[Actualité] [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands

Noter ce billet
par , 24/09/2021 à 14h11 (9116 Affichages)
Vous voudriez piloter votre Arduino en tapant des commandes depuis le Moniteur Série ? Pour cela, au lieu de réinventer la roue, utilisez plutôt une bibliothèque comme SerialCommands, simple de fonctionnement et avec une faible empreinte mémoire. Il est en effet assez fréquent d'avoir besoin d'ajuster un ou plusieurs paramètres en fonction d'événements sur votre système embarqué en cours de fonctionnement. Plutôt que de modifier la valeur d'un paramètre codée en dur dans le programme (un seuil, un coefficient P, I ou D de votre régulateur, la vitesse d'un moteur, etc.), compiler et téléverser à nouveau le programme, et recommencer la procédure si nécessaire, modifiez vos paramètres en direct et de façon interactive depuis le Moniteur Série.

Comme démonstration, je prendrais le petit programme de clignotement de LED RGB (pour faire original) ci-dessous. Ma LED RGB (à cathode commune) se mettra simplement à clignoter (fréquence 1 Hz), et quand elle sera allumée, elle sera de couleur magenta (parce que c'est plus joli !)

demo-serialCommands-rgb.ino
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
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
#include "ledRGB.h"
 
// LedRGB ne gère que les led RGB à cathode commune !!
LedRGB myLed(9, 11, 10); // rouge=pin 9, vert=pin 11, et bleu=pin 10 supportent le PWM sur Arduino Uno
 
byte colorOn = Color::magenta; // équivalent à colorOn = Color::red | Color::blue
int brightness = 100 ; // luminosité en %
 
byte ledState = Color::off;   // état de la Led, initialement éteinte
 
unsigned long previousMillis = millis();
const long interval = 500;  // intervalle = 500ms
 
void setup() {  
 
}
 
void loop() {
  unsigned long currentMillis = millis();
 
  if ((currentMillis - previousMillis) > interval) { // si intervalle de temps écoulé
    ledState = (ledState == Color::off) ? colorOn : Color::off; // bascule led On/Off
    myLed.digitalWrite_RGB(ledState, brightness);
    previousMillis = currentMillis;
  }
}


ledRGB.h
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef H_LED_RGB
#define H_LED_RGB
  #include <Arduino.h>
 
  enum Color {  red   = 1 << 2,
                green = 1 << 1,
                blue  = 1 << 0,
                yellow = red | green,
                cyan = green | blue,
                magenta = red | blue,
                white = red | green | blue,
                off = 0
             };
 
  class LedRGB{
    public:       
      LedRGB(byte pRed, byte pGreen, byte pBlue);
      void digitalWrite_RGB(byte ledColor);
      void digitalWrite_RGB(byte ledColor, int brightness);
 
    private:
      byte _pinRed, _pinGreen, _pinBlue;
    };
#endif


ledRGB.cpp
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "ledRGB.h"
 
 LedRGB::LedRGB(byte pRed, byte pGreen, byte pBlue){
        _pinRed = pRed;
        _pinGreen = pGreen;
        _pinBlue = pBlue;
        pinMode(_pinRed, OUTPUT);
        pinMode(_pinGreen, OUTPUT);
        pinMode(_pinBlue, OUTPUT);       
        }
 
 void LedRGB::digitalWrite_RGB(byte ledColor) {
        digitalWrite(_pinRed  , (ledColor & Color::red) ? HIGH : LOW);
        digitalWrite(_pinGreen, (ledColor & Color::green) ? HIGH : LOW);
        digitalWrite(_pinBlue , (ledColor & Color::blue) ? HIGH : LOW);
      }
 
void LedRGB::digitalWrite_RGB(byte ledColor, int brightness) {
        analogWrite(_pinRed  , 255*((ledColor & Color::red) ? brightness : 0) / 100);
        analogWrite(_pinGreen, 255*((ledColor & Color::green) ? brightness : 0) / 100);
        analogWrite(_pinBlue , 255*((ledColor & Color::blue) ? brightness : 0) / 100);  
      }


Supposons que je veuille régler la couleur de ma LED qui clignote, ainsi que sa luminosité. Ces deux paramètres sont dans des variables globales du fichier principal avec des valeurs initiales non satisfaisantes, et qu'il faudra ajuster en cours de fonctionnement :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
byte colorOn = Color::magenta; // équivalent à colorOn = Color::red | Color::blue
int brightness = 100 ; // luminosité en %

Par exemple avec la commande rgb suivante à saisir dans le Moniteur Série, suivie de 3 ou 4 paramètres :
rgb 0 0 0 ==> LED éteinte
rgb 1 0 0 ==> rouge
rgb 0 1 0 ==> vert
rgb 0 0 1 ==> bleu
rgb 1 1 0 ==> rouge + vert = jaune
rgb 0 1 1 ==> vert + bleu = cyan
rgb 1 0 1 ==> rouge + bleu = magenta
rgb 1 1 1 ==> rouge + vert + bleu = magenta
rgb 1 1 0 50 ==> rouge + vert = jaune, brillance = 50%

Et si vous avez oublié la syntaxe des commandes ou comment fonctionne la synthèse additive des couleurs primaires, la commande help vous fera un rappel.

Tant qu'à faire, l'implémentation de ces commandes série ne doit pas remettre en cause le programme principal, en le modifiant le moins possible.
Le programme principal modifié devient (modifications en rouge) :

demo-serialCommands-rgb.ino
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
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
#include "ledRGB.h"
#include "ledSerialCommands.h"

// LedRGB ne gère que les led RGB à cathode commune !!
LedRGB myLed(9, 11, 10); // rouge=pin 9, vert=pin 11, et bleu=pin 10 supportent le PWM sur Arduino Uno

byte colorOn = Color::magenta; // équivalent à colorOn = Color::red | Color::blue
int brightness = 100 ; // luminosité en %

byte ledState = Color::off;   // état de la Led, initialement éteinte

unsigned long previousMillis = millis();
const long interval = 500;  // intervalle = 500ms

void setup() {  
  Serial.begin(115200);
  init_serial_commands();
}

void loop() {

  update_serial_commands();

  unsigned long currentMillis = millis();

  if ((currentMillis - previousMillis) > interval) { // si intervalle de temps écoulé
    ledState = (ledState == Color::off) ? colorOn : Color::off; // bascule led On/Off
    myLed.digitalWrite_RGB(ledState, brightness);
    previousMillis = currentMillis;
  }
}

Fonctionnement de SerialCommands

Pour déclarer un gestionnaire général pour les commandes série :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
char serial_command_buffer_[17];
SerialCommands serial_commands_(&Serial, serial_command_buffer_, sizeof(serial_command_buffer_), "\r\n", " ");
  • Pour la communication série, l'adresse de l'objet Serial est passée en paramètre.
  • Terminaison des commandes avec \r\n (NewLine et Carriage Return).
  • Séparateur entre les paramètres, caractère <espace> : " ".


Pour déclarer les commandes :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
SerialCommand cmd_rgb_("rgb", cmd_rgb);
SerialCommand cmd_brightness_down_("-", cmd_brightness_down, true); // commande "one key"
SerialCommand cmd_brightness_up_("+", cmd_brightness_up, true);     // commande "one key"
SerialCommand cmd_help_("help", cmd_help);
En paramètre de chaque commande déclarée, la commande telle qu'elle doit être saisie dans le Moniteur Série et la fonction de rappel associée.
Lorsque le troisième paramètre est à true, on déclare une commande sur une touche (one key). Ici les commandes + et - permettent d'augmenter ou diminuer la luminosité.

Pour ajouter les commandes au gestionnaire, appel depuis le setup() :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
serial_commands_.AddCommand(&cmd_rgb_);
serial_commands_.AddCommand(&cmd_brightness_down_);
serial_commands_.AddCommand(&cmd_brightness_up_);
serial_commands_.AddCommand(&cmd_help_);
serial_commands_.SetDefaultHandler(cmd_unrecognized);

Pour appeler le gestionnaire, appel depuis la boucle loop() :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
serial_commands_.ReadSerial();

Dans les fonctions de rappel de chaque commande, on récupère le ou les paramètres qui suivent en appelant à chaque fois la méthode Next() :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
char* parameter_str = sender->Next();  // paramètre suivant

Le projet final :


demo-serialCommands-rgb.ino
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
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
#include "ledRGB.h"
#include "ledSerialCommands.h"
 
// ledRGB ne gère que les led RGB à cathode commune !!
LedRGB myLed(9, 11, 10); // rouge=pin 9, vert=pin 11, et bleu=pin 10 supportent le PWM sur Arduino Uno
 
byte colorOn = Color::magenta; // équivalent à colorOn = Color::red | Color::blue
int brightness = 100 ; // luminosité en %
 
byte ledState = Color::off;   // état de la Led, initialement éteinte
 
unsigned long previousMillis = millis();
const long interval = 500;  // intervalle = 500ms
 
void setup() {  
  Serial.begin(115200);
  init_serial_commands();
}
 
void loop() {
  update_serial_commands();
 
  unsigned long currentMillis = millis();
 
  if ((currentMillis - previousMillis) > interval) { // si intervalle de temps écoulé
    ledState = (ledState == Color::off) ? colorOn : Color::off; // bascule led On/Off
    myLed.digitalWrite_RGB(ledState, brightness);
    previousMillis = currentMillis;
  }
}

ledRGB.h
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef H_LED_RGB
#define H_LED_RGB
  #include <Arduino.h>
 
  enum Color {  red   = 1 << 2,
                green = 1 << 1,
                blue  = 1 << 0,
                yellow = red | green,
                cyan = green | blue,
                magenta = red | blue,
                white = red | green | blue,
                off = 0
             };
 
  class LedRGB{
    public:       
      LedRGB(byte pRed, byte pGreen, byte pBlue);
      void digitalWrite_RGB(byte ledColor);
      void digitalWrite_RGB(byte ledColor, int brightness);
 
    private:
      byte _pinRed, _pinGreen, _pinBlue;
    };
#endif

ledRGB.cpp
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "ledRGB.h"
 
 LedRGB::LedRGB(byte pRed, byte pGreen, byte pBlue){
        _pinRed = pRed;
        _pinGreen = pGreen;
        _pinBlue = pBlue;
        pinMode(_pinRed, OUTPUT);
        pinMode(_pinGreen, OUTPUT);
        pinMode(_pinBlue, OUTPUT);       
        }
 
 void LedRGB::digitalWrite_RGB(byte ledColor) {
        digitalWrite(_pinRed  , (ledColor & Color::red) ? HIGH : LOW);
        digitalWrite(_pinGreen, (ledColor & Color::green) ? HIGH : LOW);
        digitalWrite(_pinBlue , (ledColor & Color::blue) ? HIGH : LOW);
      }
 
void LedRGB::digitalWrite_RGB(byte ledColor, int brightness) {
        analogWrite(_pinRed  , 255*((ledColor & Color::red) ? brightness : 0) / 100);
        analogWrite(_pinGreen, 255*((ledColor & Color::green) ? brightness : 0) / 100);
        analogWrite(_pinBlue , 255*((ledColor & Color::blue) ? brightness : 0) / 100);  
      }

ledSerialCommands.h
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef H_LED_SERIAL_COMMANDS
#define H_LED_SERIAL_COMMANDS
  #include <SerialCommands.h> //https://www.arduino.cc/reference/en/libraries/serialcommands/
 
  void init_serial_commands(void);
  void update_serial_commands(void);
 
  void cmd_rgb(SerialCommands* sender);
  void cmd_brightness_down(SerialCommands* sender);
  void cmd_brightness_up(SerialCommands* sender);
  void cmd_help(SerialCommands* sender);
  void cmd_unrecognized(SerialCommands* sender, const char* cmd);  // la fonction appelée si la commande saisie est inconnue
#endif

ledSerialCommands.cpp
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
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
#include "ledSerialCommands.h"
#include "ledRGB.h"
 
extern byte colorOn;
extern int brightness;
 
char serial_command_buffer_[17];
/* Gestionnaire général pour les commandes série
   Pour la communication série, l'adresse de l'objet Serial est passée en paramètre
   Terminaison des commandes \r\n, NewLine et Carriage Return
   Séparateur entre les paramètres, caractère espace " "                                                 */
SerialCommands serial_commands_(&Serial, serial_command_buffer_, sizeof(serial_command_buffer_), "\r\n", " ");
 
SerialCommand cmd_rgb_("rgb", cmd_rgb);
SerialCommand cmd_brightness_down_("-", cmd_brightness_down, true); // commande "one key"
SerialCommand cmd_brightness_up_("+", cmd_brightness_up, true);     // commande "one key"
SerialCommand cmd_help_("help", cmd_help);
 
// -----------------------------------------------------------------------------
void cmd_rgb(SerialCommands* sender)
{
  int tab[3], i = 0;
  bool error = false;
  while (i < 3 && !error) {
    char* parameter_str = sender->Next();  // paramètre suivant
    if (strcmp(parameter_str, "0") ==  0 || strcmp(parameter_str, "1") == 0) {
      tab[i] = atoi(parameter_str);
      i++;
    }
    else {
      error = true;
    }
  }
 
  if (!error) {
    colorOn = ((tab[0] == 1) ? Color::red   : 0) |
              ((tab[1] == 1) ? Color::green : 0) |
              ((tab[2] == 1) ? Color::blue  : 0);
 
    char* parameter_str = sender->Next(); // si paramètre supplémentaire, c'est le paramètre de brillance
    if (parameter_str != NULL) {
      brightness = atoi(parameter_str);
    }
  }
  else {  // Si erreur
    sender->GetSerial()->println(F("Erreur de syntaxe"));
    sender->GetSerial()->println(F("Voir l'aide en tapant la commande [help]"));
  }
}
 
void cmd_brightness_down(SerialCommands* sender)
{
  brightness -= 5;
  if (brightness < 0) brightness = 0;
 
  sender->GetSerial()->print(F("brightness = "));
  sender->GetSerial()->println(brightness);
}
 
void cmd_brightness_up(SerialCommands* sender)
{
  brightness += 5;
  if (brightness > 100) brightness = 100;
 
  sender->GetSerial()->print(F("brightness = "));
  sender->GetSerial()->println(brightness);
}
 
void cmd_help(SerialCommands* sender)
{
  sender->GetSerial()->println(F("Exemples de commandes :"));
  sender->GetSerial()->println(F("[rgb 1 0 1]  --> rouge + bleu = magenta"));
  sender->GetSerial()->println(F("[rgb 1 1 0]  --> rouge + vert = jaune"));
  sender->GetSerial()->println(F("[rgb 1 1 0 50]  --> rouge + vert = jaune, brillance = 50%"));
}
 
void cmd_unrecognized(SerialCommands* sender, const char* cmd)
{
  sender->GetSerial()->print(F("Commande inconnue ["));
  sender->GetSerial()->print(cmd);
  sender->GetSerial()->println(F("]"));
}
 
void init_serial_commands(void)
{
  /* Ajout des commandes au gestionnaire principal */
  serial_commands_.AddCommand(&cmd_rgb_);
  serial_commands_.AddCommand(&cmd_brightness_down_);
  serial_commands_.AddCommand(&cmd_brightness_up_);
  serial_commands_.AddCommand(&cmd_help_);
  serial_commands_.SetDefaultHandler(cmd_unrecognized);
}
 
void update_serial_commands(void)
{
  serial_commands_.ReadSerial(); // Appel au gestionnaire de commandes série
}

Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Viadeo Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Twitter Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Google Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Facebook Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Digg Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Delicious Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog MySpace Envoyer le billet « [Arduino] Pilotez votre Arduino depuis le Moniteur Série avec SerialCommands » dans le blog Yahoo

Catégories
Programmation , Arduino

Commentaires

  1. Avatar de boy30
    • |
    • permalink
    Bonjour, j'ai essayé votre code en copiant collant pour l'instant, dans l'espoir de l'utiliser dans un de mes projets Arduino cependant, je ne peux que utiliser les fonctions brightness (avec les touche + et -).
    En effet, l'appel à la fonction rgb par rgb 0 1 1 ou rgb 1 0 0 etc... et l'appel à help ne s'exécutent pas ou du moins, il ne se passe rien.
    Il est vrai aussi que je n'ai pas de led RGB branché sur ma carte UNO , peut-être est-ce la cause mais la fonction "help" devrait fonctionner.
    Bref, quelque chose ne colle pas, pourriez-vous me guider à réparer ce bug ?
    Cordialement
  2. Avatar de f-leb
    • |
    • permalink
    Bonjour,

    Pas facile de savoir, entre l'installation de la bibliothèque, les modifications éventuelles du code et le montage derrière...
    Le bug est probablement dans ce que tu ne nous a pas encore montré

    Pour approfondir, tu devrais ouvrir une nouvelle discussion dans le forum Arduino en montrant tes codes et ce que tu as modifié.
  3. Avatar de f-leb
    • |
    • permalink
    Dans le dossier d'installation de la bibliothèque, sous Windows c'est par défaut dans ...Documents\Arduino\libraries\SerialCommands, tu as un fichier library.properties.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    name=SerialCommands
    version=2.1
    author=Pedro Tiago Pereira <tiago.private@gmail.com>
    maintainer=Pedro Tiago Pereira <tiago.private@gmail.com>
    sentence=An Arduino library to tokenize and parse commands received over a serial port. 
    paragraph=Simple, small footprint, no dynamic memory allocation
    category=Data Processing
    url=https://github.com/ppedro74/Arduino-SerialCommands
    architectures=*
    Est-ce que tu es au moins sur la version 2.1 ? Est-ce que les programmes dans les exemples (comme SerialCommandsSimple) fonctionnent bien chez toi ?