Envoi et réception de données ASCII

Bonjour !

Voilà, j'ai un problème, je n'arrive pas à faire en sorte de traiter correctement des données reçues et ça m'énerve :0

Je m'explique : d'un côté j'ai Pure Data qui est chargé d'envoyer une suite de données pour actionner un moteur de cette façon :

1) aller à la position axe X 2) aller à la position axe Y 3) activer électroaimant 4) aller à la position axe X 5) aller à la position axe Y 6) désactiver électroaimant

Bref, en soi Pure Data envoi, à la suite, des données. Mon soucis étant de pouvoir séparer ces données pour qu'elles soient traitées différemment, or en l'état actuel ma carte Arduino reçois le gros paquet de données et je ne sais pas comment faire pour séparer tout ça.

De l'aide serait plus que bienvenue... Merci beaucoup

Bonjour,

Moi ça ne m'énerve pas mais je ne comprends rien à ton explication.

Avec ce genre d'explication j'espère que tu n'auras pas d'autres réponses ! Relis la présentation de ton problème et mets toi à la place d'un lecteur lambda ! Il faut donner des précisions ... ton matériel, ton programmme notamment, ...

Je ne comprends pas non plus que ce soit la carte Arduino qui reçoit. Ce n'est pas la carte Arduino qui émet ?

Il est vrai que je ne connais pas "Pure Data". Donc je réponds : il faut séparer tes données avec le plus grand soin.

Bon courage Géryko

hum... désolé, je me suis mal exprimé c'est vrai.

Pour essayer d'être plus clair , Arduino doit traiter une suite d'instruction séparées. Autant dans Pure Data je peux envoyer des instructions à la suite, autant je n'arrive pas à faire en sorte que la carte Arduino (Uno en l'occurrence) sépare ces données pour qu'elles effectuent les actions voulues, en l'occurrence :

1) aller à la position axe X 2) aller à la position axe Y 3) activer électroaimant 4) aller à la position axe X 5) aller à la position axe Y 6) désactiver électroaimant

Pour ça, Pure Data envoie, à la suite :

position X (int 0 ---> 8) position Y (int 0 ---> 8) activation (int 1) position X (int 0 ---> 8) position Y (int 0 ---> 8) désactivation (0)

Ma question étant :

Comment puis-je faire pour que Arduino sépare ces données et sache laquelle est quoi ? Qu'elle ne traite pas l'activation (int 1) pour une position ? Il arrive que mon Arduino "saute" une instruction, j'ai essayé toutes les vitesses de connection et 115200 bauds semble être la plus stable, comment puis-je faire pour que ça n'arrive plus ?

Merci, j'espère avoir été plus clair.

Franchement non ce n'est pas beaucoup plus clair.

Si j'essaye de combler les trous : Tu as un programme (Pure Data) qui tourne sur ton PC, et qui envoie une chaîne de caractères via la liaison série et vers un arduino ?

A quoi ressemble EXACTEMENT le flux de caractères reçu par l'arduino ? Qu'est-ce qui te fais dire que des fois une instruction est sautée ? Donne ton code source Arduino COMPLET, sans lequel personne ne pourra t'aider

Bonjour bricoleau,

Un (Pure data) serait donc un programme ?

Merci pour l'information. Bien à toi Géryko

J'imagine que c'est ça : http://fr.wikipedia.org/wiki/Pure_Data

Mais peu importe. Tu connais quelquechose qui tourne sur un PC, et qui ne serait pas un programme ? à part un ventilo, je vois pas.

Bref visiblement on a un TRUC qui mouline sur un PC et qui envoie des data sous forme de signaux sur une liaison série. Nous, on est sur un arduino à l'autre bout du fil et on essaye de recoller les morceaux

re Bonjour,

Là c’est clair. J’ai enfin compris la question.

A+

Bon, décidemment j’ai le chic pour m’embarquer dans des trucs complexes et ne pas savoir les expliquer en retour, toutes mes excuses, à force de passer tout mon temps là-dedans j’en retire des évidences qui ne sont évidente que pour moi :blush:

Oui, Pure-Data est un logiciel de programmation, et le programme (appelé “patch”) que j’ai fait était chargé d’envoyer une suite de commandes à un Arduino qui se devait de les traiter.

Seulement, à force de persévérance j’ai résolu mon soucis, peut-être que mon programme sera plus clair que mes explications ? :

/*
Principe de fonctionnement :

La carte Arduino attends une connection série.
Lorsque les données sont reçues, une boucle va se charger de remplir un tableau avec lesdites données.
Comme il n'y a que 4 données (4 positions), la taille va donc être que 4.
Une fois le tableau rempli des coordonnées ( if (i == TAILLE_TABLEAU) ), le programme peut continuer avec les actions voulues.
*/

#define TAILLE_TABLEAU 4

int tab[TAILLE_TABLEAU];

int posDepartX = tab[0];
int posDepartY = tab[1];
int posArriveeX = tab[2];
int posArriveeY = tab[3];

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

