Odometrie robot tondeuse

Bonjour, je suis toujours sur mon projet de robot tondeuse.

Voici la configuration:

2 moteurs CC , dont un pour la roue droite et un pour la roue gauche.

Capteur de position monté sur l'axe de roue ou du moteur, et sortie en quadrature de phase pour chacun des moteurs.

Je souhaite utiliser une arduino mega pour recuperer la position des moteurs.

Je cherche donc des methodes pour gerer la position du robot.

Pour demarrer je souhaite simplement faire rouler le robot tout droit a une vitesse variable.

Pour faire des tests j'ai commandé ceci sur aliexpress:

https://fr.aliexpress.com/item/1005008001263253.html?spm=a2g0o.order_list.order_list_main.11.35935e5bINBrXZ&gatewayAdapt=glo2fra

Mes capteurs sont ceux la:

https://fr.aliexpress.com/item/1005005071771659.html?algo_pvid=960b9d57-dd1a-4073-9831-78722e0f4cb4&algo_exp_id=960b9d57-dd1a-4073-9831-78722e0f4cb4-1&pdp_npi=4%40dis!EUR!6.15!5.29!!!6.29!5.41!%40211b613917323674125256908ec77c!12000031526886199!sea!FR!4329881368!X&curPageLogUid=USwI5I5Tw9ey&utparam-url=scene%3Asearch|query_from%3A

Est ce que quelqu'un aurais déja fait se genre demontage? Je cherche des infos sur la methode a utiliser.

Merci d'avance

vos encodeurs peuvent vous donner la vitesse de chaque roue. Dans le cas idéal, si les vitesses sont égales, vous allez tout droit.

On peut utiliser l'approche avec un PID pour maintenir cette vitesse identique sur les deux roues. on trouve des trucs sur internet, par exemple ici

Mais dans la pratique (et surtout sur terrain extérieur) vous pouvez déraper d'un côté et la roue tourne mais la tondeuse n'a pas bougé...

Je viens de regarder, il n'y a pas d'exemple de code. Juste un programme sans asservissement

Par contre je viens de me rendre compte que le capteur a sortie en quadrature de phase n'est apparement pas necessaire.

Bonjour cyrilcarlita2

Les servo que tu as commandé ne te donnent aucune information en retour.
Le capteur que tu as est un peu trop précis pour ce genre d'application, mais peut être tout à fait utilisable quand même.
L'idéal est de prendre des moteurs avec codeur attenant:
Il y en a même avec une roue.


La résolution de l'encodeur par tour de roue, est la réduction * 11 (11 étant le nombre d'impulsions à l'axe du moteur)

Pour "lire" ces encodeurs, il y a la bibliothèque Encoder.h.

Pour commander tes moteur, via des signaux PWM, il te faut des ponts en H comme ceci:
image

Qui est un pont qui peut commander 2 moteurs. Ce pont est bien entendu, pour le type de moteur ci-dessus :wink:

PS: Au vu de la photo du post#6, ma proposition est bien sûre que pour essayer la "mécanique" en plus petit.

Cordialement
jpbbricole

Bonsoir,

Je me permets une petite intrusion dans ce fil en espérant qu'elle sera courte.

Je connaissais les petits servo-moteurs à débattement limité.

Apparemment, le servo-moteur employé ici est à rotation continue. Pour autant, pour le commander, il faut lui envoyer un créneau dont la largeur va définir sa position.

Donc, je suppose que si on veut une rotation continue, lorsque l'on a atteint la position "360°" avec un créneau de largeur maxi, il faut tout de suite envoyer un créneau de largeur mini pour le faire basculer à la position "0°" ... en espérant qui aille à la position "0°" en continuant sa rotation et non pas en revenant en marche arrière. Oui, non ?

Cordialement.

Pierre.

En fait ma tondeuse ressemble a sa: (je la reçois mardi, je pourrais ainsi l'examiner en détail elle est piloté par une radiocommande type modélisme)

Moteur en 24v avec reducteur

Bonsoir ChPr

Dans le cas des servo 360°, le créneau décide de la vitesse de rotation, pas de l'angle, ce moteur est à l'arrêt, manche au milieu.
C'est un abus de langage que d'appeler ça un servo, c'est plus un moteur asservi en vitesse.

Cordialement
jpbbricole

Bonsoir cyrilcarlita2

Pour entraîner ces moteurs, c'est ce genre de pont en H:
image

Cordialement
jpbbricole

Je pense pouvoir reutiliser l'electronique qui gere le motoreducteur. Si c'est pas possible je testerais un module de ce type...

Je cherche des infos sur l'asservissement , j'ai jamais fais se genre de truc.

Bonsoir cyrilcarlita2

Il s'agit de lire les encodeurs et de transposer ça en signaux de commande des moteur, en général du PWM.
Tu peux essayer de poser la question du comment à ChatGPT, c'est bonne expérience :wink:

Cordialement
jpbbricole

'servo 360' = rotation continue en fait = moteurs dont la vitesse de rotation dépend de la largeur de l'impulsion reçue( signal analogue à celui envoyé aux vrais servos

Asservissement me parait excessif pour ces 'ex-servos (asservissement de position) mis en boucle ouverte'

on a une variation de vitesse, pas d'asservissement

Pour faire simple, je veux retirer la radiocommande et piloter les moteurs avec ma carte arduino mega qui elle meme est piloté par mon programme python. J'ai déja fais le programme qui gère le gps RTK pour le positionnement par satelite...

Bonsoir al1fch

Juste :+1:

Bonne soirée
jpbbricole

Merci "jpbbricole" pour cette précision : c'est donc une commande en vitesse et non en position. Voilà qui est plus clair. :slightly_smiling_face:

Cordialement.

Pierre.

Je vais tester chatgpt, on vera se qu'il me propose

Voila ce que chatgpt me propose:

#include <VarSpeedServo.h>

// Définition des pins pour les servomoteurs
#define MOTOR_LEFT_PIN 9
#define MOTOR_RIGHT_PIN 10

// Définition des pins pour les capteurs de quadrature (A et B)
#define ENCODER_LEFT_A_PIN 2
#define ENCODER_LEFT_B_PIN 3
#define ENCODER_RIGHT_A_PIN 4
#define ENCODER_RIGHT_B_PIN 5

// Variables pour le comptage des impulsions
volatile long encoderLeftCount = 0;
volatile long encoderRightCount = 0;

// Variables pour les moteurs
VarSpeedServo motorLeft;
VarSpeedServo motorRight;

// Paramètre de calibration (nombre d'impulsions par mètre)
long pulsesPerMeter = 10000; // Nombre d'impulsions pour parcourir 1 mètre

// Variables pour la gestion des commandes
char command[32];
int distanceCommand = 0;
int rotationCommand = 0;

// Fonction d'interruption pour capteur de quadrature
void encoderLeftInterruptA() {
  if (digitalRead(ENCODER_LEFT_B_PIN) == HIGH) {
    encoderLeftCount++;
  } else {
    encoderLeftCount--;
  }
}

void encoderRightInterruptA() {
  if (digitalRead(ENCODER_RIGHT_B_PIN) == HIGH) {
    encoderRightCount++;
  } else {
    encoderRightCount--;
  }
}

// Fonction d'initialisation
void setup() {
  // Initialisation des servomoteurs
  motorLeft.attach(MOTOR_LEFT_PIN);
  motorRight.attach(MOTOR_RIGHT_PIN);

  // Initialisation des capteurs de quadrature
  pinMode(ENCODER_LEFT_A_PIN, INPUT);
  pinMode(ENCODER_LEFT_B_PIN, INPUT);
  pinMode(ENCODER_RIGHT_A_PIN, INPUT);
  pinMode(ENCODER_RIGHT_B_PIN, INPUT);

  // Attachement des interruptions
  attachInterrupt(digitalPinToInterrupt(ENCODER_LEFT_A_PIN), encoderLeftInterruptA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_RIGHT_A_PIN), encoderRightInterruptA, CHANGE);

  // Initialisation du port série pour recevoir les commandes
  Serial.begin(9600);
  Serial.println("Prêt à recevoir des commandes.");
}

// Fonction pour avancer
void moveForward(int distanceInCm) {
  long targetPulses = distanceInCm * (pulsesPerMeter / 100); // Conversion en impulsions

  encoderLeftCount = 0;
  encoderRightCount = 0;

  motorLeft.write(90); // Moteur gauche à pleine vitesse dans le sens horaire
  motorRight.write(90); // Moteur droit à pleine vitesse dans le sens horaire

  while (encoderLeftCount < targetPulses && encoderRightCount < targetPulses) {
    // Attente jusqu'à ce que la distance soit parcourue
  }

  motorLeft.write(0); // Arrêt du moteur gauche
  motorRight.write(0); // Arrêt du moteur droit
}

