Aller au contenu


Photo
- - - - -

Exosquelette pour piloter les bras de HumaOne


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

#1 Telson

Telson

    Membre chevronné

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

Posté 05 juillet 2016 - 11:05

Je suis à la recherche actuellement, en parallèle du développement de mon bipède HumaOne,  d'informations sur la possibilité de transmettre via un module bluetooth des valeurs provenant de 10 potentiomètres.

 

J'aimerai bien concevoir un exosquelette composé de 10 potentiomètres (5 par bras) pour piloter les mouvements des bras de mon bipède (5 servomoteurs par bras).

 

Un module bluetooth sur l'exo. et un sur le robot.

 

Attention, je ne vais pas essayer de développer un exo. pour concurrencer la NASA....non....non........Enfin pas tout de suite......

Il existe bien des exemples pour piloter un servomoteur via un potentiomètre avec une transmission bluetooth mais je m'interroge sur la façon de procéder pour communiquer 10 consignes.

Première hypothèse : je lis les 10 potentiomètres (10 valeurs de consigne) et je transfère une trame contenant ces 10 consignes.

Questions :

  • comment passer les 10 consignes dans la transmission sans perdre ses petits lors de la lecture.Dans une transmission numérique il existe une vérification d'erreur...comment la mettre en oeuvre......
  • faut t'il passer les consignes une par une mais si, par exemple, la consigne P5 n'est pas reçu alors à la réception de P6 le programme risque de penser que c'est en fait P5 qu'il reçoit,
  • faut t'il passer toutes les consignes en même temps avec un séparateur entre chaque consigne : " ; " pour les scinder ou les coder par byte, donc une trame de 10 byte et à lire byte par byte......Oh punaise......je ne suis pas sûr d'être clair là !!!

Deuxième hypothèse :je lis les consignes une par une et je transmets les consignes une par une avec un drapeau avant chaque consigne, exemple : j'envoie 1, puis consigne de P1, j'envoie 2 puis consigne de P2.....j'envoie 10 puis consigne de P10......C'est clair là par contre...non??!!

Questions :

Si des informations sont perdues à la réception, exemple : je perds la transmission du drapeau 5 mais je reçois la consigne P5....Mon programme est alors perdu, car il pense recevoir un numéro de drapeau.....Mais non..C'est une consigne.....Dommage !!!......plantage...

 

Donc selon vous quelle serait la meilleur méthode :

  1. je lis toutes mes consignes et je transmets une trame contenant que mes consignes ou numéro de consigne + consignes, ...
  2. Je lis mes consignes une par une et je transmets d'abord le numéro de la consigne puis la valeur de la consigne,
  3. autres solutions ???je suis preneur là...si...si !!

Ensuite se posera la question du temps :

 

lire les 10 consignes et faire 1 transmission, puis 1 réception/décodage

lire les 10 consignes et faire 20 transmissions (10 drapeaux + 10 consignes), puis 20 réceptions/décodage

lire les 10 consignes et faire 10 transmissions (10 * [drapeau +  consigne]), puis 10 réceptions/décodage

 

je vais m'arrêter là pour le moment avec les questions en sachant très bien que j'effleure à peine la problématiques avec ces premières questions.

 

Ou alors pire encore je suis complétement à côté...Ouais et bien c'est possible aussi.....Mais vous allez m'aider hein!!!???...SIiiiiiiiiiiiiiiiiiiiiiiiii......NON???....Oh punaise !!!

 

Je suis preneur de toutes informations ou lien à lire sauf si cela relève d'un travail de thésard, que je ne suis pas à même d'appréhender....

 

 

Merci par avance.



#2 Gyro49

Gyro49

    Habitué

  • Membres
  • PipPip
  • 246 messages
  • Gender:Male
  • Location:Angers, France
  • Interests:Les nouvelles technologies

Posté 05 juillet 2016 - 05:15

Bonsoir,

 

Je n'arrive pas à visualiser la notion d'exosquelette.

Je sais ce que c'est mais comment il s'imbrique dans le projet HumaOne, de se fait j'ai plusieurs questions ?

 

