Cours:SaeRobotique : Différence entre versions
(→Séquence 2 : tâches complexes individuelles + réalisation shield) |
|||
| (52 révisions intermédiaires par 3 utilisateurs non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
| − | |||
[[Cours:SaeRobotique correction|{{Vert|<big><big>Corrections enseignants</big></big>}}]] | [[Cours:SaeRobotique correction|{{Vert|<big><big>Corrections enseignants</big></big>}}]] | ||
| − | |||
| − | + | [[Cours:SaeRobotiqueSuiviLigne]] | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | [[Cours:SaeRobotiqueTennis]] | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | =Ressources communes= | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | =Ressources= | ||
==structure du programme== | ==structure du programme== | ||
| Ligne 73 : | Ligne 22 : | ||
| − | + | int main() | |
| − | + | { | |
| − | + | while(1) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
{ | { | ||
| − | case etapeInit: | + | // lecture des capteurs en début de boucle |
| + | switch (etapeActive) | ||
| + | { | ||
| + | case etapeInit: | ||
// si ... etapeSuivante= | // si ... etapeSuivante= | ||
break; | break; | ||
| − | + | case etapeChercheBalle: | |
// si ... etapeSuivante= | // si ... etapeSuivante= | ||
break; | break; | ||
| − | + | case etapeDeplacementVersBalle: | |
// si ... etapeSuivante= | // si ... etapeSuivante= | ||
break; | break; | ||
| + | } | ||
| + | |||
| + | // on modifie l'étape active pour la prochaine boucle | ||
| + | etapeActive=etapeSuivante; | ||
} | } | ||
| − | |||
| − | |||
| − | |||
} | } | ||
</source> | </source> | ||
| Ligne 106 : | Ligne 53 : | ||
===Exécuter une action une seule fois :=== | ===Exécuter une action une seule fois :=== | ||
<source lang=cpp> | <source lang=cpp> | ||
| − | + | while(1) | |
{ | { | ||
static bool dejaFait=false; | static bool dejaFait=false; | ||
| Ligne 122 : | Ligne 69 : | ||
| | | | ||
<source lang=cpp> | <source lang=cpp> | ||
| − | void | + | 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(); | faireMonAction(); | ||
triggerTime += 500; // prochaine exécution dans 500ms | triggerTime += 500; // prochaine exécution dans 500ms | ||
| − | + | } | |
| + | } | ||
} | } | ||
</source> | </source> | ||
|| | || | ||
<source lang=cpp> | <source lang=cpp> | ||
| − | void | + | 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; | |
| − | case etapeX: | + | uint32_t currentTime=millis(); |
| + | |||
| + | switch (etapeActive) | ||
| + | { | ||
| + | case etapeX: | ||
if ( qqch) | if ( qqch) | ||
{ | { | ||
| Ligne 151 : | Ligne 125 : | ||
} | } | ||
break; | break; | ||
| − | + | case etapeY: | |
if ( currentTime >= (triggerTime + duree ) ) | if ( currentTime >= (triggerTime + duree ) ) | ||
{ | { | ||
| Ligne 157 : | Ligne 131 : | ||
} | } | ||
break; | break; | ||
| − | + | case etapeZ: | |
... | ... | ||
break; | break; | ||
| + | } | ||
| + | etapeActive=etapeSuivante; | ||
} | } | ||
| − | |||
} | } | ||
</source> | </source> | ||
| Ligne 168 : | Ligne 143 : | ||
===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 152 : | ||
#undef debug // mode sans debug | #undef debug // mode sans debug | ||
| − | + | int main() | |
{ | { | ||
| − | + | ... | |
| + | while(1) | ||
| + | { | ||
| + | #ifdef debug | ||
Serial.println("juste si debug"); | Serial.println("juste si debug"); | ||
| − | + | #endif | |
| + | } | ||
} | } | ||
</source> | </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> | |
| − | + | |} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | == | + | ===changement d'état d'un capteur=== |
| − | {| | + | {| |
|- | |- | ||
| − | ! | + | ! au front montant d'un capteur !! 1x si le capteur est actif suffisamment longtemps |
|- | |- | ||
| − | | | + | | <source lang=cpp> |
| − | + | bool valeurActuelle=valeurInit; | |
| − | + | bool valeurPrecedente=valeurInit; | |
| + | |||
| + | ... | ||
| + | int main() | ||
| + | { | ||
| + | ... | ||
| + | while(1) | ||
| + | { | ||
| + | valeurPrecedente=valeurActuelle; | ||
| + | valeurActuelle=lireValeurCapteur(); | ||
| + | if ( (valeurPrecedente==false) and (valeurActuelle==true) ) | ||
| + | { | ||
| + | // action, par ex: | ||
| + | nombreFrontMontant++; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </source> | ||
| + | || <source lang=cpp> | ||
| + | bool valeurActuelle=valeurInit; | ||
| + | int8_t dureeActif=0; | ||
| + | bool isFront=true; | ||
| + | |||
| + | ... | ||
| + | int main() | ||
| + | { | ||
| + | ... | ||
| + | while(1) | ||
| + | { | ||
| + | valeurActuelle=lireValeurCapteur(); | ||
| + | if (valeurActuelle==true) | ||
| + | { | ||
| + | if (dureeActif>=20) | ||
| + | { | ||
| + | // faire l'action, par ex | ||
| + | if (isFront==true) | ||
| + | { | ||
| + | isFront=false; | ||
| + | nombreFrontMontant++; | ||
| + | } | ||
| + | } | ||
| + | else dureeActif++; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | dureeActif=0; | ||
| + | isFront=true; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </source> | ||
| + | |} | ||
| + | |||
| + | ===filtrer un capteur tor=== | ||
| + | |||
| + | {| class="wikitable" | ||
|- | |- | ||
| − | + | ! filtrer un capteur TOR !! sous forme de fonction pour filtrage de plusieurs capteurs | |
|- | |- | ||
| − | | | + | | <source lang=cpp> |
| − | + | ||
| − | + | bool rawValue=readCapteur(); | |
| + | static bool value=false; | ||
| + | |||
| + | const uint8_t filterValue=12; | ||
| + | static uint8_t nbTrue=0; | ||
| + | static uint8_t nbFalse=0; | ||
| + | |||
| + | if ( rawValue ) | ||
| + | { | ||
| + | if ( nbTrue>= filterValue) | ||
| + | { | ||
| + | value=true; | ||
| + | nbFalse=0; | ||
| + | } | ||
| + | else nbTrue++; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | if ( nbFalse>= filterValue) | ||
| + | { | ||
| + | value=false; | ||
| + | nbTrue=0; | ||
| + | } | ||
| + | else nbFalse++; | ||
| + | } | ||
| + | </source> | ||
| + | || <source lang=cpp> | ||
| + | void filtreTor(bool rawValue,bool & value,uint8_t filterValue,uint8_t & nbTrue,uint8_t & nbFalse) | ||
| + | { | ||
| + | if ( rawValue ) | ||
| + | { | ||
| + | if ( nbTrue>= filterValue) | ||
| + | { | ||
| + | value=true; | ||
| + | nbFalse=0; | ||
| + | } | ||
| + | else nbTrue++; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | if ( nbFalse>= filterValue) | ||
| + | { | ||
| + | value=false; | ||
| + | nbTrue=0; | ||
| + | } | ||
| + | else nbFalse++; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | ... | ||
| + | bool rawValue=rawValueTab[i]; | ||
| + | static bool value=false; | ||
| + | |||
| + | const uint8_t filterValue=5; | ||
| + | static uint8_t nbTrue=0; | ||
| + | static uint8_t nbFalse=0; | ||
| + | filtreTor(rawValue,value,filterValue,nbTrue,nbFalse); | ||
| + | ... | ||
| + | } | ||
| + | </source> | ||
|} | |} | ||
| − | *[[Media: | + | ===Optimiser l'exécution d'une fonction=== |
| − | *[[Media: | + | <source lang=cpp> |
| − | *[[Media: | + | inline void setVitesse(int16_t vmG, int16_t vmD) __attribute__((always_inline)); |
| − | *[[Media: | + | |
| + | void setVitesse(int16_t vmG, int16_t vmD) | ||
| + | { | ||
| + | // code de la fonction | ||
| + | ... | ||
| + | } | ||
| + | |||
| + | </source> | ||
| + | |||
| + | ==Diagramme d'état== | ||
| + | |||
| + | Pour aller plus loin dans la programmation sous forme de [https://fr.wikipedia.org/wiki/Automate_fini {{Rouge|machine à état fini]}}, vous utiliserez comme base le programme suivant : | ||
| + | |||
| + | [[Media:TestFiniteStateMachine.zip]] | ||
| + | |||
| + | ==Composants Kicad== | ||
| + | |||
| + | *Résistances : | ||
| + | **symbole R | ||
| + | **boitier suivant la valeur : 1206(CMS)/Axial DIN0309 (traversant) | ||
| + | *Condensateur | ||
| + | **symbole C | ||
| + | **boitier suivant la valeur 1206(CMS) | ||
| + | *VNH7070 | ||
| + | **télécharger et décompresser le fichier [[Media:VNH7070BASTR.zip]] | ||
| + | **ajouter la librairie en suivante la page : https://www.snapeda.com/about/import/#KiCad6 | ||
| + | **{{Rouge|attention}} : pour l'ajout de la librairie de l'empreinte, indique comme "pseudo nom" {{Rouge|VNH7070BASTR}} | ||
| + | **modèle 3d | ||
| + | ***ajouter le fichier VNH7070BASTR.step | ||
| + | ***faire une rotation sur X de 90° | ||
| + | *Arduino Nano | ||
| + | **symbole Arduino_Nano_v2.x | ||
| + | **modèle 3d | ||
| + | ***télécharger et décompresser : [[Media:Arduino_nano.STEP.zip]] | ||
| + | ***dans les propriétés de la carte (éditeur de pcb), onglet modèle 3d | ||
| + | ****ajouter le fichier téléchargé | ||
| + | ****rotation X 90 | ||
| + | ****rotation Z -90 | ||
| + | ****décalage Z 11mm | ||
| + | ***ajouter 2 barrettes M/F | ||
| + | ***${KICAD9_3DMODEL_DIR}/Connector_PinSocket_2.54mm.3dshapes/PinSocket_1x15_P2.54mm_Vertical.step | ||
| + | ***décaler le 2ème en X de 15,24mm | ||
| + | *bornier à vis : Screw_Terminal_01x02 | ||
| + | *MPU-9250 | ||
| + | **mettre 2 barrettes sécables 4 contacts, espacées de 6 pas | ||
| + | **[[Media:SparkFun MPU-9250 Breakout.step.zip]] | ||
| + | *convertisseur de niveau gt1167 {{Rouge|A modifier, pas le bon écartement !!}} | ||
| + | **utiliser la librairie : [[Media:BOB-12009.zip]] | ||
| + | **modèle 3d : | ||
| + | ***BOB-12009.step | ||
| + | ****rotation 90/0/0 | ||
| + | ****translation 0/0/9 | ||
| + | ***ajouter 2 barrettes M/F : ${KICAD9_3DMODEL_DIR}/Connector_PinSocket_2.54mm.3dshapes/PinSocket_1x06_P2.54mm_Vertical.step | ||
| + | ****rotation 0/0/0 | ||
| + | ****translation 5.08/6.35/0 et -5.08/6.35/0 | ||
| + | *Autres : [[Media:SaeS2_2025.zip]] | ||
| + | *GroveH : [[Media:groveH.zip]] | ||
| + | *Connecteur à vis : [[Media:1729131.zip]] | ||
Version actuelle datée du 18 juin 2025 à 13:43
Sommaire
Ressources communes
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");
}
}
|
changement d'état d'un capteur
| au front montant d'un capteur | 1x si le capteur est actif suffisamment longtemps |
|---|---|
bool valeurActuelle=valeurInit;
bool valeurPrecedente=valeurInit;
...
int main()
{
...
while(1)
{
valeurPrecedente=valeurActuelle;
valeurActuelle=lireValeurCapteur();
if ( (valeurPrecedente==false) and (valeurActuelle==true) )
{
// action, par ex:
nombreFrontMontant++;
}
}
}
|
bool valeurActuelle=valeurInit;
int8_t dureeActif=0;
bool isFront=true;
...
int main()
{
...
while(1)
{
valeurActuelle=lireValeurCapteur();
if (valeurActuelle==true)
{
if (dureeActif>=20)
{
// faire l'action, par ex
if (isFront==true)
{
isFront=false;
nombreFrontMontant++;
}
}
else dureeActif++;
}
else
{
dureeActif=0;
isFront=true;
}
}
}
|
filtrer un capteur tor
| filtrer un capteur TOR | sous forme de fonction pour filtrage de plusieurs capteurs |
|---|---|
bool rawValue=readCapteur();
static bool value=false;
const uint8_t filterValue=12;
static uint8_t nbTrue=0;
static uint8_t nbFalse=0;
if ( rawValue )
{
if ( nbTrue>= filterValue)
{
value=true;
nbFalse=0;
}
else nbTrue++;
}
else
{
if ( nbFalse>= filterValue)
{
value=false;
nbTrue=0;
}
else nbFalse++;
}
|
void filtreTor(bool rawValue,bool & value,uint8_t filterValue,uint8_t & nbTrue,uint8_t & nbFalse)
{
if ( rawValue )
{
if ( nbTrue>= filterValue)
{
value=true;
nbFalse=0;
}
else nbTrue++;
}
else
{
if ( nbFalse>= filterValue)
{
value=false;
nbTrue=0;
}
else nbFalse++;
}
}
int main()
{
...
bool rawValue=rawValueTab[i];
static bool value=false;
const uint8_t filterValue=5;
static uint8_t nbTrue=0;
static uint8_t nbFalse=0;
filtreTor(rawValue,value,filterValue,nbTrue,nbFalse);
...
}
|
Optimiser l'exécution d'une fonction
inline void setVitesse(int16_t vmG, int16_t vmD) __attribute__((always_inline));
void setVitesse(int16_t vmG, int16_t vmD)
{
// code de la fonction
...
}
Diagramme d'état
Pour aller plus loin dans la programmation sous forme de machine à état fini, vous utiliserez comme base le programme suivant :
Media:TestFiniteStateMachine.zip
Composants Kicad
- Résistances :
- symbole R
- boitier suivant la valeur : 1206(CMS)/Axial DIN0309 (traversant)
- Condensateur
- symbole C
- boitier suivant la valeur 1206(CMS)
- VNH7070
- télécharger et décompresser le fichier Media:VNH7070BASTR.zip
- ajouter la librairie en suivante la page : https://www.snapeda.com/about/import/#KiCad6
- attention : pour l'ajout de la librairie de l'empreinte, indique comme "pseudo nom" VNH7070BASTR
- modèle 3d
- ajouter le fichier VNH7070BASTR.step
- faire une rotation sur X de 90°
- Arduino Nano
- symbole Arduino_Nano_v2.x
- modèle 3d
- télécharger et décompresser : Media:Arduino_nano.STEP.zip
- dans les propriétés de la carte (éditeur de pcb), onglet modèle 3d
- ajouter le fichier téléchargé
- rotation X 90
- rotation Z -90
- décalage Z 11mm
- ajouter 2 barrettes M/F
- ${KICAD9_3DMODEL_DIR}/Connector_PinSocket_2.54mm.3dshapes/PinSocket_1x15_P2.54mm_Vertical.step
- décaler le 2ème en X de 15,24mm
- bornier à vis : Screw_Terminal_01x02
- MPU-9250
- mettre 2 barrettes sécables 4 contacts, espacées de 6 pas
- Media:SparkFun MPU-9250 Breakout.step.zip
- convertisseur de niveau gt1167 A modifier, pas le bon écartement !!
- utiliser la librairie : Media:BOB-12009.zip
- modèle 3d :
- BOB-12009.step
- rotation 90/0/0
- translation 0/0/9
- ajouter 2 barrettes M/F : ${KICAD9_3DMODEL_DIR}/Connector_PinSocket_2.54mm.3dshapes/PinSocket_1x06_P2.54mm_Vertical.step
- rotation 0/0/0
- translation 5.08/6.35/0 et -5.08/6.35/0
- BOB-12009.step
- Autres : Media:SaeS2_2025.zip
- GroveH : Media:groveH.zip
- Connecteur à vis : Media:1729131.zip