LYCÉE → PRÉPA · L19

Module L19 · Partie I · Robotique et systèmes embarqués

Perception : estimer l’état du monde à partir de capteurs qui mentent.

Un gyroscope dérive, un accéléromètre tremble, un GPS saute de 3 mètres, une caméra voit des pixels et pas des objets. Le robot doit pourtant savoir où il est et ce qui l’entoure. La perception est l’art de combiner des mesures bruitées avec un modèle du mouvement pour obtenir une estimation meilleure que chaque source. Ce module construit le filtre de Kalman, fusionne une IMU, et pose les bases du traitement d’images.

Durée : 4 séances · Prérequis : L10, L11, L12, séance 28. Objectifs : modèle capteur et bruit, filtres simples (moyenne, médiane, passe-bas, complémentaire), filtre de Kalman 1D puis multidimensionnel (prédiction/correction, covariances), EKF pour un modèle non linéaire, fusion IMU (attitude), calibration, images (convolution, gradients, seuillage, détection de contours et de droites), caméra (modèle sténopé, calibration, homographie), un détecteur de ligne pour robot suiveur.

Ce que vous saurez faire à la fin
  • Implémenter un filtre de Kalman et régler ses matrices de bruit avec méthode.
  • Estimer l’attitude d’un robot à partir d’une IMU 6 axes.
  • Détecter une ligne, un marqueur ou un obstacle dans une image avec NumPy.
  • Expliquer ce qu’une caméra mesure vraiment et comment passer des pixels aux mètres.

Références : Probabilistic Robotics (Thrun, Burgard, Fox) chapitres 2-3 et 6-7, « Kalman and Bayesian Filters in Python » (Labbe, gratuit), Computer Vision: Algorithms and Applications (Szeliski, gratuit), cours CS231a.

Fiche de cours · Définitions

Perception, filtrage, vision : définitions

Définition (estimation d’état). Un système a un état caché xt (position, vitesse) qui évolue selon xt = f(xt−1, ut) + wt (bruit de processus) et produit des mesures zt = h(xt) + vt (bruit de mesure). Un filtre calcule la croyance bel(xt) = p(xt | z1:t, u1:t) récursivement.
Définition (filtre bayésien). Deux étapes : prédiction bel⁻(xt) = ∫ p(xt | xt−1, ut) bel(xt−1) dxt−1 ; correction bel(xt) = η·p(zt | xt)·bel⁻(xt). Kalman = filtre bayésien pour un système linéaire à bruits gaussiens ; EKF = linéarisation ; filtre particulaire = représentation par échantillons.
Définition (gaussienne multivariée). N(μ, Σ) de densité ∝ exp(−½(x − μ)ᵀΣ⁻¹(x − μ)). Σ (covariance, symétrique définie positive) décrit l’incertitude : ses vecteurs propres sont les axes de l’ellipse d’incertitude, ses valeurs propres les variances le long de ces axes. Stable par transformation affine : si x ∼ N(μ, Σ), Ax + b ∼ N(Aμ + b, AΣAᵀ).
Définition (filtre linéaire, convolution, réponse impulsionnelle). Un filtre linéaire invariant est une convolution y = h ∗ x. Passe-bas (moyenne glissante, exponentiel) lisse ; passe-haut (dérivée) détecte les variations. Le filtre médian n’est pas linéaire mais supprime les valeurs aberrantes.
Définition (image, gradient, contour, descripteur). Image = fonction I(x, y) (niveaux de gris) ou 3 canaux. Gradient ∇I = (∂I/∂x, ∂I/∂y) estimé par Sobel ; les contours sont les maxima de ‖∇I‖ (Canny). Un point d’intérêt (coin de Harris, FAST) est une position localement distinctive ; un descripteur (ORB, SIFT) résume son voisinage pour l’apparier entre images.
Définition (caméra sténopé, calibration). Un point 3D (X, Y, Z) se projette en (u, v) = (fxX/Z + cx, fyY/Z + cy) : matrice intrinsèque K. La calibration estime K et la distorsion (damier) ; l’extrinsèque [R | t] situe la caméra dans le monde.

Fiche de cours · Formules

Le filtre de Kalman et les formules de vision