Si HumaOne fait bougé son coude, est-ce l'exosquelette sera en esclave pour reproduire le mouvement ?

Lors du déplacement de l'épaule de l'exosquelette, l'épaule de HumaOne n'aura pas encore atteint la position final donc conflit maître ->esclave ->maître

 

Sinon, personnellement je prendrais la deuxième hypothèse : envoyer en un seul message les valeurs des potars séparés par les drapeaux de référence.

 

Est-ce qu'il ne serait pas possible de mettre en place un arduino en maître (commande HumaOne et émission) et un simple atmega (en shield) en réception les deux en communication rx/tx pour être sûr de ne pas rater une trame.

 

Bonne chance 



#3 Telson

Telson

    Membre chevronné

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

Posté 05 juillet 2016 - 08:14

C'est l'exo qui est maître. Il communique les informations au robot qui exécute les mouvements.

 

Tu évoques la possibilité de conflit......En fait je ne pense pas que nous puissions parler de conflit mais plutôt de temps d'exécution.

 

Il me semble évident que si les mouvements de l'exo. sont trop rapides alors les servomoteurs du robot, avant même d'atteindre la position de la première consigne pourrons en recevoir une autre.....

 

Ce sera par conséquent à l'utilisateur de déplacer l'exo. suffisamment lentement  pour que les mouvements soient totalement réalisés avant d'en réaliser un autre sinon les mouvements du robot ne correspondront pas aux mouvements de l'exo.

 

++



#4 levend

levend

    Pilier du forum

  • Membres
  • PipPipPipPipPip
  • 5 572 messages
  • Gender:Male
  • Location:Vendée
  • Interests:Robotique, informatique, architecture et patrimoine...

Posté 05 juillet 2016 - 09:20

Pour faire ça sur PC, on utilisait une structure, par exemple

struct sTrame {

int iP1;

int iP2;

int iP3;

int iP4;

int iP5;

int iP6;

int iP7;

int iP8;

int iP9;

int iP10;

} ;

comme cela une consigne ne risque pas d'être prise pour une autre.

 

Tu peux aussi ajouter un numéro de trame.

 

C'est ce l'on faisait sur PC, maintenant je ne sais pas ce que ça vaut sur l'arduino.

 

Edit : int n'est peut-être pas le type le plus approprié, byte le serait mieux.


Imprimante 3D : Prusa i3 (MK1) + CR-10S + CR-10 S5 + Artillery Sidewinder X2 + CR-30 + Elegoo Mars + Anycubic Wash & cure 2 + Phrozen Sonic Mega 8K + Phrozen Cure Mega

#5 Telson

Telson

    Membre chevronné

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

Posté 05 juillet 2016 - 10:49

oui....
 
il faut que je trouve de la documentation sur la structure d'une trame.....
 
je comprends bien qu'il faut pour envoyer une information Serial.write(data); // envoie de la data
 
Mais quelle sera la structure de : data.

 

Prenons un exemple...Je souhaite envoyer 3 consignes d'angle P1=45, P2 = 17 et P3 = 28....alors comment envoyer 45,17 et 28 dans la même data....

 

faut t'il sinon faire une boucle du style

 

for i=1 to 3

{

Serial.write(TAB-data[i])

}

 

Ho punaise j'me sens gros boulet là !!



#6 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 934 messages
  • Gender:Male
  • Location:Anglet
  • Interests:Robotique, Entrepreneuriat, Innovation, Programmation, Résolution de problème, Recherche de solutions, Mécanique, Electronique, Créer, Concevoir

Posté 05 juillet 2016 - 11:03

ça fait partie des tutos que je m'étais dit que je devais faire ... 
Un tuto en deux partie avec deux approches :
Une première version string 
Une seconde version structure de donnée 

 

tu peux déjà regarder ce qu'à fait jekert ici c'est sympas ça se rapproche un de l'approche de la version " string" sauf que moi j'allais proposer un truc du genre $12,123,200; comme format de " string " 
et la deuxième partie de ce tuto ça utilise des union et des structure comme ici  et du coup faudrait que je finisse d'abord ce tuto ... Utilisant des tableaux de bytes ...

 

