[TANGO E5] RETROFIT D'UN ROBOT TANGO E5

amauplin
Tondeur fraichement arrivé
Messages : 1
Inscription : ven. mai 17, 2024 6:19 pm

[TANGO E5] RETROFIT D'UN ROBOT TANGO E5

Message par amauplin »

Bonjour à toutes et à tous,

Voici quelques lignes pour vous décrire mon projet :

L'année dernière je me décide à acheter mon premier robot tondeuse, un John Deere Tango E5 série 1 à deux pas de chez moi. Je profite d'une après midi de beaux temps pour installer le fil périphérique. Et lance le robot. Tout fonctionne quelques petit détails a corriger sur le parcours mais rien de méchant.
Cette année je me décide à reprendre le fil périphérique afin de mieux le disposer pour que le robot soit plus efficace. Je passe une nouvelle après midi pour effectuer les travaux, vais chercher mon robot, je branche le tout, et... rien !! Petite investigation et il s'avère que les fourmis ont élue domicile dans le boitier de la base et ont fini par détériorer la carte mère de la base. Le robot ne reçois aucun signal du fil périphérique, donc il ne démarre pas. Je cherche quelques pistes et me résous à prononcer le décès de la carte de la base.

Je me retrouve donc avec un Tango orphelin qui cherche désespérément un signal de sa base.
Je me suis renseigné pour acheter une nouvelle carte pour ma base, plus de 350€ soit le prix de mon robot actuellement.
IMG_6942.jpg
IMG_6942.jpg (1.15 Mio) Consulté 1172 fois
J'ai donc décidé de dépouiller le petit mouton vert et de garder que ses trois moteurs et son châssis plutôt robuste à mon sens.

J'ai donc débuté par un peu de mécanique, une révision des roues avant avec l'ajout de roulements pour les pivot de rotation et d'autre roulements pour l'intérieur des roues. Quelques pièces en impression 3d et les roues tournent désormais comme un charme.

Ceci étant, c'est parti pour l'aventure ! Donnons un peu de plomb dans la cervelle de cette boite a roues.

Identification des moteurs :

Moteur de lame EBMPAPST ECI 63.20 24VDC 8.5A 0.36Nm 4000rpm
Moteur d'avance EBMPAPST ECI 42.20N 24VDC 1.25A 3.6Nm 40rpm

Chaque moteur ont :

3 gros fils de puissances pour les phases
A - VIOLET
B- JAUNE
C - MARRON

et 5 petit fils pour les capteurs a effet hall
VCC (5v) - ROUGE
GND - NOIR
HA - BLANC
HB - GRIS
HC - VERT

J'ai trouvé des drivers de moteur brushless qui correspondent aux spécifications :
https://www.omc-stepperonline.com/fr/co ... w-bld-510b
Facilité à régler adaptable pour les trois moteurs

Choix d'un système de batterie :
Deux batteries 12v en série pour avoir du 24v et un chargeur Victron Bluetooth pour suivre la charge lors des expérimentations.

Pour le fil périphérique il existe un kit de développement chez roboshop :
https://eu.robotshop.com/fr/products/ro ... dering-kit

Un ADXL345 pour mesurer les chocs et faire en sorte que le robot s'arrête en cas de problème

Une boussole numérique QMC5883 pour que notre aventurier du gazon garde le cap

Pour contrôler tout ce petit monde, un Arduino MEGA un peu modifié pour l'occasion.
IMG_7170.jpg
IMG_7170.jpg (1.2 Mio) Consulté 1172 fois
J'écris un petit code pour lancer un test et voila que mon robot bien immobile jusqu'à la reprend vie !

Code : Tout sélectionner

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <DFRobot_QMC5883.h>

Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
DFRobot_QMC5883 compass(&Wire, 0xD);

// DECLARATION DES BROCHES
#define MOTEUR_ROUE_GAUCHE 6                 // Broche pour le moteur de la roue gauche
#define MOTEUR_ROUE_DROITE 7                 // Broche pour le moteur de la roue droite
#define DIR_MOTEUR_ROUE_GAUCHE 5             // Broche pour la direction du moteur de la roue gauche
#define DIR_MOTEUR_ROUE_DROITE 4             // Broche pour la direction du moteur de la roue droite
#define CAPTEUR_FIL_PERPH_AVANT A5           // Broche pour le capteur de fil périphérique avant
#define CAPTEUR_FIL_PERPH_LATERAL_GAUCHE A1  // Broche pour le capteur de fil périphérique latéral gauche
#define CAPTEUR_FIL_PERPH_LATERAL_DROIT A0   // Broche pour le capteur de fil périphérique latéral droit