Modèle : xt = A xt−1 + B ut + w, w ∼ N(0, Q) ; zt = H xt + v, v ∼ N(0, R)
Prédiction : x̂⁻ = A x̂ + B u ; P⁻ = A P Aᵀ + Q
Correction : K = P⁻Hᵀ(H P⁻ Hᵀ + R)⁻¹ ; x̂ = x̂⁻ + K(z − H x̂⁻) ; P = (I − K H) P⁻ innovation z − Hx̂⁻ ; K ∈ [0, 1] pondère mesure vs prédiction selon leurs incertitudes
Cas scalaire : K = σ²pred/(σ²pred + σ²mes) ; σ²post = σ²predσ²mes/(σ²pred + σ²mes) — fusionner deux mesures indépendantes : 1/σ² = 1/σ₁² + 1/σ₂²
EKF : remplacer A par le jacobien F = ∂f/∂x et H par ∂h/∂x évalués en x̂ ; prédire avec f et h non linéaires
Filtre particulaire : poids wi ∝ p(z | xi) ; rééchantillonner quand Neff = 1/Σwi² < N/2
Filtre exponentiel : yk = αxk + (1 − α)yk−1 ; constante de temps τ ≈ Ts(1 − α)/α ; fréquence de coupure fc = 1/(2πτ)
Sobel : Gx = [[−1, 0, 1], [−2, 0, 2], [−1, 0, 1]] ∗ I ; ‖∇I‖ = √(Gx² + Gy²) ; orientation atan2(Gy, Gx)
Projection : u = fx X/Z + cx ; taille apparente ∝ 1/Z ; stéréo : Z = f·b/d (b : base, d : disparité en pixels)

Fiche de cours · Théorèmes et démonstrations

Démonstrations à savoir refaire (1/2)

Théorème 1 (fusion optimale de deux mesures gaussiennes). Deux estimations indépendantes x₁ ∼ N(μ₁, σ₁²) et x₂ ∼ N(μ₂, σ₂²) d’une même grandeur se combinent en μ = (σ₂²μ₁ + σ₁²μ₂)/(σ₁² + σ₂²), σ² = σ₁²σ₂²/(σ₁² + σ₂²) — la variance combinée est plus petite que chacune.
Par Bayes, la densité a posteriori est ∝ exp(−(x − μ₁)²/2σ₁²)·exp(−(x − μ₂)²/2σ₂²). L’exposant est un polynôme du second degré en x : −½[x²(1/σ₁² + 1/σ₂²) − 2x(μ₁/σ₁² + μ₂/σ₂²)] + const. On l’identifie à −(x − μ)²/2σ² : 1/σ² = 1/σ₁² + 1/σ₂² et μ/σ² = μ₁/σ₁² + μ₂/σ₂², d’où les formules (les précisions 1/σ² s’additionnent). Comme 1/σ² > 1/σ₁², σ < σ₁. Réécriture : μ = μ₁ + K(μ₂ − μ₁) avec K = σ₁²/(σ₁² + σ₂²) — c’est exactement la correction de Kalman scalaire : la mesure « tire » l’estimation d’autant plus qu’elle est précise par rapport à la prédiction.
Théorème 2 (le gain de Kalman minimise la variance a posteriori). Parmi les estimateurs linéaires x̂ = x̂⁻ + K(z − Hx̂⁻), le gain K = P⁻Hᵀ(HP⁻Hᵀ + R)⁻¹ minimise tr(P), la somme des variances des composantes.
Erreur e = x − x̂ = (I − KH)e⁻ − Kv avec e⁻ l’erreur de prédiction (covariance P⁻) et v le bruit de mesure (covariance R), indépendants. Donc P = (I − KH)P⁻(I − KH)ᵀ + KRKᵀ (forme de Joseph, valable pour tout K). Dérivons tr(P) par rapport à K : ∂tr(P)/∂K = −2(I − KH)P⁻Hᵀ + 2KR = 0 ⇔ K(HP⁻Hᵀ + R) = P⁻Hᵀ ⇔ K = P⁻Hᵀ(HP⁻Hᵀ + R)⁻¹. En substituant dans la forme de Joseph, on obtient P = (I − KH)P⁻. Le filtre de Kalman est donc l’estimateur linéaire de variance minimale ; si les bruits sont gaussiens, c’est aussi l’estimateur bayésien exact (la gaussienne reste gaussienne sous les opérations linéaires et le produit — Théorème 1).

Fiche de cours · Théorèmes et démonstrations

Démonstrations à savoir refaire (2/2)

