Bienvenue sur le site de l'équipe Poivron

Ici nous vous informerons des dernières nouvelles concernant l'avancement de nos projets et autres !

Bonne lecture !

Suivez notre évolution par flux RSS logo RSS

Dernières nouvelles

Protocole de message et nouveau PAMI

14 janvier 2026

 Protocole de messages

Finalement, nous avons repris le protocole de message. Nous avons maintenant deux couches bien séparée, la partie protocolaire et messagerie. Pour le protocolaire, la trame est composée ainsi :

  • 2 octets de début : 0xFF 0xFF
  • 1 octet pour la taille du message
  • Les données
  • 1 octet de fin 0x00

Côté applicatif, nous gardons 3 types de messages :

  1. Demande de donnée
  2. Envoi de son état
  3. Envoi d’une commande

 PAMI

C’est pas encore vraiment un PAMI, c’est à dire qu’il n’est pas pressenti pour participer à la coupe de France de Robotique, même s’il suit le règlement.

L’idée c’est de testé les servomoteurs Feetech pour la propulsion et vérifier si on peut appliquer notre architecture de code de déplacement à ces servomoteurs.

Voici la modélisation 3D :


Modélisation PAMI 2026

Et le début de la réalisation mécanique :


PAMI 2026 - en construction

PAMI 2026 à côté de son grand frère

PAMI 2026 à côté de son grand frère

0 commentaire


Performance et protocole de communication (USB)

2 décembre 2025

 HID

Nous avons travaillé sur la lecture d’une manette USB, qui serait vraiment pratique pour piloter un robot. Nous sommes tombés sur un os, tout bête, mais qui nous a fait perdre du temps. TinyUSB prévoit par défaut 256 octets pour le descripteur HID. Et il nous a fallu un peu de temps pour trouver cette limite et réaliser que notre descripteur faisait 499 octets...

Bref, nous reportons notre code sur l’HID à plus tard.

 Performances brutes

Nous reprenons alors nos essais de performances avec un Raspberry Pi Pico en client. La différence de résultats, entre un PC hôte et un Raspberri Pi Pico hôte, est notable :


Performance USB CDC - 1 seul périphérique

Dans le cas du Raspberri Pi Pico hôte deux choses nous surprennent :

  1. Le pic de vitesse pour des paquets de 120 octets dépasse celui de l’ordinateur.
  2. La vitesse s’effondre lorsque la taille du paquet augmente pour se stabiliser à 70 ko/s

Quand nous regardons le temps passé pour émettre le message, nous nous apercevons d’un temps qui augmente par palier de 1 milliseconde à chaque bloc de 64 octets.


Temps pour envoyer un message

Nous supposons qu’il y a quelque chose dans TinyUSB qui est responsable de ce temps d’attente, mais sans certitude.

 Le découpage des messages

La réception des messages est un point assez sensible. Avec l’I2C, nous n’avions pas de soucis. Une trame I2C, délimitée par le bit de stop et le bit de fin, contenait un seul message : une réception, un message, un traitement. Facile ! ou presque...

Avec l’USB, ou d’autres protocoles modernes comme l’UDP, la trame reçue peut contenir plusieurs messages. Elle peut ne pas contenir le début du 1er message, ni la fin du dernier message.

Notre première étape est de stocker les données reçues (avec tuh_cdc_read()) dans un tampon tournant avec :

  • un pointeur vers où écrire les prochaines données ;
  • un pointeur vers où lire les données.

Enfin, nous avons un protocole qui défini différents messages, répartis en 2 familles :

  • Les messages ASCII, commencent par ’>’ et se terminent par ’\n’
  • Des messages binaires, commencent par ’r’, ’w’ ou ’d’. leur entête donne leur taille et ils se terminent tous par ’\0’

Nous recopions le tampon tournant vers un tampon normal pour l’analyser. Ce tampon est parcouru afin de détecter un caractère de début. Une fois le caractère de début détecté, la suite est parcourue jusqu’à trouver le caractère fin et sa position. Dans le cas des messages binaires, cette position est comparée avec celle déduite de la taille du message. Évidemment, à chaque étape, il faut prévoir le cas où nous arrivons à la fin du tampon.