// Seuils des capteurs
#define VAL_DECL_CAPTEUR 50      // Seuil de détection du capteur avant
#define VAL_DECL_CAPTEUR_LAT 50  // Seuil de détection des capteurs latéraux
#define AMPLITUDE_CHOC_AVANCE 4
#define AMPLITUDE_CHOC_LATERAL 5
#define CORRECTEUR_CAP 0.8
#define KP_SUIVI_CAP 4

// VITESSES
#define VITESSE_DEPLACEMENT_TONTE 180  // Vitesse de déplacement rapide
#define VITESSE_APPROCHE 60            // Vitesse d'approche

// VARIABLES
int VAL_CAP_AVANT = 0;  // Valeur du capteur avant
int VAL_CAP_AVANT_ANCIEN;
int VAL_CAP_LATERAL_GAUCHE = 0;  // Valeur du capteur latéral gauche
int VAL_CAP_LATERAL_GAUCHE_ANCIEN;
int VAL_CAP_LATERAL_DROIT = 0;  // Valeur du capteur latéral droit
int VAL_CAP_LATERAL_DROIT_ANCIEN;

int CAP_ACTUEL;
int CAP_CIBLE = 90;

void setup() {
  Serial.begin(9600);
  // Configuration des broches en sortie
  pinMode(MOTEUR_ROUE_GAUCHE, OUTPUT);
  pinMode(MOTEUR_ROUE_DROITE, OUTPUT);
  pinMode(DIR_MOTEUR_ROUE_GAUCHE, OUTPUT);
  pinMode(DIR_MOTEUR_ROUE_DROITE, OUTPUT);

  if (!accel.begin()) {
    while (1)
      Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
  }
  if (!compass.begin()) {
    while (1)
      Serial.println("Could not find a valid QMC5883 sensor, check wiring!");
  } else if (compass.isQMC()) {
    Serial.println("Initialize QMC5883");
  }

  // Démarrage de la communication série
}