Théorème 3 (propagation de la covariance). Si x ∼ N(μ, Σ) et y = Ax + b, alors Cov(y) = AΣAᵀ ; pour y = f(x) non linéaire, Cov(y) ≈ JΣJᵀ avec J = ∂f/∂x(μ).
Cov(y) = E[(y − E[y])(y − E[y])ᵀ] = E[A(x − μ)(x − μ)ᵀAᵀ] = AΣAᵀ. Non linéaire : f(x) ≈ f(μ) + J(x − μ) (Taylor à l’ordre 1), donc y − f(μ) ≈ J(x − μ) et on applique le cas linéaire. C’est l’étape de prédiction de Kalman (P⁻ = APAᵀ + Q) et le fondement de l’EKF ; l’approximation est mauvaise si f est très courbée à l’échelle de Σ (d’où le filtre « unscented » qui propage des points sigma).
Théorème 4 (la moyenne glissante est un passe-bas, et sa réponse en fréquence). La moyenne de N échantillons a pour gain |H(f)| = |sin(πNfTs)/(N sin(πfTs))| : 1 en f = 0, nul en f = k/(NTs).
yk = (1/N)Σj=0N−1 xk−j. Pour xk = ei2πfkTs, yk = xk·(1/N)Σj e−i2πfjTs ; la somme géométrique vaut (1 − e−i2πfNTs)/(1 − e−i2πfTs), de module sin(πNfTs)/sin(πfTs). Le premier zéro est à f = 1/(NTs) : moyenner N = 10 échantillons à 100 Hz annule exactement un parasite à 10 Hz (et ses harmoniques) — utile pour rejeter 50 Hz avec N = 20 à 1 kHz. Le bruit blanc de variance σ² est réduit à σ²/N (Théorème 2 de L11).
Théorème 5 (détecteur de Harris). Un pixel est un coin si la matrice M = Σvoisinage [[Ix², IxIy], [IxIy, Iy²]] a deux valeurs propres grandes.
Le changement d’apparence pour un déplacement (u, v) est E(u, v) = Σ [I(x+u, y+v) − I(x, y)]² ≈ Σ (uIx + vIy)² = (u, v)M(u, v)ᵀ (Taylor à l’ordre 1). E est une forme quadratique ; ses valeurs propres λ₁, λ₂ mesurent la variation d’apparence dans les deux directions principales. Zone plate : λ₁ ≈ λ₂ ≈ 0. Contour : une seule grande (glisser le long du contour ne change rien). Coin : les deux grandes — le motif est localisable dans toutes les directions, donc appariable. Score de Harris : det(M) − k·tr(M)² = λ₁λ₂ − k(λ₁ + λ₂)², sans calculer les valeurs propres.

Fiche de cours · Méthodes

Méthodes et pièges

Méthode — concevoir un filtre de Kalman. (1) Choisir l’état (assez pour être markovien : position et vitesse). (2) Écrire A (physique : x += v·Ts), B, H (ce que mesure chaque capteur). (3) Q : incertitude sur le modèle (accélérations non modélisées : Q ∝ Ts²) ; R : variance des capteurs (fiche technique ou mesure à l’arrêt). (4) Vérifier sur simulation : l’erreur doit rester dans ±2√P (cohérence) ; sinon Q ou R est faux. (5) Tester la robustesse aux mesures aberrantes (seuil sur l’innovation normalisée, test du χ²).
Méthode — régler un filtre passe-bas. Identifier la bande utile du signal (un robot ne change pas de vitesse à 50 Hz) et les parasites ; choisir fc entre les deux ; accepter la latence induite (τ ≈ 1/(2πfc)) et la vérifier dans la boucle de contrôle (un retard trop grand déstabilise un PID).
Méthode — pipeline de vision classique. Niveaux de gris → flou gaussien (réduire le bruit) → gradient/contours ou seuillage (HSV pour la couleur) → morphologie (ouverture/fermeture) → composantes connexes → filtrage par aire/forme → mesure (centroïde, boîte). Toujours regarder les images intermédiaires.

Pièges : R trop petit (le filtre suit le bruit) ou Q trop petit (le filtre ignore les mesures, « confiance excessive ») ; angles non ramenés dans ]−π, π] dans l’innovation ; fusionner deux capteurs corrélés comme s’ils étaient indépendants (variance sous-estimée) ; seuils de couleur fixés sous un éclairage et testés sous un autre ; distorsion non corrigée avant toute mesure géométrique.

Fiche de cours · Exercices corrigés

Exercices corrigés

