Bonjour,
Merci pour vos réponses.
Effectivement je vous en ai dit très peu sur le système que je souhaite asservir. Sans plus de mystère, je souhaite asservir un quadricoptère de type X.
Situation actuelle
Actuellement, j'ai réalisé deux asservissements de type P et PI (le PID sera pour quand les précédents seront OK).
Le capteur que j'utilise est un MPU6050 (gyro 3 axes + accéléro 3axes). La lecture du capteur se fait via le port série à un débit de 57600 bauds et utilise une interruption pour signaler que de nouvelles données sont présentes dans sa FIFO.
Dans un premier temps je me suis fixé comme contrainte de stabiliser mon quadri en assiette (pour le moment, peu importe s'il "glisse").
En d'autres thermes, ma consigne est angulaire. Dans un soucis de simplicité de mise en oeuvre, ma consigne de base est 0° sur chaque axe : le drone à donc une assiette "plate".
Pour tester mon implémentation, j'équipe mon quadri de 2 hélices du même axe et je fixe l'autre axe de manière à ce qu'il puisse basculer sur un seul axe : ce point vous parait clair ou un schéma vous aiderait ?
Constat
Dans le cas de mon asservissement de type proportionnel, lorsque je valorise mes gains P à 0, je constate que mon drone se stabilise seul. Si je le penche à 90° d'un côté et que je lâche, il revient tranquillement à sa position d'équilibre, en 2-3sec. Ce temps de réponse ne me convient pas car trop élevé. Je souhaiterais obtenir un temps de réponse de l'ordre de 0.5s : cela vous semble-t-il réalisable ? Surréaliste ?
Lorsque je valorise les gains P avec une valeur > 0 (0.5 par expl), le temps de réponse est nettement meilleur mais le drone part en instabilité : le dépassement augmente à chaque oscillation et finirait par tourner sur lui-même si je ne l'arrête pas.
J'ai donc tenté de diminuer petit à petit mes gains P mais je pers en réactivité par conséquent.
J'en viens donc à me m'interroger sur mon implémentation qui ne comporte pas de timer. Voici un extrait de mon code source :
Fonction principale
loop()
{
// 1 - Lecture des consignes
cmd = getCommands();
// 2 - Mesure du capteur
mesures = getMesures();
// 3 - Calcul des erreurs
errors = calcErrors(cmd, mesures);
// 4 - Calcul des commandes : asservissement P
cmdMot = asservissementP(errors, cmd_h);
// 5 - Application des commandes calculées
motA.write(cmdMot[0]);
motB.write(cmdMot[1]);
motC.write(cmdMot[2]);
motD.write(cmdMot[3]);
}
Fonction d'asservissement
/**
* Calcul les commandes de chacun des moteurs en fonctions des erreurs par rapport à la consigne
* pour un quadricoptère de type X :
*
* (A) (B) x
* \ / z ↑
* X \|
* / \ +----→ y
* (C) (D)
*
* Les moteurs A et D tournent dans le sens horaire
* Les moteurs B et C tournent dans le sens anti-horaire
*
* Asservissement de type Proportionnel
*
* @param float[3] errors : tableau des erreurs Yaw, Pitch, Roll
* @param float cmd_h : commande des gaz
*/
int* asservissementP(float errors[3], int cmd_h)
{
float Kp[3] = {1.5, 1.5, 1}; // Coefficient P dans l'ordre : Yaw, Pitch, Roll
static int commandes[4] = {0,0,0,0};
if (cmd_h == 0) {
return commandes;
}
// Initialisation des commandes moteur
int cmd_motA = cmd_h;
int cmd_motB = cmd_h;
int cmd_motC = cmd_h;
int cmd_motD = cmd_h;
// Yaw - Lacet (Z)
cmd_motA -= errors[0] * Kp[0];
cmd_motD -= errors[0] * Kp[0];
cmd_motC += errors[0] * Kp[0];
cmd_motB += errors[0] * Kp[0];
// Pitch - Tangage (Y)
cmd_motA -= errors[1] * Kp[1];
cmd_motB -= errors[1] * Kp[1];
cmd_motC += errors[1] * Kp[1];
cmd_motD += errors[1] * Kp[1];
// Roll - Roulis (X)
cmd_motA -= errors[2] * Kp[2];
cmd_motC -= errors[2] * Kp[2];
cmd_motB += errors[2] * Kp[2];
cmd_motD += errors[2] * Kp[2];
// Cas limites [0, 180]
commandes[0] = normaliser(cmd_motA);
commandes[1] = normaliser(cmd_motB);
commandes[2] = normaliser(cmd_motC);
commandes[3] = normaliser(cmd_motD);
return commandes;
}
Que pensez-vous de mon implémentation à première vue ?