les deux pouvant intégrer un checksum.

 

laquelle des deux approche t'intéresse le plus ? 


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#7 Telson

Telson

    Membre chevronné

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

Posté 06 juillet 2016 - 06:12

oh punaisse, il faut que je lise l'histoire des unions et autres documentation car j'ai vraiment du mal à raccrocher les wagons......



#8 cocothebo

cocothebo

    Membre passionné

  • Membres
  • PipPipPip
  • 341 messages
  • Gender:Male

Posté 06 juillet 2016 - 10:06

Bonjour pour revenir à ta premiere question:

 

 

  • comment passer les 10 consignes dans la transmission sans perdre ses petits lors de la lecture.Dans une transmission numérique il existe une vérification d'erreur...comment la mettre en oeuvre......

Ici il y a deux choses à différencier. Quand tu veux transmettre de l'information, il te faut un protocole (au moins 1).

 

Par exemple des que tu as une variable dans un programme, son but au final est de transmettre de l'information d'un point A à un point B de ton programme.

Niveau "protocole", soit on reste dans le très simple, une variable de type "byte" ou "char", que l'on pourrait qualifier de protocole implicite, et dans mon exemple byte ou char c'est la même taille mémoire, mais normalement pas le même type de donnée (un nombre et un caractère le tout sur 8 bits).

Après on peut complexifier, avec des union/structures/objets (si on est dans un langage orienté objet), qui permet ce coup ci de définir un protocole propriétaire, ma structure, je mets ce que je veux comme type de variable dedans, et le nombre que je veux.

Après on peut encore complexifier en utilisant par exemple des fichiers xml de configuration, etc. etc.

 

Bref la transmission d'info est déjà présente localement dans un programme.

 

Ce que tu veux faire c'est que cette information que tu veux transmettre maintenant ne soit plus nécessairement en local dans un programme mais entre deux programmes. On rajoute donc une couche de protocole pour transmettre une info locale via un autre média.

Dans ton cas ça semble être du "sans fil" donc on va partir sur du bluetooth (mais wifi, zigbee ou autre aura le meme impact). Le bluetooth à déjà un protocole très complexe d'implémenter mais on s'en fiche nous on va l'utiliser comme un UART (liaision série), mais tout ce qui est correction d'erreur gestion de l'odonancement des paquets, réémissions des paquets perdus (etc. etc.) est géré par le module bluetooth et ses librairies.

Ce qu'il reste à faire c'est envoyé ton information locale via cette liaison.

 

Pour résumer le pavé précédent, ce que tu dois définir toi c'est ce que tu veux transmettre, suivant quel canal, si on part sur un module bluetooth, la stack bluetooth est déjà implémentée (heureusement, sinon c'est très très compliqué), et un mode permet généralement de faire une liaison série virtuelle.

Ne reste plus qu'a transmettre les bonne informations sur cette liaison. 

Pour cela soit on fait ça de manière pas propre non evolutive en balanceant juste les valeurs une a une et en espérant que ca fonctionne, mais comme tu te le demandes, si jamais quelquechose se passe mal, le programme qui recoit ne saura pas ou il en est. C'est pourquoi la faut définir un semblant de protocole qui te permet de savoir à quoi correspondent tes données. Le plus simple pour moi et qui implique une évolutivité correcte, une bonne gestion des erreurs est d'utiliser un format TLV (Tag Length Value):

  • TAG: a voir ce que tu veux mettre, par exemple un tag par potar
  • Length: la longueur de la value qui suit
  • Value: ben la valeur que tu souhaites transmettre, si c'est un type simple (byte, int, char, ...) c'est facile, tu l'envoie directement, si c'est un type complexe (truc/union) il faut le serialiser (l'ecrire ne forme de hcaine d'octets en gros)

Bien sur les structures de types TLV peuvent être imbriquées, une valeur pouvant être un TLV elle même, mais il faut que tu programme sache que pour tel TAG, la valeur est aussi un TLV. Cela permet par exemple de rajouter des "méta données" comme des checksum, hash, signature, ou tout et n'importe quoi.

 

