Besoin d'un peu d'aide pour mon robot autonome

Bonjour tout le monde,

Voila, je suis nouveau dans le monde de l'Arduino, de l'electronique et de la programmation, et apres avoir realise quelques petits projets tres basiques et avoir appris les rudiments du code, je me retrouve aujourd'hui un peu bloque et j'aurais donc besoin de votre aide, etant donne que je ne suis pas parvenu pour le moment a trouver des reponses a mon probleme sur le net ni a imaginer une solutionqui puisse fonctionner.

Mon projet est assez simple, je suis en train de faire un robot autonome a deplacement aleatoire.
Le robot est deja realise et fonctionne, simplement je souhaiterais ameliorer certains aspects, notamment son comportement en cas de blocage contre un obstacle non detectable.

Deja, un peu de description:
Le robot foncionne grace a une carte arduino uno, deux servos MG995, deux capteurs ultrasons en facade et deux interrupteurs de contact eux aussi en facade pour detecter les chocs. Le chassis est pour le moment en carton, et la batterie est une 7.2V 6 elements 1800mah qui alimente directement l'arduino ainsi que les servos.

Le robot fonctionne plutot bien, mais il lui arrive a certaines occasions de se retrouver coince dans des recoins de mon appartement, car il heurte parfois des obstacles situes au dessus de son champ de vision et hors d'atteinte des capteurs de contact et continue a avancer indefiniment dans le vide.

Sa logique de base fonctionne comme suit:
-s'il n'y a rien devant lui sur une distance superieure a 6cm, il va tout droit.
-si le capteur ultrasons gauche detecte un obstacle a moins de 6cm, le robot fait machine arriere et tourne a 90 degres vers la droite, puis repart sur le cycle marche avant
-meme principe pour un obsatcle du cote droit,
-meme principe egalement en ce qui concerne la detection des chocs

Je voudrais en fait faire en sorte que le robot ne puisse effectuer une marche avant que pendant un temps maximal defini a l'avance, puis qu'une fois ce temps passe il effectue une marche arriere puis change de trajectoire. Ca permettrait de lui eviter de mouliner betement pendant des heures lorsqu'il se retrouve bloque et de pouvoir repartir dans une autre direction, le tout sans avoir a ajouter de capteur supplementaire.

Or, le probleme c'est qu'il faut que le robot puisse continuer a detecter les obstacles lorsque celui ci se trouve en marche avant. Or avec les methodes que j'utilise, ca ne fonctionne pas. Je comprends tres bien pourquoi ca ne marche pas, mais n'ai aucune idee de la facon de contourner ce probleme.

Savez vous comment je peux m'y prendre pour faire en sorte que le robot avance pendant un certain temps, revienne en arriere puis tourne tout en continuant de prendre en compte les entrees des capteurs en permanence?

Merci beaucoup d'avance pour votre aide!

bonjour,
l'aléatoire s'appelle ramdom

Bonjour Infobarquee,