Exercice 1. Un robot avance sur un rail. État (x, v), Ts = 0,1 s, mesure de position par ultrason σ = 2 cm à chaque pas, bruit de processus sur l’accélération σa = 0,5 m/s². Écrire A, H, Q, R. Après une longue durée, la variance de position converge vers ≈ 1,2 cm² ; expliquer pourquoi elle est inférieure à la variance de mesure (4 cm²).
Correction. A = [[1, Ts], [0, 1]], H = [1, 0], R = [0,02²] = 4·10⁻⁴ m². Bruit de processus issu d’une accélération aléatoire a : Δx = ½aTs², Δv = aTs ⇒ Q = σa²·[[Ts⁴/4, Ts³/2], [Ts³/2, Ts²]] = 0,25·[[2,5·10⁻⁵, 5·10⁻⁴], [5·10⁻⁴, 10⁻²]]. La variance stationnaire est inférieure à R parce que le filtre combine chaque mesure avec la prédiction issue de toutes les mesures passées (Théorème 1 : les précisions s’ajoutent) ; elle ne tend pas vers 0 car Q réinjecte de l’incertitude à chaque pas — l’équilibre (équation de Riccati) dépend du rapport Q/R.
Exercice 2. Une caméra f = 800 px, c = (320, 240), à 1,2 m de haut, axe horizontal. Un objet est vu en (520, 400). Il est au sol : calculer sa position (X, Z) devant la caméra.
Correction. Rayon : (u − cx, v − cy, f) = (200, 160, 800). Le sol est le plan Y = 1,2 m (axe Y vers le bas). Le point est λ·(200, 160, 800) avec λ·160 = 1,2 ⇒ λ = 0,0075. Donc Z = 6,0 m, X = 1,5 m (à droite), Y = 1,2 m ✓. Sensibilité : ∂Z/∂v = −fh/(v − cy)² = −800·1,2/160² = −3,75 cm par pixel — l’erreur croît comme Z² : à 6 m, un pixel vaut ~4 cm ; à 12 m, ~15 cm. D’où l’intérêt du lidar ou de la stéréo à distance.
Exercice 3. Un signal de gyroscope est intégré pour obtenir un angle. Avec un biais constant b = 0,01 rad/s et un bruit blanc σ = 0,02 rad/√s, donner l’erreur d’angle après 100 s, et expliquer comment un accéléromètre corrige le problème (filtre complémentaire).
Correction. Biais : erreur = b·t = 1 rad après 100 s (dérive linéaire). Bruit blanc intégré (marche aléatoire) : σθ = σ√t = 0,2 rad (croissance en √t). Le biais domine. L’accéléromètre donne l’inclinaison absolue (via la gravité) sans dérive mais avec beaucoup de bruit haute fréquence (accélérations du robot). Filtre complémentaire : θ = α(θ + ω·Ts) + (1 − α)θacc avec α ≈ 0,98 — le gyroscope filtré passe-haut (dérive éliminée) + l’accéléromètre filtré passe-bas (bruit éliminé), les deux filtres se complétant à 1. Un filtre de Kalman avec l’état (θ, b) estime en plus le biais explicitement.

01 / Filtrer

Le problème : une vraie mesure de capteur

Chaque capteur a sa faiblesse : le télémètre est bruyant mais ne dérive pas ; l’accéléromètre est précis à court terme mais son biais, intégré deux fois, donne une erreur en t². L’idée de la fusion : prendre le court terme de l’un et le long terme de l’autre.

01 / Filtrer

Filtres simples : passe-bas, médian, complémentaire

Fréquence de coupure et retard

Le passe-bas y += α(x − y) a une constante de temps τ ≈ dt/α : α = 0,05 à 50 Hz lisse sur 0,4 s et retarde d’autant — mortel pour un robot qui doit réagir. Le retard de phase est le prix de tout filtre linéaire causal ; c’est pourquoi on préfère un modèle (« le robot ne peut pas sauter de 1 m en 20 ms ») à un simple lissage. Le médian n’est pas linéaire : il supprime les valeurs aberrantes sans les étaler, mais ne réduit pas le bruit gaussien.

02 / Kalman

Le filtre de Kalman en 1D : prédire, puis corriger avec le bon gain

Ce que fait chaque ligne

Prédiction : x ← Fx + Bu (la physique), P ← FPFᵀ + Q (l’incertitude grandit : on n’a pas mesuré). Correction : innovation y = z − Hx (ce que la mesure dit de neuf), S = HPHᵀ + R (incertitude de l’innovation), gain K = PHᵀS⁻¹ (confiance dans la mesure relativement au modèle), x ← x + Ky, P ← (I − KH)P (l’incertitude diminue). Si R est grand (capteur mauvais), K → 0 et on ignore la mesure ; si P est grand (on est perdu), K → 1 et on croit la mesure. C’est le filtre bayésien du module L11 pour des gaussiennes et un modèle linéaire, et il est optimal dans ce cas (Kalman, 1960 — il a guidé Apollo). Le module L10 donne les outils : produits matriciels, inverses (petites), covariances.

02 / Kalman

Régler Q et R, détecter les aberrations, tester la cohérence

Le NIS (normalized innovation squared) moyen doit valoir ≈ 1 : s’il est ≫ 1, le filtre est trop sûr de lui (Q ou R sous-estimés) ; ≪ 1, trop prudent. C’est le test standard de cohérence. R se mesure sur le capteur immobile ; Q se règle pour obtenir NIS ≈ 1. La distance de Mahalanobis rejette les mesures impossibles selon le filtre lui-même — bien mieux qu’un seuil fixe.

02 / Kalman

EKF : quand le modèle n’est pas linéaire — un robot différentiel

Linéariser autour de l’estimation