Si c'es juste pour envoyer les positions des 10 capteurs (potars), tu dois pouvoir te passer d'un format TLV (même si au final c'est pas très couteux), mais si tu veux en plus rajouter des informations de vitesse, de force, de temps, etc. ça peut servir.

Et le gros avantage, c'est que tu dois dans le cas d'un TLV définir une grammaire de comment est composé chaque Tag, ce qui permet d'avoir un protocole bien défini et surtout que le programme reconnaisse chaque ordre même si ils arrivent dans le désordre, bref normalement si c'est bien fait, toute l'information nécessaire à reconstruire la demande initiale est présente.



#9 Telson

Telson

    Membre chevronné

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

Posté 06 juillet 2016 - 10:55

Bon,

 

Je me lance...je vais certainement raconter des conneries mais il faut attaquer par un bout.

 

Partons sur l'hypothèse que j'ai d'un côté une carte arduino + module bluetooth en émission et de l'autre côté une carte arduino + module bluetooth en réception.

 

Toutes les configurations sont réalisées d'un côté comme de l'autre.

 

De chaque côté j'ai déclaré une structure du type :

 

struct TRAME {

uint8_t P1;
uint8_t P2;
uint8_t P3;

};

 

De chaque côté j'ai déclaré une variable :

 

TRAME mes_donnees;

 

Ensuite du côté émission j'initialise mes-données :

mes_donnees.P1= 45;
mes_donnees.P2= 27;
mes_donnees.P1= 116;

 

Et j'expédie le tout :

Serial.write(mes_donnees);

 

Est ce que du côté réception je pourrais récupérer les données ainsi :

Serial.read(mes_donnees);

broche1 = map(mes_donnees.P1, 0,1023,0,180);
broche2 = map(mes_donnees.P2, 0,1023,0,180);
broche3 = map(mes_donnees.P3, 0,1023,0,180);

 

 

Mon imagination me fait rêver ou est ce possible......

 

P.S.

Faite attention de ne pas vous étouffer de rire en lisant ça les gars hein !!!



#10 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 934 messages
  • Gender:Male
  • Location:Anglet
  • Interests:Robotique, Entrepreneuriat, Innovation, Programmation, Résolution de problème, Recherche de solutions, Mécanique, Electronique, Créer, Concevoir

Posté 06 juillet 2016 - 11:14

Ah ah ! C'est presque ça qu'il faut faire ! Mais si tu essaye de compiler tu vas voir que ça marche pas car le Serial.write ne sait pas utiliser les données de type TRAME que tu viens de créer... 

Alors que si tu crées un tableau de type
 

​uint8_t p[3]={45,27,116};

/* Equivalent à
 uint8_t p[3]; 
 p[0]=45;
 p[1]=27;
 p[2]=116;
*/

tu pourras alors faire : 
 

Serial.write(p,3);

Mais si tu veux pouvoir à là fois bien structurer toutes tes variables dans une structure et facilement les envoyer avec un tableau c'est l'union qui va te sauver la mise ;) Il va te permettre de sérialiser ta trame sans rien faire de plus que déclarer l'union avec à la fois un tableau et ta structure et utiliser la bonne forme au bon moment ! 

re jette un oeil ici le temps que je fasse le tuto sur l'union =)  qui doit suivre le tuto sur la structure =) 

Mais peut être que je devrais d'abord faire un tuto juste sur l'envois des données sans union et juste avec les tableaux... mais ça ça me paraîssait plus basique et largement couvert par de nombreux tuto comparé à ceux sur les structures et unions ...


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#11 Telson

Telson

    Membre chevronné

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

Posté 07 juillet 2016 - 01:59

si tu crées un tableau de type

​uint8_t p[3]={45,27,116};
/* Equivalent à
 uint8_t p[3]; 
 p[0]=45;
 p[1]=27;
 p[2]=116;
*/
tu pourras alors faire : 
Serial.write(p,3);

Ok....

 

cependant dans l'exemple du tableau ci-dessus, je serais obliger de faire 3 transmission (Serial.write(p,0), Serial.write(p,1), Serial.write(p,2)) pour envoyer la totalité du contenu du tableau ??

 

