Table des matières

TP – Asservissement en distance du mBot : Correcteur PID

Objectifs

Prérequis

Lirairie mBot: bibliotheque_arduino_mbot

Activité

www.lextronic.fr_41997-large_default_robot-mbot-explorer-bluetooth-p1050015.jpg

Forcer le mBot à suivre une cible à 20 cm de distance.

1) Principe général de l’asservissement

Le robot doit se stabiliser à 20 cm de l’obstacle.

L’erreur est définie par : e = D_{mes} - D_{cons}

La commande est donnée par un correcteur PID : v = K_p e + K_i \int e\, dt + K_d \frac{de}{dt}

Rôle des trois termes

Filtrage du dérivé

Le capteur ultrason étant bruyant, on utilise un dérivé filtré :

d_{filt} = \alpha\, d_{filt} + (1 - \alpha)\, \frac{e - e_{prev}}{dt}

Anti-windup (limitation de l’intégrale)

I = \mathrm{clip}(I + e\,dt,\; -I_{max},\; I_{max})

Reset si inversion du signe de l’erreur :

e \cdot e_{prev} < 0 \Rightarrow I = 0

Saturation moteurs

v =
\begin{cases}
V_{max} & \text{si } v > V_{max} \\
-V_{max} & \text{si } v < -V_{max} \\
v & \text{sinon}
\end{cases}

Zone de vitesse minimale

|v| < V_{min} \Rightarrow v =
\begin{cases}
V_{min} & \text{si } v > 0 \\
-V_{min} & \text{si } v < 0
\end{cases}


2) Travail demandé

Partie A — Analyse conceptuelle


Partie B — Expérimentations

Étape 1 : Action P seule

Questions :


Étape 2 : Action PI

Questions :


Étape 3 : Action PID

Questions :


Partie C — Analyse des données série

Les données typiques affichées :

D = distance mesurée
e = erreur
v = commande moteur
I = intégrale
d = dérivée filtrée

Questions :


3) Synthèse finale

Rédiger un paragraphe répondant aux questions suivantes :


4) Bonus facultatif

#include "mCoreLite.h"
 
mCoreLite bot;
 
// ----- CONSIGNE -----
float Dcons = 20.0;      // distance cible (cm)
 
// ----- PARAMÈTRES PID -----
float Kp = 6.0;          // proportionnel
float Ki = 0.15;         // intégral
float Kd = 0;          // dérivé (amortissement)
 
// ----- MEMOIRES PID -----
float integral = 0.0;
float e_prev = 0.0;
unsigned long lastTime = 0;
 
// ----- SECURITE INTEGRALE (ANTI-WINDUP) -----
float Imax = 50.0;       // limite de l'intégrale
 
// ----- VITESSE -----
int Vmin = 60;           // évite les sifflements
int Vmax = 200;          // saturation
 
// ----- FILTRE DERIVÉ -----
// (évite les tremblements dus au bruit US)
float alpha = 0.7;       // 0 = pas de filtre, 1 = filtre fort
float d_filtered = 0.0;
 
void setup() {
  Serial.begin(115200);
  bot.botSetup();
  lastTime = millis();
}
 
void loop() {
 
  // ----- 1) MESURE -----
  float Dmes = bot.distanceCM();
 
  // ----- 2) ERREUR -----
  float e = Dmes - Dcons;
 
  // ----- 3) TEMPS -----
  unsigned long now = millis();
  float dt = (now - lastTime) / 1000.0;
  if (dt <= 0) dt = 0.001;   // sécurité
  lastTime = now;
 
  // ----- 4) ZONE MORTE -----
  if (fabs(e) < 1.0) {
    integral = 0;           // détendre l'intégrale
    bot.motors(0,0);
    debug(Dmes, e, 0, integral, 0);
    return;
  }
 
  // ----- 5) INTÉGRALE + ANTI-WINDUP -----
  integral += e * dt;
  if (integral >  Imax) integral =  Imax;
  if (integral < -Imax) integral = -Imax;
 
  // Réinitialisation si inversion de signe de l'erreur
  if (e * e_prev < 0) integral = 0;
 
  // ----- 6) DÉRIVÉE (/!\ capteur bruyant) -----
  float derivative = (e - e_prev) / dt;
  e_prev = e;
 
  // Filtre passe-bas sur le dérivé
  d_filtered = alpha * d_filtered + (1 - alpha) * derivative;
 
  // ----- 7) SORTIE PID -----
  float v = Kp * e + Ki * integral + Kd * d_filtered;
 
  // ----- 8) SATURATION -----
  if (v >  Vmax) v =  Vmax;
  if (v < -Vmax) v = -Vmax;
 
  // ----- 9) VITESSE MINIMALE -----
  if (fabs(v) > 0 && fabs(v) < Vmin) {
    v = (v > 0) ? Vmin : -Vmin;
  }
 
  // ----- 10) ACTION -----
  // v > 0 → avancer (cible trop loin)
  // v < 0 → reculer (cible trop proche)
  bot.motors(-v, v);
 
  // ----- 11) DEBUG -----
  debug(Dmes, e, v, integral, d_filtered);
}
 
// ================== DEBUG ======================
void debug(float D, float e, float v, float I, float d) {
  Serial.print("D=");
  Serial.print(D);
  Serial.print("  e=");
  Serial.print(e);
  Serial.print("  v=");
  Serial.print(v);
  Serial.print("  I=");
  Serial.print(I);
  Serial.print("  d=");
  Serial.println(d);
}