Geckrobot : Pilotage d’une patte

Maintenant que je suis en paix avec le fonctionnement de mes servomoteurs, je retourne à mon geckrobot. Cet article est une première tentative d’implémentation d’une librairie Arduino pour piloter les pattes du robot en m’appuyant sur les modèles géométriques directe et inverse ainsi que la librairie HerkuleXLib.

1 Mise en œuvre

En préambule, je décris les éléments du dispositif expérimental qui me permettent de tester le pilotage d’une patte.

1.1 Éléments de la patte

Je réutilise mon premier prototype de patte, dont les mouvements sont décrits par le schéma cinématique, comme présenté ci-dessous.

Pour la liaison entre 01 et 02, j’ai découpé, percé, puis plié une plaque d’aluminium de 1,5 mm (cette vidéo m’a aidé). Pour la liaison entre 02 et 03, j’ai juste assemblé les servomoteurs 1 et 2 ensemble. Enfin pour la liaison entre 03 et 04, j’ai utilisé des éléments standards en aluminium (marque Lynxmotion). Du côté opposé au palonnier, les éléments sont assemblés aux servomoteurs avec un roulement à bille (aligné à l’axe du palonnier) afin d’assurer une liaison pivot plus solide. Aussi j’ai matérialisé le point 04 par la pointe d’un stylo positionné à l’extrémité de ma patte.

Notez que la géométrie de cette patte ne correspond PAS aux solutions optimales calculée ici.

1.2 La maquette

J’ai réalisé une maquette sur laquelle est fixée la patte pour faciliter mes essais. Elle est principalement faite à partir d’Isorel (recyclage d’un fond de tiroir). Les équerres en aluminium sont pliées comme montré sur les photos, à l’aide d’un bout de “corde à piano” de diamètre 3 mm pour arrondir les angles. La carte Arduino est fixée sur la maquette, à l’arrière.

1.3 Configurer les servomoteurs

Repartant de la configuration utilisée pour cet article (ID = 253 pour tous les servomoteurs), il faut me changer les ID. J’utilise modifyID_MEGA.ino que j’ai rajouté aux exemples de la librairie (disponible depuis la v1.2) pour les numéroter 0, 1 et 2 respectivement pour les liaisons en 01, 02 et 03.

Les liaisons mécaniques limitent les mouvements de la patte, j’ai donc configuré les positions minimale et maximale pour chaque servomoteur. J’ai aussi remis les paramètres d’accélération par défaut et la vitesse de communication avec les servomoteur à 666666 bps. Le code suivant m’a permis de procéder comme le montre la vidéo ci-après.

#include <HkxSetup.h>

// global variables
byte ID = 0; // ID of the servo
HkxPrint* printoutLib;
HkxPrint* printoutCode;
HkxCommunication* communication;
HkxSetup* setupServos;
String message;
uint16_t overloadPWMThreshold;
int16_t minPosition, maxPosition;

void setup() {
  delay(2000); // wait 2 seconds to open the serial monitor

  printoutLib = new HkxPrint(Serial, 9600);  // Printout errors on the serial monitor
  printoutCode = new HkxPrint(*printoutLib, true, true, true);  // Printout errors on the serial monitor
  communication = new HkxCommunication(HKX_115200, Serial1, *printoutLib);  // Communication with the servo on Serial1
  setupServos = new HkxSetup(*communication, *printoutLib);  // setup the servos

  setupServos->setAllBaudRate(HKX_666666);
  setupServos->clearOneStatus(ID);
  setupServos->setAllAcceleration (50, 504); //Default values

  setupServos->getPWMPositionLimits(ID, &overloadPWMThreshold, &minPosition, &maxPosition);
  
  // All servos torque break and led off, but active servo torque free and led blue
  setupServos->setAllTorqueLEDControl(HKX_TORQUE_BREAK, HKX_LED_OFF);
  setupServos->setOneTorqueLEDControl(ID, HKX_TORQUE_FREE, HKX_LED_BLUE);
  printoutCode->infoPrint(" \" ID \" then number of the servo");
  printoutCode->infoPrint(" \" min \" to set the current position as the mimum");
  printoutCode->infoPrint(" \" max \" to set the current position as the maxium");

}