Est ce que je peux faire

 

trame = "D + p[0] + "/" + p[1] + "/" + p[2]+ "F"

Serial.write(trame);

 

Ensuite à la réception je me débrouille pour scinder ma donnée trame en fonction de D, des / et de F......

 

Désolé !! :crazy:       :dash2:



#12 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 934 messages
  • Gender:Male
  • Location:Anglet
  • Interests:Robotique, Entrepreneuriat, Innovation, Programmation, Résolution de problème, Recherche de solutions, Mécanique, Electronique, Créer, Concevoir

Posté 07 juillet 2016 - 02:34

Ok....

 

cependant dans l'exemple du tableau ci-dessus, je serais obliger de faire 3 transmission (Serial.write(p,0), Serial.write(p,1), Serial.write(p,2)) pour envoyer la totalité du contenu du tableau ??

 

 

non , de la même façon que quand tu fais Serial.write("hello"); tu envois h e l l o => 5 bytes
Serial.write(p,3); permet d'envoyer les 3 uint8_t en un coup. Le trois c'est le nombre de Bytes à envoyer =) p c'est le pointeur qui pointe vers l'adresse à partir de laquelle tu envois 3 bytes.  

ça c'est la deuxième approche dont je te parlais plus haut en #6
 

 

 

trame = "D + p[0] + "/" + p[1] + "/" + p[2]+ "F"

Serial.write(trame);

 

 

Oui tu peux faire ça si tu déclare trame comme étant un string ... et du coup là tu reviens à la première approche dont je te parlais utilisant un string en #6, et du coup tu te retrouve avec D45/27/116F  là où moi je te proposais $45,27,116;   ... en gros c'est bien le même formalisme mais avec caractère de début de trame séparateur et fin de trame différent ... 
 


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#13 Telson

Telson

    Membre chevronné

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

Posté 07 juillet 2016 - 03:16

Oh punaise j'avais rien compris moi quelle gros boulet.....

 

Donc c'est super si Serial.write(p,3) envoie les 3 bytes en même temps moi cela me convient complétement.....

 

Mais comme je suis gros gros boulet....si....si.....à la réception il fait comment le boulet pour récupérer chaque byte séparément........Mais ........C'est qu'il est vraiment boulet le gars !!!

 

:thank_you: :thank_you: :thank_you: :thank_you:



#14 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 934 messages
  • Gender:Male
  • Location:Anglet
  • Interests:Robotique, Entrepreneuriat, Innovation, Programmation, Résolution de problème, Recherche de solutions, Mécanique, Electronique, Créer, Concevoir

Posté 07 juillet 2016 - 04:33

Pour te prouver que tu n'es pas boulet je te laisse essayer de proposer quelque chose ;) et je suis presque sûr que tu seras presque tout bon ;) Aller ne me fait pas mentir ! :P


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#15 Telson

Telson

    Membre chevronné

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

Posté 07 juillet 2016 - 06:05

Gros malin va.....

 

je vais essayer de trouver quelque chose sur le sujet et ma vengeance sera terrible !!!!



#16 Telson

Telson

    Membre chevronné

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

Posté 08 juillet 2016 - 01:33

Allez j'me lance......
 
Deux questions concernant ce code :
  • Faut t'il utiliser char ou string pour la variable : octetReception
  • Est ce que cela va fonctionner.....Je n'ai pas de module bluetooth pour tester.....PFeeeeeeeeee
/*************************************************************
PROGRAMME DE DECODAGE D'UNE TRAME DU TYPE : /N°broche*consigne : exemple /9*126 = sur broche 9 consigne 126°
**************************************************************/

// --- Déclaration des variables globales ---
byte compteur;
char octetReception=0; // variable de réception CHAR OU STRING ???????????
byte flagbroche;
byte flagconsigne;
byte broche;
byte consigne;


void setup()
{
//c'est un exemple, donc rien ici...aller circulez...
}