Merci pour ta reponse rapide, mais je ne pense pas que ca repondre completement a ma question (ou peut etre que j'ai mal compris, auquel cas excuse moi). Ca peut toutefois m'etre utile pour fixer un temps de declenchement aleatoire, donc je vais garder ca de cote!

Je n'ai pas acces a mon code la tout de suite, mais voila en tres gros et simplifie a quoi ca ressemble au niveau de la partie loop:

void loop(){

if (ultrasonicdistance>6){
   Servo1.write(120)
   Servo2.write(70)
   Delay(150)}

else if (0<ultrasonicdistance<6){
   Servo1.write(70)
   Servo2.write(120)
   delay(800)
   Servo1.write(60)
   Servo2.write(60)}


else if (capteur1 == HIGH){
   Servo1.write(70)
   Servo2.write(120)
   delay(800)
   Servo1.write(60)
   Servo2.write(60)}
   
}

Ce que je voudrais, ce serait arriver a un resultat un peu comme ci dessous, le robot avancerait pendant 15 secondes au maximum tant qu'aucun capteur ne lui dit de faire le contraire.
Le probleme c'est que lorsque je fais ca avec ce code, le robot ne s'arrete pas malgre la presence d'un obstacle, il continue a avancer jusqua ce que les 15 secondes + la marche ariere/pivot soit finis avant de recommencer un nouveau cycle de detection:
Encore une fois, je comprends pourquoi ca ne fonctionne pas mais je ne vois pas comment contourner le probleme...

void loop(){

if (ultrasonicdistance>6){
   Servo1.write(120)
   Servo2.write(70)
   Delay(15000)

   Servo1.write(70)
   Servo2.write(120)
   delay(800)
   Servo1.write(60)
   Servo2.write(60)



}

else if (0<ultrasonicdistance<6){
   Servo1.write(70)
   Servo2.write(120)
   delay(800)
   Servo1.write(60)
   Servo2.write(60)}


else if (capteur1 == HIGH){
   Servo1.write(70)
   Servo2.write(120)
   delay(800)
   Servo1.write(60)
   Servo2.write(60)}
   
}

Ne pas accorder trop d'importance a la redaction du code ci dessus, c'est juste pour expliquer l'idee en gros vu que je ne l'ai pas sous la main tout de suite...

Merci d'avance!

dans ce cas, ne mets pas ceci :wink:

Mon projet est assez simple, je suis en train de faire un robot autonome a deplacement aleatoire.

je pense que pour contourner ton pb, il faut revoir la position de tes capteurs et contacts.
mais sans le code entier, pas évident.

ta logique n'est pas bonne dans tes bouts de code.
je ferai un truc de ce genre

on lit valeurs US et état contact
si US>5 ET contact LOW => tout droit
si US < 7 OU contact HIGH => marche arrière et on tourne

dans ton code tu ne regarde qu'une condition à la fois, donc pas top.
pas besoin de delay, sauf pour donner le temps aux US de renvoyer l'info.

En fait, par aleatoire, j'entends que le robot n'a aucune idee de son positionnement et se deplace plus ou moins de facon aleatoire dans la piece.
Desole pour la mauvaise formulation.

on lit valeurs US et état contact
si US>5 ET contact LOW => tout droit

En fait c'est bien comme ca dans ma version actuelle, meme un peu plus complique vu que j'ai deux capteurs ultrasons et 2 contacts, mais tu as raison de le souligner

si US < 7 OU contact HIGH => marche arrière et on tourne

Je prefere que le robot effectue des actions differentes selon s'il a percute quelque chose ou selon s'il a detecte quelque chose a distance, d'ou ce choix. Modifier le positionnement des capteurs est une solution possible mais que je prefererais eviter pour tout un tas de raisons...

L'interet pour moi de pouvoir faire fonctionner les detecteurs tout en effectuant un deplacement programme serait non seulement d'eviter toute situation de blocage prolonge mais aussi de lui permettre d'adopter des trajectoires moins rectilignes, pour augmenter ses chances de visiter des endroits moins accessibles. Au lieu d'aller tout le temps en ligne droite, il pourrait faire par exemple 3 metres en avant, tourner a gauche, avancer de deux metres, tourner a droite et ainsi de suite jusqua ce qu'il detecte un obstacle et recommence cette routine.

pas besoin de delay, sauf pour donner le temps aux US de renvoyer l'info.

Edit: Je mets le delay pour que les servos puissent atteindre leur position, sans delay comment puis je faire en sorte que le robot recule selon une distance definie ou tourne selon un angle defini?

Je prefere que le robot effectue des actions differentes selon s'il a percute quelque chose ou selon s'il a detecte quelque chose a distance, d'ou ce choix. Modifier le positionnement des capteurs est une solution possible mais que je prefererais eviter pour tout un tas de raisons...

pourquoi se compliquer la vie au niveau de la détection?

L'interet pour moi de pouvoir faire fonctionner les detecteurs tout en effectuant un deplacement programme serait non seulement d'eviter toute situation de blocage prolonge mais aussi de lui permettre d'adopter des trajectoires moins rectilignes, pour augmenter ses chances de visiter des endroits moins accessibles. Au lieu d'aller tout le temps en ligne droite, il pourrait faire par exemple 3 metres en avant, tourner a gauche, avancer de deux metres, tourner a droite et ainsi de suite jusqua ce qu'il detecte un obstacle et recommence cette routine.

faut peut être arrêter ton cahier des charges :slight_smile:
pose sur le papier ce que tu veux exactement et fais tes conditions après.

Salut Forcerouge, je pense que tu aurais intérêt à utiliser des fonctions.
Quand certaines conditions sont réunies (if(......){
Tu envoie le prog dans une fonction:
la_fonction();
} //fin if
//......
la_fonction(){
//ici tu fait ce que tu veux pendant un temps donné; ou tu soumets à des tests...ext
} // fin de la fonction, le prog retourne d'où il est parti

Edit: Tu peux également passer des paramètres à (aux) fonction(s).

pourquoi se compliquer la vie au niveau de la détection?

Pour plusieurs raisons:
-qu'il couvre la plus grande zone possible, en faisant par exemple des zigzag au lieu d'aller tout droit
-parce qu'il peut se retrouver bloque par plein d'obstacles differents et que meme avec tous les capteurs possibles il est impossible de prendre en compte tous les cas de figure qui pourraient se presenter, donc il peut se retrouver bloque dans certaines situations
-pour conserver une taille adaptee
-pour conserver des pins disponibles afin de commander d'autres fonctions non necessaires au deplacement

faut peut être arrêter ton cahier des charges
pose sur le papier ce que tu veux exactement et fais tes conditions après.

Mon cahier des charges est deja pas mal defini et ce que je demande me parait plutot simple:

-si rien devant (cas1): avancer pendant 15 sec tout en continuant a verifier en permanence qu'il n'y a rien devant, puis faire demi tour au bout de ces 15 secondes. Si pendant ces 15 secondes l'appareil detecte un obstacle, passer au cas 2 immediatement aumoment de la detection, meme si l'action n'est pas terminee.
-autrement (cas 2): eviter l'obstacle puis rpartir sur le cas 1

Ca me parait tres simple a visualiser nettement moins a programmer mais peut etre que j'explique mal...
Le seul truc c'est que je souhaite que les action consecutives a la detection d'un obstacle aient la priorite par rapport aux actions de deplacement.

Merci pour tes reponses en tout cas, c'est sympa, meme si pour le moment je ne sais toujours pas comment proceder :slight_smile:

Carolyne:
Salut Forcerouge, je pense que tu aurais intérêt à utiliser des fonctions.
Quand certaines conditions sont réunies (if(......){
Tu envoie le prog dans une fonction:
la_fonction();
} //fin if
//......
la_fonction(){
//ici tu fait ce que tu veux pendant un temps donné; ou tu soumets à des tests...ext
} // fin de la fonction, le prog retourne d'où il est parti

Edit: Tu peux également passer des paramètres à (aux) fonction(s).

Ahhh, merci Carolyne, je pense que la je suis sur la bonne voie!

Je comptais justement modifier mon code pour integrer ces fonctions, et ce que tu dis me conforte justement dans cette idee!
Dans ton post, tu parles, de "fin if", qui est , je pense, la partie cle qui me permettrait d'y parvenir.

Comment faire du coup exactement pour mettre fin a cette fonction dans le cas ou un detecteur repere quelque chose?
Pourrais tu me donner un exemple concret pour que je puisse me rendre compte de comment ca s'ecrirait plus ou moins?

J'essaierai de poster une version de mon code tout a l'heure pour que ca soit plus clair et plus simple a comprendre pour tout le monde.
Merci en tout cas

Comment faire du coup exactement pour mettre fin a cette fonction

Tu remarquera que j'ai mis le "fin if" en commentaire (derrière des "//")
C'est parce qu'en fait, les blocs se fermes avec l'accolade fermante "}"
Pour un test conditionnel "if(...)"; quand la condition n'est plus vraie le prog sort du bloc et execute la suite (ce qu'il y a après).
Pareil avec les fonctions; pareil avec les whiles.
Comme l'a dit infobarquee, il faut que tu mette sur papier ton prog en pseudo-code (en français quoi), genre :
si telle situation alors faire ceci
mais si telle autre aussi alors faire cela
....ext.
Soumets le pseudo-code; et déjà on verra si c'est cohérent. Quand ton truc sera au point, il suffira de le traduire en syntaxe Arduino.
ça paraît facile, mais tu va voir que ça ne l'est pas si tant. Il faut que tu visualise chaque cas, chaque actions de la bestiole.

Déjà il faut bannir les delay() qui bloquent l'exécution. Il faut remplacer ça par une gestion du temps avec millis().
Mais cela à pour conséquence une refonte de ton programme.
En gros il faut utiliser millis() de cette façon:

duree = xxxx      // cette variable contient la durée de la temporisation à effectuer
temps = millis();
hors_temps=TRUE;
while(temps+duree<millis()){
  //bloc de code exécuté pendant l'attente
  // ici tu peux tester des capteurs et prendre des décisions
  // si tu trouves une condition de sortie anticipée tu fais
  hors_temps=FALSE;  // pour indiquer que l'on est sortie avant la fin de la temporisation
  break;    // pour sortir du while avant la condition de fin
  // suite du code exécuté pendant l'attente
}
if (hors_temps){
   // code exécuté si sortie après le delais
}else{
   // code exécuté si sortie prématurée
}

Merci deja pour vos reponses!

Je vais essayer vos deux propositions, deja de mettre par ecrit la description de ce que je souhaite que le programme fasse precisement ainsi qu'essayer de regarder du cote de la fonction millis()

Pour le moment, j'ai modifie mon code pour le decouper plutot par fonctions, sur les conseils de Carolyne. Le voici donc:

#include <Servo.h>
Servo Droite;
Servo Gauche;

const int serialPeriod = 250;       // only print to the serial console every 1/4 second
unsigned long timeSerialDelay = 0;
//long TempsMarcheAvantMax = 15000;
const int loopPeriod = 20;          // a period of 20ms = a frequency of 50Hz
unsigned long timeLoopDelay = 0;


// specify the trig & echo pins used for the ultrasonic sensors
const int TrigPin = 10;
const int EchoPin = 11;
const int TrigPinGauche = 12;
const int EchoPinGauche = 13;

long unsigned ultrasonic2Distance;
long unsigned ultrasonicGDistance;
int ultrasonic2Duration;
int ultrasonicGDuration;
int OnOff = 4;
int touchDroite = 7;
int touchGauche = 6;


void setup()
{
    Serial.begin(9600);
    Droite.attach(8); // servo on digital pin 10
    Gauche.attach(9);
    Droite.write(85);
    Gauche.write(95);
    delay(800);
    Droite.write(95);
    Gauche.write(85);
    delay(800);
    Droite.write(90);
    Gauche.write(90);
  
    // ultrasonic sensor pin configurations
    pinMode(TrigPin, OUTPUT);
    pinMode(EchoPin, INPUT);
    pinMode(OnOff, INPUT);
    pinMode(touchDroite, INPUT);
    pinMode(touchGauche, INPUT);
    pinMode(TrigPinGauche, OUTPUT);
    pinMode(EchoPinGauche, INPUT);
}


void loop()
{
    int etattouchDroite = digitalRead(touchDroite);
    int etattouchGauche = digitalRead(touchGauche);
    debugOutput(); // prints debugging messages to the serial console
    
    if(millis() - timeLoopDelay >= loopPeriod)
    {
        readUltrasonicSensors(); // read and store the measured distances
      readUltrasonicSensors2();
        timeLoopDelay = millis();
    }
    
        int etatBouton = digitalRead(OnOff);
     if(etatBouton==HIGH) { 
       Stop();
     }
    
    else if(((ultrasonic2Distance >= 7) || (ultrasonic2Distance <= 0)) && ((ultrasonicGDistance >= 6) || (ultrasonicGDistance <= 0))){ 
            MarcheAvant();
      }
   else if(ultrasonic2Distance <= 6){
     EviterDroite();
     }
     else if(ultrasonicGDistance <= 6){
     EviterGauche();
     }
     if(etattouchDroite != HIGH) {
       ContournerDroite();       
     }
     if(etattouchGauche != HIGH) {
       ContournerGauche();       
     }
     
}
void Stop(){
  Droite.write(90);
  Gauche.write(90);
}


void MarcheAvant(){
  Droite.write(80);
  Gauche.write(100);
}

void EviterDroite(){
  Droite.write(100);
  Gauche.write(80);
  delay(1500);
  Droite.write(80);
  Gauche.write(80);
  delay(1500);
}
void EviterGauche(){
  Droite.write(100);
  Gauche.write(80);
  delay(1500);
  Droite.write(100);
  Gauche.write(100);
  delay(1500);
}
void ContournerGauche(){
  Droite.write(100);
  Gauche.write(80);
  delay(1000);
  Droite.write(100);
  Gauche.write(100);
  delay(800);
}

void ContournerDroite(){
  Droite.write(100);
  Gauche.write(80);
  delay(1000);
  Droite.write(80);
  Gauche.write(80);
  delay(800);
}
void readUltrasonicSensors()
{
    // ultrasonic 2
    digitalWrite(TrigPin, HIGH);
    delayMicroseconds(10);                  // must keep the trig pin high for at least 10us
    digitalWrite(TrigPin, LOW);
    
    ultrasonic2Duration = pulseIn(EchoPin, HIGH);
    ultrasonic2Distance = (ultrasonic2Duration/2)/29;
    if (ultrasonic2Distance > 1000){
      ultrasonic2Distance = 50;
    }
    

    
}
void readUltrasonicSensors2()
{
    // ultrasonic 2
    digitalWrite(TrigPinGauche, HIGH);
    delayMicroseconds(10);                  // must keep the trig pin high for at least 10us
    digitalWrite(TrigPinGauche, LOW);
    
    ultrasonicGDuration = pulseIn(EchoPinGauche, HIGH);
    ultrasonicGDistance = (ultrasonicGDuration/2)/29;
    if (ultrasonicGDistance > 1000){
      ultrasonicGDistance = 50;
    }

    
}

void debugOutput(){
  int etatBouton=digitalRead(OnOff);
  int etattouchDroite=digitalRead(touchDroite);
    if((millis() - timeSerialDelay) > serialPeriod)
    {
        Serial.print("ultrasonDroit: ");
        Serial.print(ultrasonic2Distance);
        Serial.print("   ");
        Serial.print("UltrasonGauche:");
        Serial.print(ultrasonicGDistance);
        Serial.print("   ");
        Serial.print("cm: ");
        Serial.print(etatBouton);
        Serial.println(etattouchDroite);
        
        timeSerialDelay = millis();
    }
}

Ce code est fonctionnel, le robot se deplace correctement donc si quelqu'un souhaite l'utiliser tel quel pour son robot, aucun souci!

Voyez vous un moyen a partir de ce code d'arriver a faire en sorte que le robot puisse effectuer une suite de deplacements programmes en marche avant tout en conservant la gestion des capteurs en parallelle?

Je regarde du cote de ce que vous avez deja propose en attendant mais ca n'est pas encore tres clair pour moi.
Encore merci,

Pour plusieurs raisons:
-pour conserver des pins disponibles afin de commander d'autres fonctions non necessaires au deplacement

ca change rien car tu utilises les même pins :wink:

évidemment que le découpage par fonctions est nettement mieux.
je pensais à ca en mettant, même si non mentionné

on lit valeurs US et état contact
si US>5 ET contact LOW => tout droit
si US < 7 OU contact HIGH => marche arrière et on tourne

je connais pas la forme de ton robot, mais le fait de faire marche arrière avant de pivoter, peut éviter un blocage dans un angle.
qui dit marche arrière, dit aussi que l'on est certain de pas rencontrer d'obstacle sur 6cm au moins pour tourner, vu que l'on est arrivé par là :wink:

il faudrait que tu nous dise réellement ce a quoi va consister le robot.
topo d'une pièce, nettoyage, faire jouer le chat ou le coinc, etc...?
en fonction de tout ca et avec le papier, tu pourras déterminer tous les cas de figures, sauf un escalier qui va à la cave :slight_smile:
tu peux t'inspirer de ceci

je connais pas la forme de ton robot, mais le fait de faire marche arrière avant de pivoter, peut éviter un blocage dans un angle.
qui dit marche arrière, dit aussi que l'on est certain de pas rencontrer d'obstacle sur 6cm au moins pour tourner, vu que l'on est arrivé par là :wink:

Il recule bien dans la version de mon code actuel (voir post juste au dessus), donc pas de souci de ce cote la :wink:
Il n'y a pas vraiment de probleme quant a son fonctionnement actuel en fait, si ce n'est dans les rare cas ou il lui arrive de se bloquer contre quelque chose, auquel cas les roues vont patiner indefiniment. C'est pour ce genre de situations que j'aimerais que le robot se comporte differement au bout de 15 secondes.

il faudrait que tu nous dise réellement ce a quoi va consister le robot.

Oui c'est vrai, j'ai oublie de le mentionner, le but est de realiser un robot aspirateur,

en fonction de tout ca et avec le papier, tu pourras déterminer tous les cas de figures, sauf un escalier qui va à la cave :slight_smile:

Tout est au meme niveau chez moi hormis quelques seuils de portes qui ne posent pas de probleme majeur, du coup pas de souci de ce cote la :slight_smile:

tu peux t'inspirer de ceci
R.Damil, un mini robot ultra simple, à très basse consommation - Archives - Robot Maker

Merci, je vais jeter un coup d'oeil.

J'ai mis quelques photos de mon robot en pieces jointes afin de mieux visualiser le bestiau :wink:
En esperant qu'il vous plaise, je l'ai baptise Jean Claude.