void loop() {
  int16_t currentPosition;

  // Get the behaviour
  byte error = setupServos->getBehaviour(ID, HKX_NO_VALUE, HKX_NO_VALUE, HKX_NO_VALUE, HKX_NO_VALUE, &currentPosition, HKX_NO_VALUE, HKX_NO_VALUE, HKX_NO_VALUE, HKX_NO_VALUE, HKX_NO_VALUE);
  if(error == 0){
    message = "ID=";
    message += ID;
    message += " position=";
    message += currentPosition;
    printoutCode->infoPrint(message);
  } else if(error == 1){
    printoutCode->errorPrint("Input not correct");
  } else if(error == 2){
    printoutCode->errorPrint("Servo not connected");
  } else if(error == 3){
    printoutCode->errorPrint("Data not consistent");
  }

  // Get 
  if (Serial.available() > 0) {
    String income = Serial.readString();
    if(income.equals("ID")){
      printoutCode->infoPrint("Enter the ID");
      while(Serial.available() < 1) {};
      setupServos->setOneTorqueLEDControl(ID, HKX_TORQUE_BREAK, HKX_LED_OFF);
      String income = Serial.readString();
      ID = income.toInt();
      setupServos->setOneTorqueLEDControl(ID, HKX_TORQUE_FREE, HKX_LED_BLUE);
      setupServos->getPWMPositionLimits(ID, &overloadPWMThreshold, &minPosition, &maxPosition);
      printoutCode->infoPrint("ID has been modified");
    } else if(income.equals("min")){
      minPosition = currentPosition;
      setupServos->setOnePWMPositionLimits(ID, overloadPWMThreshold, minPosition, maxPosition);
      message = "min position of ID=";
      message += ID;
      message += " has been modified";
      printoutCode->infoPrint(message);
    } else if(income.equals("max")){
      maxPosition = currentPosition;
      setupServos->setOnePWMPositionLimits(ID, overloadPWMThreshold, minPosition, maxPosition);
      message = "max position of ID=";
      message += ID;
      message += " has been modified";
      printoutCode->infoPrint(message);
    } else {
      printoutCode->warningPrint("Incorrect input");
    }
    

  }
  
  delay(1000); // refresh every second
}

Pour télécharger le fichier : setupServos_MEGA

J’en ai aussi profité pour déterminer la valeur de la position absolue des servomoteurs pour les angles nuls du modèle (lorsque 01, 02, 03 et 04 sont alignés). J’ai mesuré les valeurs de X0, Y0, Z0, Y1, Y2 et Y3 (cf. la définition des paramètres) comme montré sur la figure ci-dessous. J’obtiens les valeurs :
  • servomoteur 0, zero0 = – 2,5°
  • servomoteur 1, zéro1 = – 34,8°
  • servomoteur 2, zéro2 = -111,4°
  • X0 = 0 mm
  • Y0 = 40 mm
  • Z0 = 150 mm
  • Y1 = 34 mm
  • Y2 = 44 mm
  • Y3 =120 mm

parameters definition

2 Objectifs

Je démarre avec cet article l’écriture d’une librairie Arduino pour le Geckrobot. J’implémente pour l’occasion une première classe, dont le but est de piloter une patte et que j’appelle GkrLeg.

Je souhaite ici avoir la possibilité de déplacer une patte de deux manières :
  • Le mouvement aticulaire pour lequel la génération de trajectoire s’applique aux servomoteurs. C’est en réalité ce qu’il se passe quand on utilise directement la librairie HerkuleXLib. GkrLeg doit malgré tout permettre de surmonter les limitations de la librairie (dues au protocole de communication) – en particulier la limite de temps de mouvement.
  • Le mouvement spatial pour lequel la génération de trajectoire s’applique au point 04, permettant de le déplacer linéairement dans l’espace.

La différence entre ces deux types de mouvements est illustrée par la vidéo ci-dessous. À gauche est présenté un mouvement spatial quand à droite un mouvement articulaire, ces deux mouvements ayant les mêmes points de départ et d’arriver.

3 Le code

Je ne publie pas encore mon code parce qu’il n’est pas suffisamment mature. Je précise juste que pour les besoins de cet article j’ai fait des modifications (bug et nouvelles fonctions) de la librairie HerkuleXLib que je publierai dans la version 1.3.