//RAPPEL : TRAME DU TYPE : /N°broche*consigne : exemple /9*126 = sur broche 9 consigne 126°
void loop()
{

//Initialisaton des variables
compteur=0;
flagbroche=0;
flagconsigne=0;
broche = "";
consigne="";
while (Serial.available()>0) // tant qu'un octet en réception
{
        octetReception=Serial.read(); // Lecture de l'octet reçu
        compteur = compteur+1;//incrémentation du compteur pour connaitre le nombre d'octet lu...

        if (octetReception=="/") //&& (flagbroche==0) && (flagconsigne==0)&& (compteur==1)
        // si l'octet reçu = "/" c'est que nous commençons à lire une nouvelle trame.
        //donc dans tous les cas de figure il faut repartir du début de la procédure de lecture
        //et ce même si les flag et compteur indiquent le contraire
          {
                flagbroche = 1; //on se prépare à recevoir ensuite le n° de la broche et on l'indique avec flagbroche=1
                //ICI nous initialisons les variables pour gérer la lecture d'une nouvelle trame et ce même si les flag et compteur 
                // indiquent le contraire
                flagconsigne=0;
                broche = "";
                consigne="";
                compteur = 1;//il faut considérer que c'est bien le premier octet lu de la nouvelle trame
          }
        else if (octetReception!="/") && (octetReception!="*") && (flagbroche==1) && (flagconsigne==0) && (compteur==2)
        //si Octet reçu != "/" ET Octet reçu!= "*" ET flagbroche=1 ET flagconsigne=0 ET compteur==2  alors     C'est le N° de la broche
        //danger si perte de N° broche et * alors consigne sera considérer comme N° broche....punaise...ERREUR
        //Mais non car le prochain octet sera "/" et nous recommençerons lecture nouvelle trame, celle-ci, incomplète sera perdu....
          }
                broche = octetReception;//récupération du N° de la broche
          }
        else if (octetReception!="/") && (octetReception=="*") && (flagbroche==1) && (flagconsigne==0) && (compteur==3)
        ////si Octet reçu != "/" ET Octet reçu = "*" ET flagbroche=1 ET flagconsigne=0 ET (compteur==3)     
          {
                flagconsigne = 1;//on se prépare à recevoir ensuite la consigne et on l'indique avec flagconsigne=1
          }
        else if (octetReception!="/") && (octetReception!="*") && (flagbroche==1) && (flagconsigne==2) && (compteur==4)
        //si Octet reçu!= "/" ET Octet reçu!= "*" ET flagbroche=1 ET flagconsigne=1 ET (compteur==4)      alors     C'est la consigne
          {
                 flagconsigne = 1;
          }
        else
        // ERREUR : tous les autres cas sont des erreurs..........
            {
               break; // sort de la boucle while
            }


        if compteur=4 && flagbroche==1 && flagconsigne==1//La trame est complète !!
        {
            pulseLen = map(consigne, 0, 180, tab_pulsemin[broche], tab_pulsemax[broche] );
            //les tab ne sont pas déclarés dans cette  exemple mais vous comprendrez....non...tant pis...:-)
            pwm.setPWM(broche, 0, pulseLen);
            break; // sort de la boucle while       
        }
        
} // fin tant que  octet réception



}//fin de LOOP


 
Bon c'est j'espère un bon début..........

#17 gerardosamara

gerardosamara

    Membre passionné

  • Membres
  • PipPipPip
  • 374 messages
  • Gender:Male
  • Location:Costa Rica & Bretagne
  • Interests:La vie sous les tropiques

Posté 08 juillet 2016 - 08:58

Salut,

 

1) Personnellement j'utilise le type de variable "char" mais il manque une variable string pour stocker les octets recus ( si plus d'1 octet dans le message )

 

String receive;

char=c;

c=Serial.read(); // Lecture de l'octet reçu

receive+=c;  // Ajout l'octet recu à la variable receive

 

 

2) Pas besoin du break pour sortir de la boucle "while" , le critère est déja dans la condition "Serial.available()>0"


Pura vida

 

Ma chaine youtube  https://www.youtube....EQ5MTR3A/videos

Tutoriel MIT Inventor2  https://www.robot-ma...e-robot-mobile/


#18 Telson

Telson

    Membre chevronné

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

