DRONE réalisé grâce à Lobodol !
infrared4ever
13 Messages
Le vendredi 15 octobre 2021 à 22:31:40
Bonjour à tous,
grâce à l'excellent tutoriel de lobodol j'ai réalisé un drone "quadcopter". J'ai conçu et réalisé toute la partie électronique ainsi que l'informatique de l'émetteur et du récepteur HF.
Le tutorial est trés bien fait et j'ai suivi exactement les instructions. Malheureusement j'ai rencontré un problème au démarrage des moteurs.
Voici la situation :
Les sorties vers les "esc" que j'utilise ne sont pas les mêmes que celles du tutorial.
Dans le tutorial il est écrit:
"// Set pins #4 #5 #6 #7 HIGH
PORTD |= B11110000;
// Wait until all pins #4 #5 #6 #7 are LOW
while (PORTD >= 16) "
J'utilise les sorties B1, B2, B3 et B4
pour les mettre au niveau "haut" j'écris : "PORTB |=B00011110;//toutes les 4 voies "HIGH" (B1..B4)"
Pour mettre toutes les "esc" au niveau bas j'écris: "PORTB &=B11100001"
De ce fait, l'instruction "while (PORTD >= 16) " doit être changée mais je ne sais pas quel est le nombre qu'il faut mettre à la place du nombre "16".
En fait j'ai essayé plusieurs conbinaisons mais rien ne fonctionne.
La phase d'amorçage se fait par un créneau à 1000 microsec sur les 4 "esc" puis suit la commande "gaz" mixée avec les 3 autres axes de l'IMU.
Quand je remplace les valeurs attribuées aux 4 "esc", par la commande commune des gaz (1000 à 2000 microsec), tout fonctionne parfaitement: les moteurs démarrent sans problème.
Quand je remplace le parametre "gaz" par sa valeur modifiée par le 'roll', le 'pitch' et le 'yaw': les moteurs ne démarrent pas et émettent une note à intervalle régulier...
A la place du nombre "16" j'ai essayé l'instruction suivante:
while (PORTB & B00011110 >= 0x02) mais cela ne fonctionne pas....
Puis je solliciter un conseil pour connaitre le nombre correct à mettre à la place de "16" ?
merci à nouveau pour l'excellent tutorial
grâce à l'excellent tutoriel de lobodol j'ai réalisé un drone "quadcopter". J'ai conçu et réalisé toute la partie électronique ainsi que l'informatique de l'émetteur et du récepteur HF.
Le tutorial est trés bien fait et j'ai suivi exactement les instructions. Malheureusement j'ai rencontré un problème au démarrage des moteurs.
Voici la situation :
Les sorties vers les "esc" que j'utilise ne sont pas les mêmes que celles du tutorial.
Dans le tutorial il est écrit:
"// Set pins #4 #5 #6 #7 HIGH
PORTD |= B11110000;
// Wait until all pins #4 #5 #6 #7 are LOW
while (PORTD >= 16) "
J'utilise les sorties B1, B2, B3 et B4
pour les mettre au niveau "haut" j'écris : "PORTB |=B00011110;//toutes les 4 voies "HIGH" (B1..B4)"
Pour mettre toutes les "esc" au niveau bas j'écris: "PORTB &=B11100001"
De ce fait, l'instruction "while (PORTD >= 16) " doit être changée mais je ne sais pas quel est le nombre qu'il faut mettre à la place du nombre "16".
En fait j'ai essayé plusieurs conbinaisons mais rien ne fonctionne.
La phase d'amorçage se fait par un créneau à 1000 microsec sur les 4 "esc" puis suit la commande "gaz" mixée avec les 3 autres axes de l'IMU.
Quand je remplace les valeurs attribuées aux 4 "esc", par la commande commune des gaz (1000 à 2000 microsec), tout fonctionne parfaitement: les moteurs démarrent sans problème.
Quand je remplace le parametre "gaz" par sa valeur modifiée par le 'roll', le 'pitch' et le 'yaw': les moteurs ne démarrent pas et émettent une note à intervalle régulier...
A la place du nombre "16" j'ai essayé l'instruction suivante:
while (PORTB & B00011110 >= 0x02) mais cela ne fonctionne pas....
Puis je solliciter un conseil pour connaitre le nombre correct à mettre à la place de "16" ?
merci à nouveau pour l'excellent tutorial
Le dimanche 17 octobre 2021 à 16:53:08
Salut infrared4ever et bienvenue !
Ravis que mes articles te plaisent :)
Avant tout, il faut bien comprendre d'où sort la valeur 16. Pour ça, il faut que tu soit capable de faire la conversion binaire <-> décimale et vice-versa.
Dans mon code, on y voit ceci :
Les broches 4 à 7 sont les 4 derniers bits du PORTD (qui lui est sur 8 bits).
16 exprimé en binaire sur 8 bits donne : 0001000. Dans ce cas, on voit bien que la sortie #4 est à l'état HAUT. Pour que toutes les sorties (4, 5, 6 & 7) soit à l'état BAS, il faut que PORTD soit strictement inférieur à 16. 15 en binaire s'écrit 00001111 : on voit bien que les sorties 4 à 7 sont bien à 0. Comme la condition dans le while exprime la condition pour continuer la boucle, on dit bien "tant que PORTD est supérieur ou égal à 16 c'est que toutes les sorties ne sont pas revenues à l'état BAS => continu".
Dans ton cas, tu veux utiliser les broches du port B. Attention, les broches 8, 9, 10 & 11 sont utilisées pour décoder les signaux de la radiocommande. Tu ne peux donc pas les utiliser pour générer les signaux des ESC.
Ravis que mes articles te plaisent :)
Avant tout, il faut bien comprendre d'où sort la valeur 16. Pour ça, il faut que tu soit capable de faire la conversion binaire <-> décimale et vice-versa.
Dans mon code, on y voit ceci :
// On boucle tant que toutes les sorties ne sont pas retournées à l'état LOW
while (PORTD >= 16) {
// ...
}
Les broches 4 à 7 sont les 4 derniers bits du PORTD (qui lui est sur 8 bits).
16 exprimé en binaire sur 8 bits donne : 0001000. Dans ce cas, on voit bien que la sortie #4 est à l'état HAUT. Pour que toutes les sorties (4, 5, 6 & 7) soit à l'état BAS, il faut que PORTD soit strictement inférieur à 16. 15 en binaire s'écrit 00001111 : on voit bien que les sorties 4 à 7 sont bien à 0. Comme la condition dans le while exprime la condition pour continuer la boucle, on dit bien "tant que PORTD est supérieur ou égal à 16 c'est que toutes les sorties ne sont pas revenues à l'état BAS => continu".
Dans ton cas, tu veux utiliser les broches du port B. Attention, les broches 8, 9, 10 & 11 sont utilisées pour décoder les signaux de la radiocommande. Tu ne peux donc pas les utiliser pour générer les signaux des ESC.
infrared4ever
13 Messages
Le lundi 18 octobre 2021 à 10:41:55
Bonjour Lobodol,
merci pour ta réponse.
Entre-temps j'avais résolu le pb: en fait les "esc" nécessitent d'être initialisées pendant un
certain temps avant de recevoir l'ordre en provenance du TX.
Les entrées que j'utilisent en provenance du Rx sont différentes de celles
décrites dans ton tutoriel, d'où l'utilisation de PIN différentes
Mon code final est:
PORTB |=B00011110;//toutes les 4 voies "HIGH" (B1..B4)
value=PORTB & B00011110;
while (value >= 0x02)
{
now = micros();
difference = now - loop_timer; etc...
Tout fonctionne parfaitement bien.
Je suis passé à la phase suivante: comparaison des ordres envoyés par le
TX aux positions relevées par l'IMU 6050 sur les 3 axes X (pitch), Y
(roll) et Z (yaw) pour implémenter le PID
Mon souci concerne les temps de calcul des "float".
A la suite de mes essais, je ferai un bref compte rendu dans ce forum
Merci encore pour tes conseils
cordialement
merci pour ta réponse.
Entre-temps j'avais résolu le pb: en fait les "esc" nécessitent d'être initialisées pendant un
certain temps avant de recevoir l'ordre en provenance du TX.
Les entrées que j'utilisent en provenance du Rx sont différentes de celles
décrites dans ton tutoriel, d'où l'utilisation de PIN différentes
Mon code final est:
PORTB |=B00011110;//toutes les 4 voies "HIGH" (B1..B4)
value=PORTB & B00011110;
while (value >= 0x02)
{
now = micros();
difference = now - loop_timer; etc...
Tout fonctionne parfaitement bien.
Je suis passé à la phase suivante: comparaison des ordres envoyés par le
TX aux positions relevées par l'IMU 6050 sur les 3 axes X (pitch), Y
(roll) et Z (yaw) pour implémenter le PID
Mon souci concerne les temps de calcul des "float".
A la suite de mes essais, je ferai un bref compte rendu dans ce forum
Merci encore pour tes conseils
cordialement
infrared4ever
13 Messages
Le jeudi 16 novembre 2023 à 10:12:24
Bonjour Lobodol,
je reprends contact avec toi car je souhaite plus d'explications à propos des interruptions qui offrent la possibilté de mesurer la durée des voies en provenance du Rx.
Pour initialiser les 4 sources des interruptions tu écris:
Les pins 8, 9, 10 et 11 vont créer une interruption à chaque changement d'état
La routine appelée par ces 4 interruptions est (je reprends ton programme ci-dessous) :
Cette routine est positionnée par (voir plus haut) "Set PCINT0" (digital input 8)
Cette routine traite les 4 pins (8, 9, 10 et 11) en 1 seule routine alors que les initialisations pré-positionnent 4 routines (1 routine par pin: 4 pins==>4 routines)
QUESTION IS:
sauf erreur de ma part, les 3 autres pins (9, 10 et 11) n'apparaissent pas dans le traitement de leur propre interruption,
Comment sont traitées les 3 autres routines d'interruption alors que uniquement l'interruption apparaissant sur la pin 8 est prise en consideration ?
Merci pour le temps que tu voudras bien consacrer à mon interrogation.
je reprends contact avec toi car je souhaite plus d'explications à propos des interruptions qui offrent la possibilté de mesurer la durée des voies en provenance du Rx.
Pour initialiser les 4 sources des interruptions tu écris:
PCICR |= (1 << PCIE0); //Set PCIE0 to enable PCMSK0 scan.
PCMSK0 |= (1 << PCINT0); //Set PCINT0 (digital input 8) to trigger an interrupt on state change.
PCMSK0 |= (1 << PCINT1); //Set PCINT1 (digital input 9)to trigger an interrupt on state change.
PCMSK0 |= (1 << PCINT2); //Set PCINT2 (digital input 10)to trigger an interrupt on state change.
PCMSK0 |= (1 << PCINT3); //Set PCINT3 (digital input 11)to trigger an interrupt on state change.
Les pins 8, 9, 10 et 11 vont créer une interruption à chaque changement d'état
La routine appelée par ces 4 interruptions est (je reprends ton programme ci-dessous) :
/**
* This Interrupt Sub Routine is called each time input 8, 9, 10 or 11 changed state.
* Read the receiver signals in order to get flight instructions.
*
* This routine must be as fast as possible to prevent main program to be messed up.
* The trick here is to use port registers to read pin state.
* Doing (PINB & B00000001) is the same as digitalRead(8) with the advantage of using less CPU loops.
* It is less conveniant but more efficient, which is the most important here.
*
* @see https://www.arduino.cc/en/Reference/PortManipulation
*/
ISR(PCINT0_vect)
{etc.}
Cette routine est positionnée par (voir plus haut) "Set PCINT0" (digital input 8)
Cette routine traite les 4 pins (8, 9, 10 et 11) en 1 seule routine alors que les initialisations pré-positionnent 4 routines (1 routine par pin: 4 pins==>4 routines)
QUESTION IS:
sauf erreur de ma part, les 3 autres pins (9, 10 et 11) n'apparaissent pas dans le traitement de leur propre interruption,
Comment sont traitées les 3 autres routines d'interruption alors que uniquement l'interruption apparaissant sur la pin 8 est prise en consideration ?
Merci pour le temps que tu voudras bien consacrer à mon interrogation.
infrared4ever
13 Messages
Le jeudi 16 novembre 2023 à 15:57:37
Bonjour Lobodol,
j'ai réalisé un Tx émettant sur 5 voies et dont la durée reste fixe mais variable à volonté (autour de 1500 microsec) afin de localiser l'origine du problème suivant.
La lecture de la durée des voies par ISR est fluctuante alors que le Tx ne varie pas (vérification à l'oscilloscope)
ci joint un tableau dans lequel se voit bien la fluctuation de la durée des voies, principalement le YAW et le PITCH
La valeur injectée par le Tx est environ 1490 microsec: on voit la variabilité principalement sur le YAW et le PITCH alors que le Tx n'a pas varié.
Toute proposition pour solutionner ce problème est la bienvenue....
Merci pour votre aide
YAW: 2000.0 PITCH: 2000.0 ROLL: 2000.0 Gaz: 2000.0 Trim: 2000.0
YAW: 1480.0 PITCH: 1500.0 ROLL: 1491.0 Gaz: 1491.0 Trim: 1487.0
YAW: 1496.0 PITCH: 1497.0 ROLL: 1478.0 Gaz: 1492.0 Trim: 1484.0
YAW: 2000.0 PITCH: 1823.0 ROLL: 1486.0 Gaz: 1497.0 Trim: 1490.0
YAW: 1511.0 PITCH: 1486.0 ROLL: 1494.0 Gaz: 1490.0 Trim: 1484.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 1499.0 Gaz: 1496.0 Trim: 1473.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 2000.0 Gaz: 2000.0 Trim: 1488.0
YAW: 1866.0 PITCH: 1498.0 ROLL: 1490.0 Gaz: 1480.0 Trim: 2000.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 1482.0 Gaz: 1492.0 Trim: 1482.0
YAW: 1492.0 PITCH: 1490.0 ROLL: 1492.0 Gaz: 1484.0 Trim: 1488.0
YAW: 1518.0 PITCH: 1486.0 ROLL: 1490.0 Gaz: 1494.0 Trim: 1488.0
YAW: 2000.0 PITCH: 1000.0 ROLL: 1502.0 Gaz: 1496.0 Trim: 1488.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 1494.0 Gaz: 1494.0 Trim: 1482.0
YAW: 2000.0 PITCH: 1376.0 ROLL: 1498.0 Gaz: 1490.0 Trim: 1486.0
YAW: 1000.0 PITCH: 2000.0 ROLL: 1672.0 Gaz: 1486.0 Trim: 1480.0
YAW: 1496.0 PITCH: 2000.0 ROLL: 1492.0 Gaz: 1490.0 Trim: 1484.0
YAW: 2000.0 PITCH: 1514.0 ROLL: 1488.0 Gaz: 1490.0 Trim: 1486.0
j'ai réalisé un Tx émettant sur 5 voies et dont la durée reste fixe mais variable à volonté (autour de 1500 microsec) afin de localiser l'origine du problème suivant.
La lecture de la durée des voies par ISR est fluctuante alors que le Tx ne varie pas (vérification à l'oscilloscope)
ci joint un tableau dans lequel se voit bien la fluctuation de la durée des voies, principalement le YAW et le PITCH
La valeur injectée par le Tx est environ 1490 microsec: on voit la variabilité principalement sur le YAW et le PITCH alors que le Tx n'a pas varié.
Toute proposition pour solutionner ce problème est la bienvenue....
Merci pour votre aide
YAW: 2000.0 PITCH: 2000.0 ROLL: 2000.0 Gaz: 2000.0 Trim: 2000.0
YAW: 1480.0 PITCH: 1500.0 ROLL: 1491.0 Gaz: 1491.0 Trim: 1487.0
YAW: 1496.0 PITCH: 1497.0 ROLL: 1478.0 Gaz: 1492.0 Trim: 1484.0
YAW: 2000.0 PITCH: 1823.0 ROLL: 1486.0 Gaz: 1497.0 Trim: 1490.0
YAW: 1511.0 PITCH: 1486.0 ROLL: 1494.0 Gaz: 1490.0 Trim: 1484.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 1499.0 Gaz: 1496.0 Trim: 1473.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 2000.0 Gaz: 2000.0 Trim: 1488.0
YAW: 1866.0 PITCH: 1498.0 ROLL: 1490.0 Gaz: 1480.0 Trim: 2000.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 1482.0 Gaz: 1492.0 Trim: 1482.0
YAW: 1492.0 PITCH: 1490.0 ROLL: 1492.0 Gaz: 1484.0 Trim: 1488.0
YAW: 1518.0 PITCH: 1486.0 ROLL: 1490.0 Gaz: 1494.0 Trim: 1488.0
YAW: 2000.0 PITCH: 1000.0 ROLL: 1502.0 Gaz: 1496.0 Trim: 1488.0
YAW: 2000.0 PITCH: 2000.0 ROLL: 1494.0 Gaz: 1494.0 Trim: 1482.0
YAW: 2000.0 PITCH: 1376.0 ROLL: 1498.0 Gaz: 1490.0 Trim: 1486.0
YAW: 1000.0 PITCH: 2000.0 ROLL: 1672.0 Gaz: 1486.0 Trim: 1480.0
YAW: 1496.0 PITCH: 2000.0 ROLL: 1492.0 Gaz: 1490.0 Trim: 1484.0
YAW: 2000.0 PITCH: 1514.0 ROLL: 1488.0 Gaz: 1490.0 Trim: 1486.0
| | | | |
Ci dessous le prog de l'ISR: //ici converge les interruptions reçues sur les PIN 8, 9, 10 et 11 en provenance du Tx (pour TEENSY 4.0) void unique_ISR(void)//les 4 ISR sont rassemblées dans la même routine "unique_ISR" { current_time=micros(); //RAPPEL // PORTB Pins 8-13 //PIN utilisées pour lecture data TX //PIN 8, 9, 10, 11, 12 //pinMode(8, INPUT_PULLUP);//yaw //pinMode(9, INPUT_PULLUP);//pitch //pinMode(10, INPUT_PULLUP);//roll //pinMode(11, INPUT_PULLUP);//throttle //pinMode(12, INPUT_PULLUP);//trimmer //duree_voies[0] //actual_state[0] = digitalRead(8);// YAW actual_state[0]=GPIO7_DR & 0b0000010000000000000000; if (previous_state[0]==LOW && actual_state[0]==HIGH) { //démarrage chrono duree_voies[0]=current_time; previous_state[0]=HIGH; } else if (previous_state[0]==HIGH && actual_state[0]==LOW) { duree_voie_temp=micros()-duree_voies[0]; duree_voies[0] = duree_voie_temp; previous_state[0]=LOW; } //++++++++++++++++++++++++++++++++++++++++++++++++ FIN YAW ++++++++++++++++++++++++++ //duree_voies[1] actual_state[1]=GPIO7_DR & 0b0000000000100000000000; //actual_state[1]=digitalRead(9);// PITCH if (previous_state[1]==LOW && actual_state[1]==HIGH) { //démarrage chrono duree_voies[1]=current_time; previous_state[1]=HIGH; } else if (previous_state[1]==HIGH && actual_state[1]==LOW) { //enregistrement chrono duree_voie_temp=micros()-duree_voies[1]; duree_voies[1] = duree_voie_temp; previous_state[1]=LOW; } //+++++++++++++++++++++++++++++++++++++++++++++++ FIN PITCH ++++++++++++++++++++++++++ //duree_voies[2] actual_state[2]=GPIO7_DR & 0b0000000000000000000001; //actual_state[2]=digitalRead(10);// ROLL if (previous_state[2]==LOW && actual_state[2]==HIGH) { //démarrage chrono duree_voies[2]=current_time; previous_state[2]=HIGH; } else if (previous_state[2]==HIGH && actual_state[2]==LOW) { //enregistrement chrono duree_voie_temp=micros()-duree_voies[2]; duree_voies[2] = duree_voie_temp; previous_state[2]=LOW; } //+++++++++++++++++++++++++++++++++++++++++++++ FIN ROLL +++++++++++++++++++++++++++ //duree_voies[3] actual_state[3]=GPIO7_DR & 0b0000000000000000000100; //actual_state[3]=digitalRead(11);// THROTTLE if (previous_state[3]==LOW && actual_state[3]==HIGH) { //démarrage chrono duree_voies[3]=current_time; previous_state[3]=HIGH; } else if (previous_state[3]==HIGH && actual_state[3]==LOW) { //enregistrement chrono duree_voie_temp=micros()-duree_voies[3]; duree_voies[3] = duree_voie_temp; previous_state[3]=LOW; } //++++++++++++++++++++++++++++++++++++++++++ FIN THROTTLE ++++++++++++++++++++++++++ //duree_voies[4] actual_state[4]=GPIO7_DR & 0b0000000000000000000010; //actual_state[4]=digitalRead(12);// TRIMMER if (previous_state[4]==LOW && actual_state[4]==HIGH) { //démarrage chrono duree_voies[4]=current_time; previous_state[4]=HIGH; } else if (previous_state[4]==HIGH && actual_state[4]==LOW) { //enregistrement chrono duree_voie_temp=micros()-duree_voies[4]; duree_voies[4] = duree_voie_temp; previous_state[4]=LOW; } //+++++++++++++++++++++++++++++++++++++++++++++++++ FIN TRIM ++++++++++++++++++++++++++ } | | | ||
infrared4ever
13 Messages
Le jeudi 16 novembre 2023 à 16:05:11
Bonjour,
je remets au propre le programme ci-dessous, désolé pour ce contre temps.
je remets au propre le programme ci-dessous, désolé pour ce contre temps.
//ici converge les interruptions reçues sur les PIN 8, 9, 10 et 11 en provenance du Tx (CPU TEENSYDUINO)
void unique_ISR(void)// ATTENTION: PINs correspondant au TEENSY4.0
{
current_time=micros();
//RAPPEL
// PORTB Pins 8-13
//PIN utilisées pour lecture data TX
//PIN 8, 9, 10, 11, 12
//pinMode(8, INPUT_PULLUP);//yaw
//pinMode(9, INPUT_PULLUP);//pitch
//pinMode(10, INPUT_PULLUP);//roll
//pinMode(11, INPUT_PULLUP);//throttle
//pinMode(12, INPUT_PULLUP);//trimmer
//duree_voies[0]
//actual_state[0] = digitalRead(8);// YAW
actual_state[0]=GPIO7_DR & 0b0000010000000000000000;
if (previous_state[0]==LOW && actual_state[0]==HIGH)
{
//démarrage chrono
duree_voies[0]=current_time;
previous_state[0]=HIGH;
}
else if (previous_state[0]==HIGH && actual_state[0]==LOW)
{
duree_voie_temp=micros()-duree_voies[0];
duree_voies[0] = duree_voie_temp;
previous_state[0]=LOW;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++ FIN YAW ++++++++++++++++++++++++++
//duree_voies[1]
actual_state[1]=GPIO7_DR & 0b0000000000100000000000;
//actual_state[1]=digitalRead(9);// PITCH
if (previous_state[1]==LOW && actual_state[1]==HIGH)
{
//démarrage chrono
duree_voies[1]=current_time;
previous_state[1]=HIGH;
}
else if (previous_state[1]==HIGH && actual_state[1]==LOW)
{
//enregistrement chrono
duree_voie_temp=micros()-duree_voies[1];
duree_voies[1] = duree_voie_temp;
previous_state[1]=LOW;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++ FIN PITCH ++++++++++++++++++++++++++
//duree_voies[2]
actual_state[2]=GPIO7_DR & 0b0000000000000000000001;
//actual_state[2]=digitalRead(10);// ROLL
if (previous_state[2]==LOW && actual_state[2]==HIGH)
{
//démarrage chrono
duree_voies[2]=current_time;
previous_state[2]=HIGH;
}
else if (previous_state[2]==HIGH && actual_state[2]==LOW)
{
//enregistrement chrono
duree_voie_temp=micros()-duree_voies[2];
duree_voies[2] = duree_voie_temp;
previous_state[2]=LOW;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ FIN ROLL +++++++++++++++++++++++++++
//duree_voies[3]
actual_state[3]=GPIO7_DR & 0b0000000000000000000100;
//actual_state[3]=digitalRead(11);// THROTTLE
if (previous_state[3]==LOW && actual_state[3]==HIGH)
{
//démarrage chrono
duree_voies[3]=current_time;
previous_state[3]=HIGH;
}
else if (previous_state[3]==HIGH && actual_state[3]==LOW)
{
//enregistrement chrono
duree_voie_temp=micros()-duree_voies[3];
duree_voies[3] = duree_voie_temp;
previous_state[3]=LOW;
}
//++++++++++++++++++++++++++++++++++++++++++ FIN THROTTLE ++++++++++++++++++++++++++
//duree_voies[4]
actual_state[4]=GPIO7_DR & 0b0000000000000000000010;
//actual_state[4]=digitalRead(12);// TRIMMER
if (previous_state[4]==LOW && actual_state[4]==HIGH)
{
//démarrage chrono
duree_voies[4]=current_time;
previous_state[4]=HIGH;
}
else if (previous_state[4]==HIGH && actual_state[4]==LOW)
{
//enregistrement chrono
duree_voie_temp=micros()-duree_voies[4];
duree_voies[4] = duree_voie_temp;
previous_state[4]=LOW;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++ FIN TRIM ++++++++++++++++++++++++++
}
Le lundi 20 novembre 2023 à 12:04:36
Salut @infrared4ever, tu peux mettre ton code en forme en le mettant entre balise [code][/code] stp?
Parce que là c'est difficile à lire...
Parce que là c'est difficile à lire...
infrared4ever
13 Messages
Le jeudi 23 novembre 2023 à 16:34:31
Bonjour,
je suis novice pour la programmation et je ne comprends pas ce que veut dire "mettre ton code en forme en le mettant entre balise ".
Pourrais tu me donner un exemple sur qq lignes de code s'il te plait ?
Merci pour ton aide
je suis novice pour la programmation et je ne comprends pas ce que veut dire "mettre ton code en forme en le mettant entre balise ".
Pourrais tu me donner un exemple sur qq lignes de code s'il te plait ?
Merci pour ton aide
infrared4ever
13 Messages
Le mercredi 6 décembre 2023 à 15:02:19
Bonjour,
j'ai réalisé un montage uniquement avec la partie" "BF" pour envoyer les 5 voies vers le Rx afin de savoir d'où
venait l'erreur de lecture de la durée des voies.
Le résultat est probant: le CPU (ARDUINO, ESP32 ou TEESY 4.0) ne peut discriminer les
différentes voies uniquement si les fronts contigus (i.e. le front
descendant du crêneau "n" suivit par le font montant du crêneau "n+1")
sont distants de au moins 1 microsec.
Quand cette distance temporelle devient inférieure à ce laps de temps de 1 µsec les erreurs apparaissent.
Dans le montage "classique"" le taux d'erreur est proche de 8 à 10%. A cause
de l'inertie mécanique du drone, cela ne se voit pas à l'oeil nu mais
se voit trés bien en scrutant le log de debug (voir mon screeshot
précédent).
Pour résoudre ce problème et atteindre un taux d'erruer de lecture de zero pour cent (0%) , j'ai conçu un autre algorithme.
Pour cela nous fabriquons une interruption UNIQUEMENT sur le voie du premier
crêneau (ici, le YAW) et c'est à partir de cette interruption que se
fait la lecture sur la totalité des voies.
Je livre ci-dessous l'algorithme, lequel ne génère aucune erreur.
En utilisant le fait que uniquement l'ISR soit déclenchée par le YAW (ou
bien toute autre 1ere voie) et la lecture des voies qui suivent soit
declenchée à partir de l'activation de l'ISR, la question du
chevauchement des fronts de 2 voies consécutives reste sans objet. Le
coût de cet algorithme est une perte de qq µsec pour assurer le bon
positionnement du début de lecture de chaque voie consécutive.
Une lecture éronnée de la durée d'une voie peut avoir des conséquences
désastreuses sur la stabilté du drône à cause de l'effet cumulatif de la
fonction"intégrale" du PID.
Merci d'avance à la communauté pour vos remarques et suggestions.
j'ai réalisé un montage uniquement avec la partie" "BF" pour envoyer les 5 voies vers le Rx afin de savoir d'où
venait l'erreur de lecture de la durée des voies.
Le résultat est probant: le CPU (ARDUINO, ESP32 ou TEESY 4.0) ne peut discriminer les
différentes voies uniquement si les fronts contigus (i.e. le front
descendant du crêneau "n" suivit par le font montant du crêneau "n+1")
sont distants de au moins 1 microsec.
Quand cette distance temporelle devient inférieure à ce laps de temps de 1 µsec les erreurs apparaissent.
Dans le montage "classique"" le taux d'erreur est proche de 8 à 10%. A cause
de l'inertie mécanique du drone, cela ne se voit pas à l'oeil nu mais
se voit trés bien en scrutant le log de debug (voir mon screeshot
précédent).
Pour résoudre ce problème et atteindre un taux d'erruer de lecture de zero pour cent (0%) , j'ai conçu un autre algorithme.
Pour cela nous fabriquons une interruption UNIQUEMENT sur le voie du premier
crêneau (ici, le YAW) et c'est à partir de cette interruption que se
fait la lecture sur la totalité des voies.
Je livre ci-dessous l'algorithme, lequel ne génère aucune erreur.
//+++++++++++++++++++++++++++ ALGORITHME SANS ERREURS +++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++ RC_ISR() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
void RC_ISR(void)// algorithme global pour analyser la durée des voies à partir du déclenchement YAW
{// entrée dans le HIGH du YAW
// démarrage chrono
// on est dans le YAW
duree_voies[0]=micros();
/*
//RAPPEL (dans le SETUP())
//PIN utilisées pour lecture data TX
//PIN 8, 9, 10, 11, 12 (PORTB)
pinMode(8, INPUT_PULLUP);//yaw
pinMode(9, INPUT_PULLUP);//pitch
pinMode(10, INPUT_PULLUP);//roll
pinMode(11, INPUT_PULLUP);//throttle
pinMode(12, INPUT_PULLUP);//trimmer
attachInterrupt(digitalPinToInterrupt(8), RC_ISR, RISING);
*/
while ((GPIO7_DR & 0b0000010000000000000000)==0b0000010000000000000000)//(digitalRead(8)==HIGH)//bit16
{ // YAW } duree_voie_temp=micros()-duree_voies[0]; duree_voies[0] = duree_voie_temp; if ((duree_voies[0]>2050) || (duree_voies[0]<900)) { duree_voies[0]= previous_duree_voies[0]; } previous_duree_voies[0]=duree_voies[0]; delayMicroseconds(30); //on arrive dans le PITCH duree_voies[1]=micros(); while ((GPIO7_DR & 0b0000000000100000000000)==0b0000000000100000000000)// bit12 (digitalRead(9)==HIGH)// { // PITCH } duree_voie_temp=micros()-duree_voies[1]; duree_voies[1] = duree_voie_temp; if ((duree_voies[1]>2050) || (duree_voies[1]<850)) { duree_voies[1]= previous_duree_voies[1]; } previous_duree_voies[1]=duree_voies[1]; delayMicroseconds(30); //on arrive dans le ROLL duree_voies[2]=micros(); while ((GPIO7_DR & 0b0000000000000000000001)==0b0000000000000000000001)//(digitalRead(10)==HIGH) //bit0 { // ROLL } duree_voie_temp=micros()-duree_voies[2]; duree_voies[2] = duree_voie_temp; if ((duree_voies[2]>2050) || (duree_voies[2]<900)) { duree_voies[2]= previous_duree_voies[2]; } previous_duree_voies[2]=duree_voies[2]; delayMicroseconds(30); //on arrive dans le THROTTLE duree_voies[3]=micros(); while ((GPIO7_DR & 0b0000000000000000000100)==0b0000000000000000000100)//(digitalRead(11)==HIGH) //bit2 { // THROTTLE } duree_voie_temp=micros()-duree_voies[3]; duree_voies[3] = duree_voie_temp; if ((duree_voies[3]>2050) || (duree_voies[3]<900)) { duree_voies[3]= previous_duree_voies[3]; } previous_duree_voies[3]=duree_voies[3]; delayMicroseconds(30); //on arrive dans le TRIMMER duree_voies[4]=micros(); while ((GPIO7_DR & 0b0000000000000000000010)==0b0000000000000000000010)//(digitalRead(12)==HIGH) //bit1 { // TRIM } duree_voie_temp=micros()-duree_voies[4]; duree_voies[4] = duree_voie_temp; } //++++++++++++++++++++++++++++++++++++++++++ FIN RC_ISR() ++++++++++++++++++++++++++++++++++++++++++++++++++++++En utilisant le fait que uniquement l'ISR soit déclenchée par le YAW (ou
bien toute autre 1ere voie) et la lecture des voies qui suivent soit
declenchée à partir de l'activation de l'ISR, la question du
chevauchement des fronts de 2 voies consécutives reste sans objet. Le
coût de cet algorithme est une perte de qq µsec pour assurer le bon
positionnement du début de lecture de chaque voie consécutive.
Une lecture éronnée de la durée d'une voie peut avoir des conséquences
désastreuses sur la stabilté du drône à cause de l'effet cumulatif de la
fonction"intégrale" du PID.
Merci d'avance à la communauté pour vos remarques et suggestions.
Le jeudi 7 décembre 2023 à 19:25:30
Salut @Infrared4ever,
C'est super intéressant de voir comment tu as résolu le problème des erreurs de lecture de durée des voies. Ton approche avec l'interruption sur la première voie (Yaw) semble vraiment ingénieuse pour éviter les erreurs dues aux fronts contigus.
J'ai quelques questions pour mieux comprendre ton algorithme :
C'est super intéressant de voir comment tu as résolu le problème des erreurs de lecture de durée des voies. Ton approche avec l'interruption sur la première voie (Yaw) semble vraiment ingénieuse pour éviter les erreurs dues aux fronts contigus.
J'ai quelques questions pour mieux comprendre ton algorithme :
- Comment as-tu déterminé les valeurs spécifiques (2050, 900, etc.) dans les conditions de vérification de la durée des voies ? Est-ce basé sur des tests empiriques ?
- Comment gères-tu la synchronisation initiale entre le début de l'interruption Yaw et le début de la lecture des autres voies ? La perte de quelques microsecondes semble acceptable, mais comment assures-tu la précision de cette synchronisation ?
- As-tu rencontré des situations où ton algorithme montre des limites ou des cas où il pourrait être amélioré davantage ?
infrared4ever
13 Messages
Le jeudi 7 décembre 2023 à 21:32:14
Salut Lobodol,
merci pour avoir jeté un oeil sur le problème rencontré et la solution apportée.
Je réponds à tes questions:
Travaillant avec une vieille console de télécommande 5voies, la piste des potentiomètres est un petit peut détériorée et parfois la lecture de la valeur de la tension sur le potentiometre peut être totalement erronée. Les valeurs normales (en ce qui concerne mon Tx) sont comprises entre 0 et 4095. La valeur est ensuite calibrée pour être transformée en 1000 - 2000 microsecondes dans le Tx lui-même. Le CPU qui gère les signaux émis dans le Tx est un PIC16F88 (ou similaire).
Les valeurs des durées calculées à partir de la tension lue sur les 5 potentiometres de voies (mon Tx émet sur 5 voies: YAW, PITCH, ROLL, THROTLE et TRIM) peuvent sortir de l'intervale 900 - 2050 (à cause d'un défaut sur la piste du potentiomètre): à ce moment là je substitue à la valeur (erronée) trouvée la valeur précédente (valeur "correcte") ce qui filtre les valeurs finales en les gardant dans un éventail de valeurs acceptables. Exemple pour le YAW en cas de lecture erronée sur le potentiomètre[0] il y a substitution ainsi: "duree_voies[0]= previous_duree_voies[0];". Les valeurs 900-2050 ont été fixées aprés différents essais sur mon Tx mais si le potentiomètres ont des pistes en trés bon état il est inutile de réaliser cette correction. Une simple instruction avec l'opérateur "constrain() est suffisante.
La synchronisation initiale se fait par le passage sur front montant dans l'ISR car l'appel de l'interruption est ainsi programmée dans le "setup()". Uniquement le front montant du YAW déclenche l'ISR: à ce moment précis se declenche le chrono de temps: "duree_voies[0]=micros();" La boucle reste active tant que le signal du YAW reste au niveau "HIGH". Lorsque le signal du YAW passe au niveau "LOW", le chrono s'arrète et la durée du créneau est transférée dans la variable propre au YAW: "duree_voie_temp=micros()-duree_voies[0];
duree_voies[0] = duree_voie_temp;" et ainsi de suite pour la lecture du signal suivant (qui est automatiquement au niveai "HIGH" sur un "pin" propre au signal détecté. Ici, le signal suivant est le PITCH (par construction et il apparait sur le pin9 (digitalRead(9)==HIGH).
Le temps de basculer du pin8 (siège de l'ISR du 1er créneaux qui est ici le YAW) vers le pin9 (qui est le pin sur lequel arrive le créneaux du PITCH, qq microsecondes sont perdues mais la perte est acceptable.
En conclusion, aprés différents essais, cet algorithme fonctionne parfaitement bien.
Je précise malgré tout que je l'ai implémenté sur ESP32 puis sur TEENSY4.0 pour des questions de rapidité de calcul. Le Teensee4.0 "galope" à 600mhz et a une forte puissance de calcul en virgule flotante, ce qui est impératif pour l'accomplissement des calculs du PID. Si un GPS puis un magnétomètre sont ajoutés au récepteur (pour le "GPS Return Home" en particulier) alors il est impératif d'utiliser ce type de processeur. Il faut que je trouve maintenant un GPS et un compas compatibles avec le Teensy4.0 afin de réaliser la construction d'un drone assez gros pour transporter du matériel comme par exemple une caméra.
Je te remercie à nouveau pour ton attention et pour l'ensemble de ton travail de mise à disposition de tes compétences en matière de modélisme et j'espère que nous pourrons à nouveau partager notre expérience.
merci pour avoir jeté un oeil sur le problème rencontré et la solution apportée.
Je réponds à tes questions:
Travaillant avec une vieille console de télécommande 5voies, la piste des potentiomètres est un petit peut détériorée et parfois la lecture de la valeur de la tension sur le potentiometre peut être totalement erronée. Les valeurs normales (en ce qui concerne mon Tx) sont comprises entre 0 et 4095. La valeur est ensuite calibrée pour être transformée en 1000 - 2000 microsecondes dans le Tx lui-même. Le CPU qui gère les signaux émis dans le Tx est un PIC16F88 (ou similaire).
Les valeurs des durées calculées à partir de la tension lue sur les 5 potentiometres de voies (mon Tx émet sur 5 voies: YAW, PITCH, ROLL, THROTLE et TRIM) peuvent sortir de l'intervale 900 - 2050 (à cause d'un défaut sur la piste du potentiomètre): à ce moment là je substitue à la valeur (erronée) trouvée la valeur précédente (valeur "correcte") ce qui filtre les valeurs finales en les gardant dans un éventail de valeurs acceptables. Exemple pour le YAW en cas de lecture erronée sur le potentiomètre[0] il y a substitution ainsi: "duree_voies[0]= previous_duree_voies[0];". Les valeurs 900-2050 ont été fixées aprés différents essais sur mon Tx mais si le potentiomètres ont des pistes en trés bon état il est inutile de réaliser cette correction. Une simple instruction avec l'opérateur "constrain() est suffisante.
La synchronisation initiale se fait par le passage sur front montant dans l'ISR car l'appel de l'interruption est ainsi programmée dans le "setup()". Uniquement le front montant du YAW déclenche l'ISR: à ce moment précis se declenche le chrono de temps: "duree_voies[0]=micros();" La boucle reste active tant que le signal du YAW reste au niveau "HIGH". Lorsque le signal du YAW passe au niveau "LOW", le chrono s'arrète et la durée du créneau est transférée dans la variable propre au YAW: "duree_voie_temp=micros()-duree_voies[0];
duree_voies[0] = duree_voie_temp;" et ainsi de suite pour la lecture du signal suivant (qui est automatiquement au niveai "HIGH" sur un "pin" propre au signal détecté. Ici, le signal suivant est le PITCH (par construction et il apparait sur le pin9 (digitalRead(9)==HIGH).
Le temps de basculer du pin8 (siège de l'ISR du 1er créneaux qui est ici le YAW) vers le pin9 (qui est le pin sur lequel arrive le créneaux du PITCH, qq microsecondes sont perdues mais la perte est acceptable.
En conclusion, aprés différents essais, cet algorithme fonctionne parfaitement bien.
Je précise malgré tout que je l'ai implémenté sur ESP32 puis sur TEENSY4.0 pour des questions de rapidité de calcul. Le Teensee4.0 "galope" à 600mhz et a une forte puissance de calcul en virgule flotante, ce qui est impératif pour l'accomplissement des calculs du PID. Si un GPS puis un magnétomètre sont ajoutés au récepteur (pour le "GPS Return Home" en particulier) alors il est impératif d'utiliser ce type de processeur. Il faut que je trouve maintenant un GPS et un compas compatibles avec le Teensy4.0 afin de réaliser la construction d'un drone assez gros pour transporter du matériel comme par exemple une caméra.
Je te remercie à nouveau pour ton attention et pour l'ensemble de ton travail de mise à disposition de tes compétences en matière de modélisme et j'espère que nous pourrons à nouveau partager notre expérience.
Le vendredi 8 décembre 2023 à 08:15:24
Yo !
Merci beaucoup pour ta réponse détaillée ! C'est super intéressant de voir comment tu as résolu le problème lié aux potentiomètres de ta vieille radiocommande. La substitution des valeurs erronées par les valeurs précédentes semble être une solution ingénieuse pour maintenir des valeurs acceptables, c'est bien joué !
Il me semble qu'un filtre de kalman permet de faire ce genre de correction mais c'est complexe à implémenter. Là, ta solution semble simple et rebuste.
Et c'est génial que tu aies pu adapter l'algorithme sur ESP32 et TEENSY4.0 pour gagner en rapidité de calcul. La puissance de calcul en virgule flottante du TEENSY4.0 semble vraiment utile pour les calculs du PID, surtout si tu envisages d'ajouter un GPS et un magnétomètre pour des fonctionnalités comme le "GPS Return Home".
Bonne chance dans ta quête de trouver un GPS et un compas compatibles avec le TEENSY4.0 pour la construction de ton drone !
C'est toujours cool de voir des passionnés comme toi partager leur expérience et leurs connaissances dans le domaine du modélisme. Hésite pas à partager la suite, ça m'intéresse de ouf !
Ciao et bonnes aventures avec ton drone !
Merci beaucoup pour ta réponse détaillée ! C'est super intéressant de voir comment tu as résolu le problème lié aux potentiomètres de ta vieille radiocommande. La substitution des valeurs erronées par les valeurs précédentes semble être une solution ingénieuse pour maintenir des valeurs acceptables, c'est bien joué !
Il me semble qu'un filtre de kalman permet de faire ce genre de correction mais c'est complexe à implémenter. Là, ta solution semble simple et rebuste.
Et c'est génial que tu aies pu adapter l'algorithme sur ESP32 et TEENSY4.0 pour gagner en rapidité de calcul. La puissance de calcul en virgule flottante du TEENSY4.0 semble vraiment utile pour les calculs du PID, surtout si tu envisages d'ajouter un GPS et un magnétomètre pour des fonctionnalités comme le "GPS Return Home".
Bonne chance dans ta quête de trouver un GPS et un compas compatibles avec le TEENSY4.0 pour la construction de ton drone !
C'est toujours cool de voir des passionnés comme toi partager leur expérience et leurs connaissances dans le domaine du modélisme. Hésite pas à partager la suite, ça m'intéresse de ouf !
Ciao et bonnes aventures avec ton drone !
infrared4ever
13 Messages
Le mardi 19 décembre 2023 à 16:18:49
Salut Lobodol,
Bien que la solution apportée pour utiliser la nouvelle ISR reste robuste il apparait rapidement que cette solution reste trés limitée car trés gourmante en ressources et, en particulier, trés gourmande en resources de gestion de la "pile" du CPU au moment de l'appel de l'ISR.
Pour me faire comprendre, le programme global de gestion du drône peut être divisé en 3 parties:
- partie 1: lecture des largeurs de voies envoyées par le Tx opérée par l'ISR calée sur la détection du premier créneau (le YAW dans notre cas)
- partie 2: lecture des données de l'IMU 6050: YAW, PITCH et ROLL
- partie 3: synthèse des parties 1 et 2: calcul du PID et action sur les 4 moteurs.
On constate que chaque programme testé séparemment fonctionne parfaitement bien mais le fonctionnement de la totalité des programmes entraine toujours des erreurs de lecture sur différentes données.
Aprés différents essais de programmation sur différents algorithmes, il est apparu que le temps de sauvegarde des paramètres dans la "pile" du CPU Teensy4.0 pouvait être trop important et entrainait des erreurs de lectures de certaines variables.
Ce temps devenait prohibitif lorsque l'ISR se déclenchait au moment où le CPU travaillait à l'intérieur d'une routine.
A ce moment là, la quantité de variables à sauvegarder dans la pile prenait trop de temps de processus et cela entrainait des erreurs de lecture sur les données elles mêmes recueillies par l'ISR.
Il a donc fallu régler ce problème. Pour ce faire nous avons remplacé l'ISR par une routine qui est déclenchée dans le programme principal (partie 3, ci-dessus).
Avec cette routine il n'y a plus de problème de "pile" et les données sont intactes.
Voici la routine utilisée:
Le résultat est impeccable et cela se vérifie sur les commandes envoyées aux 4 moteurs comme le montre les cas suivants:
En l'absence d'envoi d'ordre venant de la console ou bien de l'IMU:
On constate que la largeur de voies pour chaque moteur est égale à la valeur de la voie pour les gaz (1216 microsec)
Yaw_Rx: 1344.0 | Pitch_Rx: 1472.0 | Roll_Rx: 1504.0 | Gaz: 1216.0 | trim: 1008.0
Yaw_IMU: 1352.22 | Pitch_IMU: 1478.02 | Roll_IMU: 1507.43
dYAW: 0.0 | dPITCH: 0.0 | dROLL: 0.0
moteurs: M1: 1216.00 | M2: 1216.00 | M3: 1216.00 | M4: 1216.00
CAS DU YAW:
YAW (le nez va à gauche)
On constate que les moteurs M2 et M4 sont activés et les moteurs M1 et M3 sont "appauvris"
Yaw_Rx: 1616.0 | Pitch_Rx: 1472.0 | Roll_Rx: 1504.0 | Gaz: 1168.0 | trim: 1008.0
Yaw_IMU: 1350.50 | Pitch_IMU: 1477.55 | Roll_IMU: 1506.80
dYAW: 272.2 | dPITCH: 0.0 | dROLL: 0.0
moteurs: M1: 1000.00 | M2: 1551.98 | M3: 1000.00 | M4: 1551.96
CAS DU PITCH (le nez "up")
on constate que les moteurs M2 et M3 sont activés et les moteurs M1 et M4 sont "appauvris"
Yaw_Rx: 1344.0 | Pitch_Rx: 1696.0 | Roll_Rx: 1536.0 | Gaz: 1184.0 | trim: 1024.0
Yaw_IMU: 1347.90 | Pitch_IMU: 1477.89 | Roll_IMU: 1509.76
dYAW: 0.0 | dPITCH: 206.2 | dROLL: 0.0
moteurs: M1: 1000.00 | M2: 1475.45 | M3: 1475.58 | M4: 1000.00
CAS DU ROLL (le bord droit "up")
On constate que les moteurs M3 et M4 sont activés et que les moteurs M1 et M2 sont "appauvris"
Yaw_Rx: 1344.0 | Pitch_Rx: 1472.0 | Roll_Rx: 1344.0 | Gaz: 1408.0 | trim: 1536.0
Yaw_IMU: 1342.69 | Pitch_IMU: 1495.64 | Roll_IMU: 1523.50
dYAW: 0.0 | dPITCH: 0.0 | dROLL: -97.7
moteurs: M1: 1263.46 | M2: 1263.38 | M3: 1552.54 | M4: 1552.62
ATTENTION: Le positionnement des moteurs sur le squelette du Drône va se faire en fonction des résultats obtenus dans cette simulation.
Il est possible de nommer les moteurs différemment en fonction du placement souhaité sur le squelette du Drône.
CONCLUSION
L'utilisation de ce nouvel algorithme qui n'appelle pas la fonctionnalité d'une ISR confère au CPU une plus grande capacité de traitement de l'information en épargnant un temps de calcul important au préalable alloué à la constitution de la "pile" de données constituée au moment du déclenchement de l'ISR par un signal extérieur.
Il est donc possible d'utiliser les ressources du CPU dans la gestion supplémentaire d'un GPS et d'un compas.
Pour plus de transparence dans la gestion des données, je fais appel aux ressources de la Communauté pour pouvoir utiliser des algorithmes "transparents" sur la gestion du GPS par la liaison I2C et sur la gestion du compas par la laison UART.
A nouveau un grand merci à Lobodol pour m'avoir donné l'envie de m'intéresser à la construction et à la commande logicielle d'un Drône.
Bon courage à vous tous.
Bien que la solution apportée pour utiliser la nouvelle ISR reste robuste il apparait rapidement que cette solution reste trés limitée car trés gourmante en ressources et, en particulier, trés gourmande en resources de gestion de la "pile" du CPU au moment de l'appel de l'ISR.
Pour me faire comprendre, le programme global de gestion du drône peut être divisé en 3 parties:
- partie 1: lecture des largeurs de voies envoyées par le Tx opérée par l'ISR calée sur la détection du premier créneau (le YAW dans notre cas)
- partie 2: lecture des données de l'IMU 6050: YAW, PITCH et ROLL
- partie 3: synthèse des parties 1 et 2: calcul du PID et action sur les 4 moteurs.
On constate que chaque programme testé séparemment fonctionne parfaitement bien mais le fonctionnement de la totalité des programmes entraine toujours des erreurs de lecture sur différentes données.
Aprés différents essais de programmation sur différents algorithmes, il est apparu que le temps de sauvegarde des paramètres dans la "pile" du CPU Teensy4.0 pouvait être trop important et entrainait des erreurs de lectures de certaines variables.
Ce temps devenait prohibitif lorsque l'ISR se déclenchait au moment où le CPU travaillait à l'intérieur d'une routine.
A ce moment là, la quantité de variables à sauvegarder dans la pile prenait trop de temps de processus et cela entrainait des erreurs de lecture sur les données elles mêmes recueillies par l'ISR.
Il a donc fallu régler ce problème. Pour ce faire nous avons remplacé l'ISR par une routine qui est déclenchée dans le programme principal (partie 3, ci-dessus).
Avec cette routine il n'y a plus de problème de "pile" et les données sont intactes.
Voici la routine utilisée:
//++++++++++++++++++++++++++++++++++RC_lect_voies() ++++++++++++++++++++++++++++++++++++++++
void RC_lect_voies(void)
{
//++++++++++++ attendre "HIGH" sur une des 5 pins (8, 9, 10, 11, 12) (bit 16, 12, 0, 2, 1) 0b000000010001000000000111
while ((GPIO7_DR & 0x011007) > 0x000000)//attente durant le HIGH
{
delayMicroseconds(50);
}
//++++++++++++++++++++++++++++++++++++++++++++++ attente "LOW" +++++++++++++++++++++++++++++++++++++++
while ((GPIO7_DR & 0x011007)== 0x000000)//+++++ attente LOW
{
delayMicroseconds(50);
}
//démarrage sur le niveau HIGH du YAW
//démarrage chrono
duree_voies[0]=micros();
while ((GPIO7_DR & 0x010000)==0x010000)//(digitalRead(8)==HIGH)//bit16 (0b000000010000000000000000)
{
// YAW
}
duree_voie_temp=micros()-duree_voies[0];
duree_voies[0] = duree_voie_temp;
delayMicroseconds(10);
//on arrive dans le PITCH
duree_voies[1]=micros();
while ((GPIO7_DR & 0x000800)== 0x000800 )//0b000000000000100000000000)==0b000000000000100000000000)// bit12 (digitalRead(9)==HIGH)//
{
// PITCH
}
duree_voie_temp=micros()-duree_voies[1];
duree_voies[1] = duree_voie_temp;
delayMicroseconds(10);
//on arrive dans le ROLL
duree_voies[2]=micros();
while ((GPIO7_DR & 0x000001) == 0x000001 )//0b000000000000000000000001)==0b000000000000000000000001)//(digitalRead(10)==HIGH) //bit0
{
// ROLL
}
duree_voie_temp=micros()-duree_voies[2];
duree_voies[2] = duree_voie_temp;
delayMicroseconds(10);
//on arrive dans le THROTTLE
duree_voies[3]=micros();
while ((GPIO7_DR & 0x000004)== 0x000004 )//0b000000000000000000000100)==0b000000000000000000000100)//(digitalRead(11)==HIGH) //bit2
{
// THROTTLE
}
duree_voie_temp=micros()-duree_voies[3];
duree_voies[3] = duree_voie_temp;
delayMicroseconds(10);
//on arrive dans le TRIMMER
duree_voies[4]=micros();
while ((GPIO7_DR & 0x000002)== 0x000002)//0b000000000000000000000010)==0b000000000000000000000010)//(digitalRead(12)==HIGH) //bit1
{
//
// TRIM
}
duree_voie_temp=micros()-duree_voies[4];
duree_voies[4] = duree_voie_temp;
//vérification générale de la durée des voies
for (cc_8=0;cc_8<5;cc_8++)
{
//duree_voies[cc_8]=constrain(duree_voies[cc_8],1000,2000);
if ((duree_voies[cc_8]>2000) || (duree_voies[cc_8]<1000))
{
duree_voies[cc_8]= previous_duree_voies[cc_8];
}
previous_duree_voies[cc_8]=duree_voies[cc_8];
}
}
//+++++++++++++++++++FIN RC_lect_voies() +++++++++++++++++++++++++++++++++++
Le résultat est impeccable et cela se vérifie sur les commandes envoyées aux 4 moteurs comme le montre les cas suivants:
En l'absence d'envoi d'ordre venant de la console ou bien de l'IMU:
On constate que la largeur de voies pour chaque moteur est égale à la valeur de la voie pour les gaz (1216 microsec)
Yaw_Rx: 1344.0 | Pitch_Rx: 1472.0 | Roll_Rx: 1504.0 | Gaz: 1216.0 | trim: 1008.0
Yaw_IMU: 1352.22 | Pitch_IMU: 1478.02 | Roll_IMU: 1507.43
dYAW: 0.0 | dPITCH: 0.0 | dROLL: 0.0
moteurs: M1: 1216.00 | M2: 1216.00 | M3: 1216.00 | M4: 1216.00
CAS DU YAW:
YAW (le nez va à gauche)
On constate que les moteurs M2 et M4 sont activés et les moteurs M1 et M3 sont "appauvris"
Yaw_Rx: 1616.0 | Pitch_Rx: 1472.0 | Roll_Rx: 1504.0 | Gaz: 1168.0 | trim: 1008.0
Yaw_IMU: 1350.50 | Pitch_IMU: 1477.55 | Roll_IMU: 1506.80
dYAW: 272.2 | dPITCH: 0.0 | dROLL: 0.0
moteurs: M1: 1000.00 | M2: 1551.98 | M3: 1000.00 | M4: 1551.96
CAS DU PITCH (le nez "up")
on constate que les moteurs M2 et M3 sont activés et les moteurs M1 et M4 sont "appauvris"
Yaw_Rx: 1344.0 | Pitch_Rx: 1696.0 | Roll_Rx: 1536.0 | Gaz: 1184.0 | trim: 1024.0
Yaw_IMU: 1347.90 | Pitch_IMU: 1477.89 | Roll_IMU: 1509.76
dYAW: 0.0 | dPITCH: 206.2 | dROLL: 0.0
moteurs: M1: 1000.00 | M2: 1475.45 | M3: 1475.58 | M4: 1000.00
CAS DU ROLL (le bord droit "up")
On constate que les moteurs M3 et M4 sont activés et que les moteurs M1 et M2 sont "appauvris"
Yaw_Rx: 1344.0 | Pitch_Rx: 1472.0 | Roll_Rx: 1344.0 | Gaz: 1408.0 | trim: 1536.0
Yaw_IMU: 1342.69 | Pitch_IMU: 1495.64 | Roll_IMU: 1523.50
dYAW: 0.0 | dPITCH: 0.0 | dROLL: -97.7
moteurs: M1: 1263.46 | M2: 1263.38 | M3: 1552.54 | M4: 1552.62
ATTENTION: Le positionnement des moteurs sur le squelette du Drône va se faire en fonction des résultats obtenus dans cette simulation.
Il est possible de nommer les moteurs différemment en fonction du placement souhaité sur le squelette du Drône.
CONCLUSION
L'utilisation de ce nouvel algorithme qui n'appelle pas la fonctionnalité d'une ISR confère au CPU une plus grande capacité de traitement de l'information en épargnant un temps de calcul important au préalable alloué à la constitution de la "pile" de données constituée au moment du déclenchement de l'ISR par un signal extérieur.
Il est donc possible d'utiliser les ressources du CPU dans la gestion supplémentaire d'un GPS et d'un compas.
Pour plus de transparence dans la gestion des données, je fais appel aux ressources de la Communauté pour pouvoir utiliser des algorithmes "transparents" sur la gestion du GPS par la liaison I2C et sur la gestion du compas par la laison UART.
A nouveau un grand merci à Lobodol pour m'avoir donné l'envie de m'intéresser à la construction et à la commande logicielle d'un Drône.
Bon courage à vous tous.
Martini
2 Messages
Le lundi 26 février 2024 à 03:14:56
Très bonne réponse, très détaillée, j'ai beaucoup appris, merci.
——————————————————————————————————————————————————————————————————————————————
skysmotor.co.uk vend les produits suivants en ligne : moteur pas à pas pancake à couple élevé, motoréducteur pas à pas, servomoteurs, réducteur planétaire et peut être acheté en ligne si nécessaire.
——————————————————————————————————————————————————————————————————————————————
skysmotor.co.uk vend les produits suivants en ligne : moteur pas à pas pancake à couple élevé, motoréducteur pas à pas, servomoteurs, réducteur planétaire et peut être acheté en ligne si nécessaire.