Je vais quand même donner quelques détails algorithmiques du déplacement spatial dont je présente l’organigramme logique ci-dessous.

Geckrobot: space motion algo

Veillez noter les points suivants :
  • Lorsque j’utilise le symbole “→”, c’est que je converti une coordonnée articulaire en coordonnée cartésienne – ou inversement – à l’aide des modèles cinématiques direct ou inverse.
  • La variable t est le temps à l’instant donné.
  • Vous remarquerez que je génère des sous-mouvements pour atteindre les états i+2 (et non i+1) aussi bien en terme de position que de temps de déplacement. Cela permet d’avoir un recouvrement entre les sous-mouvements. En effet, pour un mouvement donné, le servomoteur génère une trajectoire de vitesse avec phases d’accélération et de décélération qui, sans ce recouvrement, génère des saccades donc des vibrations (illustré au paragraphe 4.1). Nous obtenons ainsi une trajectoire plus fluide.
  • J’ai limité le nombre de pas (nS) afin que la durée d’un pas (variable i) ne soit pas inférieure à 50 ms. Cette durée minimum me permet de garantir que le microcontrôleur a le temps d’effectuer les calculs (position et temps) du prochain pas (i+1) pendant le laps de temps du mouvement. Cela signifie aussi que plus on souhaite effectuer un déplacement rapide, moins celui-ci risque d’être précis en terme de position (le pas de 2 mm n’étant alors plus forcément respecté).
  • D’un autre côté, je m’assure aussi que la durée d’un pas (variable i) ne dépasse pas 1400 ms. Comme expliqué au second point, j’effectue un recouvrement entre mes sous-mouvements. La durée du sous-mouvement peut donc aller jusqu’à 2800 ms suivant ce critère qui me garanti de ne pas dépasser la durée maximum de mouvement autorisé par le protocole de 2845 ms.

4 Quelques déconvenues

4.1 Recouvrement

Pour mettre en avant l’intérêt d’un recouvrement entre les sous-mouvements j’ai fait la vidéo ci-dessous, à gauche sans recouvrement, à droite avec recouvrement. Le premier déplacement permet de calibrer la position zéro des servomoteurs et utilise un mouvement articulaire (non cartésien). Pour les mouvements suivants, on voit qu’à gauche ceux-ci sont plus saccadés qu’à droite.

4.2 Trop d’approximations

Vous avez bien compris que la maquette telle que je l’ai faite a pour but de tester et illustrer mes développements sur l’exemple d’une table traçante. J’ai réutilisé la trajectoire de l’illustration du recouvrement en descendant jusqu’à Z = 0 (coordonnée théorique du plan de la feuille) pour que le stylo trace une ligne droite de 100 mm. On voit sur ce premier essai que si le stylo écrit bien sur le début de la trajectoire, celui-ci ne laissera sa marque que sur les 20 premier millimètres. J’ai vite compris que l’axe du servomoteur 0 n’était pas exactement perpendiculaire avec le plan de la feuille.

Pour compenser le défaut de perpendicularité, j’ai fait un second essai pour lequel je démarre ma trajectoire à Z=0 et la termine à Z=-1mm. Sur la vidéo qui suit vous remarquerez que cette fois le stylo écrit au début, à la fin, mais pas au milieu… De plus la ligne qui devrait faire 100 mm de long n’en fait que 80 mm et pour couronner le tout, la ligne n’est pas droite (cf. photo après la vidéo) !

straight line 2

5 Sortons les grands moyens

Mon hypothèse est que mes problèmes viennent d’un assemblage peu précis (maquette et patte) et que les mesures approximatives de mes constantes à la règle n’arrangent rien à l’affaire !

Pour pallier à ce problème, j’aimerais d’abord renforcer un petit peu ma maquette pour rigidifier la partie verticale, actuellement trop flexible. Aussi je prévois de tester une approche par apprentissage. Pour cela, il faut commencer par collecter des données expérimentales, puis faire tourner un algorithme d’optimisation pour qu’il calcule les valeurs des constantes qui donnent la meilleurs corrélation avec les données expérimentales. Me restera alors plus qu’à tester expérimentalement mon code avec ces valeurs.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *