Cours:SaeRobotiqueSuiviLigne : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
(Robot "joueur de tennis")
(Utiliser des librairies arduino avec un main)
(29 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
 +
=Utiliser des librairies arduino avec un main =
 +
 +
[[Cours:ArduinoSansLoopSetup|Arduino sans loop/setup]]
 +
 +
 +
Un certain nombre de librairies utilisent les fontions arduino [https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c delay/delayMicroseconds/millis/micros]
 +
 +
Ces fonctions utilisent le Timer0 et en particulier l'interruption de débordement.
 +
 +
Ce Timer est configuré dans la fonction [https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c init()], qui est appelée dans le [https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/main.cpp "main arduino"]
 +
 +
{|
 +
|-
 +
|
 +
On peut donc initialiser ce Timer0 pour qu'il génère un débordement tel qu'attendu.
 +
 +
Ainsi les fonctions de gestion du temps Arduino peuvent fonctionner comme prévu et on peut ainsi utiliser les librairies qui en dépendent :
 +
 +
<source lang=cpp>
 +
void initFonctionsTempsArduino()
 +
{
 +
  sei();
 +
  // marche pour 328p et 2560 et autres ...
 +
  // à adapter suivant le µc
 +
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
 +
  TCCR0A=(1<<WGM01)|(1<<WGM00);
 +
  TCCR0B=(1<<CS01)|(1<<CS00);
 +
  TIMSK0=(1<<TOIE0);
 +
}
 +
 +
int main()
 +
{
 +
  initFonctionsTempsArduino();
 +
  Serial.begin(115200);
 +
  while(1)
 +
  {
 +
    delay(100);
 +
    Serial.println(millis());
 +
  }
 +
}
 +
</source>
 +
 +
 +
 +
||
 +
<source lang=cpp>
 +
/*
 +
Exemple pour le capteur vl53l1x :
 +
cf exemple de la librairie pour des commentaires
 +
*/
 +
#include <Wire.h>
 +
#include <VL53L1X.h>
 +
VL53L1X sensor;
 +
 +
void initFonctionsTempsArduino()
 +
{
 +
  sei();
 +
  // marche pour 328p et 2560 et autres ...
 +
  // à adapter suivant le µc
 +
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
 +
  TCCR0A=(1<<WGM01)|(1<<WGM00);
 +
  TCCR0B=(1<<CS01)|(1<<CS00);
 +
  TIMSK0=(1<<TOIE0);
 +
}
 +
 +
int main()
 +
{
 +
  initFonctionsTempsArduino();
 +
  while (!Serial) {}
 +
  Serial.begin(115200);
 +
  Wire.begin();
 +
  Wire.setClock(400000); // use 400 kHz I2C
 +
  sensor.setTimeout(500);
 +
  if (!sensor.init())
 +
  {
 +
    Serial.println("Failed to detect and initialize sensor!");
 +
    while (1);
 +
  }
 +
  sensor.setDistanceMode(VL53L1X::Long);
 +
  sensor.setMeasurementTimingBudget(50000);
 +
  sensor.startContinuous(50);
 +
  while(1)
 +
  {
 +
    Serial.print(sensor.read());
 +
    if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
 +
    Serial.println();
 +
  }
 +
}
 +
</source>
 +
|}
 +
 
= Séquence 1 : tâches élémentaires individuelles =
 
= Séquence 1 : tâches élémentaires individuelles =
  
Ligne 11 : Ligne 102 :
  
 
==Livrable 1==
 
==Livrable 1==
* faire des recherches pour rendre un dossier par groupe (pour mardi 30/05) expliquant : le pont en H, schéma sécurité et chaque partie (a, b, c)
+
* faire des recherches pour rendre un dossier par groupe (pour lundi 27/05) expliquant : le pont en H, schéma sécurité et chaque partie (a, b, c)
* évaluation le 26/05 (code + questions + fonctionnement)
+
* évaluation le 24/05 (code + questions + fonctionnement)
  
 
= Séquence 2 : tâches complexes individuelles + réalisation shield =
 
= Séquence 2 : tâches complexes individuelles + réalisation shield =
Ligne 26 : Ligne 117 :
 
** carte shield arduino nano
 
** carte shield arduino nano
  
Note : penser à laisser libres PB3, PB4, PB5 et PB6 pour la Pixy (connecteur ICSP, cf https://commons.wikimedia.org/wiki/File:Arduino-nano-pinout.png )
+
Note : penser à laisser libres PB3, PB4 et PB5 pour la Pixy (connecteur ICSP, cf https://commons.wikimedia.org/wiki/File:Arduino-nano-pinout.png )
  
 
==Livrable 2==
 
==Livrable 2==
  
* évaluation le 05/06 (code + questions + fonctionnement)
+
* évaluation le 30/06 (code + questions + fonctionnement)
  
 
= Séquence 3 : Fusion des trois tâches et programmation globale=
 
= Séquence 3 : Fusion des trois tâches et programmation globale=
Ligne 73 : Ligne 164 :
  
  
void setup() {
+
int main()
 
+
{
}
+
   while(1)
 
 
void loop() {
 
 
 
  // lecture des capteurs
 
 
 
   switch (etapeActive)
 
 
   {
 
   {
     case etapeInit:
+
     // lecture des capteurs en début de boucle
 +
    switch (etapeActive)
 +
    {
 +
      case etapeInit:
  
 
             // si ... etapeSuivante=
 
             // si ... etapeSuivante=
 
             break;
 
             break;
    case etapeChercheBalle:
+
      case etapeChercheBalle:
  
 
             // si ... etapeSuivante=
 
             // si ... etapeSuivante=
 
             break;
 
             break;
    case etapeDeplacementVersBalle:
+
      case etapeDeplacementVersBalle:
  
 
             // si ... etapeSuivante=
 
             // si ... etapeSuivante=
 
             break;
 
             break;
 +
    }
 +
 +
    // on modifie l'étape active pour la prochaine boucle
 +
    etapeActive=etapeSuivante;
 
   }
 
   }
 
  // on modifie l'étape active pour la prochaine boucle
 
  etapeActive=etapeSuivante;
 
 
}
 
}
 
</source>
 
</source>
Ligne 106 : Ligne 195 :
 
===Exécuter une action une seule fois :===
 
===Exécuter une action une seule fois :===
 
<source lang=cpp>
 
<source lang=cpp>
void loop()
+
while(1)
 
{
 
{
 
   static bool dejaFait=false;
 
   static bool dejaFait=false;
Ligne 122 : Ligne 211 :
 
|
 
|
 
<source lang=cpp>
 
<source lang=cpp>
void loop()
+
void initFonctionsTempsArduino()
 
{
 
{
  static uint32_t triggerTime=millis();
+
  sei();
  uint32_t currentTime=millis();
+
  // marche pour 328p et 2560 et autres ...
 +
  // à adapter suivant le µc
 +
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
 +
  TCCR0A=(1<<WGM01)|(1<<WGM00);
 +
  TCCR0B=(1<<CS01)|(1<<CS00);
 +
  TIMSK0=(1<<TOIE0);
 +
}
  
  if (currentTime>=triggerTime)
+
int main()
  {
+
{
 +
  initFonctionsTempsArduino();
 +
  while(1)
 +
  {
 +
    static uint32_t triggerTime=millis();
 +
    uint32_t currentTime=millis();
 +
    if (currentTime>=triggerTime)
 +
    {
 
       faireMonAction();
 
       faireMonAction();
 
       triggerTime += 500; // prochaine exécution dans 500ms
 
       triggerTime += 500; // prochaine exécution dans 500ms
  }
+
    }
 +
  }
 
}
 
}
 
</source>
 
</source>
 
||
 
||
 
<source lang=cpp>
 
<source lang=cpp>
void loop()
+
void initFonctionsTempsArduino()
 
{
 
{
  static uint32_t triggerTime=0;
+
  sei();
  uint32_t currentTime=millis();
+
  // marche pour 328p et 2560 et autres ...
 +
  // à adapter suivant le µc
 +
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
 +
  TCCR0A=(1<<WGM01)|(1<<WGM00);
 +
  TCCR0B=(1<<CS01)|(1<<CS00);
 +
  TIMSK0=(1<<TOIE0);
 +
}
  
   switch (etapeActive)
+
int main()
 +
{
 +
  initFonctionsTempsArduino();
 +
   while(1)
 
   {
 
   {
     ....
+
     static uint32_t triggerTime=0;
     case etapeX:
+
     uint32_t currentTime=millis();
 +
 
 +
    switch (etapeActive)
 +
    {
 +
      case etapeX:
 
             if ( qqch)
 
             if ( qqch)
 
             {
 
             {
Ligne 151 : Ligne 267 :
 
             }
 
             }
 
             break;
 
             break;
    case etapeY:
+
      case etapeY:
 
             if ( currentTime >= (triggerTime + duree ) )
 
             if ( currentTime >= (triggerTime + duree ) )
 
             {
 
             {
Ligne 157 : Ligne 273 :
 
             }
 
             }
 
             break;
 
             break;
    case etapeZ:
+
      case etapeZ:
 
             ...
 
             ...
 
             break;
 
             break;
 +
    }
 +
    etapeActive=etapeSuivante;
 
   }
 
   }
  etapeActive=etapeSuivante;
 
 
}
 
}
 
</source>
 
</source>
Ligne 168 : Ligne 285 :
 
===Affichage provisoire pour deboggage===
 
===Affichage provisoire pour deboggage===
  
 +
 +
{|
 +
|-
 +
|
 
<source lang=cpp>
 
<source lang=cpp>
 
#define debug  // mode debug
 
#define debug  // mode debug
Ligne 173 : Ligne 294 :
 
#undef debug // mode sans debug
 
#undef debug // mode sans debug
  
void loop()
+
int main()
 
{
 
{
  #ifdef debug
+
  ...
 +
  while(1)
 +
  {
 +
    #ifdef debug
 
       Serial.println("juste si debug");
 
       Serial.println("juste si debug");
   #endif
+
    #endif
 +
  }
 +
}
 +
 
 +
</source>
 +
||
 +
<source lang=cpp>
 +
#define DEBUG  //If you comment this line, the DEBUG_PRINT & DEBUG_PRINTLN lines are defined as blank.
 +
#ifdef DEBUG    //Macros are usually in all capital letters.
 +
  #define DEBUG_PRINT(...)    Serial.print(__VA_ARGS__)    //DEBUG_PRINT is a macro, debug print
 +
  #define DEBUG_PRINTLN(...)  Serial.println(__VA_ARGS__)  //DEBUG_PRINTLN is a macro, debug print with new line
 +
#else
 +
   #define DEBUG_PRINT(...)    //now defines a blank line
 +
  #define DEBUG_PRINTLN(...)  //now defines a blank line
 +
#endif
 +
int main()
 +
{
 +
  while(1)
 +
  {
 +
    DEBUG_PRINTLN("juste si debug");
 +
  }
 
}
 
}
  
 
</source>
 
</source>
 +
|}
  
 
==Composants/cartes==
 
==Composants/cartes==
Ligne 230 : Ligne 375 :
  
 
==liens (dont règlement concours) ==
 
==liens (dont règlement concours) ==
* concours robotique Cachan, lien vers le règlement en pdf : https://robotique-iut-2023.sciencesconf.org/data/pages/Reglement_rencontres_de_robotique_GEII_8_9_10_juin_2023_BUT1.pdf
+
* concours robotique Cachan, lien vers le règlement en pdf : https://www.festivalrobotiquecachan.fr/wp-content/uploads/Reglement_rencontres_de_robotique_GEII_BUT-1-2-3.pdf
 
*[[Cours:archive SAÉ robot joueur de tennis]]
 
*[[Cours:archive SAÉ robot joueur de tennis]]
 
*[[Cours:archive SAÉ suivi de ligne]]
 
*[[Cours:archive SAÉ suivi de ligne]]
 
*https://www.youtube.com/watch?v=xH8EIqh-2_Y
 
*https://www.youtube.com/watch?v=xH8EIqh-2_Y

Version du 21 mai 2024 à 23:28

Utiliser des librairies arduino avec un main

Arduino sans loop/setup


Un certain nombre de librairies utilisent les fontions arduino delay/delayMicroseconds/millis/micros

Ces fonctions utilisent le Timer0 et en particulier l'interruption de débordement.

Ce Timer est configuré dans la fonction init(), qui est appelée dans le "main arduino"

On peut donc initialiser ce Timer0 pour qu'il génère un débordement tel qu'attendu.

Ainsi les fonctions de gestion du temps Arduino peuvent fonctionner comme prévu et on peut ainsi utiliser les librairies qui en dépendent :

void initFonctionsTempsArduino()
{
  sei();
  // marche pour 328p et 2560 et autres ...
  // à adapter suivant le µc
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
  TCCR0A=(1<<WGM01)|(1<<WGM00);
  TCCR0B=(1<<CS01)|(1<<CS00);
  TIMSK0=(1<<TOIE0);
}

int main()
{
  initFonctionsTempsArduino();
  Serial.begin(115200);
  while(1)
  {
    delay(100);
    Serial.println(millis());
  }
}


/*
Exemple pour le capteur vl53l1x :
cf exemple de la librairie pour des commentaires
*/
#include <Wire.h>
#include <VL53L1X.h>
VL53L1X sensor;

void initFonctionsTempsArduino()
{
  sei();
  // marche pour 328p et 2560 et autres ...
  // à adapter suivant le µc
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
  TCCR0A=(1<<WGM01)|(1<<WGM00);
  TCCR0B=(1<<CS01)|(1<<CS00);
  TIMSK0=(1<<TOIE0);
}

int main()
{
  initFonctionsTempsArduino();
  while (!Serial) {}
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000); // use 400 kHz I2C
  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1);
  }
  sensor.setDistanceMode(VL53L1X::Long);
  sensor.setMeasurementTimingBudget(50000);
  sensor.startContinuous(50);
  while(1)
  {
    Serial.print(sensor.read());
    if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
    Serial.println();
  }
}

Séquence 1 : tâches élémentaires individuelles

  • Tâches de suivi de ligne (un étudiant sur chaque tâche) :
    • suivi avec caméra Pixy
    • suivi avec capteurs photorélectifs (nombre de capteurs à choisir)
    • suivi avec Lidar, en suivant un mur sur le côté
  • s'arrêter à la fin du parcours
  • À faire globalement : câblage robot, sécurité

Livrable 1

  • faire des recherches pour rendre un dossier par groupe (pour lundi 27/05) expliquant : le pont en H, schéma sécurité et chaque partie (a, b, c)
  • évaluation le 24/05 (code + questions + fonctionnement)

Séquence 2 : tâches complexes individuelles + réalisation shield

  • Tâches de suivi
    • Caméra Pixy : gestion des intersections (comportement programmé, par ex : droite puis gauche puis tout droit)
    • Capteurs photoréflectifs : détection de marques à droite (si marque : on tourne à droite à l'intersection, sinon tout droit). Détection des marques à gauche : stop et recul pendant 1 seconde (environ) et on repart (pas d'arrêt sur le second passage)
    • Lidar : suivi de mur à gauche ET à droite (priorité en suivi à droite). Faire tomber une première barre, pas la seconde.
  • Trois cartes à réaliser (une par étudiant)
    • carte avec capteurs photoreflectifs
    • carte pour détection marques gauches et droites
    • carte shield arduino nano

Note : penser à laisser libres PB3, PB4 et PB5 pour la Pixy (connecteur ICSP, cf https://commons.wikimedia.org/wiki/File:Arduino-nano-pinout.png )

Livrable 2

  • évaluation le 30/06 (code + questions + fonctionnement)

Séquence 3 : Fusion des trois tâches et programmation globale

Livrable 3

Rapport final

  • Rapport final :
    • À envoyer au format pdf par mail avant le DD/MM/YY à HH
    • Diagramme de Gantt
    • diagramme algorithme général
    • stratégie de résolution de chaque tâche
    • Mini-concours à la fin pour sélectionner le meilleur robot (évaluation des capacités du robot, par étudiant en fonction de l'organisation prévue).
    • Chiffrage incluant le matériel ainsi que les ressources humaines.


Organisation

  • Fonctionnement en trinôme sur 12 jours
    • 9h-12h
    • 13h30-16h30
  • Compte rendu écrit quotidien individuel
    • sera contrôlé chaque matin
    • doit indiquer les tâches réalisées la veille
    • doit indiquer le travail à réaliser le jour même


Ressources

structure du programme

Vous pourrez utiliser la structure de programme suivante :

enum state {etapeInit,etapeChercheBalle,etapeDeplacementVersBalle};

state etapeSuivante=etapeInit;
state etapeActive=etapeInit;


int main()
{
  while(1)
  {
    // lecture des capteurs en début de boucle
    switch (etapeActive)
    {
      case etapeInit:

            // si ... etapeSuivante=
            break;
      case etapeChercheBalle:

            // si ... etapeSuivante=
            break;
      case etapeDeplacementVersBalle:

            // si ... etapeSuivante=
            break;
    }

    // on modifie l'étape active pour la prochaine boucle
    etapeActive=etapeSuivante;
  }
}

Programmation : comment faire

Exécuter une action une seule fois :

while(1)
{
   static bool dejaFait=false;
   if (dejaFait==false)
   {
      executerMonAction();
      dejaFait=true;
   }
}

Répéter une action régulièrement

void initFonctionsTempsArduino()
{
  sei();
  // marche pour 328p et 2560 et autres ...
  // à adapter suivant le µc
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
  TCCR0A=(1<<WGM01)|(1<<WGM00);
  TCCR0B=(1<<CS01)|(1<<CS00);
  TIMSK0=(1<<TOIE0);
}

int main()
{
  initFonctionsTempsArduino();
  while(1)
  {
    static uint32_t triggerTime=millis();
    uint32_t currentTime=millis();
    if (currentTime>=triggerTime)
    {
       faireMonAction();
       triggerTime += 500; // prochaine exécution dans 500ms
    }
  }
}
void initFonctionsTempsArduino()
{
  sei();
  // marche pour 328p et 2560 et autres ...
  // à adapter suivant le µc
  // cf https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
  TCCR0A=(1<<WGM01)|(1<<WGM00);
  TCCR0B=(1<<CS01)|(1<<CS00);
  TIMSK0=(1<<TOIE0);
}

int main()
{
  initFonctionsTempsArduino();
  while(1)
  {
    static uint32_t triggerTime=0;
    uint32_t currentTime=millis();

    switch (etapeActive)
    {
      case etapeX:
            if ( qqch)
            {
               etapeSuivante=etapeY;
               triggerTime=currentTime;
            }
            break;
      case etapeY:
            if ( currentTime >= (triggerTime + duree ) )
            {
               etapeSuivante=etapeZ;
            }
            break;
      case etapeZ:
            ...
            break;
    }
    etapeActive=etapeSuivante;
  }
}

Affichage provisoire pour deboggage

#define debug   // mode debug
//ou
#undef debug // mode sans debug

int main()
{
  ...
  while(1)
  {
    #ifdef debug
       Serial.println("juste si debug");
    #endif
  }
}
#define DEBUG   //If you comment this line, the DEBUG_PRINT & DEBUG_PRINTLN lines are defined as blank.
#ifdef DEBUG    //Macros are usually in all capital letters.
   #define DEBUG_PRINT(...)    Serial.print(__VA_ARGS__)     //DEBUG_PRINT is a macro, debug print
   #define DEBUG_PRINTLN(...)  Serial.println(__VA_ARGS__)   //DEBUG_PRINTLN is a macro, debug print with new line
#else
   #define DEBUG_PRINT(...)     //now defines a blank line
   #define DEBUG_PRINTLN(...)   //now defines a blank line
#endif
int main()
{
  while(1)
  {
    DEBUG_PRINTLN("juste si debug");
  }
}

Composants/cartes

liens (dont règlement concours)