L’EKF remplace F et H par les jacobiennes (module L10) de f et h évaluées à l’estimation courante : le filtre reste celui de Kalman, appliqué à l’approximation linéaire locale. Il n’est plus optimal ni garanti (il peut diverger si la linéarisation est mauvaise), mais il est le cheval de bataille de la robotique : GPS/INS, SLAM (module L20), fusion IMU. Alternatives : UKF (points sigma, sans jacobienne), filtre particulaire (module L20). Le piège n°1 : oublier de ramener les angles dans ]−π, π] — l’innovation « 359° » au lieu de « −1° » fait exploser le filtre.

03 / IMU

Attitude à partir d’une IMU : gyroscope + accéléromètre

Vers la 3D

En 3D, l’attitude est une rotation (module L10) : on la représente par un quaternion (4 nombres, pas de blocage de cardan), on l’intègre avec le gyro 3 axes et on la corrige avec l’accéléromètre (direction du bas) et le magnétomètre (direction du nord). Les filtres de Madgwick et Mahony font cela en quelques dizaines de lignes sur un microcontrôleur — ce sont ceux des contrôleurs de vol de drones (Betaflight, PX4). Étapes obligatoires : calibration du gyro (biais au repos), de l’accéléromètre (6 positions) et du magnétomètre (ellipsoïde). Une IMU à 5 € bien calibrée et bien filtrée bat une IMU à 500 € mal utilisée.

04 / Vision

Une image est une matrice : gradients, seuils, contours

Le vocabulaire

Lissage gaussien : réduit le bruit avant de dériver (dériver amplifie le bruit). Gradient (Sobel) : où l’intensité change vite = contours. Seuillage : le plus simple des segmentations ; Otsu choisit le seuil automatiquement par l’histogramme. Morphologie (érosion, dilatation) nettoie les masques. Composantes connexes (module L05 : BFS sur les pixels) isolent les objets. Tout cela existe dans OpenCV (cv2.GaussianBlur, cv2.Sobel, cv2.threshold, cv2.findContours) en C++ optimisé, y compris sur Raspberry Pi à 30 images/s.

04 / Vision

Détecter des droites (Hough) et comprendre la caméra (sténopé, homographie)

De la calibration à la 3D

La calibration (Zhang, 2000) estime K et la distorsion de l’objectif à partir de photos d’un damier : cv2.calibrateCamera. Avec deux caméras (stéréo) ou une caméra en mouvement (structure from motion), on retrouve la profondeur par triangulation ; avec un motif projeté ou un temps de vol, les caméras 3D (RealSense, Kinect) la mesurent directement. Les réseaux convolutifs (module L14) ont remplacé les détecteurs à la main pour reconnaître des objets (YOLO en temps réel sur Jetson), mais géométrie et filtrage restent indispensables pour passer des détections aux positions et aux commandes.

Cours

Cours 1 — Caractériser un capteur : les mots exacts et comment les mesurer

CaractéristiqueDéfinitionComment la mesurerComment la traiter
Bruit (précision)Dispersion des lectures à entrée constante ; écart-type σ1000 lectures immobiles ; histogramme ; σMoyenne, Kalman (R = σ²)
Biais (justesse)Écart entre la moyenne et la vraie valeurComparer à une référence connueCalibration (soustraire), ou estimer le biais dans le filtre
DériveBiais qui évolue (température, temps)Lectures sur 1 h ; tendance ; test à plusieurs températuresModèle de biais dans l’état (IMU), recalibration, fusion avec un capteur sans dérive
Non-linéaritéRéponse ≠ droite (capteur IR : ∝ 1/d)Courbe d’étalonnage sur toute la plageModèle inverse (L10, moindres carrés), table de correspondance
RésolutionPlus petit changement détectable (LSB de l’ADC)Fiche technique ; bits de l’ADCSur-échantillonnage (+1 bit pour ×4 échantillons)
Latence / bande passanteRetard et fréquence max suivieÉchelon (choc, mouvement brusque) ; réponseCompenser dans le filtre (retard connu) ; ne pas filtrer plus que nécessaire
AberrationsValeurs impossibles occasionnelles (échos, multi-trajets)Fréquence et amplitude sur un long enregistrementMédiane, rejet par Mahalanobis (L19 §02)

Loi d’Allan (pour gyros et horloges). La variance d’Allan σ²(τ) mesure la stabilité en fonction du temps de moyennage τ : pente −1/2 (bruit blanc, la moyenne aide), plateau (instabilité du biais : moyenner plus ne sert à rien), pente +1/2 (marche aléatoire). Elle dit exactement combien de temps il est utile de moyenner un gyro — et donne les paramètres Q du Kalman.

Cours

Cours 2 — Exemple travaillé : dériver le gain de Kalman 1D et comprendre chaque terme

