Bonjour à tous !
Je me suis mis à la robotique il y a quelques temps et je commence à avoir un joli robot qui gigote bien via un des fameux Raspberry pi 3.
Seulement, des soucis se posent lors de l'émission et la réception des données pour le contrôler.
Google ne m'a pa aidé :'(
Contexte de la question :
Le robot est constitué de 4 jambes avec :
- 2 moteurs sur chaque jambe.
- 2 capteurs de rotation (1 par moteur)
- 2 capteurs de fin de course (à droite et à gauche)
Mon but est de concevoir un programme me permettant de contrôler le robot (étonnant, je sais -_- ).
Pour ce faire, j’ai créé deux threads, un de lecture des données (provenant des capteurs de vitesse et fin de course) et un d’envoi de données (pour commander les moteurs).
Le but est d’avoir ces deux threads qui tournent en continu en background pendant que le programme fait ses petits calculs pour définir quand un moteur doit tourner ou non.
Explication légèrement plus aprofondie :
Pour envoyer et recevoir les données, j’utilise des registres à décalage 16 bits.
Au cas où, j’explique :
L’envoi des données se fait via un registre a décalage « Série Parallele 16 Bit » (composant 74hc595) qui comporte 3 broches :
- « Entrée série » (SER) ou les bits a afficher en sortie seront envoyés 1 a 1
- « horloge » (CLK) qui permet l’enregistrement du bit en cours et le passage au suivant
- « horloge de registre » (RCLK) qui permet de charger toutes les données vers les sorties pour les afficher d’un coup
Le fonctionnement est simple :
0) Les bits de données à envoyer sont définis par le programme
1) Le premier bit est chargé à l’entrée série
2) Un front montant est donné sur l’entrée CLK
3) Le bit suivant est chargé sur l’entrée série
4) Un front montant est donné sur l’entrée CLK
5) Etc.
6) On répète l’opération pour tous les bits (16x au total, donc)
7) Un front descendant est envoyé sur RCLK pour charger toutes les données sur les sorties du registre d’un coup
8) Tadaaa, les moteurs tournent comme on leurs a demandé
La réception des données se fait via un autre registre à décalage, mais « Parallèle vers série 16 bit » (composant 74hc165) avec aussi 3 broches, 2 entrées et une sortie :
- La broche de « chargement des données » (PL) permettant de charger l’intégralité des données parallèles dans le registre,
- la broche « Série » (SER) ou les bits sont lisibles un par un,
- l’entrée « horloge » (CLK) qui permet de passer au bit suivant.
Le fonctionnement n’a rien de compliqué non plus :
1) Un front est envoyé sur PL (actif à l’état bas) qui fait charger les données présentes en entrée des 16 bit dans le registre (tout est sauvegardé d’un coup)
2) Le dernier bit est immédiatement disponible sur la sortie SER (la lecture se fait à l’envers, du dernier vers le 1er)
3) On lit le bit
4) Un front sur l’entrée CLK permet de charger le bit suivant
5) On lit le bit suivant
6) Front sur CLK
7) Etc
8) On répète les actions 16x au total
9)
Donc, ces deux threads vont passer leur temps à envoyer de données pour l’un et recevoir des données pour l’autre.
Normalement, je peux atteindre une fréquence avoisinant les 70Khz, ce qui est amplement suffisant pour lire les données des capteurs de vitesse des moteurs (ça ne tourne pas trop vite), mais la lecture des ces capteurs semblait complètement fausse…
Du coup, j’ai dégainé mon oscilloscope (pas d’inquiétude, tout sera expliqué) et je me suis branché sur les entrées CLK et PL du registre à décalage…
Lors de la réception des données, j’ai pu remarquer que le thread de lecture n’est exécuté que la moitié du temps (grosso merdo) via ceci :
P1230604.JPG
On visualise le chargement des 16 bit :
- en bas, l'entrée PL qui permet de charger les 16 bit dans le registre,
- puis en haut les 16 fronts d'horloge pour lire les 16 bit (du dernier vers le 1er)
P1230607.JPG
Ici, en augmentant l’échelle de temps, on voie que l’opération est répétée plusieurs fois d’affilée, c’est joli…
Si on regarde de façon bien plus large en augmentant l’échelle de temps, on remarque ceci :
P1230611.JPG
On retrouve bien nos fronts sur PL et CLK tout du long, mais avec un gap d’environ 3.5ms de temps a autres ce qui n’est pas acceptable (l’écran d’oscillo arrête pas de sauter, j’ai fait de mon mieux pour vous faire une belle image)
J’ai donc fait mes petites investigations… Il se trouve que si j’arrête l’exécution du thread envoyant les données sur le robot, il n’y a plus ces interruptions de lecture des signaux… J’imagine facilement que l’exécution de ce thread d’écriture perturbe l’exécution du thread de lecture.
Je n’ai aucune idée de ce qui pourrait arranger les choses, j’ai essayé de « vider » le thread en mettant tout le programme en commentaire, rien n’y fait…
Vous trouverez ci-joint mon code (d’ailleurs, si je peux me passer de ces déclarations de variable globales à la chaine, ça m’arrangerai )
Les parties vous intéressant sont les classes « writing » (L. 173) et « Reading »(L.221).
Comme vous le constaterez, ces codes sont relativement basiques et je les veux le plus court possible pour des raisons de performances.
Quelques idées de ce qui pourrait poser problème ?
Merci d’avance
-----