Je me présente , je m'appelle Matthieu et je suis pilote Ulm multiaxe ( petit avion biplace ).
J'habite dans le 13 a coté d’Aix en Provence ( je précise ça pour la fin de ma question)
Je viens d’acheter un kit arduini Uno afin d'essayer de réaliser un pilote automatique pour mon avion .
Je m'explique:
Sur mon appareil , il y a un compensateur qui permet de faire voler l'avion a plat .
Ce compensateur est réglable manuellement .
Mon souhait est de mettre un gros servo sur ce compensateur afin de le rendre électrique .
Il pourrait alors être piloté par deux boutons : monter descendre .
Jusqu’à la rien de bien compliqué , j'ai trouve plusieurs codes sur le net me permettant de piloter un servo avec deux boutons et en peut etre afficher sur un LCD la position du servo il faudra sans doute relayer le signal pour avoir assez de puissance pour faire bouger un servo de 60 kg mais ça je m'en inquiéterais plus tard.
mais je me suis dit qu'il serait bien pratique de pouvoir y ajouter un régulateur pid et 1 bouton afin de faire un maintient d'altitude automatique grâce a un capteur barométrique (quel modèle prendre ???) . ce système étant bien entendu deconnectable immédiatement afin de reprendre les commandes en cas de besoin.
sur le papier ça a l'air simple mais pour moi c'est très compliqué d'autant plus que je ne comprends absolument rien a la programmation .
Donc voila j'ai l’idée mais pas la connaissance.
Donc si quelqu'un peut m'aider dans mon projet (surtout partie codage la partie mécanique et électrique ne me pose pas de pb ) ça serait sympa.
Bien sur une fois le système en place et réalisé il faudra le tester et et me ferais un plaisir d'emmener balader en avion la personne qui aura pris le temps de me donner un coup de main sur ce sujet épineux (d'ou la précision sur ma localisation).
Je ne comprends pas pourquoi je n'ai jamais eu de mail m'indiquant qu'il y avait eu une reponse sur ce forum.
Désolé pour la réponse tardive .
Pour revenir a mon sujet , je n’emmènerais jamais quelqu'un avec moi sans être sur de mon appareil, c'est pour cela que je ferais les premiers tests avec un ami pilote d'essai.
effectivement la réglementation ULM est plus "légère " que dans l'aviation certifiée néanmoins cela ne veux pas dire que l'on peut faire n'importe quoi .
Le système que je veux mettre en place ne se reprends que sur le compensateur donc même en cas de pb la commande principale de profondeur n'est pas bloquée.
De plus le système peut être désactivé par un inter sur le servomoteur . et enfin , l'accouplement du servomoteur sur le compensateur sera réalisé avec une pièce imprimée en 3d permettant la rupture de cette dernière en cas d'effort trop important sur le compensateur et donc un retour immédiat a une commande manuelle .
Voila pour la partie mécanique qui sera testée et retestéé au sol et en vol a haute altitude afin de vérifier la fiabilité .
pour la partie électronique, mon projet avance bien, malgré quelques difficultés et mon niveau très bas je suis arrivé a des résultats très satisfaisants . il y a quand même un problème sur lequel je bloque depuis plus d'un mois si vous pouvez m'aider ça serait sympa.
donc j'ai crée une boucle de régulation PID que j'appelle quand je passe mon régulateur en mode "Auto" par un inter 2 position . quand je reviens en manuel le compensateur reste dans sa position et je peux le faire bouger grace a deux BP. si je reviens sur le mode auto le servo donne un accoups pour se repositionner immédiatement sur la valeur de sortie du PID or je souhaiterais qu'il fasse une rampe pour éviter l'accoups . j'ai tout essayé mais je n'y arrive pas. je me suis servi de la fonction millis pour créer une comparaison entre la dernière altitude et l’altitude actuelle et ainsi limiter la montée a 500ft / min mais ca non plus ne fonctionne pas ca marche pendant 3 sec et après le servo part d'un coup a sa valeur .avez vous une idée a me proposer ?
le servo donne un accoups pour se repositionner immédiatement sur la valeur de sortie du PID
T'as mis le capteur barométrique?
Si c'est le cas ton arduino sait approximativement l'altitude de l'avion, donc tu positionne ton servo par rapport à la altitude au moment que tu passe en AUTO.
Un servo va effectivement essayer d’aller « vite » à la nouvelle position et la plupart des PIDs sont tuné pour avoir un fort coefficient de pente pour aller rejoindre l’idéal au début si vous êtes éloigné - d’où cet à-coup.
Il faut modifier les paramètres du PID pour qu’il soit plus doux au départ - mais cela peut vous jouer des tours plus tard si les conditions de vol font qu’il y a besoin d’une compensation rapide, ou alors intégrer dans le code juste au «basculement de mode» un étage « piloté » avant de passer en full PID. L’idée serait une petite machine à état du genre(pseudo-code)
switch (modePilotage) {
case MODE_MANUEL:
SI (détection de changement de mode « manuel —> Auto ») {
angleCible = CalculerNouvelAngleCiblePID(); // cet angle génère l’à-coup si gros delta
SI (différence entre angleCible et angleActuel est importante) {
modePilotage = MODE_TRANSITION_VERS_AUTO;
angleInitial = angleActuel;
numeroEtapeTransition = 0;
topChrono = millis();
} SINON {
MettreServoA(angleCible);
modePilotage = MODE_AUTO;
}
} else {
// votre code de gestion du mode manuel
}
break;
case MODE_TRANSITION_VERS_AUTO:
SI (millis() - topChrono >= deltaT) { // est-ce le moment de faire un pas de plus dans la modification de l’angle
angleDuServo = fonctionDeTransition(angleInitial, angleCible, numeroEtapeTransition++);
MettreServoA(angleDuServo);
// ici on regarde si on a fini la transition en 100 étapes et on rapplique le même principe si l’angle cible reste trop éloigné et donnerait un à-coup
SI (numeroEtapeTransition >= 100) {
angleCible = CalculerNouvelAngleCiblePID(); // cet angle génère l’à-coup si gros delta
SI (différence entre angleCible et angleActuel est importante) {
modePilotage = MODE_TRANSITION_VERS_AUTO;
angleInitial = angleActuel;
numeroEtapeTransition = 0;
topChrono = millis();
} SINON {
MettreServoA(angleCible);
modePilotage = MODE_AUTO;
}
} SINON {
// pas le moment de faire une nouvelle étape de transition vous pouvez éventuellement regarder si un truc grave est arrivé qui nécessite d’interrompre la phase de transition
}
}
break;
case MODE_AUTO:
SI (détection de changement de mode « Auto —> Manuel») {
modePilotage = MODE_MANUEL;
} SINON {
// votre code de pilotage auto
}
break;
}
La fonctionDeTransition() peut être une simple fonction affine qui fait 100 pas entre l’angle de début et de fin ou une fonction en S (Sigmoïde)
qui vraiment serait plus douce au démarrage et à l’arrivée - à tester (et à écrire). Bien sûr ça peut être en 10 pas au lieu de 100 et deltaT est à définir pour que le servo ait le temps de réagir et en fonction du temps que vous voulez allouer à ce mode intermédiaire
savoriano:
T'as mis le capteur barométrique?
Si c'est le cas ton arduino sait approximativement l'altitude de l'avion, donc tu positionne ton servo par rapport à la altitude au moment que tu passe en AUTO.
oui j'ai mis un bmp 280 qui me permet de connaitre l'altitude précise et donc de réguler mon altitude .
je fais en sorte que ma consigne suive l'altitude tant que je suis en "manu" pour ne pas avoir d’écart consigne mesure lors du passage en "auto" et lors du passage en auto je peux alors modifier ma consigne par un impulseur rotatif
J-M-L:
Un servo va effectivement essayer d’aller « vite » à la nouvelle position et la plupart des PIDs sont tuné pour avoir un fort coefficient de pente pour aller rejoindre l’idéal au début si vous êtes éloigné - d’où cet à-coup.
merci pour cette réponse que je vais prendre le temps d’étudier car ça m'a l'air bien compliqué et ça dépasse largement mes connaissances .
pour le PID je ne peux pas l'adoucir car je veux une réponse constante a l’échelon si je fais une rampe j'ai le problème de sortir de cette rampe et de revenir au régulateur car il n'atteindra peut être jamais la valeur désirée qui evolue en permanence selon l'altitude de plus il faut que le servo parte dans le bon sens car l altitude peut etre superieur ou inferieure a la consigne lors du passage en auto .
J'espère que tu sais ce que tu fais. Qu'elles seront les conséquences si il y a enclenchement accidentel du contrôle automatique lors d'un atterrissage/décollage ?
et me ferais un plaisir d'emmener balader en avion la personne qui aura pris le temps de me donner un coup de main sur ce sujet épineux (d'ou la précision sur ma localisation).
C'est J-M-L qui a répondu le premier, c'est à lui d'y aller
Je vais proposer ma solution, pas testée
En fait elle n'est qu'intuitive, peut-être même pas adaptée....
Si j'ai bien compris actuellement tu as :
repéter à l'infini
valeurPid=calculPID(...)
appliquer(valeurPID)
fin repeter
et valeur PID est trop grande (en valeur absolue) dans certains cas (consigne éloignée de la position courante).
J-M-L propose d'affiner le PID, perso je pense qu'il y a peut-être moyen de la laisser tranquille en passant derrière lui pour limiter la pente de la courbe lors de grandes variations.
Si maxDiff la variation maximum autorisée entre 2 tours de boucles :
lastValue=0
maxDiff=0.4 // valeur choisi pour l'exemple a adapter
repéter à l'infini
valeurPid=calculPID(...)
// c'est là que je "calme le PID" si besoin
si(valeurPID>lastValue+maxDiff) alors
valeurPID=lastValue+maxDiff
sinon
si (valeurPid<lastValue-maxDiff) alors
valeurPID=lastValue-maxDiff;
fin si
fin si
lastValue=valeurPID;
// maintenant que variation est raisonnable on applique
appliquer(valeurPID)
fin repeter
supercc:
C'est J-M-L qui a répondu le premier, c'est à lui d'y aller
euh....
supercc:
J-M-L propose d'affiner le PID
comme je l'ai dit, c'est sans doute pas la meilleur approche, c'est pour cela que le pseudo code "passe derrière lui".
supercc:
perso je pense qu'il y a peut-être moyen de la laisser tranquille en passant derrière lui pour limiter la pente de la courbe lors de grandes variations.
Si maxDiff la variation maximum autorisée entre 2 tours de boucles :
Le problème de cette approche c'est que le PID attend une réponse à la valeur qu'il vous a proposé et ne voit pas la réponse attendue donc au prochain tour de PID ça peut partir en cacahuète...
l'approche que je propose c'est de demander au PID quel angle il faut obtenir et si la différence avec l'angle actuel est trop grand, gérer manuellement la transition vers cet angle, sans demander au PID quoi-que-ce soit pendant cette phase. Une fois qu'on y est, on redemande au PID quel est le nouvel angle, et on recommence. Si c'est trop grand, on gère manuellement mais sinon on est bon et on passe en auto. c'est ce que fait ma petite machine à état.
Le problème de cette approche c'est que le PID attend une réponse à la valeur qu'il vous a proposé et ne voit pas la réponse attendue donc au prochain tour de PID ça peut partir en cacahuète...
Tout a fait ! Alors dans le cas particulier d'un PID sans I et sans D cela doit marcher
Mais c'est clair que si I et D interviennent c'est mort !
Merci pour la remarque !
@Matthieu1510 tu as quoi comme coefficient P, I et D ?
alors j'ai 0.2 en p,1 en i et1 en D mais pour l'instant ca reste a affiner une fois installer pour voir le comportement du compensateur en réel . en gros je cherche a me stabiliser a +50 - 50 pieds donc je ne veux pas voler au cm pres en altitude .
j'ai très bien compris la solution de Supercc qui me parait simple mais d'apres ce que j'ai compris ca risque de deconner si je met des valeurs a i et d donc il faut que je comprenne la proposition de JML qui me parait tres compliquée.
pour le PID j'ai borné les valeurs de sortie peut etre que le code de super CC pourait convenir dans ce cas ?
// boucle de regul PID
double computePID(double inp){
currentTime = millis(); //get current time
elapsedTime = (double)(currentTime - previousTime); //compute time elapsed from previous computation
if (error < -9000000/kp) {
error = -9000000/kp;
}
delay(10);
if (error > 9000000/kp) {
error = 9000000/kp;
}
delay(10);
if (cumError < -9000000/ki) {
cumError = -9000000/ki;
}
delay(10);
if (cumError > 9000000/ki) {
cumError = 9000000/ki;
}
delay(10);
if (rateError < -9000000/kd) {
rateError = -9000000/kd;
}
delay(10);
if (rateError > 9000000/kd) {
rateError = 9000000/kd;
}
delay(10);
double out;
out = kperror + kicumError + kd*rateError; //PID output
lastError = error; //remember current error
previousTime = currentTime; //remember current time
return out;//have function return the PID output //Serial.println(out);
}
Oublie ma solution bancale et fait une sigmoïde comme J-M-L te l'indique.
D'après ce que j'ai compris la solution s'écrirait plus (J-M-L me corrigera j'espère si je me trompe) :
repeter a l'infini
si (mode = auto) alors
// si l'altitude a atteindre n'est pas trop loin de celle actuelle
// on confie la gestion au PID, comme actuellement.
si abs(altitudeActuelle - altitudeAAtteindre) < altitudeSeuil
valeur = pid();
// sinon on confie la gestion la fonction sigmoïde.
sinon
valeur= sigmoide();
fin si
appliquer(valeur)
fin si
fin repeter
Borner les valeurs d'un PID, comme je le faisais, est une mauvaise idée, ce n'est plus un PID De plus il ne gère pas aussi bien les transitions souples de la sigmoïde.
L'algo n'est pas plus compliqué même s'il est vrai qu'il fait faire une fonction sigmoïde mais cela ne doit être plus compliqué qu'un PID
Matthieu1510:
j'ai très bien compris la solution de Supercc qui me parait simple mais d'apres ce que j'ai compris ca risque de deconner si je met des valeurs a i et d donc il faut que je comprenne la proposition de JML qui me parait tres compliquée.
--> Lors du changement de mode de pilotage, le Servo reçoit une nouvelle consigne très différente et donc réagit violemment, vous ne contrôlez aucunement le temps qui va s'écouler pour atteindre la consigne ni comment il y va, c'est juste dépendant des capacités de votre Servo et c'est généralement très direct !
Je vous propose d'insérer une phase de transition entre le mode Manuel et le mode Automatique où vous allez calculer les modifications d'angles du Servo dans le temps
--> vous allez calculer pendant un certain temps l'angle que vous voulez donner pour que la transition entre la valeur actuelle et la valeur future soit plus douce. à vous de définir la tête de la courbe entre les 2, je vous propose une courbe en S
supercc:
D'après ce que j'ai compris la solution s'écrirait plus (J-M-L me corrigera j'espère si je me trompe) :
repeter a l'infini
si (mode = auto) alors
// si l'altitude a atteindre n'est pas trop loin de celle actuelle
// on confie la gestion au PID, comme actuellement.
si abs(altitudeActuelle - altitudeAAtteindre) < altitudeSeuil
valeur = pid();
// sinon on confie la gestion la fonction sigmoïde.
sinon
valeur= sigmoide();
fin si
appliquer(valeur)
fin si
fin repeter
Non - je propose de ne faire cela que pendant la phase de transition entre mode manuel vers mode automatique; Vous avez envie peut-être d'une réaction brutale en mode automatique si les conditions se dégradent - donc vous ne voulez pas de sigmoïde en mode auto, juste à la transition entre les 2.
Merci mais c'est foireux, car mon algo ne prends pas en compte ce cas :
Vous avez envie peut-être d'une réaction brutale en mode automatique si les conditions se dégradent
qui me parait plus saint ! je ne vois pas ce qui justifierai un passage de l'état PID à l'état Sigmoide. Le pilote doit savoir dans quel état il est et ne pas faire le yoyo entre les états je pense.
Il sera temps plus tard d'envisager de compléter par :
si altitude == 1000 et passager == J-M-L alors
lopping();
fin si