Ok, bon ben suis pas rendu avec tout ça
Essaye déjà ce que t'ont proposé sandro et thot ! =)
Posté 01 septembre 2019 - 08:13
Ok, bon ben suis pas rendu avec tout ça
Essaye déjà ce que t'ont proposé sandro et thot ! =)
Si mon commentaire vous a plus laissez nous un avis !
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!
Posté 02 septembre 2019 - 02:24
@Sandro : juste pour te faire un retour, j'ai testé à 90ms ça a l'air de fonctionner carrément mieux niveau latence, par contre j'ai des pertes d'octets comme tu le précisais si je ne dis pas de bêtises.
Bon je continue mes recherches avec vos conseils
Faut que j'arrive à mélanger ces deux idées de Thot et Sandro, tintin tiiiinnnn gros challenge, ça sent la galère, zou à moi google ^^
EDIT : Si vous avez des liens qui explique le pourquoi tu comment avec surtout du code d'exemple que je puisse avoir une idée, welcome.
Posté 06 septembre 2019 - 12:30
Avec le 90ms (sans utiliser de start byte), il y a aura en effet des pertes des pertes de paquets si tu tu lis pendant qu'un paquet est en train d'arriver.
Je t'ai écris un code d'exemple qui fonctionne avec un Arduino (j'ai pas d'ESP) et un Raspberry en utilisant un start byte et une checksum :
Arduino :
#define SIZE_OFF_DONNEES 3 //nbr d'octets sans start byte et checksum struct Donnees { //les données que tu veux envoyer (SIZE_OFF_DONNEES octets) uint8_t toto; int16_t tata; }; Donnees donnees; void envoyer_donnees() { uint8_t donnees_a_envoyer[SIZE_OFF_DONNEES+2]; donnees_a_envoyer[0]=42; //start byte donnees_a_envoyer[1]=donnees.toto; donnees_a_envoyer[2]=donnees.tata>>8; //octet de poids fort de tata (on pourrait écrire donnees.tata/256, mais c'est plus lent à calculer) donnees_a_envoyer[3]=donnees.tata&0xFF; //octet de poids faible de tata (on pourrait écrire donnees.tata%256, mais c'est plus lent à calculer) uint8_t checksum=0; for(int i=0; i<SIZE_OFF_DONNEES+1; i++) //calcul du xor entre tous les bytes (sauf la checksum) pour calculer la checksum { checksum=checksum^donnees_a_envoyer[i]; } donnees_a_envoyer[SIZE_OFF_DONNEES+1]=checksum; //on rajoute la checksum à la fin Serial.write(donnees_a_envoyer, SIZE_OFF_DONNEES+2); } void setup() { Serial.begin(115200); donnees.toto=0; donnees.tata=1000; } void loop() { donnees.toto=donnees.toto+1; donnees.tata=donnees.toto+1000; envoyer_donnees(); delay(100); //tu mets ce que tu veux, ça ne doit même pas être constant. Alternativement, tu peux envoyer tes données depuis un timer }
Raspberry Pi:
#include <iostream> #include "rs232.h" using namespace std; #define SIZE_CHARGE_UTILE 3 //nombre d'octets utiles à envoyer (on envois 2 octets en plus pour le début de paquet et la checksum) #define SIZE_PAQUET SIZE_CHARGE_UTILE+2 //nombre d'octets d'un paquet (y compris start byte et checksum) int cport_nr(24); //24=ttyACM0 // 0 = ttyS0 ls /dev/tty* int bdrate(115200); // Baud char mode []={'8','N','1',0}; // 8 data bits, no parity, 1 stop bit struct Donnees { //les données que tu veux recevoir uint8_t toto; int16_t tata; }; uint8_t received_data[4096+SIZE_CHARGE_UTILE+2]; //taille du buffer d'entrée (4096) + taille pour un paquet unsigned int nbr_bytes_in_buffer=0; void process_received_package(Donnees &donnees) { cout<<(unsigned int)donnees.toto<<endl; cout<<(int)donnees.tata<<endl; cout<<endl; } void get_received_data_and_process() { unsigned int n = RS232_PollComport(cport_nr, received_data+nbr_bytes_in_buffer, 4096); //on écrit les nouvelles données à l'adresse received_data+nbr_bytes_in_buffer de manière à ce qu'ils soient après ceux déjà présents nbr_bytes_in_buffer+=n; //on a maintenant n octets de plus dans notre buffer (ie les n octets qu'on vient de lire) unsigned int start_index=0; //premier octet du buffer pas encore lu while(start_index+SIZE_PAQUET<=nbr_bytes_in_buffer) //tant qu'il y a assez de données dans le buffer pour potentiellement faire un paquet complet { //vérifions que le (potentiel) paquet commence bien par 42 if(received_data[start_index]!=42) //si le premier octet n'est pas 42, alors il ne s'agit pas du début du paquet { cerr<<"invalide byte:"<<(unsigned int)received_data[start_index]<<endl; start_index++; //on ignore le premier octet continue; //on arrête ce tour du while, et on repart pour un nouveau tour avec l'octet suivant (si la condition du while est toujours respectée) } //vérifions que le potentiel paquet est valide (checksum correcte) uint8_t checksum=0; for(unsigned int i=0; i< SIZE_PAQUET ; i++) { checksum=checksum^received_data[start_index+i]; } if(checksum!=0) //normalement on doit obtenir 0, car le dernier octet est sensé être le xor des précédents, et n xor n=0 { cerr<<"invalide checksum"<<endl; start_index++; //on ignore le premier octet continue; //on arrête ce tour du while, et on repart pour un nouveau tour avec l'octet suivant (si la condition du while est toujours respectée) } //on sait maintenant qu'on a un paquet valide, qu'on peut donc traiter uint8_t paquet[SIZE_PAQUET]; memcpy(paquet,received_data+start_index,SIZE_PAQUET); //on récupère le paquet (nb : il serait plus optimisé de lire directement dans received_data, mais ça rendrait le code moins clair) struct Donnees donnees; donnees.toto=paquet[1]; donnees.tata=256*paquet[2]+paquet[3]; process_received_package(donnees); //on traite les donnees utiles //on considère tout un paquet comme traité start_index+=SIZE_PAQUET; } //il reste maintenant moins de sizeof(UnionDonneesARecevoir) octets. Pour préparer l'appel suivant à la fonction, on actualise le nombre restant d'octets et on met tous les octets restant au début du buffer nbr_bytes_in_buffer=nbr_bytes_in_buffer-start_index; //nombre d'octets restant memmove(received_data,received_data+start_index,nbr_bytes_in_buffer); //on déplace les octets restants vers le début du buffer (nb : il faut utilise memmove au lieu de memcpy car il y a potentiellement chevauchement des zones d'origine et de destination) } int main(int argc, char **argv) { if (RS232_OpenComport(cport_nr, bdrate, mode,0)) { cout <<"-----> Ne peut pas ouvrir le port com.\n \n"; exit(-1); } cout << "-----> Port de communication ouvert PI. \n \n"; while(1) { get_received_data_and_process(); usleep(100000); } return 0; }
Quelques remarques :
- j'ai décidé de ne pas utiliser d'unions, car selon les cas (par exemple si elle contient un char suivit d'un int), il n'est pas spécifié si des octets "vides" doivent être insérés ou pas. Il y a donc un risque qu'en utilisant des unions le code devienne faux si on change de compilateur ou de plateforme
- tu remarquera que je découpe explicitement les données en octets (en particulier toto, qui est sur 16 bits) : là encore, il s'agit de garantir que ça marchera sur n'importe quel appareil (certains stockent l'octet de poids fort d'abord, d'autre celui de poids faible, du coup si tu as la mal chance de tomber sur un de chaque, le résultat est faux)
- pour transmettre des floats, il y a plusieurs possibilités : juste envoyer les octets correspondants (mais ça donnera des résultats faux si de l'autre coté c'est pas interprété pareil), ou envoyer les informations dans un format que tu décide (par exemple 1 octet pour la partie entière suivit d'un entier entre 0 et 99 pour la partie décimale)
D'après le (petit) test que j'ai fait, je n'ai pas de pertes de données (tant que la communication électrique vas bien). Il est "normal" que tu voies des messages "invalide byte" au tout début : celà correspond simplement aux données déjà présentes dans le buffer quand ton programme se lance et est prêt à lire. Dans la version sans vérification, tu aurais probablement des valeurs absurdes à la place (sans que le programme détecte que c'est du n'importe quoi, alors qu'ici les données corrompues sont juste ignorées)
Si tu as des questions, n'hésite pas (je pourrais probablement te répondre jusqu'à demain (vendredi) début d'aprèm, et ensuite qu'à partir de samedi soir ou dimanche)
Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...
Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.
Posté 06 septembre 2019 - 10:53
Je suis ce post et je me pose une question : il n'y a pas d'UART sur une carte arduino ? c'est le MC qui doit tout gérer ?
Posté 06 septembre 2019 - 12:18
Je viens de vérifier dans la datasheet de l'ATMEGA328P (utilisé dans l'arduino Uno) : il comporte un circuit USART, qui est une extension de l'UART (et qui peut fonctionner en mode UART) : il s'agit donc bien d'une implémentation hardware (ouf!). Pour y accéder directement, c'est les pins 0 et 1 (RX et TX). En plus de ça, tu as, si mes souvenirs sont bons, une petite puce dédiée qui te transforme l'UART en UART via USB (c'est ainsi que tu peux envoyer des messages à l'ordi en utilisant Serial.print())
Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...
Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.
Posté 06 septembre 2019 - 01:45
ça faisait un petit moment que je ne suivais que de loin, et je n'avais pas vu que c'était un ESP32 et pas une Arduino,
mais bon, le résultat est le même puise que l'ESP32 a aussi un UART...
Tout ça pour dire que je ne comprends pas cette histoire de temporisation.
en liaison full-duplex, ce sont les UART de chaque carte qui devraient s'occuper de la synchro non ?
J'ai jamais joué avec du microcontroleur, mais uniquement sur PC (UART 8250)
et une fois l'UART correctement paramétrée, elle déclenche une interruption à chaque réception d'octet.
il est aussi possible de stocker temporairement ces octets dans une pile FIFO, ce qui permet de ne pas mobiliser
toutes les ressources à chaque interruption.
Idem pour l'envoi, on peut consulter l'état de l'UART pour savoir si la place est libre ou non.
Posté 06 septembre 2019 - 02:48
En théorie, il devrait être possible d'avoir une interruption à chaque octet reçu, mais ce n'est pas implémenté dans la bibliothèque qu'utilise Olivier17. En revanche, il y a bien une FIFO (buffer) de 4096 octets coté Raspi, ce qui rends possible le code que j'ai posté (ie de lire plus d'un paquet si on a du "retard").
D'ailleurs, je viens de me rendre compte que j'ai oublié de préciser quelque chose : dans le code que j'ai posté, rien n'impose de mettre des delais de 100ms : tu peux sans problème mettre un délai différent d'un coté ou de l'autre (si la bibliothèque raspi ne disait pas explicitement de ne pas l'appeler trop souvent, tu pourrais très bien ne pas mettre de delai du tout coté raspi. En gros, tant que tu appelle la fonction de lecture du raspi avant que tu n'ait accumulé 4096 octets non lus, tout ira bien (au sens que tu ne perdra pas de données)
Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...
Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.
Posté 28 octobre 2019 - 03:06
Coucou les Maker's...
Hop, pour le fun...
Je lui ai modélisé des jambes, mais pas encore les pieds, j'attend de pouvoir me prendre des capteurs de pression et de voir de quelle façon je vais modéliser les pieds via la forme et dimension des capteurs ^^
Posté 28 octobre 2019 - 06:07
Ma chaine YouTube : https://www.youtube..../oracid1/videos
0 members, 1 guests, 0 anonymous users