Situation. Avant la mesure, on croit x ∼ N(μ₀, σ₀²) (prédiction). Le capteur donne z = x + bruit, bruit ∼ N(0, r²). Quelle est la meilleure estimation après ?

Bayes : p(x | z) ∝ p(z | x) p(x) ∝ exp(−(z − x)²/2r²) · exp(−(x − μ₀)²/2σ₀²). Le produit de deux gaussiennes est une gaussienne ; en développant l’exposant et en identifiant : 1/σ² = 1/σ₀² + 1/r² (les précisions s’ajoutent) et μ = σ²(μ₀/σ₀² + z/r²) (moyenne pondérée par les précisions).

Forme « gain » : posons K = σ₀²/(σ₀² + r²). Alors μ = μ₀ + K(z − μ₀) et σ² = (1 − K)σ₀². Trois lectures : (1) K ∈ [0, 1] pondère l’innovation z − μ₀ ; (2) si r → 0 (capteur parfait) K → 1, on prend la mesure ; si σ₀ → 0 (prédiction sûre) K → 0, on l’ignore ; (3) la variance après est toujours plus petite qu’avant : une mesure, même mauvaise, informe. En dimension n, K = PHᵀ(HPHᵀ + R)⁻¹ est exactement cette formule avec des matrices.

Cours

Cours 3 — Vision : de la géométrie de la caméra aux caractéristiques

ÉtapeCe qu’elle faitOutils
Modèle de caméraPoint 3D → pixel : K [R | t] X (intrinsèques K, pose extrinsèque)Calibration par damier (cv2.calibrateCamera) ; distorsion radiale k₁, k₂ à corriger (undistort)
PrétraitementNiveaux de gris, flou gaussien, égalisation d’histogramme, seuils adaptatifscvtColor, GaussianBlur, equalizeHist, adaptiveThreshold
Caractéristiques localesPoints d’intérêt répétables (coins, blobs) + descripteurs invariants (rotation, échelle)Harris, FAST ; ORB (rapide, libre), SIFT ; appariement par distance de Hamming + ratio test
Géométrie à deux vuesHomographie (plan), matrice essentielle (mouvement de caméra), triangulationfindHomography avec RANSAC (rejette les faux appariements), findEssentialMat, recoverPose
Détection d’objetsBoîtes + classes en temps réelYOLO (réseau convolutif, L14) ; sur Jetson/Coral ; ArUco pour des marqueurs (pose 6D en quelques ms)
SegmentationClasse par pixel (route, obstacle)U-Net, SAM ; ou couleur + morphologie pour les cas simples

RANSAC (« RANdom SAmple Consensus », 1981) est l’algorithme le plus utilisé de la vision géométrique : tirer le minimum de points pour un modèle, compter ceux qui sont d’accord, garder le meilleur, raffiner. Il tolère 50 % d’aberrations et plus — ce que les moindres carrés ne supportent pas du tout.

TP guidé

TP — Fusion IMU réelle et vision avec OpenCV (sur PC + carte, 3 h)

Exercices

Exercices auto-corrigés — filtres

Exercice 1 — Filtre de Kalman générique et test de cohérence

Écrivez une classe Kalman(F, B, H, Q, R, x0, P0) avec predire(u), corriger(z) (renvoie l’innovation normalisée y²/S) et une fonction nis_moyen(kf, mesures, commandes). Vérifiez sur un système 1D vitesse constante que : la variance P converge (régime établi), le NIS moyen est ≈ 1 quand Q et R sont justes, et > 1 si R est déclaré 10× trop petit.

Correction
class Kalman:
    def __init__(self, F, B, H, Q, R, x0, P0): self.F, self.B, self.H, self.Q, self.R, self.x, self.P = F, B, H, Q, R, x0.astype(float), P0.astype(float)
    def predire(self, u): self.x = self.F @ self.x + (self.B @ u).ravel(); self.P = self.F @ self.P @ self.F.T + self.Q
    def corriger(self, z):
        y = z - self.H @ self.x; S = self.H @ self.P @ self.H.T + self.R; K = self.P @ self.H.T @ np.linalg.inv(S)
        self.x = self.x + K @ y; self.P = (np.eye(len(self.x)) - K @ self.H) @ self.P
        return float(y @ np.linalg.solve(S, y))
def nis_moyen(kf, mesures, commandes):
    return float(np.mean([(kf.predire(u), kf.corriger(z))[1] for z, u in zip(mesures, commandes)][50:]))

Exercice 2 — Filtre médian rapide et détecteur de sauts

a) median_glissant(x, k) en O(n·k) simple, puis vérifiez contre une version naïve. b) detecter_sauts(x, k, seuil) renvoie les indices où |x[i] − médiane locale| > seuil × MAD local (MAD = médiane des écarts absolus, un σ robuste : σ ≈ 1,4826 MAD).