Lorsqu’un message complet est détecté, celui-ci est ajouté à une pile de message qui sera traitée. Le pointeur de lecture du tampon tournant est mise à jour.

Honnêtement, nous nous sommes un peu emmêlé les pinceaux sur cette partie. Ce serait à refaire, nous ferions autrement. L’avantage de notre méthode est la simplicité d’envoi et de détection d’un message de texte. L’inconvénient est qu’avoir plusieurs types de message multiplie les codes de détection des messages, complexifiant l’architecture globale.

Cet art de découper les message s’appelle le framing. L’une des difficultés est le caractère de fin du message qui pourrait être contenu dans le corps du message (sauf à envoyer des données en ASCII). Deux options que nous avons étudiées mais pas retenues :

  1. L’une des solutions (byte stuffing / bourrage d’octets) consiste à doubler chaque valeur qui serait une valeur de fin de message, sauf dans le cas où il s’agit réellement de la fin du message
  2. L’autre, Consistent Overhead Byte Stuffing (COBS), consiste à se brider à des messages de 254 octets et à choisir une valeur arbitraire pour la fin du message (généralement 0). Le protocole commence le message par la position du prochain octet ayant la valeur de fin de message. Si c’est la fin du message, la valeur ne sera pas altérée. Sinon, cette valeur est remplacée par la position du prochain caractère qui vaut la valeur de fin de message. Les exemples de Wikipédia sont très parlant.

Merci à @madahin[Sharp’Attack] et à Wix [Girafes] (Legend) pour ces découvertes !

Une évolution possible / probable serait d’utiliser un entête commun à tous nos messages et de terminer le message par une somme de contrôle et un caractère de fin de message.

Bref, ce n’est pas la partie dont nous sommes le plus fier et mettre ceci au point nous a causé bien des soucis. À tel point que nous avons eu recours à un débogueur pour Raspberry Pi Pico, ce qui fut l’occasion pour nous d’écrire notre article de prise en main du débogueur.

 Partie applicative

Nous fonctionnons uniquement avec des états. Chaque carte envoie à l’hôte USB ses données. L’hôte USB dispose d’une mémoire par carte périphérique et stocke les données reçues en écrasant les précédentes.

Les périphériques peuvent envoyer une demande de lecture, en indiquant l’adresse de la carte, l’adresse du registre à lire et la taille des données demandées. L’hôte répond en envoyant les données stockées.

Après ces efforts nous avons testé le protocole pendant 3h30 avec d’un côté une carte qui lit un capteur de distance, de l’autre une carte qui allume ou éteint une DEL en fonction de la distance du capteur et au milieu notre hôte (ce à quoi nous pourrions rajouter le Pico qui nous servait de sonde de débogage, pour décrire le bazar...). Bref le test fut enfin concluant !

0 commentaire


Servomoteurs Feetech

13 août 2025

Dans le cadre de nos activités avec le Club Robotique de Riom, nous avons été amené à tester les servomoteurs Feetech. Nous proposons une documentation sur le site de Robot Maker.

Une copie au format PDF est disponible ici, au cas ou...

Bonne lecture

0 commentaire


L’USB et la carte SD

11 juillet 2025

C’est Robotronik Phelma qui nous a aiguillé vers les cartes SD à la coupe. Alors, nous prenons notre moteur de recherche favori trouvons deux-trois informations prometteuses sur les cartes SD :

  • Nous pouvons communiquer avec le protocole SPI. C’est un protocole parfaitement supporté par le Rapsberry Pi Pico ;
  • Les cartes SD ont aussi un protocole plus évolué, le SDIO ;
  • Nous trouvons un projet, qui implémente le protocole SDIO grâce aux modules PIO du Rapsberry Pi Pico : no-OS-FatFS-SD-SDIO-SPI-RPi-Pico.