// Fonction pour reculer
void moveBackward(int distanceInCm) {
  long targetPulses = distanceInCm * (pulsesPerMeter / 100); // Conversion en impulsions

  encoderLeftCount = 0;
  encoderRightCount = 0;

  motorLeft.write(10); // Moteur gauche à pleine vitesse dans le sens antihoraire (recul)
  motorRight.write(10); // Moteur droit à pleine vitesse dans le sens antihoraire (recul)

  while (encoderLeftCount < targetPulses && encoderRightCount < targetPulses) {
    // Attente jusqu'à ce que la distance soit parcourue
  }

  motorLeft.write(0); // Arrêt du moteur gauche
  motorRight.write(0); // Arrêt du moteur droit
}

// Fonction pour tourner à droite
void rotateRight(int angle) {
  long targetPulses = angle * (pulsesPerMeter / 360); // Conversion de l'angle en impulsions

  encoderLeftCount = 0;
  encoderRightCount = 0;

  motorLeft.write(90); // Moteur gauche en marche avant
  motorRight.write(0); // Moteur droit en marche arrière

  while (encoderLeftCount < targetPulses) {
    // Attente jusqu'à ce que l'angle soit parcouru
  }

  motorLeft.write(0); // Arrêt du moteur gauche
  motorRight.write(0); // Arrêt du moteur droit
}

// Fonction pour tourner à gauche
void rotateLeft(int angle) {
  long targetPulses = angle * (pulsesPerMeter / 360); // Conversion de l'angle en impulsions

  encoderLeftCount = 0;
  encoderRightCount = 0;

  motorLeft.write(0); // Moteur gauche en marche arrière
  motorRight.write(90); // Moteur droit en marche avant

  while (encoderRightCount < targetPulses) {
    // Attente jusqu'à ce que l'angle soit parcouru
  }

  motorLeft.write(0); // Arrêt du moteur gauche
  motorRight.write(0); // Arrêt du moteur droit
}

void loop() {
  // Vérification des données reçues par le port série
  if (Serial.available() > 0) {
    // Lecture de la commande série
    int index = 0;
    while (Serial.available() > 0 && index < sizeof(command) - 1) {
      command[index] = Serial.read();
      if (command[index] == '\n' || command[index] == '\r') break; // Fin de commande
      index++;
    }
    command[index] = '\0'; // Fin de chaîne

    // Analyse et exécution de la commande
    if (strncmp(command, "avance-", 7) == 0) {
      distanceCommand = atoi(&command[7]);
      moveForward(distanceCommand);
    }
    else if (strncmp(command, "reculer-", 8) == 0) {
      distanceCommand = atoi(&command[8]);
      moveBackward(distanceCommand);
    }
    else if (strncmp(command, "rotation_droite-", 16) == 0) {
      rotationCommand = atoi(&command[16]);
      rotateRight(rotationCommand);
    }
    else if (strncmp(command, "rotation_gauche-", 17) == 0) {
      rotationCommand = atoi(&command[17]);
      rotateLeft(rotationCommand);
    }
    else {
      Serial.println("Commande non reconnue.");
    }
  }
}

Qu'en pensez vous?

Bonjour cyrilcarlita2

C'est à toi d'essayer, quelles sont tes compétences en Arduino et autres?

J'ai posé la question à ChatGPT en lui posant, intégralement ton post #1 en précisant avec Encoder comme bibliothèque, regardes.

Cordialement
jpbbricole

Bonjour,
.Je ne comprend pas bien vos besoins.
Vous nous annoncez

Donc de fait, vous achetez quelque chose qui se vend, et dont on suppose qu'elle marche.

Donc il vaud mieux réutiliser tout ce qui y est incorporé et étudié pour les besoins de cet engin.

Pour l'instant, vous ne l'avez pas encore examinée, donc vous ne savez pas encore exactement quels sont vos besoins.

N'est'il pas?:thinking:

Si j’ai bien compris, Il a expliqué que ce modèle fonctionne avec une télécommande et qu’il veut enlever la télécommande pour mettre un arduino à la place du récepteur radio et que l’arduino pilote le robot de façon autonome grâce à son autre projet de GPS différentiel.

Bonsoir,

Oui çà j'ai bien compris, mais ce que vous décrivez, c'est "l’intelligence" de la machine, les "muscles" (l'électronique de puissance, les moteurs...) sont probablement parfaitement adapté, il est donc fort probable qu'il n'y ais pas besoin d'un nouveau "pont en H" ou autres...