Création d'un PA pour avion

Bonjour a toutes et a tous,

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).

Merci

Bonne journée

Merci a tous

Suis pas sûr que vous allez trouver des candidats pour faire pilote d’essai avec des composants non qualifiés et du code approximatif :slight_smile:

C’est pas régulé ce que vous avez le droit de modifier ?

J-M-L:
Suis pas sûr que vous allez trouver des candidats pour faire pilote d’essai avec des composants non qualifiés et du code approximatif :slight_smile:

C’est pas régulé ce que vous avez le droit de modifier ?

Bonjour J-M-L
La règlementation "ULM" est moins... contraignante que le cadre de l'aviation générale.
Perso , pour bien connaitre le domaine :grin:

Je me déporte du topic 8)

Bonjour,

J-M-L:
Suis pas sûr que vous allez trouver des candidats pour faire pilote d’essai avec des composants non qualifiés et du code approximatif :slight_smile:

C’est pas régulé ce que vous avez le droit de modifier ?

Ça sent le 737 max :fearful:

Cordialement,
bidouilleelec

Bonjour a tous ,

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 .

Je reviens vers vous des que j'ai compris .

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 :wink:

Je vais proposer ma solution, pas testée :wink:

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

Sans certitude car pas d'expérience.

EDIT : correction algo

supercc:
C'est J-M-L qui a répondu le premier, c'est à lui d'y aller :wink:

euh.... :fearful: :grin:

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 :wink:

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

//Serial.println(inp);

error = consigne - inp; // determine error
cumError += error * elapsedTime; // compute integral
rateError = (error - lastError)/elapsedTime; // compute derivative

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 :wink: 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 :wink:

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.

Le changement de mode se prête bien à la programmation par machine à états (cf mon tuto éventuellement)

je vais essayer d'expliquer différemment:

aujourd'hui vous avez ce comportement lorsque vous passez de manuel à Automatique:


--> 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

c'est plus compréhensible ?

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.

Bon, j'ai encore foiré :wink: mais je pense avoir compris maintenant ;-). Merci pour les jolies images !

J'arrête là avec mes propositions/interprétations foireuses...

@Matthieu1510, bonne chance pour la suite et ne va pas abîmer J-M-L hein :wink:

votre proposition de code n'est pas foireuse, c'est un possibilité. tout dépend du comportement voulu en vol.

votre proposition de J-M-L en pilote d'essai, par contre.... :confused: :stuck_out_tongue_closed_eyes:

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

:wink:

Tant que vous n’utilisez pas == dans les tests - tout les pilotes seront soumis à la même pirouette !!!