void loop() {
  float declinationAngle = (4.0 + (26.0 / 60.0)) / (180 / PI);
  compass.setDeclinationAngle(declinationAngle);
  sVector_t mag = compass.readRaw();
  compass.getHeadingDegrees();
  CAP_ACTUEL = mag.HeadingDegress*CORRECTEUR_CAP;

  // Lecture des capteurs
  VAL_CAP_AVANT = (analogRead(CAPTEUR_FIL_PERPH_AVANT) * 0.6) + (VAL_CAP_AVANT_ANCIEN * 0.4);
  VAL_CAP_LATERAL_GAUCHE = (analogRead(CAPTEUR_FIL_PERPH_LATERAL_GAUCHE) * 0.6) + (VAL_CAP_LATERAL_GAUCHE_ANCIEN * 0.4);
  VAL_CAP_LATERAL_DROIT = (analogRead(CAPTEUR_FIL_PERPH_LATERAL_DROIT) * 0.6) + (VAL_CAP_LATERAL_DROIT_ANCIEN * 0.4);

  // Lecture de l'accéléromètre
  sensors_event_t event;
  accel.getEvent(&event);

  // Vérification de la détection de choc
  if (event.acceleration.x > AMPLITUDE_CHOC_AVANCE || event.acceleration.y > AMPLITUDE_CHOC_LATERAL) {
    // Si un choc est détecté, arrêter les moteurs
    ARRET();
    while (1) { Serial.println("Choc détecté. Arrêt du robot."); }
  }

  // Affichage des valeurs des capteurs dans le moniteur série

  Serial.print("CAPT_BORD: ");
  Serial.print(VAL_CAP_LATERAL_GAUCHE);
  Serial.print(" - ");
  Serial.print(VAL_CAP_AVANT);
  Serial.print(" - ");
  Serial.print(VAL_CAP_LATERAL_DROIT);
  Serial.print(" / CAP_CIBLE: ");
  Serial.print(CAP_CIBLE);
  Serial.print(" - CAP_ACTUEL: ");
  Serial.println(CAP_ACTUEL);


  // Logique de déplacement en fonction des valeurs des capteurs
  if ((VAL_CAP_AVANT > VAL_DECL_CAPTEUR) || (VAL_CAP_LATERAL_GAUCHE > VAL_DECL_CAPTEUR_LAT && VAL_CAP_LATERAL_DROIT > VAL_DECL_CAPTEUR_LAT)) {
    Serial.println("FIL PERIPHERIQUE DETECTE - DEMI TOUR");
    // Si le capteur avant détecte le fil périphérique, arrêter et reculer
    ARRET();
    delay(800);  // Attendre un moment
    DEMI_TOUR_DROITE(VITESSE_APPROCHE, 4000);
    CAP_CIBLE = (CAP_CIBLE + 180) % 360;
    delay(800);  // Réajuster le délai si nécessaire
  } else if (VAL_CAP_LATERAL_GAUCHE > VAL_DECL_CAPTEUR_LAT) {
    Serial.println("FIL PERIPHERIQUE DETECTE - ORIENTATION");  // Si le capteur latéral gauche détecte le fil périphérique, tourner à droite
    VIRAGE_DROITE(VITESSE_APPROCHE, 200);                      // Réajuster la durée de virage si nécessaire
  } else if (VAL_CAP_LATERAL_DROIT > VAL_DECL_CAPTEUR_LAT) {
    // Si le capteur latéral droit détecte le fil périphérique, tourner à gauche
    VIRAGE_GAUCHE(VITESSE_APPROCHE, 200);  // Réajuster la durée de virage si nécessaire
    Serial.println("FIL PERIPHERIQUE DETECTE - ORIENTATION");
  } else {
    // Si aucun capteur ne détecte le fil périphérique, avancer
    AVANCER_CAP(CAP_CIBLE, VITESSE_DEPLACEMENT_TONTE);
  }
  VAL_CAP_AVANT_ANCIEN = VAL_CAP_AVANT;
  VAL_CAP_LATERAL_GAUCHE_ANCIEN = VAL_CAP_LATERAL_GAUCHE;
  VAL_CAP_LATERAL_DROIT_ANCIEN = VAL_CAP_LATERAL_DROIT;
}

// Fonctions de contrôle des mouvements

void AVANCE(int vitesse) {
  digitalWrite(DIR_MOTEUR_ROUE_GAUCHE, LOW);
  digitalWrite(DIR_MOTEUR_ROUE_DROITE, HIGH);
  analogWrite(MOTEUR_ROUE_GAUCHE, vitesse);
  analogWrite(MOTEUR_ROUE_DROITE, vitesse);
}

void AVANCER_CAP(int cap_cible, int vitesse) {
  float erreur_cap;
  const float tolerance_cap = 1;  // Tolérance d'erreur de cap

  // Calcul de l'erreur entre le cap actuel et le cap cible
  erreur_cap = cap_cible - CAP_ACTUEL;

  // Correction de l'erreur si elle dépasse 180 degrés
  if (erreur_cap > 180) {
    erreur_cap -= 360;
  } else if (erreur_cap < -180) {
    erreur_cap += 360;
  }

  // Si l'erreur est supérieure à la tolérance, corriger le cap en tournant
  if (abs(erreur_cap) > tolerance_cap) {
    if (erreur_cap > 0) {
      int correction = abs(erreur_cap)*KP_SUIVI_CAP;
      VIRAGE_FAIBLE_GAUCHE(vitesse, 100, correction);
    } else {
      int correction = abs(erreur_cap)*KP_SUIVI_CAP;
      VIRAGE_FAIBLE_DROITE(vitesse, 100, correction);
    }
  } else {
    // Si l'erreur est dans la tolérance, avancer en ligne droite
    AVANCE(vitesse);
  }
}

void ARRET() {
  analogWrite(MOTEUR_ROUE_GAUCHE, 0);
  analogWrite(MOTEUR_ROUE_DROITE, 0);
}