Posté 09 juillet 2016 - 02:05

Merci pour ces informations.
 
Compte tenu que mon code me semblait pas super un peu étrange, bref.......J'ai continué mes recherches....Et je suis tombé sur la notion de PARSER.......Mouais....il est parser par ici, il est parser par là, il ne repassera  pas par là...........Aie !! bobo la tête........
 
 
J'ai donc retenu deux principaux exemples :Sur la base du deuxième exemple
 /*
      la trame sera formaté ainsi : <1;-3;16;2294;531>
      '<' = le debut de la trame
      '>' = la fin de la trame
      ';' = délimiteur des donnees
*/

//----------
String Trame;              // Chaine pour contenir la Trame entrante
boolean TrameRecu = false; // si la Trame a été reçue dans son intégralité : Tramereçu sera = true
int NbrData = 4;           // NbrData = nombre de données reçues   exemple: 5 valeurs : 1;-3;16;2294;531

//========================
void loop() 
{
  handleCommand();//appel de la fonction
} //FIN LOOP
//=======================


//************************* routines sur événement sérial
void serialEvent()
{
  while (Serial.available()) // tant que je reçois une donnée
  {
     char incomingByte = (char)Serial.read();//le byte entrant sera chargé dans la variable incomingByte
     if (incomingByte == '>') // si valeur d'arrivée = '>' = fin de la Trame
       { 
         TrameRecu = true;  // alors TrameRecu = true
         return;
       }
     else if (incomingByte == '<')// si valeur d'arrivée = '<' = début de Trame
       { 
         Trame = "";  // Trame = vide
         TrameRecu = false; // TrameRecu = false
         return;
       }
     else //si valeur d'arrivée != '<' ET valeur d'arrivée != '>'
       {
         Trame += incomingByte; // concaténation de trame avec les valeurs reçues soit ici : 1;-3;16;2294;531
         return;
       }
  }//fin de while (Serial.available())
} // fin de void serialEvent()

void handleCommand() 
{
  if (!TrameRecu) return; // Si Tramereçu = false, alors aucune Trame a parser je quitte
  int data[NbrData];     // tableau d'entier de la taille NbrData = 4. de 0 à 4 -> 5 nombres.
  char cmd[Trame.length()+1]; // tableau de char de la taille du string Trame +1 (caractère de fin de ligne). Ce +1 OBLIGATOIRE ?
  Trame.toCharArray(cmd, Trame.length()+1);// récupère chaque valeur de Trame dans un tableau cmd de tailleTrame.length()+1)  
  char *token = strtok(cmd, ";"); // *token, c'est un pointeur, strtok(cmd, ";")->split le tableau cmd en fonction de cmd !!! COMPRENDS PAS ???

  for (int i = 0; i < NbrData+1; i++) // place de toute les valeurs dans les valeurs dans le tableau data[i]
   { 
      if (token) //COMPRENDS PAS ???
        {
      data[i] = atoi(token); //converti valeur en variable int pour pouvoir l'utiliser
      token = strtok(NULL, ";");//COMPRENDS PAS ???
        }
   }

//---Pour verif sur monitor de ce qui a été reçu
  Serial.print("data[0] = "); Serial.println(data[0]);
  Serial.print("data[1] = "); Serial.println(data[1]);
  Serial.print("data[2] = ");Serial.println(data[2]);
  Serial.print("data[3] = ");Serial.print(data[3]);
  Serial.print("data[4] = ");Serial.print(data[4]);


  TrameRecu = false;// Drapeau pour dire que nous avons traite la commande
 }
//************************Fin routines
 
 
 

Je pense que je m'approche de la vérité, juste besoin d'un peu d'info sur :
*******************************************************************************************************************************************************
char cmd[Trame.length()+1]; // tableau de char de la taille du string Trame +1 (caractère de fin de ligne). Ce +1 OBLIGATOIRE ?
Trame étant défini en string, ces variables possèdes un caractère de fin de ligne???
 
