Files
l3-ocr-slides/slides.tex
2026-10-16 16:59:18 +02:00

2188 lines
83 KiB
TeX

\documentclass{slides}
\addbibresource{slides.bib}
\title{Objets connectés et robotique}
\subtitle{L3 IFA, S5}
\date{Octobre 2026}
\titlegraphic{\flushright\includegraphics[height=1.3cm]{img/logos.png}\vspace{.5cm}}
\author{
\texorpdfstring{
\begin{table}[]
\begin{flushleft}
\begin{tabular}{ll}
& Vincent Lannurien~\inst{1} \\
& \href{mailto:vincent.lannurien@univ-brest.fr}{\texttt{vincent.lannurien@univ-brest.fr}}
\end{tabular}
\end{flushleft}
\end{table}
}
{
Vincent Lannurien
}
}
\institute{
\texorpdfstring{
\begin{table}[]
\centering
\begin{flushleft}
\begin{tabular}{F}
\inst{1}~Lab-STICC, CNRS UMR 6285, Université de Bretagne Occidentale, Brest
\end{tabular}
\end{flushleft}
\end{table}
}
{
Lab-STICC, CNRS UMR 6285, Université de Bretagne Occidentale, Brest
}
}
\begin{document}
\maketitle
\section{Introduction}
\begin{frame}{Quelques systèmes embarqués...}
\begin{figure}
\begin{subfigure}{.3\textwidth}
\centering
\includegraphics[width=\linewidth]{img/exemples/Mars_Climate_Orbiter_2.jpg}
\end{subfigure}
\begin{subfigure}{.2\textwidth}
\centering
\includegraphics[width=\linewidth]{img/exemples/Ariane_5_V88_pillars.jpg}
\end{subfigure}
\begin{subfigure}{.35\textwidth}
\centering
\includegraphics[width=\linewidth]{img/exemples/Patriot20missile202520Aug202016.jpg}
\end{subfigure}
\end{figure}
\begin{figure}
\begin{subfigure}{.18\textwidth}
\centering
\includegraphics[width=\linewidth]{img/exemples/therac-25.jpg}
\end{subfigure}
\begin{subfigure}{.3\textwidth}
\centering
\includegraphics[width=\linewidth]{img/exemples/uber-arizona.jpg}
\end{subfigure}
\begin{subfigure}{.36\textwidth}
\centering
\includegraphics[width=\linewidth]{img/exemples/titan-submersible.jpg}
\end{subfigure}
\end{figure}
\end{frame}
\begin{frame}{... devenus tristement célèbres}
\begin{itemize}
\item \url{https://en.wikipedia.org/wiki/Mars_Climate_Orbiter}
\begin{itemize}
\item problème d'unités (système métrique vs système impérial)
\end{itemize}
\item \url{https://en.wikipedia.org/wiki/Ariane_flight_V88}
\begin{itemize}
\item erreur de conversion (\textit{overflow})
\end{itemize}
\item \url{https://en.wikipedia.org/wiki/14th_Quartermaster_Detachment}
\begin{itemize}
\item bug d'arrondi (\textit{overflow})
\end{itemize}
\item \url{https://en.wikipedia.org/wiki/Therac-25}
\begin{itemize}
\item erreur de programmation concurrente (\textit{race condition})
\end{itemize}
\item \url{https://en.wikipedia.org/wiki/Death_of_Elaine_Herzberg}
\begin{itemize}
\item détection d'obstacle inopérante
\end{itemize}
\item \url{https://en.wikipedia.org/wiki/Titan_submersible_implosion}
\begin{itemize}
\item certifications de sécurité insuffisantes
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Commençons par un test...}
\begin{itemize}
\item \textit{Trolley problem} (\url{https://en.wikipedia.org/wiki/Trolley_problem}) : le dilemme du tramway
\end{itemize}
\begin{center}
\includegraphics[width=0.5\linewidth]{img/dilemma.png}
\end{center}
\begin{alertblock}{\centering \emoji{thinking}}
\begin{center}
Que feriez-vous ?
$\rightarrow$ \url{https://www.moralmachine.net/hl/fr}
\end{center}
\end{alertblock}
\end{frame}
\begin{framefont}{\small}
\begin{frame}[t]{Plan du cours}
\begin{columns}
\column{0.5\textwidth}
\tableofcontents%[hideallsubsections]
\column{0.5\textwidth}
\begin{center}
\includegraphics[width=.7\columnwidth]{img/rubo-1.png}
\end{center}
\end{columns}
\end{frame}
\end{framefont}
\section{Organisation de l'UE}
\begin{frame}{Organisation de l'UE -- Contenu}
\begin{itemize}
\item Objectifs :
\begin{itemize}
\item Savoir concevoir des systèmes cyberphysiques simples, autonomes
\item Comprendre les compromis entre performance (latence, débit) et consommation (énergie, mémoire)
\end{itemize}
\item Méthode :
\begin{itemize}
\item Le plus de \textbf{manipulations} possible !
\item Dimension \textbf{matérielle} (un peu d'électronique, un peu de mécanique)
\item Dimension \textbf{logicielle} (de l'informatique !)
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Organisation de l'UE -- Logistique}
\begin{itemize}
\item Volume horaire :
\begin{itemize}
\item CM : 8h
\item TP : 14h
\end{itemize}
\item Travail en groupes :
\begin{itemize}
\item Un robot par personne
\item Binômes possibles dans les groupes de TP
\end{itemize}
\item Examen :
\begin{itemize}
\item Démo \textbf{individuelle} lors des TP
\item Rendu de projet sur \href{https://moodlesciences.univ-brest.fr/moodle/course/view.php?id=867}{Moodle}
\end{itemize}
\item Intervenants :
\begin{itemize}
\item Vincent Lannurien -- \href{mailto:vincent.lannurien@univ-brest.fr}{\texttt{vincent.lannurien@univ-brest.fr}}
\item Kilian Le Gall -- \href{mailto:kilian.legall@univ-brest.fr}{\texttt{kilian.legall@univ-brest.fr}}
\end{itemize}
\end{itemize}
\end{frame}
\section{Projet à réaliser}
\begin{frame}{Portée du projet}
\textbf{Objectifs :}
\begin{itemize}
\item Prise en main de l'environnement de développement
\item Implantation d'algorithmes simples sur le robot
\item Étude des compromis performances/ressources
\end{itemize}
\vspace{24px}
\pause
Tout ce que l'on ne va pas faire :
\begin{itemize}
\item Électronique : montages complexes, conception de carte...
\item Traitement du signal : radio, interférences...
\item Sécurité : authentification, détection d'intrusion...
\end{itemize}
\end{frame}
\begin{frame}{Étapes du projet}
\begin{itemize}
\item Commande : Fonctionnement de base d'un robot
\begin{itemize}
\item Envoi de messages : avancer, reculer, tourner, etc.
\item Communications : filaire (série), sans-fil (radio)
\item Interface web de commande : Node.js, JavaScript
\end{itemize}
\item Environnement : capteurs et actionneurs
\begin{itemize}
\item Utilisation d'un capteur de distance
\item Fonctionnement des moteurs
\end{itemize}
\item Contrôle : Programmation de missions simples
\begin{itemize}
\item Comportement autonome :
\begin{itemize}
\item Avancer jusqu'à trouver un obstacle
\item Avancer jusqu'à trouver une ouverture
\item Faire un quart de tour
\item Contourner un objet
\end{itemize}
\end{itemize}
\item En option :
\begin{itemize}
\item Plus de capteurs (second capteur de distance, caméra monochrome...)
\item Plus de cartes (calcul déporté, communication entre robots...)
\end{itemize}
\end{itemize}
\end{frame}
\section{Contexte}
\begin{frame}{Histoire de la robotique -- Automates [\href{https://educ.arte.tv/program/faire-l-histoire-le-canard-de-vaucanson-l-automate-disparu}{réf.}]}
\begin{figure}
\centering
\includegraphics[width=0.5\linewidth]{img/vaucanson-duck.png}
\caption{Canard digérant (Jacques de Vaucanson, 1739)}
\end{figure}
\end{frame}
\begin{frame}{Histoire de la robotique -- Automates}
\begin{figure}
\centering
\includegraphics[width=0.3\linewidth]{img/serinette.png}
\caption{Serinette de Jacotel (famille Husson-Jacotel, début du XIX\textsuperscript{e})}
\end{figure}
\end{frame}
\begin{frame}{Histoire de la robotique -- Automates [\href{https://ingeniumcanada.org/fr/le-reseau/articles/les-chiens-electriques-revent-ils-de-gateries-a-haute-tension-henry-joseph}{réf.}]}
\begin{figure}
\centering
\includegraphics[width=0.7\linewidth]{img/hammond-electric-dog.png}
\caption{Chien électrique (John Hammond et Benjamin Miessner, 1915)}
\end{figure}
\end{frame}
\begin{frame}{Histoire de la robotique -- Automates}
\begin{figure}
\centering
\includegraphics[width=0.8\linewidth]{img/defenseur-du-temps-1.png}
\caption{\textit{Le Défenseur du Temps} (Jacques Monestier, 1979)}
\end{figure}
\end{frame}
\begin{frame}{Histoire de la robotique -- Robots}
\begin{figure}
\centering
\includegraphics[width=0.6\linewidth]{img/goliath.png}
\caption{Goliath, mine filoguidée activable à distance (Normandie, 1944)}
\end{figure}
\end{frame}
\begin{frame}{Histoire de la robotique -- Robots}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Accident de Tchernobyl (1986) :
\begin{itemize}
\item \textbf{Liquidateurs} : personnel civil et militaire intervenu immédiatement sur les lieux de la catastrophe nucléaire
\item 600 000 personnes ont reçu des doses équivalentes à Hiroshima ou Nagazaki
\begin{itemize}
\item Reconnaissance, détection de la radioactivité
\item Démantèlement des débris du réacteur
\item Documentation (photographie)
\item Échantillonnage des matériaux
\item Enfouissement des déchets
\end{itemize}
\end{itemize}
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=0.8\linewidth]{img/stele-liquidateurs-kharkiv.png}
\caption{Stèle à la mémoire des liquidateurs (Kharkiv, Ukraine)}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Histoire de la robotique -- Robots}
\begin{columns}
\column{0.4\linewidth}
\begin{itemize}
\item Développement de robots télécommandés pour l'inspection et le nettoyage \textbf{à distance}
\begin{itemize}
\item \textbf{Télédétection} : caméra, capteurs de radiation
\item \textbf{Télémétrie} : transmission des données vers un poste de contrôle
\item \textbf{Télémanipulation} : bras robotique pour manipuler les débris
\end{itemize}
\end{itemize}
\column{0.6\linewidth}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{img/robot-joker.png}
\caption{Robot \textbf{Joker} (1986)}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Histoire de la robotique -- Robots}
\begin{figure}
\centering
\includegraphics[width=0.7\linewidth]{img/metro-paris.png}
\caption{Ligne 14 du métro de Paris}
\end{figure}
\end{frame}
\begin{frame}{Automates ou robots ?}
\begin{itemize}
\item \textbf{Automate} :
\begin{itemize}
\item répète une séquence fixe de mouvements mécaniques
\item ne s'adapte pas à son environnement
\end{itemize}
\item \textbf{Robot} :
\begin{itemize}
\item possède des capacités de \textit{perception}
\item peut \textit{interagir} avec son environnement
\item peut prendre des décisions \textit{autonomes}
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Définitions -- Systèmes cyberphysiques}
\begin{definition}
\textit{Cyber-Physical Systems (CPS) are integrations of computation with physical processes.}~\footfullcite{leeCyberPhysicalSystems2008}
\end{definition}
\begin{itemize}
\item Énergie : \textit{smart grids}
\item Transport : systèmes ferroviaires, aviation civile, automobile autonome...
\item Santé : dispositifs médicaux "connectés"
\item Industrie : usines automatisées, robots industriels
\item Ville "intelligente"
\end{itemize}
\end{frame}
\begin{frame}{Définitions -- Systèmes cyberphysiques}
\begin{definition}
\textit{Cyber-Physical Systems (CPS) are integrations of computation with physical processes.}~\footfullcite{leeCyberPhysicalSystems2008}
\end{definition}
\begin{center}
\includegraphics[width=0.6\linewidth]{img/cps.png}
\end{center}
\addtocounter{footnote}{1}
\footnotetext{\fullcite{inderwildiImpactIntelligentCyberphysical2020}}
\end{frame}
\begin{frame}{Quelques tendances [\href{https://digital-strategy.ec.europa.eu/fr/policies/next-generation-internet-things}{réf.}]}
\begin{itemize}
\item 41 milliards d'appareils \textit{IoT} déployés en 2025
\item Intelligence artificielle de plus en plus déployée en périphérie de réseau (Apple Intelligence, Google AI Edge)
\item Défis : interopérabilité, durabilité
\end{itemize}
\begin{center}
\includegraphics[width=0.5\linewidth]{img/cloud-edge.png}
\end{center}
\end{frame}
\begin{frame}{Numérique -- Quels impacts ? (2022) [\href{https://infos.ademe.fr/magazine-avril-2022/faits-et-chiffres/numerique-quel-impact-environnemental/}{réf.}]}
\begin{columns}
\column{0.5\linewidth}
Pour chaque Français, le numérique représente :
\begin{itemize}
\item \textbf{Consommation électrique} : 10\%
\item \textbf{Empreinte carbone} : 2.5\%
\item \textbf{Déchets} : 299 kg/habitant/an
\item \textbf{Fabrication} : 78\% de l'impact
\item \textbf{Utilisation} : 21\% de l'impact
\end{itemize}
\column{0.5\linewidth}
\includegraphics[width=\columnwidth]{img/ademe-impacts.jpg}
\end{columns}
\end{frame}
\begin{frame}{Numérique -- Quels impacts ? (2025) [\href{https://infos.ademe.fr/magazine-janvier-2025/numerique-quel-impact-environnemental-en-2022/}{réf.}]}
\begin{columns}
\column{0.7\linewidth}
\begin{center}
\includegraphics[width=0.4\columnwidth]{img/ademe-impacts-2025.png}
\includegraphics[width=0.4\columnwidth]{img/ademe-impacts-2025-3.png}
\end{center}
\begin{itemize}
\item Hausse de l'impact des \textbf{centres de données} : 46\% de l'empreinte carbone du numérique
\end{itemize}
\column{0.3\linewidth}
\includegraphics[width=\columnwidth]{img/ademe-impacts-2025-2.png}
\end{columns}
\end{frame}
\section{Informatique embarquée}
\subsection{Microcontrôleurs}
\begin{frame}{Microcontrôleurs : Utilisations et limites}
\begin{columns}
\column{0.7\linewidth}
\begin{center}
\includegraphics[width=0.145\columnwidth]{img/coffee-maker.png}
\includegraphics[width=0.22\columnwidth]{img/shutter.png}
\includegraphics[width=0.21\columnwidth]{img/electric-car.png}
\end{center}
\begin{itemize}
\item \textbf{Circuit intégré} : calcul (processeur), mémoire (mémoire vive et non-volatile), interfaces d'Entrées/Sorties
\item \textbf{Non-programmable} : son comportement est gravé dans le silicium
\item \textbf{Utilisation} : partout où un processeur généraliste n'est pas nécessaire
\begin{itemize}
\item + : Plus simple à comprendre, à vérifier
\item + : Consommation d'énergie minimale
\item - : Peu flexible
\end{itemize}
\item \textbf{Coût} : en 2018, en moyenne, \$0.03 pour un µc 8-bit, \$1 pour un µc 32-bit $\rightarrow$ ratio $\frac{1}{100}$ par rapport à un PC grand public
\end{itemize}
\column{0.3\linewidth}
\includegraphics[width=\columnwidth]{img/brain.png}
\end{columns}
\end{frame}
\begin{frame}{Microcontrôleurs : Cartes électroniques}
\begin{itemize}
\item \textbf{Énergie} (VCC, GND, tension d'alimentation)
\item \textbf{Architecture} (horloge, mémoire)
\item \textbf{Signal} et \textbf{interfaces} (GPIO, ADC, PWM)
\item \textbf{Capteurs} (communications série, UART, I²C, SPI)
\item \textbf{Actionneurs} (étage de puissance, moteurs, servomoteurs)
\item \textbf{Mécanique} (moteur + réducteur, roues, châssis)
\end{itemize}
\end{frame}
\begin{frame}{Principes de câblage}
% \FIXME{} exemples... pas pédago là
\begin{itemize}
\item Tensions, masse et référence commune
\item Différence entre \textbf{tension d'alimentation} et \textbf{tension logique}
\item Transporter l'\textbf{énergie} : une différence de tension provoque la circulation d'un courant lorsque le circuit électrique est fermé (exemple : LED branchée entre $3.3V$ et $GND$)
\item Transporter l'\textbf{information} : la tension n'est pas forcément constante ; le microcontrôleur peut la faire varier pour transmettre un signal (tension proche de $0V$ = niveau logique à 0, tension proche de $3.3V$ = niveau logique à 1)
\end{itemize}
\end{frame}
\begin{frame}{Principes de câblage}
% \FIXME{} exemples... pas pédago là
\begin{itemize}
\item Commander l'allumage d'une LED, le démarrage d'un moteur, lire l'état d'un bouton, envoyer des données sur un bus de communication, etc.
\item \textbf{ADC} (\textit{Analog to Digital Converter}) : mesure la tension et la transforme en valeur numérique utilisable par le programme
\item Tension = différence de potentiel entre deux points
\begin{itemize}
\item $U_{AB} = V_{A} - V_{B}$
\end{itemize}
\item Il faut donc toujours une \textbf{référence}
\begin{itemize}
\item On choisit un point comme $0V$ : $GND$
\item $GND$ sert également de chemin de retour au courant du signal
\end{itemize}
\item GPIO à $3.3V$ signifie "GPIO à $3.3V$ au-dessus de $GND$"
\end{itemize}
\end{frame}
\begin{frame}{Principes de câblage}
% \FIXME{} exemples... pas pédago là
\begin{itemize}
\item Pull-up et pull-down : résistance de rappel pour forcer un état logique par défaut
\item Exemple : bouton poussoir connecté entre $GND$ et un GPIO configuré en entrée avec pull-up
\begin{itemize}
\item Bouton relâché : GPIO = $3.3V$ (niveau logique à 1)
\item Bouton appuyé : GPIO = $0V$ (niveau logique à 0)
\end{itemize}
\item Nécessaire lorsque le circuit n'est pas fermé (bouton relâché) pour éviter que le GPIO "flotte" et prenne des valeurs aléatoires
\end{itemize}
\end{frame}
\begin{frame}{Architecture}
\begin{columns}
\column{.5\textwidth}
\begin{figure}
\includegraphics[width=\textwidth]{img/architecture.png}
\end{figure}
\column{.5\textwidth}
\begin{alertblock}{Architecture des ordinateurs}
Le \textit{programme} est stocké en \textbf{flash} ; le \textbf{processeur} en exécute les \textit{instructions} ; l'\textbf{horloge} \textit{cadence} son fonctionnement ; la \textbf{RAM} conserve les \textit{données} nécessaires à l'exécution.
\end{alertblock}
Quelle différence entre un ordinateur et un microcontrôleur ?
\end{columns}
\end{frame}
\subsection{Raspberry Pi Pico et écosystème}
\begin{frame}
\begin{center}
\includegraphics[width=0.5\textwidth]{img/rubo-1.png}
\end{center}
\end{frame}
\begin{frame}{Raspberry Pi Pico WH : caractéristiques (RP2040)}
\begin{columns}
\column{0.4\linewidth}
\begin{alertblock}{Plateforme de \emph{prototypage}}
Permet de reprogrammer le système !
\end{alertblock}
\begin{itemize}
\item Microcontrôleur RP2040
\item CPU bicœur Arm Cortex-M0+ @ 133 MHz
\item 264 kB SRAM
\item 2 MB flash
\item Wi-Fi 2.4GHz 802.11n
\item Bluetooth 5.2
\item 26 broches GPIO
\item 2x UART, 2x SPI, 2x I²C, 16x PWM
\item Tension supportée : $1.8$ à $5.5V$
\end{itemize}
\column{0.6\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/raspberry-pi-pico-wh.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{\textit{Shield} générique}
\begin{columns}
\column{0.4\linewidth}
\begin{itemize}
\item Simplifie le câblage des capteurs et actionneurs
\begin{itemize}
\item Redistribue les broches (GPIO, VCC, GND) du Raspberry Pi Pico sur des connecteurs standards à 4 fils : $GND$, $VCC$, $signal_2$, $signal_1$
\end{itemize}
\item Fournit une masse commune sur les connecteurs (I²C, SPI...)
\item Fournit une tension d'alimentation régulée
\end{itemize}
\column{0.6\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/grove-shield.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{\textit{Breadboard} et abaisseur de tension}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item \textit{Breadboard} : permet de réaliser des montages électroniques sans soudure
\item Abaisseur de tension : permet d'alimenter le robot en $5V$ à partir d'une source à une tension plus haute
\begin{itemize}
\item \textit{e.g.}, une pile $9V$
\end{itemize}
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/breadboard-power.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Afficheur LCD}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Afficheur LCD 16x2 caractères
\item Interface I²C
\item Permet d'afficher des informations sur le robot
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/grove-lcd.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{\textit{Shield} de commande de moteurs}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item L298N : 2x "Pont en H"
\item Interface numérique sur quatre broches de signal
\begin{itemize}
\item IN1, IN2 : commande des deux moteurs gauches
\item IN3, IN4 : commande des deux moteurs droits
\end{itemize}
\item Applique une quantité réglable de puissance à une charge
\item Permet de commander deux moteurs à courant continu
\item Permet de faire varier la vitesse et le sens de rotation des moteurs
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/joy-it-sbc-motodriver2.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Télémètre à ultrasons}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Capteur de distance à ultrasons
\item Interface numérique sur une broche
\begin{itemize}
\item 3 fils : \textbf{SIG} (signal numérique bidirectionnel) + VCC + GND
\end{itemize}
\item Permet de mesurer la distance entre le robot et un obstacle
\item Principe : émettre une impulsion sonore et mesurer le temps de retour de l'écho
\begin{itemize}
\item Distance = $\frac{v_{son} \times t_{echo}}{2}$, avec $v_{son} \approx 343 m/s$ à $20°C$
\end{itemize}
\item Précision : 1 mm, portée : 30 mm à 700 mm
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/grove-ultrasonic.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Télémètre à infrarouges}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Capteur de distance à infrarouges
\item Interface I²C
\item Permet de mesurer la distance entre le robot et un obstacle
\item Principe : émettre une impulsion lumineuse et mesurer le temps de retour de l'écho
\begin{itemize}
\item Distance = $\frac{v_{lumiere} \times t_{echo}}{2}$, avec $v_{lumiere} \approx 3\times10^8 m/s$
\end{itemize}
\item Précision : 1 mm, portée : environ 2500 mm
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/vl53l1x-tof.png}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Caméra monochrome}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Caméra monochrome, focus fixe, angle de vision à 60°
\item Interface I²C
\item Permet de capturer des images et de les transmettre au microcontrôleur
\item Résolution : QVGA (320x240 pixels), format : RAW6/RAW8, taille : 76 800 octets (75 KB)
\item Débit : 30 fps $\times$ 76 800 octets = 2250 KB/s
\item Consommation d'énergie : $\lesssim$ 2 mW
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=\textwidth]{img/arducam.png}
\end{figure}
\end{columns}
\end{frame}
\subsection{Programmation et gestion des Entrées/Sorties}
\begin{frame}{Rôle d'un système d'exploitation}
\begin{alertblock}{Quizz}
Qu'est-ce que fournit un système d'exploitation ?
\end{alertblock}
\begin{center}
\includegraphics[width=0.1\linewidth]{img/os-question.png}
\end{center}
\end{frame}
\begin{frame}{Rôle d'un système d'exploitation}
\begin{center}
\includegraphics[width=0.5\linewidth]{img/os-answer.png}
\end{center}
\end{frame}
\begin{frame}[fragile]{Programmation d'un microcontrôleur}
\begin{itemize}
\item \textbf{Pas de système d'exploitation !}
\item Le programme est exécuté directement par le microcontrôleur
\item Pas de gestion de la mémoire, pas de processus
\item Accès direct aux ressources matérielles
\item Programmation en langage C/C++ ou MicroPython
\end{itemize}
\end{frame}
\begin{frame}{Programmation d'un microcontrôleur -- Lectures, écritures}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item \textbf{GPIO} : \textit{General-Purpose Input Output}
\item Lecture \textbf{analogique} : mesure d'une \textit{tension} sur certaines broches
\begin{itemize}
\item Conversion analogique vers numérique (\textit{ADC})
\item $[0.0, 3.3]\,V \rightarrow \texttt{int}\ [0,4095]$
\item Précision : 12 bits, résolution théorique : $\approx 0.81$ mV/valeur
\end{itemize}
\item Lecture/Écriture \textbf{numérique} : états \textit{logiques} (binaires)
\begin{itemize}
\item $0$ (\texttt{LOW}, 0V)
\item $1$ (\texttt{HIGH}, 3.3V ou 5V)
\end{itemize}
\end{itemize}
\column{0.5\linewidth}
\begin{figure}
\centering
\includegraphics[width=0.8\columnwidth]{img/rpi-pico-pinout.png}
\caption{Raspberry Pi Pico WH : broches GPIO\textbf{26}, GPIO\textbf{27} et GPIO\textbf{28} en entrées ADC (peuvent lire la tension en sortie d'un périphérique).}
\end{figure}
\end{columns}
\end{frame}
\begin{frame}{Raspberry Pi Pico -- \textit{Pinout} (brochage)}
\begin{figure}
\centering
\includegraphics[width=0.8\columnwidth]{img/rpi-pico-pinout.png}
\end{figure}
\end{frame}
\begin{frame}{Programmation Raspberry Pi Pico -- Comparatif des interfaces}
\begin{table}[ht]
\centering
\begin{tabular}{L{2cm} C{2.2cm} C{3.8cm} C{3.8cm}}
\toprule
\textbf{Interface} &
\textbf{Niveau d'abstraction} &
\textbf{\Circled{+}} &
\textbf{\Circled{-}} \\
\midrule
\rowcolor{rowgray}
\textbf{MicroPython} (Python)
& Haut
& Simple, interactif
& Performance, déterminisme \\
\textbf{Pico SDK} (C/C++)
& Bas à moyen
& Contrôle, performances
& Lisibilité, compilation \\
\rowcolor{rowgray}
\textbf{Arduino} (C++)
& Haut
& Portabilité, écosystème
& Contrôle, performances \\
\bottomrule
\end{tabular}
\end{table}
\end{frame}
\begin{frame}{Programmation Raspberry Pi Pico -- Comparatif des interfaces}
\begin{alertblock}{Une même tache dans différent paradigmes}
Configurer GP15 en sortie et faire clignoter une LED.
\end{alertblock}
\begin{figure}
\centering
\includegraphics[width=0.7\linewidth]{img/fritzing-led.png}
\end{figure}
\end{frame}
\begin{frame}[fragile]{Programmation Raspberry Pi Pico -- MicroPython}
\begin{minted}[fontsize=\small]{python}
from machine import Pin
from time import sleep
led = Pin(15, Pin.OUT)
while True:
led.toggle()
sleep(1)
\end{minted}
\end{frame}
\begin{frame}[fragile]{Programmation Raspberry Pi Pico -- C++ Pico SDK}
\begin{minted}[fontsize=\small]{c}
#include "pico/stdlib.h"
int main() {
gpio_init(15);
gpio_set_dir(15, GPIO_OUT);
while (true) {
gpio_put(15, 1);
sleep_ms(1000);
gpio_put(15, 0);
sleep_ms(1000);
}
}
\end{minted}
\end{frame}
\begin{frame}[fragile]{Programmation Raspberry Pi Pico -- Arduino API}
\begin{minted}[fontsize=\small]{cpp}
void setup() {
pinMode(15, OUTPUT);
}
void loop() {
digitalWrite(15, HIGH);
delay(1000);
digitalWrite(15, LOW);
delay(1000);
}
\end{minted}
\end{frame}
\begin{frame}{Quizz}
\begin{alertblock}{Quizz}
Comment faire varier l'intensité de la LED pour produire un effet de fondu, en boucle ?
\end{alertblock}
\end{frame}
\begin{frame}{PWM}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Écriture analogique ?
\begin{itemize}
\item Le microcontrôleur ne peut pas générer une tension arbitraire...
\end{itemize}
\item Décrire un phénomène continu par des modulations
\item Technique : \textit{PWM} (\textit{Pulse Width Modulation})
\begin{itemize}
\item Générer un signal carré de fréquence fixe
\item Faire varier le rapport cyclique (durée du niveau haut / période)
\item La valeur moyenne du signal est proportionnelle au rapport cyclique
\end{itemize}
\end{itemize}
\column{0.5\linewidth}
\begin{center}
\includegraphics[width=0.8\columnwidth]{img/pwm.png}
\end{center}
\begin{itemize}
\item Assuré par un composant matériel dédié pour ne pas monopoliser le processeur
\end{itemize}
\end{columns}
\end{frame}
\begin{frame}[fragile]{Mesurer le temps}
Dans le but d'évaluer les performances, mesurer la durée d'une action, etc.
\begin{minted}{cpp}
#include "pico/stdlib.h"
#include <stdio.h>
int main() {
stdio_init_all();
uint64_t start = time_us_64();
sleep_ms(250);
uint64_t stop = time_us_64();
uint64_t elapsed_us = stop - start;
printf("Elapsed: %.3f ms\n", elapsed_us / 1000.0);
}
\end{minted}
\end{frame}
\subsection{Communications}
\begin{frame}{Communications série : UART [\href{http://bts2m.free.fr/TP_Arduino/01_UART.html}{réf.}]}
\begin{itemize}
\item \textbf{UART} : \textit{Universal Asynchronous Receiver Transmitter}
\item Convertit des données \textit{parallèles} (un octet en mémoire) en données \textit{série} (des bits sur un fil)
\item Liaison avec 3 fils : \textbf{Tx} (\textit{transmit} de l'émetteur), \textbf{Rx} (\textit{receive} du récepteur), \textbf{GND} (masse)
\item \textit{Full duplex} : émission et réception simultanées ; point à point : 2 éléments
\item Vitesse : en général 9600 bauds (bits/seconde), au maximum 115200 bauds (environ 14 kB/seconde...)
\item "Masqué" derrière le port USB du Raspberry !
\end{itemize}
\begin{center}
\includegraphics[width=0.6\linewidth]{img/uart.png}
\end{center}
\end{frame}
\begin{frame}[fragile]{Communications série : UART -- Exemple : écriture}
\begin{minted}{cpp}
#include <stdio.h>
#include "pico/stdlib.h"
int main() {
// UART <-> USB
stdio_init_all();
while (true) {
// Affichage dans le terminal série
printf("Hello, World!\n");
sleep_ms(1000);
}
}
\end{minted}
\end{frame}
\begin{frame}[fragile]{Communications série : UART -- Exemple : lecture}
\begin{minted}{cpp}
#include <stdio.h>
#include "pico/stdlib.h"
int main() {
// UART <-> USB
stdio_init_all();
while (true) {
// Lecture (non-bloquante !) depuis le terminal série
int c = getchar_timeout_us(0);
if (c != PICO_ERROR_TIMEOUT) {
printf("Reçu : %c\n", c);
}
// Reste du programme...
}
}
\end{minted}
\end{frame}
\begin{frame}{Communications série : I²C [\href{https://passionelectronique.fr/liaisons-series-uart-i2c-spi/}{réf.}]}
\begin{itemize}
\item \textbf{I²C} : \textit{Inter-Integrated Circuit}
\item Topologie "maître-esclave", adresses uniques, bits de lecture/écriture
\item Liaison avec trois fils : \textbf{SDA} (signal de données), \textbf{SCL} (signal d'horloge), \textbf{GND} (masse)
\item \textit{Semi duplex} : communications bidirectionnelles, mais pas simultanées ; multi-points
\item Vitesse : en général 100 kbps (10x plus rapide que l'UART), au maximum 3.4 Mbps (environ 425 kB/seconde)
\end{itemize}
\begin{center}
\includegraphics[width=0.6\linewidth]{img/i2c.jpg}
\end{center}
\end{frame}
% \begin{frame}[fragile]{Communications série : I²C -- Exemple}
% \begin{minted}{cpp}
% printf("TODO");
% \end{minted}
% \end{frame}
\begin{frame}{Communications série : SPI [\href{https://passionelectronique.fr/liaisons-series-uart-i2c-spi/}{réf.}]}
\begin{itemize}
\item \textbf{SPI} : \textit{Serial Peripheral Interface}
\item Topologie "maître-esclave", pas d'adresses, bits de lecture/écriture
\item Liaison avec quatre fils : \textbf{MOSI} (signal de données maître vers esclave), \textbf{MISO} (signal de données esclave vers maître), \textbf{SCK} (signal d'horloge), \textbf{CS} (sélection de l'esclave)
\item \textit{Full duplex} : communications bidirectionnelles simultanées ; multi-points
\item Vitesse : en général 1 Mbps, au maximum 10 Mbps (environ 1.25 MB/seconde)
\end{itemize}
\begin{center}
\includegraphics[width=0.6\linewidth]{img/spi.png}
\end{center}
\end{frame}
% \begin{frame}[fragile]{Communications série : SPI -- Exemple}
% \begin{minted}{cpp}
% printf("TODO");
% \end{minted}
% \end{frame}
\begin{frame}{Communications sans-fil : Wi-Fi}
\begin{itemize}
\item \textbf{Wi-Fi} : norme IEEE 802.11, réseau local sans-fil
\item Topologie "point d'accès" (AP) ou "ad-hoc"
\item Vitesse : de quelques MB/s à environ 1 GB/s selon la norme (802.11a/b/g/n/ac/ax)
\item Portée : de quelques mètres à quelques dizaines de mètres selon l'environnement
\end{itemize}
\begin{center}
\includegraphics[width=0.6\linewidth]{img/zigbee-chart.png}
\end{center}
\end{frame}
\begin{frame}{Communications sans-fil : comparaison}
\begin{center}
\includegraphics[width=0.9\linewidth]{img/zigbee-table.png}
\end{center}
\end{frame}
\subsection{Chaîne de compilation}
\begin{frame}{Chaîne de compilation croisée}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{img/compilation.png}
\end{figure}
\end{frame}
\begin{frame}{Flasher le Pico : chargeur de démarrage}
\begin{columns}
\column{0.6\linewidth}
\begin{enumerate}
\item Brancher le Pico en USB en maintenant le bouton \texttt{BOOTSEL}
\item Le Pico apparaît comme un disque USB nommé \texttt{RPI-RP2}
\item Copier le firmware compilé (fichier \texttt{.uf2})
\item Le Pico redémarre et le nouveau programme s'exécute.
\end{enumerate}
\column{0.4\linewidth}
\begin{figure}
\centering
\includegraphics[width=\columnwidth]{img/pico-bootsel.png}
\end{figure}
\end{columns}
\medskip
\begin{alertblock}{En pratique}
Le programme fonctionne : on peut demander l'entrée en mode BOOTSEL par USB.
S'il ne répond plus : maintenir \textbf{BOOTSEL} en rebranchant le câble, puis charger le même fichier UF2.
\end{alertblock}
\end{frame}
\section{Robotique}
\subsection{Généralités}
\begin{frame}{Qu'est-ce qu'un robot ?}
\begin{center}
\includegraphics[width=0.5\linewidth]{img/sojourner-mars.jpg}
\footnotesize \textit{Sojourner} sur la surface de Mars, décembre 1997 [\href{https://science.nasa.gov/photojournal/sojourner-rover-near-the-dice/}{réf.}]
\end{center}
\end{frame}
\begin{frame}{Qu'est-ce qu'un robot ?}
\textbf{Robot = système de systèmes}
\begin{itemize}
\item \textbf{Mobilité} : énergie, déplacement (propulsion), orientation (direction)
\item \textbf{Charge utile} : capteurs, informations, matériels, etc.
\item \textbf{Intelligence} : contrôle, commande, communication, décision
\end{itemize}
\end{frame}
\begin{frame}{Qu'est-ce qu'un robot ? -- Mobilité}
\begin{figure}
\begin{subfigure}{.48\textwidth}
\centering
\includegraphics[width=.8\linewidth]{img/china-humanoid-robots.png}
\end{subfigure}
\begin{subfigure}{.48\textwidth}
\centering
\includegraphics[width=.6\linewidth]{img/boston-dynamics-spot.png}
\end{subfigure}
\end{figure}
\begin{figure}
\begin{subfigure}[t]{.48\textwidth}
\vspace{0pt}
\centering
\includegraphics[width=.8\linewidth]{img/drones-ukraine.png}
\end{subfigure}
\begin{subfigure}[t]{.48\textwidth}
\vspace{0pt}
\centering
\includegraphics[width=.8\linewidth]{img/usv-ifremer.png}
\end{subfigure}
\end{figure}
\end{frame}
\begin{frame}{Qu'est-ce qu'un robot ? -- Charge utile [\href{https://www.thespacereview.com/article/4951/1}{réf.}]}
\begin{figure}
\centering
\includegraphics[width=0.8\linewidth]{img/farrah-satellites.png}
\end{figure}
\end{frame}
\begin{frame}{Qu'est-ce qu'un robot ? -- Charge utile}
\begin{figure}
\begin{subfigure}{.48\textwidth}
\centering
\includegraphics[width=\linewidth]{img/boston-dynamics-weapon.png}
\end{subfigure}
\begin{subfigure}{.48\textwidth}
\centering
\includegraphics[width=\linewidth]{img/robot-industriel.png}
\end{subfigure}
\end{figure}
\end{frame}
\begin{frame}{Qu'est-ce qu'un robot ? -- Intelligence}
\begin{figure}
\begin{subfigure}{.48\textwidth}
\centering
\includegraphics[width=0.8\linewidth]{img/microcontrollers.png}
\end{subfigure}
\begin{subfigure}{.48\textwidth}
\centering
\includegraphics[width=0.8\linewidth]{img/jetson-orin-nano.png}
\end{subfigure}
\end{figure}
\end{frame}
\begin{frame}{Définitions -- Systèmes autonomes}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Robotique, systèmes autonomes~\footnote[frame]{\fullcite{kephartVisionAutonomicComputing2003}} :
\begin{itemize}
\item \textbf{Capteurs} : produisent une vue de l'environnement du système
\item \textbf{Actionneurs} : commandent le système selon son état et sa consigne
\end{itemize}
\item Objets connectés, \textit{Internet of Things} (\textit{IoT}) : contrôle, commande à distance
\end{itemize}
\column{0.5\linewidth}
\includegraphics[width=\columnwidth]{img/mape-k.png}
\end{columns}
\end{frame}
\begin{frame}{Intelligence -- Chaîne de l'information}
\begin{figure}
\centering
\includegraphics[width=0.7\linewidth]{img/chaine-traitement.png}
\end{figure}
\end{frame}
% \begin{frame}{Capteurs -- Classes}
% \begin{itemize}
% \item Proprioceptifs :
% \begin{itemize}
% \item Attitude, position, vitesse, etc.
% \item Donnent des informations sur l'état de l'élément piloté
% \end{itemize}
% \item Extéroceptifs
% \begin{itemize}
% \item Localisation, obstacles, etc.
% \item Donnent des informations sur l'environnement de l'élément piloté
% \end{itemize}
% \item Actifs
% \begin{itemize}
% \item Sonar, radar, LiDAR, etc.
% \end{itemize}
% \item Passifs
% \begin{itemize}
% \item Contacts, acoustique, gyroscope, etc.
% \end{itemize}
% \end{itemize}
% \end{frame}
\begin{frame}{Intelligence -- Capteurs [\href{https://spe-lavoisier.fr/1SI/Cours/Chapitre4.php}{réf.}]}
\begin{columns}
\column{0.5\linewidth}
Caractéristiques d'un capteur :
\begin{itemize}
\item Temps de réponse
\item Fréquence d'échantillonnage
\item Précision, finesse, résolution, stabilité
\item Coût
\item Taux d'erreur (dispersion, aberrations, etc.)
\item Robustesse (environnement)
\item Charge de calcul induite
\item Poids, consommation d'énergie, dimensions, etc.
\end{itemize}
\column{0.5\linewidth}
\includegraphics[width=\columnwidth]{img/sensor-error.png}
\begin{exampleblock}{Exemple : capteur de distance à ultrasons}
distance $\rightarrow$ temps de vol d'une onde ultrasonore
$\rightarrow$ durée d'une impulsion électrique $\rightarrow$
mesure du temps par le Pico $\rightarrow$ $d = v \times t / 2$
\end{exampleblock}
\end{columns}
\end{frame}
% \begin{frame}{Intelligence -- Actionneurs}
% \begin{columns}
% \column{0.5\linewidth}
% \begin{itemize}
% \item \TODO{} plus de détails sur les actionneurs
% \end{itemize}
% \column{0.5\linewidth}
% \TODO
% \end{columns}
% \end{frame}
\begin{frame}{Intelligence -- Contrôle, commandes, asservissement}
\begin{itemize}
\item Éléments contrôlés en boucle fermée : \textbf{asservissements}
\item Système automatique qui ajuste son comportement en fonction de \textbf{consignes} et de \textbf{mesures}
\item Exemple :
\begin{exampleblock}{\emoji{repeat} Boucle d'asservissement}
\begin{enumerate}
\item \emoji{dart} \textbf{Consigne} : objectif à atteindre (ex : avancer à 10 cm du mur)
\item \emoji{bar-chart} \textbf{Mesure} : capteur qui lit la position (GPS), la distance réelle (LiDAR), etc.
\item \emoji{cross-mark} \textbf{Erreur} : différence entre consigne et mesure
\item \emoji{brain} \textbf{Contrôleur} : calcule la \textbf{commande} à partir de l'erreur
\item \emoji{robot} \textbf{Commande} : signal envoyé au système (ex : augmenter la vitesse des moteurs)
\end{enumerate}
\end{exampleblock}
\end{itemize}
\end{frame}
\begin{frame}{Problème : le positionnement}
\begin{columns}
\column{0.6\linewidth}
\begin{itemize}
\item \textbf{Cap} = \textbf{consigne} + \textbf{erreur}
\begin{itemize}
\item Comment savoir où se trouve le robot ?
\item Comment savoir où se dirige le robot ?
\item Comment savoir où se trouve un obstacle ?
\end{itemize}
\end{itemize}
\column{0.4\linewidth}
\begin{figure}
\centering
\includegraphics[width=.8\linewidth]{img/missile.png}
\end{figure}
\end{columns}
\begin{exampleblock}{The Missile Knows Where It Is [\href{https://knowyourmeme.com/memes/the-missile-knows-where-it-is}{réf.}]}
\textit{The missile knows where it is at all times. It knows this because it knows where it isn't. By subtracting where it is from where it isn't, or where it isn't from where it is (whichever is greater), it obtains a difference, or deviation. The guidance subsystem uses deviations to generate corrective commands to drive the missile from a position where it is to a position where it isn't, and arriving at a position where it wasn't, it now is. Consequently, the position where it is, is now the position that it wasn't, and it follows that the position that it was, is now the position that it isn't.}
\end{exampleblock}
\end{frame}
\begin{frame}{Systèmes de positionnement -- Principes}
\begin{itemize}
\item \textbf{Positionnement global} : localisation dans un référentiel géographique
\begin{itemize}
\item \textbf{GNSS} (GPS, Galileo, etc.) : triangulation (trilatération) à partir de signaux satellites
\end{itemize}
\vspace{0.4cm}
\item \textbf{Positionnement local} : estimation de la position par rapport à l'environnement
\begin{itemize}
\item \textbf{Odométrie} : mesure des déplacements à partir de capteurs (ex : roues, inertie)
\item \textbf{LiDAR} : mesure des distances par laser
\item \textbf{Radar} : mesure des distances et vitesses par ondes radio
\item \textbf{Caméras} : analyse des images par vision par ordinateur
\end{itemize}
\vspace{0.4cm}
\item \textbf{Localisation} : exploitation des mesures pour estimer la position
\begin{itemize}
\item SLAM (\textit{Simultaneous Localization and Mapping}) : estimer les déplacements et la position dans un environnement local
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Systèmes de positionnement -- Comparaison}
\begin{table}
\centering
\small
\begin{tabular}{L{2cm} L{4.2cm} L{5cm}}
\toprule
\textbf{Technologie} & \textbf{Avantages} & \textbf{Limites} \\
\midrule
\rowcolor{rowgray}
\textbf{GPS/GNSS}
& Position absolue, couverture mondiale
& Peu fiable en intérieur, précision variable \\
\textbf{LiDAR}
& Mesures précises, cartographie 2D/3D
& Coût, sensibilité aux conditions météo \\
\rowcolor{rowgray}
\textbf{Radar}
& Robuste aux intempéries, mesure des vitesses
& Résolution spatiale souvent inférieure au LiDAR \\
\textbf{Caméras}
& Faible coût, information visuelle riche
& Sensibilité à l'éclairage, calcul intensif \\
\bottomrule
\end{tabular}
\end{table}
$\rightarrow$ \textbf{Fusion de capteurs} : combiner plusieurs technologies pour compenser leurs limites.
\end{frame}
\subsection{Commande à distance}
\begin{frame}[fragile]{Commande -- Communications}
\begin{itemize}
\item Architecture :
\begin{itemize}
\item PC : Envoi de commandes filaire $\rightarrow$ USB $\rightarrow$ Robot
\item Téléphone : Envoi de commandes sans fil $\rightarrow$ Wi-Fi $\rightarrow$ Robot
\end{itemize}
\item Peu importe le type de liaison, le même programme s'exécute sur le microcontrôleur
\item $\rightarrow$ Il faut programmer le Raspberry pour \textbf{recevoir}, \textbf{décoder} et \textbf{exécuter} des lignes de commande.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Commande -- Communications}
\begin{alertblock}{Communications avec le robot}
\begin{itemize}
\item Objectifs : avancer, reculer, tourner...
\item Quels éléments va-t-on commander ?
\item Sur la base de quelles informations ?
\item $\rightarrow$ De quelles \textbf{protocole} avons-nous besoin ?
\end{itemize}
\end{alertblock}
\end{frame}
\begin{frame}[fragile]{Commande -- Communications -- Syntaxe des commandes (JSON)}
\begin{center}
\resizebox{0.9\textwidth}{!}{%
\footnotesize
\begin{tabular}{p{0.42\textwidth}p{0.53\textwidth}}
\toprule
\textbf{Commande} & \textbf{Effet} \\
\midrule
\rowcolor{rowgray}
\mintinline{json}|{"left":200,"right":200}|
& Avancer des deux côtés pendant une seconde par défaut \\
\mintinline{json}|{"left":200,"right":-200,"duration":3000}|
& Tourner sur place pendant trois secondes \\
\rowcolor{rowgray}
\mintinline{json}|{"stop":true}|
& Arrêter immédiatement les roues et annuler la mission du robot \\
\mintinline{json}|{"telemetry":500}| / \mintinline{json}|{"telemetry":0}|
& Envoyer la télémétrie toutes les 500 ms / désactiver la télémétrie périodique \\
\rowcolor{rowgray}
\mintinline{json}|{"mission":1}| / \mintinline{json}|{"mission":0}|
& Sélectionner la mission 1 / désactiver la mission du robot \\
\mintinline{json}|{"info":true}|
& Envoyer une ligne séparée contenant les informations du robot \\
\rowcolor{rowgray}
\mintinline{json}|{"seq":7,"left":100,"right":100}|
& Associer l'identifiant 7 aux télémétries suivantes \\
\bottomrule
\end{tabular}
}
\end{center}
\end{frame}
\begin{frame}[fragile]{L'étiquette \texttt{seq}}
\begin{itemize}
\item Choisie par l'émetteur
\item Chaque commande qui la fournit remplace la valeur mémorisée
\item Toutes les lignes de télémétrie suivantes portent la dernière valeur
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Commande -- Communications -- Syntaxe des réponses (JSON)}
\begin{center}
\resizebox{0.9\textwidth}{!}{%
\footnotesize
\begin{tabular}{p{0.27\textwidth}p{0.68\textwidth}}
\toprule
\textbf{Champ} & \textbf{Signification} \\
\midrule
\rowcolor{rowgray}
\mintinline{text}|seq|
& Identifiant de la dernière commande, ou \mintinline{json}|-1| si aucun n'a été fourni \\
\mintinline{text}|ms|
& Temps écoulé depuis le démarrage du robot, en millisecondes \\
\rowcolor{rowgray}
\mintinline{text}|left|, \mintinline{text}|right|
& Vitesses actuellement demandées aux roues, et non vitesses mesurées \\
\mintinline{text}|moving|
& \mintinline{json}|true| si la vitesse demandée d'au moins une roue est non nulle \\
\rowcolor{rowgray}
\mintinline{text}|mission|
& Numéro de la mission sélectionnée ; \mintinline{json}|0| signifie qu'aucune mission n'est active \\
\mintinline{text}|front_mm|, \mintinline{text}|side_mm|
& Dernière distance mesurée en millimètres, ou \mintinline{json}|-1| si indisponible \\
\rowcolor{rowgray}
\mintinline{text}|front_ok|, \mintinline{text}|side_ok|
& Indique si la dernière mesure du capteur est valide ; à vérifier avant d'utiliser la distance \\
\mintinline{text}|front_q|, \mintinline{text}|side_q|
& Qualité du signal : \mintinline{text}|front_q| vaut toujours \mintinline{json}|-1| ;
\mintinline{text}|side_q| indique le taux de signal du VL53L1X, ou \mintinline{json}|-1| si indisponible \\
\rowcolor{rowgray}
\mintinline{text}|done|
& Présent avec la valeur \mintinline{json}|true| uniquement lorsque le contrôle de sécurité arrête les roues \\
\bottomrule
\end{tabular}
}
\end{center}
\end{frame}
\subsection{Interface utilisateur}
\begin{frame}{IHM -- Terminal série}
\begin{itemize}
\item \textbf{Terminal} : interface en ligne de commande
\item Permet de communiquer avec le microcontrôleur via l'UART
\item Le Pico expose un \textbf{port série virtuel} \textit{via} USB
\begin{itemize}
\item Ex. : \texttt{/dev/ttyACM0} sous Linux
\end{itemize}
\item On peut envoyer des commandes et lire les réponses du microcontrôleur
\item On utilise \texttt{screen} ou \texttt{minicom} pour ouvrir un terminal série
\begin{itemize}
\item \texttt{screen /dev/ttyUSB0 115200}
\begin{itemize}
\item \texttt{Ctrl-A} puis \texttt{Ctrl-D} pour quitter \texttt{screen}
\end{itemize}
\item \texttt{minicom -D /dev/ttyUSB0 -b 115200}
\begin{itemize}
\item \texttt{Ctrl-A} puis \texttt{X} pour quitter \texttt{minicom}
\end{itemize}
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}
\begin{figure}
\centering
\includegraphics[width=0.7\linewidth]{img/ihm-terminal.png}
\end{figure}
\end{frame}
\begin{frame}
\begin{figure}
\centering
\includegraphics[width=0.6\linewidth]{img/ihm-web.png}
\end{figure}
\end{frame}
\begin{frame}{IHM -- Interface web}
\begin{alertblock}{Quelle différence ?}
\textit{Missions firmware} et \textit{missions téléphone} ?
\end{alertblock}
\end{frame}
\subsection{Missions}
\begin{frame}{Missions -- Interface de programmation du robot}
\begin{itemize}
\item \textbf{Protocole de commande} : envoyer des commandes JSON au robot et recevoir la télémétrie
\item \textbf{Interfaces de programmation} :
\begin{itemize}
\item fonctions C++ dans \texttt{Robot.h} pour piloter le robot "de l'intérieur"
\item fonctions JavaScript dans \texttt{robot.js} pour piloter le robot "depuis l'extérieur"
\end{itemize}
\item \textbf{Missions} : séquences de commandes à exécuter sur le robot
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Missions -- Programmer des déplacements}
\begin{itemize}
\item \textbf{Objectif} : programmer une séquence de mouvements
\begin{itemize}
\item Avancer pendant 1 s, puis reculer pendant 1 s
\item Effectuer un quart de tour à gauche
\end{itemize}
\item \textbf{Commande} : vitesse des roues gauche/droite et durée
\end{itemize}
\begin{minted}[fontsize=\small]{json}
{"left":200,"right":200,"duration":1000}
\end{minted}
\begin{itemize}
\item \textbf{Enchaînement} : une nouvelle commande remplace la commande en cours
\begin{itemize}
\item Attendre la ligne \texttt{done:true} avant d'envoyer le mouvement suivant
\item Le champ \texttt{seq} renvoie le numéro de la dernière commande reçue : attendre un \texttt{done} dont le \texttt{seq} est $\geq$ à celui envoyé
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Missions -- Deux architectures}
\begin{table}
\centering
\small
\begin{tabular}{L{3cm} L{4cm} L{4cm}}
\toprule
& \textbf{Téléphone (\texttt{robot.js})}
& \textbf{Robot (\texttt{Robot.h})} \\
\midrule
\rowcolor{rowgray}
\textbf{Exécution}
& Navigateur du téléphone
& Microcontrôleur Pico \\
\textbf{Commandes}
& Envoyées successivement par HTTP
& Exécutées localement \\
\rowcolor{rowgray}
\textbf{Synchronisation}
& Attente du message \texttt{done}
& Surveillance de l'horloge (\texttt{nowMs()}) \\
\textbf{Conséquence}
& Délais liés aux échanges réseau
& Enchaînement immédiat possible \\
\bottomrule
\end{tabular}
\end{table}
\vspace{0.3cm}
\begin{itemize}
\item \textbf{Téléphone} : l'API \texttt{Mission} automatise l'enchaînement des commandes.
\item \textbf{Robot} : la mission s'exécute dans \texttt{Robot::update()}, sans attente bloquante (\texttt{sleep\_ms()}).
\end{itemize}
\end{frame}
\begin{frame}{Missions -- API et protocole de communication}
\centering
\begin{tikzpicture}[
>=Latex,
block/.style={
draw,
rounded corners=3pt,
fill=blue!5,
text width=3.2cm,
minimum height=3.4cm,
align=left,
inner sep=6pt,
font=\small
}
]
% Téléphone
\node[block] (js) at (-4,0) {
\textbf{Téléphone}\\
\textit{Navigateur web}\\[0.3cm]
\textbf{API JavaScript}\\
\texttt{robot.js}\\[0.2cm]
\footnotesize
\texttt{Robot} : commandes\\
\texttt{Mission} : séquences
};
% Robot
\node[block] (cpp) at (4,0) {
\textbf{Robot}\\
\textit{Raspberry Pi Pico}\\[0.3cm]
\textbf{API C++}\\
\texttt{Robot.h}\\[0.2cm]
\footnotesize
\texttt{drive()} : moteurs\\
\texttt{mission()} : séquences
};
% Protocole
\node[align=center] at (0,2.3) {
\textbf{Protocole JSON}\\
\scriptsize HTTP / Wi-Fi
};
% Commandes
\draw[->, thick, blue]
([yshift=0.7cm]js.east) --
node[midway, above=4pt, align=center,
font=\scriptsize, text=blue] {
\textbf{Commandes}\\
\texttt{\{"seq":42,...\}}
}
([yshift=0.7cm]cpp.west);
% Télémétrie
\draw[->, thick, ForestGreen]
([yshift=-0.7cm]cpp.west) --
node[midway, below=4pt, align=center,
font=\scriptsize, text=ForestGreen] {
\textbf{Télémétrie}\\
\texttt{\{"seq":42,"done":true,...\}}
}
([yshift=-0.7cm]js.east);
\end{tikzpicture}
\vspace{0.4cm}
\begin{itemize}
\item \textbf{Deux possibilités} : séquencer les mouvements
depuis le téléphone ou directement sur le robot.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Missions -- Tourner de 90°}
\begin{itemize}
\item \textbf{Principe} : faire tourner les roues en sens opposés
\end{itemize}
\begin{minted}[fontsize=\small]{json}
{"left":-180,"right":180,"duration":600}
\end{minted}
\begin{itemize}
\item \textbf{Problème} : sans encodeur ni gyroscope, le robot ne mesure pas son angle de rotation.
\item \textbf{Solution} : calibrer la durée du mouvement
\begin{enumerate}
\item Effectuer un virage de durée connue
\item Mesurer l'angle obtenu
\item Ajuster la durée proportionnellement
\end{enumerate}
\end{itemize}
\[
t_{\text{nouveau}} =
t_{\text{ancien}} \times
\frac{90^\circ}{\theta_{\text{mesuré}}}
\]
\begin{itemize}
\item \textbf{Limite} : calibration dépendante de la vitesse,
du sol et du niveau de batterie.
\end{itemize}
\end{frame}
\subsection{Comportement autonome et contrôle}
\begin{frame}{Un constat : le besoin de calibration}
\begin{itemize}
\item Les moteurs ne sont pas identiques
\item Les roues ne sont pas identiques
\item Le robot n'est pas parfaitement symétrique
\item Le sol n'est pas parfaitement plat
\item $\rightarrow$ Le robot ne se déplace pas \textit{exactement comme prévu}
\end{itemize}
\end{frame}
\begin{frame}{Comportement autonome -- Origines historiques}
\begin{columns}
\column{0.5\linewidth}
\begin{itemize}
\item Sans régulation : la machine peut \textbf{accélérer dangereusement} ou \textbf{ralentir}
\item Problèmes de sécurité et de fiabilité
\item $\rightarrow$ Comment stabiliser la vitesse des machines à vapeur (moulins, locomotives, etc.) ?
\end{itemize}
\column{0.5\linewidth}
\begin{center}
\includegraphics[width=\columnwidth]{img/mulhouse_electropolis.jpg}
{\footnotesize Machine à vapeur Sulzer et alternateur Brown Boveri (Electropolis, Mulhouse)}
\end{center}
\end{columns}
\end{frame}
\begin{frame}{Comportement autonome -- Théorie du contrôle}
\begin{columns}
\column{0.3\linewidth}
\includegraphics[width=\columnwidth]{img/regulateur_huygens.jpg}
\column{0.7\linewidth}
\begin{itemize}
\item Comment stabiliser la vitesse des machines à vapeur (moulins, locomotives, etc.) ?
\item \textbf{Régulateur à boules} pour machines à vapeur (James Watt \emoji{flag-scotland}) (XVIII~\textsuperscript{ème})
\item Plus la machine accélère, plus les boules s'écartent, réduisant l'arrivée de vapeur $\rightarrow$ diminution de la vitesse
\item Initialement proposé par Christian Huygens \emoji{flag-netherlands} (XVII~\textsuperscript{ème})
\item Principe purement mécanique
\item Limites :
\begin{itemize}
\item Réponse lente
\item Pas de correction d'erreur persistante
\item Pas d'anticipation des variations rapides
\item Pas adapté aux systèmes numériques !
\end{itemize}
\end{itemize}
\end{columns}
\end{frame}
\begin{frame}{Comportement autonome -- Théorie du contrôle}
\begin{columns}
\column{0.4\linewidth}
\begin{itemize}
\item \textbf{PID} : mis en équation en 1922 par Nicolas Minorsky \emoji{flag-russia}
\item Testé sur un cuirassé de l'US Navy, l'USS New Mexico
\item En pilotage automatique, en partant d'une erreur de 2 degrés, le navire a pu faire mieux qu'un barreur humain en maintenant son cap avec une précision d'1/3 de degré
\end{itemize}
\column{0.6\linewidth}
\includegraphics[width=\columnwidth]{img/uss_new_mexico.jpg}
\end{columns}
\end{frame}
\begin{frame}{Contrôle -- Fonctionnement du PID}
\begin{center}
\textit{Feedback loop} : stabiliser automatiquement des systèmes en s'appuyant sur les comportements passés
\vspace{16px}
\includegraphics[width=0.8\linewidth]{img/pid.png}
\end{center}
\end{frame}
\begin{frame}{Contrôle -- Fonctionnement du PID}
Équation du PID en version discrète (pour une implantation numérique) :
\begin{equation}
u[n] = K_p \cdot e[n] + K_i \cdot \sum_{k=0}^{n} e[k] + K_d \cdot (e[n] - e[n-1])
\end{equation}
\end{frame}
\begin{frame}{Contrôle -- Fonctionnement du PID}
Équation du PID en version discrète (pour une implantation numérique) :
\begin{equation}
u[n] = K_p \cdot e[n] + K_i \cdot \sum_{k=0}^{n} e[k] + K_d \cdot (e[n] - e[n-1])
\end{equation}
\begin{itemize}
\item Composante $p$ : correction proportionnelle à l'erreur
\begin{itemize}
\item \emoji{cross-mark} Problème : erreur persistante $\rightarrow$ délai de correction très long
\end{itemize}
\item Composante $i$ : correction proportionnelle à la somme des erreurs précédentes
\begin{itemize}
\item \emoji{cross-mark} Problème : instabilité de la trajectoire $\rightarrow$ oscillations
\end{itemize}
\item Composante $d$ : correction prédictive basée sur la variation de l'erreur
\begin{itemize}
\item \emoji{check-mark} L'erreur augmente $\rightarrow$ on "accélère" la correction
\item \emoji{check-mark} L'erreur diminue $\rightarrow$ on "freine" la correction
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Contrôle -- Objectifs du PID}
\begin{center}
{
\renewcommand{\arraystretch}{2}
\begin{tabular}{C{0.45\textwidth} C{0.45\textwidth}}
\toprule
\textbf{Sans PID} & \textbf{Avec PID} \\
\midrule
\rowcolor{rowgray}
\textcolor{BrickRed}{Réactions brutales}
& \textcolor{ForestGreen}{Réactions fluides} \\
\textcolor{BrickRed}{Oscillations}
& \textcolor{ForestGreen}{Stabilité} \\
\rowcolor{rowgray}
\textcolor{BrickRed}{Dépassement}
& \textcolor{ForestGreen}{Précision} \\
\bottomrule
\end{tabular}
}
\end{center}
\end{frame}
\subsection{Calcul déporté}
\begin{frame}{Calcul déporté -- Une affaire de compromis}
\begin{itemize}
\item Il est possible de réaliser une partie des calculs sur le PC qui commande le robot
\item Mais...
\end{itemize}
\vspace{16px}
\begin{exampleblock}{Avantages, inconvénients ?}
\begin{itemize}
\item Quels sont ici les \textbf{compromis} à réaliser ?
\item Comment appelle-t-on un tel système ?
\end{itemize}
\end{exampleblock}
\end{frame}
\begin{frame}{Calcul déporté -- Une affaire de compromis}
\begin{itemize}
\item Compromis techniques :
\begin{itemize}
\item \textbf{Temps de calcul} : PID simple adapté au Raspberry Pi Pico ?
\item \textbf{Mémoire} : quel historique des erreurs peut-on stocker ?
\item \textbf{Énergie} : gains avec le PID ?
\item \textbf{Latence} : calcul local = réponse rapide
\end{itemize}
\end{itemize}
\end{frame}
\section{Présentation des TP}
\begin{frame}{Organisation du dépôt}
\begin{itemize}
\item \texttt{robot/} : programme, drivers capteurs et actionneurs, sécurité
\begin{itemize}
\item \texttt{main.cpp} : boucle principale du robot
\item \texttt{Robot.h} : missions embarquées
\item \texttt{Config.h} : configuration matérielle
\end{itemize}
\item \texttt{robot/web/} : application web intégrée au firmware
\begin{itemize}
\item \texttt{index.html} : interface utilisateur
\item \texttt{robot.js} : envoi HTTP des commandes, lecture périodique de la télémétrie, exécution des séquences
\item \texttt{missions.js} : missions exécutées sur le téléphone
\end{itemize}
\item \texttt{schematics/} : schéma de câblage (Fritzing)
\end{itemize}
\end{frame}
\begin{frame}{Deux liaisons, deux usages}
\begin{itemize}
\item \textbf{Ordinateur $\longleftrightarrow$ Pico (USB) :}
\begin{itemize}
\item chargement du programme
\item messages sur le port série
\item \textit{en mode série}, commandes et télémétrie échangées sur ce même port
\end{itemize}
\item \textbf{Téléphone $\longleftrightarrow$ Pico (WiFi) :}
\begin{itemize}
\item le Pico sert la page HTML
\item le navigateur du téléphone exécute le JavaScript
\item \textit{en mode WiFi}, commandes et télémétrie échangées en HTTP
\end{itemize}
\end{itemize}
\begin{alertblock}{En pratique}
Le WiFi ne remplace pas complètement l'USB : toute modification du C++ \emph{ou de la page web} nécessite de recompiler et de recharger le Pico.
\end{alertblock}
\end{frame}
\begin{frame}{Mission sur le Pico ou sur le téléphone ?}
\begin{columns}[T]
\column{0.5\linewidth}
\textbf{Mission sur le Pico} (\texttt{Robot.h})
\begin{itemize}
\item \Circled{1} Relevé capteur
\item \Circled{2} Décision dans la boucle du Pico
\item \Circled{3} Commande des moteurs
\end{itemize}
\column{0.5\linewidth}
\textbf{Mission sur le téléphone} (\texttt{missions.js})
\begin{itemize}
\item \Circled{1} Relevé capteur
\item \Circled{2} Télémétrie par WiFi
\item \Circled{3} Décision dans le navigateur
\item \Circled{4} Commande par WiFi
\item \Circled{5} Commande des moteurs
\end{itemize}
\end{columns}
\begin{alertblock}{En pratique}
Le trajet par le téléphone ajoute des délais et des risques de perte de communication.
\end{alertblock}
\end{frame}
\begin{frame}{Progression des séances de TP}
\begin{center}
\begin{tabular}{@{}lp{0.30\textwidth}p{0.55\textwidth}@{}}
\toprule
\textbf{TP} & \textbf{Thème} & \textbf{Objectifs} \\
\midrule
\rowcolor{rowgray}
1 & Découverte & Compiler, charger, piloter par USB puis WiFi \\
2 & Missions sur le téléphone & Programmer des mouvements depuis la page \\
\rowcolor{rowgray}
3 & Interface web & Commandes et mesures échangées en HTTP \\
4 & Deux boucles de décision & Comparer les distances d'arrêt robot / téléphone \\
\rowcolor{rowgray}
5 & Suivi de mur & Corriger la trajectoire sur le robot \\
6 & Correcteur PID & Atténuer les oscillations du suivi de mur \\
\rowcolor{rowgray}
7 & Mission autonome & Modéliser le robot comme un système à états \\
\bottomrule
\end{tabular}
\end{center}
\end{frame}
\appendix
\section{Bibliographie}
\begin{frame}[allowframebreaks]{Références}
\nocite{*}
\printbibliography[heading=none]
\end{frame}
\section{API de programmation}
\begin{frame}{Mission firmware ou mission téléphone}
\small
\begin{tabular}{@{}p{0.16\textwidth}p{0.36\textwidth}p{0.4\textwidth}@{}}
& \textbf{Firmware} & \textbf{Téléphone} \\
\hline
Code & \texttt{Robot::mission()} & \texttt{Mission.run()}, configurée par \texttt{missions.js} \\
Capteurs & mis à jour avant chaque appel & dernière télémétrie reçue \\
Réaction & arrêt dans la même passe & télémétrie, puis requête, puis commande d'arrêt \\
Perte de liaison & \texttt{enforceSafety()} arrête et annule & plus de commandes ; échéance et délai de liaison du robot \\
\end{tabular}
\bigskip
Les deux passent par les mêmes commandes de déplacement et les mêmes contrôles de sécurité du firmware.
\end{frame}
\subsection{API Robot.h}
\begin{frame}{Boucle principale}
\texttt{Robot::update()} s'exécute à chaque passe, dans cet ordre :
\begin{enumerate}
\item mise à jour des capteurs ;
\item \texttt{readCommands()} ;
\item \texttt{mission()} ;
\item \texttt{enforceSafety()} ;
\item télémétrie ;
\item affichage.
\end{enumerate}
\bigskip
\alert{Rien de ce qu'elle appelle ne doit attendre} : une passe bloquée retarde aussi les contrôles d'échéance et de liaison.
\end{frame}
\begin{frame}[fragile]{Se déplacer : \texttt{drive()}}
\begin{footnotesize}
\begin{verbatim}
void drive(int left, int right, uint32_t durationMs = DEFAULT_DURATION_MS);
\end{verbatim}
\end{footnotesize}
\begin{itemize}
\item Fixe les deux vitesses, de $-255$ à $+255$, et arme une échéance.
\item \texttt{durationMs} est plafonnée à \texttt{MAX\_DURATION\_MS} (5000).
\item Chaque appel remplace le précédent : pour continuer, rappeler
\texttt{drive()} avant l'échéance.
\end{itemize}
\bigskip
\texttt{enforceSafety()} arrête les roues à l'échéance ou à la perte de liaison.
\begin{itemize}
\item \texttt{motors.stop()} arrête tout de suite.
\item Ne pas appeler \texttt{motors.set()} : un mouvement sans échéance est traité comme une faute et arrêté à la passe suivante.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Une mission firmware}
\begin{scriptsize}
\begin{verbatim}
static constexpr const char* MISSION_NAMES = "wiggle";
void mission() {
switch (_mission) {
case 0: break;
case 1: wiggle(); break;
default: break;
}
}
bool _wiggleLeft = false;
uint32_t _wiggleAt = 0;
void wiggle() {
if (nowMs() - _wiggleAt < 400) return; // not yet
_wiggleAt = nowMs();
_wiggleLeft = !_wiggleLeft;
drive(_wiggleLeft ? -150 : 150, _wiggleLeft ? 150 : -150, 400);
}
\end{verbatim}
\end{scriptsize}
\small
Une mission rend la main à chaque appel, garde son état dans des membres, utilise \texttt{nowMs()} pour le temps et \texttt{drive()} pour bouger.
\end{frame}
\begin{frame}[fragile]{API \texttt{Robot.h} : une mission firmware}
\begin{scriptsize}
\begin{verbatim}
void wiggle() {
if (nowMs() - _wiggleAt < 400) return; // pas encore
_wiggleAt = nowMs();
_wiggleLeft = !_wiggleLeft;
drive(_wiggleLeft ? -150 : 150, _wiggleLeft ? 150 : -150, 400);
}
\end{verbatim}
\end{scriptsize}
\begin{itemize}
\item \texttt{mission()} est appelée à chaque passe de la boucle et ne doit jamais attendre.
\item Une mission est donc une machine à états : \texttt{\_wiggleLeft} est l'état, \texttt{\_wiggleAt} la date de la dernière transition. Chaque appel change d'état ou rend la main.
\item \texttt{drive()} arme une échéance ; \texttt{enforceSafety()} arrête les roues quand elle passe.
\item Les capteurs sont lus avant chaque appel : la mission peut s'arrêter dans la même passe.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Capteurs et temps}
\texttt{front} (ultrasons) et \texttt{side} (VL53L1X, désactivé par défaut) sont mis à jour au début de chaque passe.
\begin{footnotesize}
\begin{verbatim}
if (front.valid() && front.distanceMm() < 200) { ... }
\end{verbatim}
\end{footnotesize}
\begin{itemize}
\item \texttt{valid()} : la \textbf{dernière} mesure a réussi.
\item \texttt{distanceMm()} vaut $-1$ sauf si \texttt{valid()}.
\end{itemize}
\bigskip
\texttt{nowMs()} repasse à zéro après environ 49 jours :
\begin{footnotesize}
\begin{verbatim}
if (nowMs() - startedAt > 1000) // juste : survit au passage à zéro
if (nowMs() > startedAt + 1000) // faux : casse au passage à zéro
\end{verbatim}
\end{footnotesize}
\end{frame}
\begin{frame}{Ajouter une commande}
\texttt{execute()} reçoit chaque commande analysée comme un
\texttt{JsonReader} :
\medskip
\begin{tabular}{@{}ll@{}}
\texttt{has(key)} & champ présent ? \texttt{null} vaut absent \\
\texttt{integer(key, fallback = 0)} & le champ en \texttt{long} \\
\texttt{boolean(key, fallback = false)} & le champ en \texttt{bool} \\
\end{tabular}
\bigskip
\begin{itemize}
\item \texttt{has()} distingue un champ absent d'un zéro.
\item \texttt{execute()} ne doit pas attendre.
\item Pour répondre, suivre \texttt{sendInfo()} : remplir un \texttt{JsonWriter}, puis passer son \texttt{finish()} à \texttt{\_radio.send()}.
\end{itemize}
\end{frame}
\subsection{API robot.js}
\begin{frame}[fragile]{Le client \texttt{Robot}}
\begin{footnotesize}
\begin{verbatim}
import { Robot, Mission } from './robot.js';
const bot = new Robot();
bot.start(); // GET /api/lines toutes les 100 ms
const seq = bot.forward(200, 1500); // POST /api/command, rend seq aussitôt
await bot.waitUntilDone(seq);
\end{verbatim}
\end{footnotesize}
\small
\begin{tabular}{@{}lp{0.6\textwidth}@{}}
\texttt{drive}, \texttt{forward}, \texttt{turnLeft}\ldots & envoient une commande, rendent son \texttt{seq} sans attendre \\
\texttt{stop()}, \texttt{mission(n)}, \texttt{telemetry(ms)} & \texttt{\{stop\}}, \texttt{\{mission\}}, \texttt{\{telemetry\}} \\
\texttt{last}, \texttt{info} & dernière télémétrie, dernière ligne \texttt{info} \\
\texttt{connected} & le robot a répondu dans la dernière seconde \\
\texttt{on(listener)} & appelé pour chaque ligne reçue \\
\end{tabular}
\end{frame}
\begin{frame}[fragile]{Attendre le robot}
\begin{footnotesize}
\begin{verbatim}
waitUntil(test, timeoutMs = 10000, aborted = null)
waitUntilDone(seq, timeoutMs = 6000, aborted = null)
\end{verbatim}
\end{footnotesize}
\begin{itemize}
\item \texttt{waitUntil()} rend le premier message reçu après l'appel pour
lequel \texttt{test(message)} est vrai, ou \texttt{null} à
l'expiration ou si \texttt{aborted()} est vrai.
\item \texttt{waitUntilDone(seq)} attend une ligne \texttt{done} dont le
\texttt{seq} est \textbf{au moins} \texttt{seq} : une commande
suivante remplace l'étiquette.
\item Préférer \texttt{waitUntilDone()} à une attente de la durée
demandée : \texttt{ms} dit quand le robot a arrêté les roues.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Une mission téléphone : \texttt{Mission}}
\begin{footnotesize}
\begin{verbatim}
new Mission('carre')
.forward(180, 1000)
.turnRight(180, 600)
.repeat(4)
.stopWhen((t) => t.front_ok && t.front_mm < 200, 'quelque chose devant')
.run(bot); // -> { completed, stoppedAt, reason }
\end{verbatim}
\end{footnotesize}
\begin{itemize}
\item \texttt{run()} règle la télémétrie à 100 ms, envoie chaque étape et
attend sa ligne \texttt{done}, au plus sa durée plus 2 s.
\item Elle s'arrête plus tôt si \texttt{stopWhen} est vrai, si
\texttt{aborted()} est vrai ou si une étape n'a pas de \texttt{done}.
\item Elle laisse toujours le robot arrêté.
\item \texttt{stopWhen()} teste la dernière télémétrie reçue, pas une
mesure en direct.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{API \texttt{robot.js} : une mission téléphone}
\begin{scriptsize}
\begin{verbatim}
const bot = new Robot();
bot.start();
await new Mission('carre')
.forward(180, 1000)
.turnRight(180, 600)
.repeat(4)
.stopWhen((t) => t.front_ok && t.front_mm < 200, 'quelque chose devant')
.run(bot);
\end{verbatim}
\end{scriptsize}
\begin{itemize}
\item Chaque étape envoie une commande et attend sa ligne \texttt{done}.
\item \texttt{stopWhen()} teste la dernière télémétrie reçue : réagir
demande une requête, puis une commande d'arrêt.
\item Même commandes, même sécurité firmware qu'une mission firmware.
\end{itemize}
\end{frame}
\end{document}