void VIRAGE_DROITE(int vitesse, int time) {
  digitalWrite(DIR_MOTEUR_ROUE_GAUCHE, LOW);
  digitalWrite(DIR_MOTEUR_ROUE_DROITE, LOW);
  analogWrite(MOTEUR_ROUE_GAUCHE, vitesse);
  analogWrite(MOTEUR_ROUE_DROITE, vitesse);
  delay(time);
  ARRET();
}

void VIRAGE_FAIBLE_DROITE(int vitesse, int time, int force) {
  digitalWrite(DIR_MOTEUR_ROUE_GAUCHE, LOW);
  digitalWrite(DIR_MOTEUR_ROUE_DROITE, HIGH);
  analogWrite(MOTEUR_ROUE_GAUCHE, vitesse - force);
  analogWrite(MOTEUR_ROUE_DROITE, vitesse);
  delay(time);
  ARRET();
}

void VIRAGE_GAUCHE(int vitesse, int time) {
  digitalWrite(DIR_MOTEUR_ROUE_GAUCHE, HIGH);
  digitalWrite(DIR_MOTEUR_ROUE_DROITE, HIGH);
  analogWrite(MOTEUR_ROUE_GAUCHE, vitesse);
  analogWrite(MOTEUR_ROUE_DROITE, vitesse);
  delay(time);
  ARRET();
}

void VIRAGE_FAIBLE_GAUCHE(int vitesse, int time, int force) {
  digitalWrite(DIR_MOTEUR_ROUE_GAUCHE, LOW);
  digitalWrite(DIR_MOTEUR_ROUE_DROITE, HIGH);
  analogWrite(MOTEUR_ROUE_GAUCHE, vitesse);
  analogWrite(MOTEUR_ROUE_DROITE, vitesse - force);
  delay(time);
  ARRET();
}

void DEMI_TOUR_DROITE(int vitesse, int time) {
  digitalWrite(DIR_MOTEUR_ROUE_GAUCHE, LOW);
  digitalWrite(DIR_MOTEUR_ROUE_DROITE, LOW);
  analogWrite(MOTEUR_ROUE_GAUCHE, vitesse);
  analogWrite(MOTEUR_ROUE_DROITE, vitesse);
  delay(time);
}
IMG_7084.jpg
IMG_7084.jpg (1.14 Mio) Consulté 1172 fois
J'ai encore de nombreux problèmes à régler :

- Cap non fiable
- Vitesse de moteurs roues en boucle ouverte
- Pas d'IMU
- Pas de capteur en cas d'obstacle non couvert par les fils périphérique
- Pas de retour a la base automatique ni de guidage vers celle ci
- Faux contacts au niveau des connexions
et j'en passe qui viendront plus tard.

Pour les intéressés et les intéressants, hésitez par a brainstormer des idées de solutions technique dans les commentaires pour faire avancer mon projet. Je suis actuellement sur un développement de carte PCB dédié pour continuer a travailler sur mon projet. Ajout d'un IMU avec boussole électronique witmotion 901B en I2C, Ajout d'une puce GPS pour localiser le robot, Ajout d'une antenne HC12 pour communiquer entre la base et le robot, entre une télécommande et le robot...

Bonne lecture et curieux d'avoir vos retours,
Bonne soirée
A
Electric_Sheep
Tondeur fraichement arrivé
Messages : 1
Inscription : ven. août 30, 2024 5:54 pm

Re: [TANGO E5] RETROFIT D'UN ROBOT TANGO E5

Message par Electric_Sheep »

Bien le bonjour Amauplin !

Je découvre tout juste ce thread prometteur, merci pour le partage de votre expérience.
Un Tango E5 en panne est arrivé chez moi il y a quelques jours, le but étant justement de le rétrofiter! ^^

Suis pas mécontent de croiser par hasard quelqu'un qui a eu la même drôle d'idée, encore merci!

Par ici, je pensais de base partir non pas sur de l'Arduino, mais sur un ensemble comprenant une carte Pixhawk pour la navigation avec INAV, un ESP32 pour la gestion d'énergie, des outils et accessoires (avec du RTK); ainsi qu'une camera OpenIPC pour la retransmission du signal video en HD: pour tondre chez moi ou ailleurs depuis mon canapé, en manuel ou en automatique.

Pour en reparler?
Répondre