Correction des interférences Steppers-Servo

Type de séance : Planifiée · Durée : 4h

Réalisé durant la scéance :

Interférences entre les Steppers et le servomoteur (actionneur)

Suite à la session précédente où j’avais réussi à actionner les steppers afin de faire rouler le PAMI, j’avais remarqué que le fait de déclarer un servomoteur suffisait à provoquer des erreurs. Les steppers devenaient sacadés, changaient de direction et vibrait, tandis que le servomoteur tournait de manière erratique même lorsqu’aucune commande ne le pilotait. Avec l’aide d’Emma Villain, nous avons effectué plusieurs essais.

Hypothèse 1 : Problème de Pins

Nous avons changé le branchement du servomoteur sur le second set de Pin dédiés aux servos. Cela n’a eu aucun impact.

Hypothèse 2 : Problème de carte

Nous avons ensuite tenté d’exécuter le programme sur une autre carte PAMI afin de voir si le problème était unique à la carte que nous utilisions. Les résultats ontté identique à la première : sacades, vibrations, servomoteur erratique… Emma a donc controlé chaque pin pour détecter de potentiels défauts. Selon ses vérifications, aucun Pin n’est défectueux ce qui se confirme par le fait que les PAMI fonctionnaient relativement bien à l’édition précédente.

Hypothèse 3 : Incompatibilité de bibliothèques

Adrien a évoqué la possibilité d’une incompatibilité entre ce certaines bibliothèques C++. J’ai donc cherché des éléments afin de vérifier cette hypothèse.

Résolution du problème

Il s’avère que la bibliothèque FastAccelStepper, contrairement à AccelStepper, utilise les modules de timer matériels afin de pouvoir calculer les mouvement des steppers en arrière-plan (lui perettant d’être beaucoup plus performant qu’AccelStepper). Or les servomoteurs utilisent ces même timer matériel afin de calculer leurs position et mouvement. Ainsi, les deux utilisait la même ressource au même moment, provoquant des interférences entre les steppers et le servomoteur.

Par défaut, les servomoteur pilotés par la bibliothèque ESP32Servo et les steppers pilotés par la bibliothèque FastAccelStepper utilisent les modules MCPWM (Motor Control PWM) & PCNT (Pulse Counter). Le module MCPWM génère les impulsions de pas tandis que le PCNT compte le nombre exact de pas effectués en arrière-plan. Comme les deux bibliothèques se servent des deux signaux en même temps, ils reçoivent par erreur des commandes parasites adressé à l’autre type de moteur et agissent de manière erratique.

La solution la plus simple est de configurer les steppers sur un second module de timer : le module RMT (Remote Control Peripheral). Le RMT fonctionne comme un générateur d’ondes programmable très précis et peut donc effectuer les même actions que les modules MCPWM et PCNT.

Pour effectuer cette configuration, il suffit de d’ajouter l’indicatif DRIVER_RMT juste après la définition des Pins Step des steppers :

FastAccelStepperEngine engine;
FastAccelStepper *leftmotor = nullptr;
FastAccelStepper *rightmotor = nullptr;

engine.init();

leftmotor = engine.stepperConnectToPin(LEFT_STEP_PIN, DRIVER_RMT);
rightmotor = engine.stepperConnectToPin(RIGHT_STEP_PIN, DRIVER_RMT);

Une fois cette commande en place, les steppers utiliserons le module RMT pour leurs calculs et laisserons les modules MCPWM et PCNT aux servomoteurs. Il n’y aura donc plus aucune interférence.

Une fois le comme téléversé dans le PAMI, les roues (steppers) et l’actionneur (servomoteur) agissent de manière indépendante.

Notre problème est résolu !

Optimisation du code

J’ai découvert de nouvelles fonctions j’ai donc pu simplier la procédure go(distanceMm)

void go(float distanceMm)
{
  leftmotor->move(!LEFT_MOTOR_INVERTED ? DistanceToStep(distanceMm) : -DistanceToStep(distanceMm));
  rightmotor->move(!RIGHT_MOTOR_INVERTED ? DistanceToStep(distanceMm) : -DistanceToStep(distanceMm));
  WaitForMotors();
}

Procédure de rotation

J’ai programmé une procédure de rotation turn(angle) allié à une fonction AngleToStep(angleDeg) convertissant les angles en degré en steps en fonction des dimentions PAMI.

// Pour les rotations et virages
#define WHEEL_BASE_MM 96.6f  // Distance entre les deux points de contact des roues (en mm)

float AngleToStep(float angleDeg)
{
  const float wheelTravelMm = (angleDeg * PI / 180.0f) * (WHEEL_BASE_MM / 2);
  return lroundf(wheelTravelMm / wheelCircumferenceMm * stepsPerWheelRevolution);
}
void turn(float angle)
{
  leftmotor->move(!LEFT_MOTOR_INVERTED ? AngleToStep(angle) : -AngleToStep(angle));
  rightmotor->move(!RIGHT_MOTOR_INVERTED ? -AngleToStep(angle) : AngleToStep(angle));
  WaitForMotors();
}

Je n’ai pas encore eu l’occasion de tester les rotations, mais cela ne devrais pas prendre trop de temps

Conclusion de la scéance :

Le PAMI est maintenant capable de se déplacer linéairement et d’utiliser ses actionneurs. Il faudra maintenant continuer les fonctions et procédures, tester les rotations, puis se pencher sur les éléments encore non pris en charge (tirette, télémètre à ultrason, switch…).

A faire lors de la prochaine scéance :

Type de tâche Description Priorité
Prgrammation continuer à programmer le PAMI 1
Documentation Mettre à jour la documentation sur la programmation des PAMI 2
Conception Brainrainstorm à propos du Graal 3