Communication série entre Arduino et Raspberry

Bonsoir, mon projet est plus simple à dire qu'à faire et, le titre spoile déjà mon intention...

J'ai suivi ce tutoriel : Électronique en amateur: Communication par USB entre Raspberry Pi et Arduino

Et malgré les quelques difficultés surmontées, je reste bloqué :

Du côté Rpi, je peux recevoir le message grâce à :

#!/usr/bin/python3



import serial

ser = serial.Serial('/dev/ttyACM0', 9600)

while True:
    
    print(ser.readline())

Mais pour envoyer, il y a un problème qui pêche à cause de mon manque de connaissance...

Ce premier code envoye le message "1" en série et, allume donc la LED associée sur mon arduino :

#!/usr/bin/python3

import serial

ser = serial.Serial('/dev/ttyACM0', 9600)

print (ser.name)

c = int(1)

while True :
    ser.write(b'1\r\n')

Mais, comment envoyer la valeur de c c'est à dire un truc du genre :

ser.write(b'str(c)\r\n')

Et, question subsidiaire, y a t'il un moyen de ne pas mettre "b' \r\n" a chaque fois ?

Bonsoir,

Le fait de mettre juste ceci marche :

ser.write(b'1')

La LED 1 s'allume...

ser.write(b'123')

Les LEDs 1,2 et 3 s'allument...

Mais, pas moyen d'y mettre une variable avant mais, tant pis, je vais mettre pleins de if...

Le programme actuel arduino et le suivant :

#define LED1 2
#define LED2 3
#define LED3 4

int message = 0;


void setup()
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available())  {
    message = Serial.read()-'0';  // on soustrait le caractère 0, qui vaut 48 en ASCII
    
    switch (message) {
    case 1:
      digitalWrite(LED1, HIGH);
      break;
    case 2:
      digitalWrite(LED2, HIGH);
      break;
    case 3:
      digitalWrite(LED3, HIGH);
      break;
    case 4:
      digitalWrite(LED1, LOW);
      break;
    case 5:
      digitalWrite(LED2, LOW);
      break;
    case 6:
      digitalWrite(LED3, LOW);
      break;
    }
  }
}

Pour revenir aux problèmes Arduino, comment communiquer tout d'abord un nombre en série ? J'ai fait ceci :

unsigned long c = 0;
unsigned long b = 0;

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

void loop() {
  b = 0;
  if (Serial.available())
  {
  while (Serial.available()) {
    c = Serial.read();
    if ( c >= 48 && c <= 57) {
          b = b*10 + (c - 48);
    }
  }
    Serial.println(b);
  }
  delay(500);
}

Mais, je voudrais afficher juste la dernière étape, soit juste le nombre entré...

Et, comment étendre aux nombres décimaux puis, aux caractères puis mots ?

lisez ce bon tuto en anglais: Serial Input Basics ou alors mon petit tuto en français

Merci beaucoup ; ton code marche très bien mais, ceux du tutoriel anglais n'affiche rien, ce n'est pas grave...

Concernant ton code, pour Msg++, j'ai compris que c'est l'incrémentation qui augment mais, comment l'écrire autrement ?
Msg = Msg + 1 ?

Et pourquoi utiliser boolean ecouter() ?

void loop() {
  if (! ecouter()) {
    Serial.println(message);
  }
  if (message == '1') {Serial.println("Salut");}
  if (message == "coucou") {Serial.println("Coucou à toi");}
}

Savez-vous comment faire pour que ceci marche ?

Calvin-duino:
Et pourquoi utiliser boolean ecouter() ?

parce que vous voulez du code non bloquant donc la loop() tourne tout en capturant la "phrase" dans le buffer et quand la phrase est prête vous pouvez la traiter

ça c'est du grand nmporte quoi

  if (message == '1') {Serial.println("Salut");}
  if (message == "coucou") {Serial.println("Coucou à toi");}

On ne compare pas une c-string (un tableau de caractère terminé par '\0') avec l'opérateur ==, ça ne fonctionne pas comme cela. il faut utiliser la fonction strcmp() par exemple

--> cf les fonctions utiles pour les c-strings dans stdlib.h et string.h

PS/ il y a plusieurs façon d'augmenter de 1 une variable, par exemple

int calvin = 0;
calvin++; 
calvin +=1;
calvin  = calvin + 1;

J'ai réussi à resoudre tous mes problèmes et, cela marche comme je le veux.