*******************************************************************************************************************************************************
char *token = strtok(cmd, ";"); // *token, c'est un pointeur, strtok(cmd, ";")->split le tableau cmd en fonction de cmd !!! COMPRENDS PAS ???
Qu'est ce que l'ont fait là? Des pointeurs sur toutes les données différentes de ";" ????

*******************************************************************************************************************************************************
if (token)//COMPRENDS PAS ???
Si (token).....alors là aucune idée......
 
*******************************************************************************************************************************************************
token = strtok(NULL, ";");//COMPRENDS PAS ???
Même punition ??!! Aucune idée
*******************************************************************************************************************************************************
 
Merci par avance pour votre soutien.......

#19 Path

Path

    Made By Humans

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

Posté 09 juillet 2016 - 10:53

Salut Telson,

 

Dans Ash, j'ai fait quelque chose qui ressemble : une transmission série. Je vais pas résoudre ton pb mais peut-être, si je t'explique ce que j'ai fait, cela pourra t'aider. Je ne prétend pas que c'est LA solution, c'en est une. 

 

Mon protocole est un peu différent du tien. Je ne transmet que du texte. Pas du binaire. Je trouve cela plus facile à traiter. (mais c'est plus lourd à transmettre). Je crois que c'est donc plus simple pour t'expliquer. Je sépare les trames avec des caractères de fin de ligne. Et à l'intérieur des trames, je sépare les infos par des ':'. C'est très similaire au tien. Mes trames ressemblent à ça :

 

COMMAND:value[:value[:value[...]]]\n

 

Lire une trame revient à lire une ligne de texte : 

void loop() {
  if (Serial.available()>0)  {
    dataFromPI = Serial.readStringUntil('\n');
    parseAndDispatch(dataFromPI);
  }
}

Dans parseAndDispatch, j'analyse les données reçues en découpant la trame. Pour faire ça, je cherche la position de chaque séparateur ( : ) et je fais un tableau de string avec ces paramètres.

void parseAndDispatch(String dataFromPI) {

  // Dé-sérialiser en analysant la trame

  // get Command (première partie de la trame)
  int dataLength = dataFromPI.length();
  int firstSep = dataFromPI.indexOf(SEPARATOR);
  if(firstSep == -1) return; // indexOf retourne -1 s'il ne trouve pas
  if(firstSep + 1 >= dataLength) return;
  String cmd = dataFromPI.substring(0,firstSep);

  // get args (suite de la trame) on découvre le nombre d'arguments
  String arrayArgs[MAX_ARGS];
  unsigned int index = 0;
  while(firstSep + 1 < dataLength && index < MAX_ARGS) {
    int secondSep = dataFromPI.indexOf(SEPARATOR, firstSep+1);
    // pour le dernier argument
    if(secondSep == -1) {
      secondSep = dataLength;
    }
    String arg = dataFromPI.substring(firstSep+1, secondSep);
    firstSep = secondSep;
    arrayArgs[index] = arg;
    index++;
  }

  // On dispatch

  if(cmd == "DIST") {
    doDistanceCommand();
  }
  if(cmd == "SERVOH") {
    doServoHCommand(arrayArgs);
  }
  if(cmd == "SERVOV") {
    doServoVCommand(arrayArgs);
  }
  if(cmd == "MOTOR") {
    doMotorCommand(arrayArgs);
  }
}

Et, par exemple, le code de la commande du servo horizontal :

void doServoHCommand(String arrayArgs[]) {
  int pos = arrayArgs[0].toInt();
  servoH.write(pos);
}

Ce code fonctionne bien. C'est avec ça que je pilote le uno depuis le raspberry dans Ash.

 

Pour blinder un peu le protocole, comme tu as une transmission sans fil et tu peux perdre des données, tu peux ajouter en début de trame la taille de la trame. Cela te permet de vérifier qu'une trame reçue est complète.

 

Dans mon code, j'ai pris l'hypothèse que l'émetteur est de confiance et qu'il formate toujours les trames correctement ;)


  • gerardosamara aime ceci

#20 Telson

Telson

    Membre chevronné

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

Posté 09 juillet 2016 - 12:30

Punaise c'est aussi du lourd .......

 

Merci






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

0 members, 0 guests, 0 anonymous users