Correction
def median_glissant(x, k):
    h = k // 2; xp = np.pad(x, h, mode="edge"); return np.array([np.median(xp[i:i + k]) for i in range(len(x))])
def detecter_sauts(x, k=15, seuil=5.0):
    m = median_glissant(x, k); e = np.abs(x - m); mad = np.median(e) * 1.4826 + 1e-9      # MAD global : écart-type robuste
    return [int(i) for i in np.where(e > seuil * mad)[0]]

Exercices

Exercices auto-corrigés — capteurs et images

Exercice 3 — Calibration d’un capteur non linéaire et propagation d’incertitude

Un capteur IR donne une tension v ≈ a/(d + b) + c. À partir de mesures (d, v) bruitées : a) ajustez (a, b, c) par Gauss-Newton ou scipy.optimize.least_squares si disponible, sinon par une grille sur b + moindres carrés linéaires sur (a, c) ; b) écrivez distance(v) (modèle inverse) ; c) propagez l’incertitude : si v a un écart-type σ_v, quel est l’écart-type de d à 10 cm et à 60 cm ? (dérivée numérique du modèle inverse). Concluez sur la plage utile.

Correction
def ajuster(d, v):
    best = None
    for b in np.linspace(0, 10, 201):
        X = np.column_stack([1 / (d + b), np.ones_like(d)]); (a, c), res, *_ = np.linalg.lstsq(X, v, rcond=None)
        err = ((X @ [a, c] - v)**2).sum()
        if best is None or err < best[0]: best = (err, a, b, c)
    return best[1:]
def distance(v, a, b, c): return a / (v - c) - b
def incertitude_distance(v, a, b, c, sigma_v=0.02, h=1e-4):
    return abs(distance(v + h, a, b, c) - distance(v - h, a, b, c)) / (2 * h) * sigma_v

Exercice 4 — Composantes connexes et centroïdes d’une image binaire

composantes(masque) étiquette les composantes 4-connexes d’une image booléenne (BFS, L05) et renvoie une liste de (aire, centroïde (ligne, colonne)) triée par aire décroissante ; plus_gros_objet(masque, aire_min) renvoie le centroïde du plus gros ou None. C’est le détecteur d’obstacle/balle le plus simple.

Correction
from collections import deque
def composantes(masque):
    H, W = masque.shape; vu = np.zeros_like(masque); out = []
    for i in range(H):
        for j in range(W):
            if masque[i, j] and not vu[i, j]:
                vu[i, j] = True; file = deque([(i, j)]); pts = []
                while file:
                    a, b = file.popleft(); pts.append((a, b))
                    for c, d in ((a+1, b), (a-1, b), (a, b+1), (a, b-1)):
                        if 0 <= c < H and 0 <= d < W and masque[c, d] and not vu[c, d]: vu[c, d] = True; file.append((c, d))
                out.append((len(pts), (float(np.mean([p[0] for p in pts])), float(np.mean([p[1] for p in pts])))))
    return sorted(out, key=lambda c: -c[0])
def plus_gros_objet(masque, aire_min=5):
    c = composantes(masque); return c[0][1] if c and c[0][0] >= aire_min else None

05 / Défis

Défi ★ — Régler un filtre de Kalman comme un ingénieur

Consigne

1) Simulez un capteur de température (vraie valeur : rampe puis palier) lu à 1 Hz avec bruit σ = 0,5 et un saut aberrant de +8 °C à t = 40 s. 2) Kalman 1D avec état (température, pente) ; mesurez R sur 30 s de palier ; réglez Q pour NIS ≈ 1 ; ajoutez le rejet d’aberration par Mahalanobis. 3) Comparez au passe-bas et au médian : tracez, et donnez pour chacun le retard (temps pour atteindre 90 % d’un échelon) et le RMS. 4) Rédigez en 10 lignes votre procédure de réglage, réutilisable pour n’importe quel capteur.

Piste

Procédure : (1) capteur immobile → R = variance mesurée ; (2) choisir le modèle (constant, pente, accélération) selon la physique ; (3) Q petit → filtre lent mais lisse ; augmenter jusqu’à NIS ≈ 1 ; (4) seuil de rejet χ² à 3σ ; (5) vérifier sur un échelon réel que le retard est acceptable ; (6) enregistrer les données brutes et rejouer hors ligne à chaque changement de réglage.

05 / Défis

Défi ★★ — Suiveur de ligne par vision, simulé de bout en bout

Consigne