Un problème de code ici : message[positionMsg++]

Avec cette formulation, ca marche impec mais, si j'écris message[positionMsg = positionMsg + 1], la plus rien ne s'affiche. Est ce qu'il y a quelque chose qui m'échappe ?

Bonjour,

message[positionMsg++] est une post incrémentation
C'est équivalent à message[positionMsg]; positionMsg = positionMsg + 1;

message[positionMsg = positionMsg + 1] l'égalité est évaluée avant [], donc c'est une pré incrémentation
c'est équivalent à positionMsg = positionMsg + 1; message[positionMsg];
Donc on pointe l'octet suivant

if (!strcmp(message, "Bonjour")) {Serial.println ("Salut");}
    if (!strcmp(message, "1")) {Serial.println ("Salut2");}

Ca s'est les lignes qui marchent, comment l'introduier dans un switch ?

 switch (message) {

en C/C++ ce n'est pas possible

Les case doivent être des nombres cardinaux constants.

Il faut utiliser une suite de if, else if

Merci pour toute votre aide;

Je vous met mon code si cela peut aider ;

const byte tailleMax = 50;
char message[tailleMax + 1];

const char marqueurDeFin = '#';

#define LED1 2
#define LED2 3
#define LED3 4

boolean ecouter()
{
  static byte positionMsg = 0;
  boolean cours = true;

  while (Serial.available() && cours) {
    int c = Serial.read();
    
    if (c != -1) {
      
      switch (c) {
        case marqueurDeFin:
          message[positionMsg] = '\0';
          positionMsg = 0;
          cours = false;
        break;
        
        default:
          if (positionMsg <= tailleMax - 1) { message[positionMsg]= (char) c; positionMsg = positionMsg + 1;  }
        break;
      }
    }
  }
  return cours;
}

void setup() {
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  Serial.begin(9600);
  Serial.println("Bonjour Raspberry");
}

void loop() {
  if (! ecouter()) {
    Serial.println(message);
    if (!strcmp(message, "Allumer")) {
      Serial.println ("Salut");
      digitalWrite(LED1, HIGH);
      digitalWrite(LED2, HIGH);
      digitalWrite(LED3, HIGH);
      }
    if (!strcmp(message, "Eteindre")) {
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      }
    if (!strcmp(message, "1")) {digitalWrite(LED1, HIGH);}
    if (!strcmp(message, "2")) {digitalWrite(LED2, HIGH);}
    if (!strcmp(message, "3")) {digitalWrite(LED3, HIGH);}
    if (!strcmp(message, "4")) {digitalWrite(LED1, LOW);}
    if (!strcmp(message, "5")) {digitalWrite(LED2, LOW);}
    if (!strcmp(message, "6")) {digitalWrite(LED3, LOW);}
  }
}

Quand j'écris Allumer#, cela affiche Salut mais, je n'arrive pas à le lire correctement avec mon Raspberry...

#!/usr/bin/python3

import time
import serial

ser=serial.Serial('/dev/ttyACM0', 9600)
print(ser.readline())
time.sleep(1)
ser.write(b'Allumer#')
print(ser.readline())
print(ser.readline())
print(ser.readline())
print(ser.readline())

Déjà, les leds s'allument et s'éteignent si je leurs demande...
Mais, je ne lis pas le "Salut" au premier print(ser.readline()), ce premier affiche b'Allumer\r\n'
Savez-vous pourquoi ? Il est affiche au deuxième print(ser.readline())...

Les deux derniers ne servent à rien ils m'ont permis une vérification que rien n'est envoyé...

Et, comment écrire le texte du ser.readline() dans une variable ?
Pour faire ensuite des print (variable) ou pour comparer variable1 et variable2...

Pour le switch/case:

--> mettre tous les mots possibles dans un tableau et parcourir le tableau en comparant avec l'entrée reçue et si on trouve utiliser l'indice du tableau trouvé pour le switch/case

voilà un exemple que j'avais posté récemment dans le forum anglais

réglez la console à 115200 bauds et envoyez CRLF en fin de ligne. tapez "Hallo" ou "Salut" par exemple

const char * stringsOfInterst[] = {
  "Hello", "Salut", "Hallo", "Ciao", "Ahoj", "Bog", "Marhaba", "Hej", "Ni Hao", "Shalom", "Namaste"
};

// to simplify the swicth case
enum {
  _Hello_, _Salut_, _Hallo_, _Ciao_, _Ahoj_, _Bog_, _Marhaba_, _Hej_, _NiHao_, _Shalom_, _Namaste_
};

// or to handle things through index
const char * language[] = {
  "English", "French", "German", "Italian", "Czech", "Croatian", "Turkish", "Swedish", "Chinese", "Hebrew", "Hindi"
};

const byte nbWords = sizeof(stringsOfInterst) / sizeof(stringsOfInterst[0]);


// ************************************************************************
// ************ small function to read the Serial input *******************
// ************************************************************************
// when entry is complete (found the endMark), function returns true
// and the c-string message has the text we entered
// ************************************************************************

const byte maxInput = 20;
char message[maxInput + 1]; // +1 for a trailing '\0'


boolean getInputTillEndMarker(const char endMark)
{
  boolean endOfMessage = false;
  static byte index = 0;
  if (Serial.available()) {
    int r = Serial.read();
    if (r != -1) {
      if (r == endMark) {
        endOfMessage = true;
        index = 0; // get ready for next one
      }
      else {
        if (r != '\r') { // Ignore CR
          message[index++] = (char) r;
          message[index] = '\0'; // denote the end of the c-string
          if (index >= maxInput) index = maxInput - 1; // don't overflow if input too long for bufer
        }
      }
    }
  }
  return endOfMessage;
}


// ************************************************************************
void setup() {
  Serial.begin(115200);
  Serial.println("*** Hello tester ***");

  for (byte i = 0; i < nbWords; i++) {
    Serial.print(stringsOfInterst[i]); Serial.print(" ");
  }

  Serial.print("\n\nEnter Hello in one language: ");
}

// ************************************************************************
void loop() {
  // read an input from the Serial line
  if (getInputTillEndMarker('\n')) {
    int languageIndex;
    boolean found = false;

    Serial.print("\""); Serial.print(message); Serial.println("\"");

    // try to find which word we entered
    for (languageIndex = 0; languageIndex < nbWords; languageIndex++) {
      if (!strcmp(message, stringsOfInterst[languageIndex])) {
        found = true;
        break;
      }
    }

    if (found) {
      Serial.print("This is "); Serial.println(language[languageIndex]);

      // you can also use languageIndex for more complicated stuff now per language in a switch / case and the enum makes it readable
      switch (languageIndex) {
        case   _Hello_ :
          Serial.println("I live in London");
          break;

        case  _Salut_ :
          Serial.println("je vis en France");
          break;

        case  _Hallo_ :
          Serial.println("Sauerkraut!");
          break;

        case  _Ciao_ :
          Serial.println("I love pizza");
          break;

        case  _Ahoj_ :
          Serial.println("You get the idea");
          break;

        case  _Bog_ :
          break;

        case  _Marhaba_ :
          break;

        case  _Hej_ :
          break;

        case  _NiHao_ :
          break;

        case  _Shalom_ :
          break;

        case  _Namaste_ :
          break;
      }

    } else {
      Serial.print("Sorry \""); Serial.print(message); Serial.println("\" is not in my dictionnary.");
    }
    Serial.print("\nEnter 'Hello' in one language: ");
  }
}

Et pour le message lu par le raspberry, une idée de ce qui cloche ? et de comment le mettre dans une variable ?

vous avez connecté à la fois le RPI et la console Serial de l'IDE sur les broches Séries (0 et 1) ??

Je connecte l'Arduino en usb sur le rpi pourquoi ?

ok donc l'Arduino n'est pas connecté à votre PC, juste au PI

Oui ;

Calvin-duino:

#!/usr/bin/python3

import time
import serial

ser=serial.Serial('/dev/ttyACM0', 9600)
print(ser.readline())
time.sleep(1)
ser.write(b'Allumer#')
print(ser.readline())
print(ser.readline())
print(ser.readline())
print(ser.readline())




Déjà, les leds s'allument et s'éteignent si je leurs demande...
Mais, je ne lis pas le "Salut" au premier print(ser.readline()), ce premier affiche b'Allumer\r\n' 
Savez-vous pourquoi ? Il est affiche au deuxième print(ser.readline())...

Les deux derniers ne servent à rien ils m'ont permis une vérification que rien n'est envoyé...

Et, comment écrire le texte du ser.readline() dans une variable ?
Pour faire ensuite des print (variable) ou pour comparer variable1 et variable2...

faut lire un tuto Python là avec toutes vos questions...

C'est ce que j'ai fait mais, je sais pas.