Le protocole SDIO ressemble au protocole de communication SPI, avec 4 lignes de données et des commandes normalisées pour commander la carte SD (probablement les mêmes qu’en SPI). C’est surtout une vitesse de transfert 4 fois plus élevée pour la même fréquence d’horloge qui nous intéresse. Vous trouverez assez facilement des documents décrivant le protocole SDIO, En voici un au hasard.

Concernant le projet no-OS-FatFS-SD-SDIO-SPI-RPi-Pico, le README est particulièrement encourageant : il annonce des vitesses de lecture et d’écriture supérieures à 10 Mo/s. Maintenant, nous voulons tester ça !

Adaptateur de carte SD

Côté brochage de la carte, nous n’arrivons pas à trouver la description dans la norme, mais de nombreux sites proposent tous le même brochage, que voici :


Brochage carte SD

C’est un commentaire dans le code qui nous explique comment raccorder l’adaptateur SD avec le microcontrôleur :
Extrait de simple_sdio/main.c (no-OS-FatFS-SD-SDIO-SPI-RPi-Pico) /* SDIO Interface */ static sd_sdio_if_t sdio_if = { /* Pins CLK_gpio, D1_gpio, D2_gpio, and D3_gpio are at offsets from pin D0_gpio. The offsets are determined by sd_driver\SDIO\rp2040_sdio.pio. CLK_gpio = (D0_gpio + SDIO_CLK_PIN_D0_OFFSET) % 32; As of this writing, SDIO_CLK_PIN_D0_OFFSET is 30, which is -2 in mod32 arithmetic, so: CLK_gpio = D0_gpio -2. D1_gpio = D0_gpio + 1; D2_gpio = D0_gpio + 2; D3_gpio = D0_gpio + 3; */ .CMD_gpio = 3, .D0_gpio = 4, .baud_rate = 125 * 1000 * 1000 / 6 // 20833333 Hz };

C’est donc l’heure du shopping ! Nous cherchons un adaptateur de carte SD, mais qui support le protocole SDIO. Attention, certains adaptateurs n’offrent que le protocole SPI ! Nous sommes en amont du projet et nous ne sommes pas prêts à faire des compromis là-dessus.

Après quelques minutes de recherche, nous nous agaçons. Ce truc va nous coûter des sous, mettre du temps à arriver... Bref, nous trouvons une autre solution, pas forcément des plus élégantes :


Adaptateur carte SD

Non, nous n’avons pas soudé les fils directement sur une carte SD, ceci aurait été problématique pour la lire sur un ordinateur. Il s’agit d’un adaptateur de carte SD vers micro SD. En utilisant des cartes micro-SD, nous pouvons les connecter à la plaque de test ou les sortir pour les lire sur le PC. Pile ce qu’il nous fallait.


Carte SD reliée au RP2040 sur plaque d’essai

Test unitaire

Nous prenons le code de no-OS-FatFS-SD-SDIO-SPI-RPi-Pico et modifions l’exemple SDIO pour mesurer la vitesse d’écriture. Nous sommes d’abord ravis de voir apparaître les fichiers avec le bon contenu sur la carte SD. Puis en regardant les vitesses d’écriture, le doute s’installe :

Écrit: 38 octets en  46995 us
Écrit: 4066 octets en  30379 us
Écrit: 65482 octets en  28264 us

Comme si, plus nous écrivions de données, plus le temps total de l’opération diminuait. Ce qui n’est pas logique.

Des essais suivants montrent qu’il y a :

  1. Un coût fixe, en temps, assez élevé pour la moindre écriture (peu importe la quantité de données)
  2. Un coût aléatoire, probablement dû à l’age de la carte SD ou à la qualité du câblage

Mais globalement nous atteignons une vitesse de l’ordre de 2 Mo/s, et ça, c’est top !

Intégration avec le code USB

Aviez-vous remarqué que dans le nom du projet no-OS-FatFS-SD-SDIO-SPI-RPi-Pico, il y avait FsFAT ?

Bref, notre code USB et le code SDIO utilisent la même bibliothèque. À nous de créer un bout de code pour que la bibliothèque gère les deux supports. Si vous vous rappelez de notre article précédent, vous vous souvenez que :

  • FsFAT peut gérer plusieurs disques
  • Qu’il n’y a que quelques fonctions à adapter qui s’appellent disk_*

Nous reprenons la structure décrite dans diskio.c de FsFAT et sélectionnons la "bonne" fonction disk_* en fonction du numéro du disque. Les disques 0 et 1 sont des cartes SD et les fonctions disk_* appellent leurs homologues SDIO_disk_* tandis que les disques 2 à 9 sont des périphériques USB et les fonctions disk_* appellent leurs homologues USB_disk_*.


Architecture logicielle - USB + Carte SD

Côté performances

Au lieu de nous contenter d’une ou deux écritures sur la carte, nous lançons des écritures de 64 ko sur la carte SD et sur la clé USB. Nous restreignons l’acquisition à 1 minute et obtenons le graphique suivant.


Performance d’écriture (USB vs carte SD)

L’écart, en termes de performance, est sans appel.

Si nous réalisons le même exercice mais juste avec les écritures sur la carte SD, nous obtenons beaucoup plus de points en une minute, ce qui permet de valider la stabilité des résultats.


Performance d’écriture (carte SD)

Nous observons bien quelques pics de lenteurs autour de 0,5 à 1 Mo/s mais la vitesse moyenne d’écriture se situe bien autour de 2,0 Mo/s, ce qui est une très bonne nouvelle.
Écrire à la fois sur la carte SD et sur la clé USB n’est pas le plus utile ici ! Ce qui nous intéresse vraiment, c’est d’avoir la pile USB hôte fonctionnelle avec la capacité d’écrire des logs massivement !

Notre code est disponible sur notre dépôt !

0 commentaire


L’USB hôte, la clé USB et les fichiers

11 juillet 2025

Alors, oui, nous avons une piste pour régler nos problèmes de communication, surtout que l’USB nous avait été chaudement recommandé à la coupe.
Mais nous avions un autre souhait pour notre robot, avoir des logs. Mais pas juste une LED qui s’allume en cas de soucis, des vrais logs, des gros fichiers avec plein de données dedans !

Nous voyons que notre code de démonstration supporte la classe "Mass Storage", nous sommes donc sur la bonne voie. Mais que se passe-t-il lorsque nous connectons une clé USB ? Eh bien, pas grand-chose :

A device with address 1 is mounted
A device with address 1 is unmounted 

Alors comment aller plus loin ?

La bibliothèque TinyUSB propose une liste de fonctions pour gérer les périphériques "Mass Storage", accessible dans le fichier msc_host.h. Mais en observant ces fonctions, il n’y a rien qui ressemble à ouvrir ou fermer un fichier.

Du MSC au fichier : le système de fichier

Les fonctions USB vont permettre de lire ou d’écrire une plage d’octet sur le périphérique, comme si nous accédions à une mémoire — ce qui est le cas. C’est très bien pour écrire une donnée brute, mais pour créer des fichiers qui seront lisibles sur un ordinateur, il manque toute une couche logicielle. Ces fonctions USB sont inspirées du protocole SCSI dont nous avons la liste compréhensible des commandes. Et rien là-dedans ne permet d’ouvrir, lire ou écrire des fichiers. Il s’agit plutôt de fonctions pour copier des morceaux de mémoire.

Pour gérer des fichiers, il faut un système de fichier. Un système de fichier est une organisation de la mémoire qui contient :

  • d’une part une table de partition qui indique le nom des fichiers, leur arborescence dans les répertoires, leur taille et où trouver leur contenu
  • d’autre part, le contenu des fichiers aux endroits indiqués par la table de partition.

Sur microcontrôleur, il n’y a pas beaucoup de systèmes de fichier qui seraient à la fois simples et reconnus par un ordinateur. Le principal candidat est FAT/exFAT. Il s’agit en réalité d’une famille de système de fichiers (FAT12, FAT16, FAT32, exFAT). FAT12, le plus ancien date de 1980 et était utilisé sous QDOS, l’ancêtre de MS-DOS tandis que exFAT est encore couramment utilisé sur les cartes SD. Ces systèmes de fichier regroupent la mémoire par blocs pour faciliter sa gestion.

Si nous parlons d’une famille de système de fichier, c’est qu’au lieu d’implémenter la spécification, nous utilisons une bibliothèque qui gère toute cette famille. Cette bibliothèque, c’est FsFAT !

Interface entre TinyUSB et FsFAT

L’interface en TinyUSB et FsFAT se résume à quelques fonctions. Chacune de ces fonctions prend en argument le numéro du "disque" sur lequel effectuer les opérations.

  • disk_initialize : rien à faire, la connexion à la clé est gérée par l’USB
  • disk_status : renvoyer 0 si la clé correspondant à ce disque est branché, 1 sinon.
  • disk_read : appeler la fonction tuh_msc_read10 avec les bons paramètres, attendre que les tâches USB se soient bien exécutées
  • disk_write : appeler la fonction tuh_msc_write10 avec les bons paramètres, attendre que les tâches USB se soient bien exécutées
  • disk_ioctl : obtenir la taille et le nombre de blocs contenus sur la clé

Le code à étudier est certainement l’explorateur de fichier fourni dans les exemples de TinyUSB.

C’est un détail, mais FsFAT demande une fonction qui renvoie la date actuelle. Si vous n’avez pas d’horloge à l’heure sur votre microcontrôleur, Vous pouvez renvoyer n’importe quelle date, mais c’est cette date qui apparaîtra comme date de création ou de modification du fichier.

Côté architecture logicielle, nous avons "juste" rajouté la couche FsFAT à notre projet précédent :


Architecture logicielle - USB + FsFAT

Écrire dans un fichier

Nous étions un peu là pour ça, non ?

Pour écrire dans un fichier, la procédure est la suivante :

  1. f_mount : monter le système de fichier ;
  2. f_open : ouvrir le fichier ;
  3. f_write : écrire dans le fichier ;
  4. f_sync : forcer les écritures qui pourraient avoir été mises en attente ;
  5. f_close : fermer le ficher - une bonne pratique, pas forcément utile ici.

Rien de sorcier, mais il y a une petite subtilité. Les chemins sont sous cette forme :

[disque#:][/]répertoire/fichier

Les crochets [...] indiquent des éléments facultatifs. Si vous n’indiquez pas de disque, FsFAT supposera que vous cherchez à écrire sur le disque 0. Dans notre cas, ceci nous a joué un tour. Si nous connections la clé USB directement sur le Raspberry Pi Pico, elle obtenait l’adresse 1. Nous avions codé en dur l’adresse du disque dans nos fonctions disk_*. Mais en ajoutant un hub, l’adresse de la clé passait à 2 et plus rien ne marchait. C’est embêtant au début, mais très flexible par la suite. Vous pouvez gérer plusieurs clés USB par exemple. Imaginez en garder une en permanence sur le robot et une qui reçoit automatiquement les derniers logs lorsque vous la branchée.

Pour plus de détails, lisez la bonne documentation.

Alors, nous y sommes ?

Les performances ? Pas terribles, nous ne dépassons pas les 64 ko/s, ce qui est aussi la limite trouvée par rppicomidi dans son projet pico-usb-host-msc-demo... D’après le projet de rppicomidi, c’est la conception de l’USB sur le Raspberry Pi Pico qui n’est pas faite pour obtenir de bonnes performances en mode "hôte". De notre côté, nous n’avons pas les compétences pour nous prononcer sur la cause, mais nous réalisons le même constat...

Alors 64 ko/s, ça paraîtrait OK pour du log, mais ça veut dire que nous utilisons un cœur complet pour écrire sur la clé, et que notre ressource USB ne fait qu’écrire les logs, Or nous comptons sur l’USB pour la communication intra-robot, pas question de partir sur une solution qui semble déjà montrer ses limites...

Vous trouverez notre code en ligne ici !

0 commentaire

page précédente 1 2 3 4 5 6 7 8 9 ... 37

Copyright "POIVRON" 2011-2023, tous droits réservés
Administration du site