Construisez une boucle complète : 1) un « monde » : une ligne courbe sur un plan (fonction y(x)) ; 2) une caméra virtuelle sur le robot (position, cap) qui produit une image 40×60 du sol devant lui (utilisez l’homographie inverse pour échantillonner le plan) ; 3) le détecteur de ligne du module (seuil, centre de la rangée du bas, et aussi celle du milieu pour anticiper) ; 4) un PID (séance 29) qui commande la vitesse angulaire ; 5) le modèle de mouvement différentiel (EKF slide) ; 6) 500 pas de simulation, tracé de la trajectoire par-dessus la ligne. Ajoutez du bruit d’image et un flou de mouvement : jusqu’à quel bruit le suiveur tient-il ?

Piste (caméra virtuelle)
def image_sol(pose, ligne, h=40, w=60, portee=(0.1, 0.6), largeur=0.4):
    """Chaque pixel (i, j) regarde un point du sol devant le robot ; on lit la couleur du monde à cet endroit."""
    x, y, th = pose; img = np.full((h, w), 0.6)
    for i in range(h):
        d = portee[1] - (portee[1] - portee[0]) * i / h                  # rangée du haut = loin
        for j in range(w):
            lat = (j - w / 2) / w * largeur * (d / portee[0])              # perspective : plus loin = plus large
            X = x + d * np.cos(th) - lat * np.sin(th); Y = y + d * np.sin(th) + lat * np.cos(th)
            if abs(Y - ligne(X)) < 0.02: img[i, j] = 0.1
    return img

05 / Défis

Défi ★★★ — Esprit prépa : dériver Kalman et implémenter un UKF

Consigne

1) Démontrez la formule du gain de Kalman en 1D : deux estimations gaussiennes indépendantes (μ₁, σ₁²) et (μ₂, σ₂²) de la même quantité ; montrez que la fusion optimale (au sens du maximum de vraisemblance ou de Bayes) est μ = (σ₂² μ₁ + σ₁² μ₂)/(σ₁² + σ₂²) avec 1/σ² = 1/σ₁² + 1/σ₂², et identifiez K. 2) Généralisez : montrez que K = PHᵀ(HPHᵀ + R)⁻¹ minimise la trace de la covariance a posteriori. 3) Implémentez le filtre de Kalman sans parfum (UKF) : 2n + 1 points sigma propagés par f et h, sans jacobienne ; comparez à l’EKF sur le robot différentiel avec un bruit fort (l’EKF diverge, l’UKF non ?). 4) Lisez le résumé de l’article original de Kalman (1960) et expliquez pourquoi il a été refusé par une revue avant d’être publié.

Piste (UKF)
def points_sigma(x, P, kappa=0.0):
    n = len(x); L = np.linalg.cholesky((n + kappa) * P)
    pts = [x] + [x + L[:, i] for i in range(n)] + [x - L[:, i] for i in range(n)]
    w = np.full(2 * n + 1, 1 / (2 * (n + kappa))); w[0] = kappa / (n + kappa)
    return np.array(pts), w
# Prédiction : propager chaque point par f, moyenne et covariance pondérées + Q.
# Correction : propager par h, covariance croisée Pxz, K = Pxz Pzz⁻¹. Attention aux angles dans les moyennes (moyenne circulaire).

06 / Vérification

Dans un filtre de Kalman, si on augmente R (bruit de mesure) :

Deux questions supplémentaires

1. Pourquoi intégrer deux fois un accéléromètre est-il désespéré à long terme ? Un biais constant b donne une erreur de position ½bt² : quadratique en temps.

2. Pourquoi une caméra seule ne mesure-t-elle pas la distance ? La projection perd la profondeur : tous les points d’un rayon donnent le même pixel. Il faut une seconde vue, une hypothèse (le sol est plan) ou un capteur actif.

Référence

Les mots à retenir

MotDéfinition
Bruit / biais / dériveAléa à chaque mesure / décalage constant / décalage qui évolue.
Passe-bas / médianLisse (retarde) / supprime les aberrations.
Filtre complémentaireHaute fréquence d’un capteur + basse fréquence d’un autre, gains fixes.
KalmanPrédiction (F, Q) puis correction (H, R) ; gain optimal pour gaussiennes linéaires.
Innovation / NISMesure − prédiction / test de cohérence.
MahalanobisDistance normalisée par la covariance ; rejet d’aberrations.
EKF / UKFKalman linéarisé par jacobiennes / par points sigma.
IMU / attitudeGyro + accéléro (+ magnéto) → orientation ; quaternions en 3D.
Convolution / gradient / seuilOutils de base du traitement d’images.
HoughDétection de droites par votes.
Sténopé / intrinsèquesModèle de caméra ; matrice K.
HomographiePlan ↔ image par une matrice 3×3.

Pour continuer

Vous estimez l’état du monde

Module suivant : localisation et cartographie — filtre particulaire, cartes d’occupation, SLAM, et l’architecture logicielle d’un robot (ROS 2).

À faire chez soi

← L18SommaireL20 : Localisation, cartographie, ROS →