Extraction donnée pour commander un ou plusieurs servomoteur

Bonsoir à tous et toute,
j'ai un petit projet ou j'ai un programme python qui envoi des données à mon arduino via la voie série. mon soucis réside dans l'extraction des données reçue par la voie série.
si je rentre cette donnée -------> AA 9.5 AB 8.5 AC 3.5 avec mon code ci-dessous le résultat en retour es un y
Hors j'aimerai récupérer les valeurs 9.5 8.5 3.5 afin que ces données me commande des servomoteurs. dans mon exemple il y a que pour 3 Servo mais ca peu être plus. Je comprends pas.

char data[20];
char AA[4];
char AB[4];
char AC[4];

void setup()
	{
	Serial.begin(9600);  
	}
void loop()
{ 
  if(Serial.available()>=20){
    for(char i=0; i<20; i = i +1)
    { 
      data[i] = Serial.read();
    }      
  	sscanf(data, "AA %s AB %s AC %s" , AA,AB,AC);  
  	Serial.println(atof(AA));  
  	Serial.println(atof(AB));
  	Serial.println(atof(AC));
  } 
 }

Je ne comprends pas mon erreur ou mes erreurs. Si mon data je lui met la donnée "AA 9.5 AB 8.5 AC 3.5" et que je ne passe pas par la fonction Serial. available alors pas de soucis je retrouve bien mes 3 valeurs.
Quelqu'un peut m'aider ou m'aiguiller?
Merci d'avance

Bonjour,

En C/C++ les chaines de caractère doivent se terminer par un \0. Il faut donc ajouter ce 0 à la fin (et agrandir le buffer)
Il vaut mieux aussi agrandir les buffer de réception au cas ou les espaces seraient inclus (ce n'est peut être pas nécessaire)

char data[21];
char AA[6];
char AB[6];
char AC[6];

void setup()
	{
	Serial.begin(9600);  
	}
void loop()
{ 
  if(Serial.available()>=20){
    for(char i=0; i<20; i = i +1)
    { 
      data[i] = Serial.read();
    }
    data[20]=0;  // fin de chaine

    sscanf(data, "AA %s AB %s AC %s" , AA,AB,AC);  

    Serial.println(atof(AA));  
  	Serial.println(atof(AB));
  	Serial.println(atof(AC));
  } 
 }

Remarque: tu pourrais utiliser %f pour récupérer les flottants.

Merci beaucoup kamill. Pourquoi met t'on le tableau à 0 la fin de chaine?
J'ai pas compris "tu pourrais utiliser %f pour récupérer les flottants." quels va etre la différence avec les caractères? Peut etre la commande futur des servo moteurs?

Je viens de tester cela fonctionne bien par contre si ma valeur AA à changer et passe de 9.5 a 8.1 et que je la saisie dans le moniteur série et bien en faite la nouvelle valeur 8.1 n'est pas prise en compte et on me réaffiche dans le moniteur 9.5. Logiquement avec la boucle a chaque tour si cela change le résultat doit changer aussi non?

meme en vidant les tableaux AA AB AC ca ne réagit pas comme il faudrait ca me met les valeurs a 0

Il n'y a pas de raison que ça réaffiche la valeur précédente.
Par contre ton programme n'est pas très robuste. S'il reste des caractères dans le buffer (par exemple si le moniteur envoie cr lf) ils ne seront pas éliminés et ça va dysfonctionner.

oui c'est beaucoup de découverte pour moi je n'ai jusqu'a présent jamais traiter les chaine de caractère j'y vais a tâtons malheureusement
Par contre c'est toujours la meme chaine que j'envoie juste les valeur qui change.
Je fais mes manipulation sous tinker CAD pas de soucis tout fonctionne mais dès le passage en réelle sur l'IDE et arduino Uno et bien mon premier envoie AA 3.5 AB 5.5 AC 3.5 me renvoie bien 3.50 5.50 3.50 si je renvoie maintenant AA 1.5 AB 5.5 AC 3.5 le résultat renvoie 3.50 5.50 3.50 c'est bizarre et si je vide comme tu la fait avec data la j'obtien 0.00 0.00 3.50

La je reste sec.
Et comme je viens juste de déménager mes cartes arduino sont dans les cartons et je ne peux pas essayer.

Ce nest grave l'échange est super intéressant japprends plein de chose.
A quoi sert le data[20] =0 //fin de chaine
Le vidage du buffer?

Non il sert à marquer la fin de la chaine.
Si la chaine n'est pas terminée par 0, les fonctions ne savent pas ou il faut s'arrêter de traiter la chaine et on risque de gros disfonctionnements.

D'accord je comprends mieux

Suite a mes soucis évoqués plus haut y a t'il quelqu'un qui a une idée?

Personnellement je n'aime pas beaucoup l'utilisation de sscanf, il y a parfois des effets bizarres (surtout si la chaine n'est pas strictement conforme à ce qu'on attend).
J'utilise souvent strstr ou strtok
Avec strstr ça donne

char data[21];

void setup()
	{
	Serial.begin(9600);  
	}
void loop()
{ 
  if(Serial.available()){
    int n=Serial.readBytes(data,sizeof data-1);
    data[n]=0;

    Serial.println(data);
    
    // traite le message reçu de forme AA 9.5 AB 8.5 AC 3.5
    float a,b,c;
    char *p;
    p=strstr(data,"AA");
    if (p!=NULL)
    {
      p+=2;
      a=atof(p);
      p=strstr(p,"AB");
      if (p!=NULL)
      {
        p+=2;
        b=atof(p);
        p=strstr(p,"AC");
        if (p!=NULL)
          c=atof(p+2);
        Serial.println(a);
        Serial.println(b);
        Serial.println(c);
      }
    }
  } 
}

A oui je ne connais pas ces deux fonctions je regarde alors

effectivement cela fonctionne sans soucis sur l'iDE arduino avec cette façon
je vais décortiquer ton code afin de comprendre le cheminement et les 2 expressions strstr strtok

Merci énormément pour ton aide vraiment précieuse

hello kamill j'ai compris le strstr va chercher la premiere occurence en AA AB ou AC dans l'ordre ou l'on avance depuis le premier caractère c'est bien cela et le p va cherche les 2 chaines qui suive

Oui. On recherche la première occurrence, on met cette adresse dans p et on lit la valeur numérique qui est 2 caractères plus loin.

merci beaucoup je comprends mieux comment il faut s'y prendre

Si cela peut aider :

Où j'exploite diverses possibilités :

  • strtok()
  • sscanf()
  • expression régulière

merci beucoup