void loop()
  {
    // a chaque fin de programme, le tableau est remis à zéro
    for (int i = 0; i < TAILLE_TABLEAU; i++)
    {
      tab[i] = 0;
    }
    
    if (Serial.available() > 0) // si des données sont reçues
      {
        for (int i = 0; i < TAILLE_TABLEAU; i++)
        {
          tab[i] = Serial.read(); // initialiser le tableau avec les données reçues
          if (i == TAILLE_TABLEAU)
          {
            /*
            entrer code allant chercher les positions dans le tableau et les appliquer aux moteurs.
            Par exemple, où "3" et "5" sont les pins PWM des 2 moteurs XY et 7 la pin de l'aimant :
          
            analogWrite(3, map(0, posDepartX, 0, 254));
            analogWrite(5, map(0, posDepartY, 0, 254));
            delay(1000);
            digitalWrite(7, HIGH);
            analogWrite(3, map(0, posArriveeX, 0, 254));
            analogWrite(5, map(0, posArriveeY, 0, 254));
            digitalWrite(7, LOW);
          
          */
          }
        }
      }
  }

Encore désolé si je suis super vague, je suis un amateur qui apprends tout par lui-même et quasiment tout seul donc je n’ai que rarement l’occasion d’expliquer à d’autres personnes que moi-même ce que je fait, ce que je veux faire et ce que je veux que ça fasse.

Bonsoir RoKN,

J’espère que tu n’es pas faché. Pas facile de se faire comprendre par l’écriture.
La technique est une chose, se faire comprendre en est une autre. Il faut les 2 : Bon exercice.

Au niveau programmation je suis débutant aussi, je vais laisser la main à “d’autres spécialistes”.

Deux petites remarques

  1. au départ, je transmettrais à 9600 bits/s (pour laisser plus de temps à la réaction)
    ça ne peut pas faire de mal.
  2. j’ai parcouru ton programme.
    Je pense qu’il faut d’abord recevoir dans ton tableau et seulement après, en dehors de la boucle for,
    traiter les données.

Bon courage
Géryko

J'étais un peu faché au début de ta première réponse mais je me suis rendu compte que la "faute" venait de mes explications nébuleuses :)

Bref, pour ce qui est de la vitesse de connection, j'ai rencontré quelques soucis avec des vitesses inférieures à 115200 : Lors du débug, à réception des données j'utilisai un "Serial.println" pour afficher ces dernières, seulement je me suis rendu compte que les données retournées étaient instables, correctement retranscrites. Je me suis dis, au début, que ça venait de la vitesse de connection (qui était de 9600 à ce moment), mais en l'augmentant ça ne me le faisait plus. Puis je me suis dis que les soucis venaient peut-être du fait de l'écriture de ces données dans le terminal, que ça utilisait aussi la connection série et que ça perturbait le flux de données, je ne sais pas si c'est le cas mais le fait est qu'une fois les "Serial.println" retirés, je n'ai plus rencontré de soucis tout en laissant la vitesse à 115200.

A mon sens, la logique de ton programme arduino devrait être la suivante :

  1. par défaut je suis en veille, en attente de réception de données sur le port série
  2. lorsque des données arrivent, je les stocke en mémoire jusqu’à les avoir toutes reçues
  3. une fois la trame complète chargée en mémoire, je l’analyse pour vérifier qu’elle est correcte (pas de morceaux perdus)
  4. je décode la trame et engage les actions requises

L’étape 3) est celle qui me semble le point faible de ta solution.
Si tu te contentes de transmettre une consigne sur 4 octets, sans aucun mécanisme de sécurité, tu es à la merci de problèmes de transmission.
Je te conseille d’ajouter des données supplémentaires dans le message, qui te permettront de détecter que la réception est incomplète ou erronée.
Par exemple : clé d’identification sur 4 octets binaires (un nombre quelconque mais fixe, genre ta date de naissance) + les 4 octets de consigne + une signature calculée à partir des 4 octets de consignes (par exemple un XOR binaire, à défaut d’un vrai CRC).

En réception, tu charges tout dans un buffer, et tu ne traites les consignes que si la clé et la signature sont correctes.

Ainsi par exemple, ton programme pourrait ressembler à ça (en restant sur des variables globales)

...

#define TAILLE_BUFFER 50

uint8_t buffer[TAILLE_BUFFER];
uint8_t lg_buffer;

void ReceptionBuffer()
{
  uint8_t c;

  lg_buffer = 0;
  while (Serial.available() > 0)
  {
    c = Serial.read();
    if (lg_buffer < TAILLE_BUFFER)
    {
      buffer[lg_buffer] = c;
      lg_buffer++;
    }
    if (Serial.available() == 0)
    {// si transmission en cours attendre l'éventuel prochain octet
      delay(50);
    }
  }
}

uint8_t BufferOK()
{
// cette fonction vérifie que le format reçu est correct (contenu + longueur)
// par analyse du contenu de la variable globale buffer[]
// retourne 1 si OK, 0 si KO
   ...
}

int posDepartX;
int posDepartY;
int posArriveeX;
int posArriveeY;

void DecoderConsigne()
{
// cette fonction valorise les 4 variables ci-dessus à partir de la variable globale buffer[]
  ...
}

void TraiterConsigne()
{
// cette fonction fait ce qu'il y à faire en fonction des valeurs des 4 variables ci-dessus
  ...
}

void loop()
{
  if (Serial.available() > 0)
  {
    ReceptionBuffer();
    if (BufferOK())
    {
        DecoderConsigne();
        TraiterConsigne();
    }
  }
}