Stage OpenAMR — Robot mobile autonome & accostage de précisionOpenAMR Internship — Autonomous Mobile Robot & Precision Docking
TechnologiesTechnologies (10)
Stage R&D chez Botshare (Berlin) sur la plateforme open-source OpenAMRobot. J'ai remis en service un robot mobile, lui ai donné une navigation autonome, puis conçu son accostage de précision par vision (bundle d'AprilTags, asservissement visuel) pour la recharge sans fil. ROS2 · Nav2 · Gazebo · micro-ROS · Vision.R&D internship at Botshare (Berlin) on the open-source OpenAMRobot platform. I recommissioned a mobile robot, gave it autonomous navigation, then designed its vision-based precision docking (AprilTag bundle, visual servoing) for wireless charging. ROS2 · Nav2 · Gazebo · micro-ROS · Vision.
Lire la présentation complèteRead the full introduction
Stage R&D chez Botshare (Berlin) sur la plateforme open-source OpenAMRobot. J'ai remis en service un robot mobile, lui ai donné une navigation autonome, puis conçu son accostage de précision par vision (bundle d'AprilTags, asservissement visuel) pour la recharge sans fil. ROS2 · Nav2 · Gazebo · micro-ROS · Vision.R&D internship at Botshare (Berlin) on the open-source OpenAMRobot platform. I recommissioned a mobile robot, gave it autonomous navigation, then designed its vision-based precision docking (AprilTag bundle, visual servoing) for wireless charging. ROS2 · Nav2 · Gazebo · micro-ROS · Vision.
Parcourir les sectionsBrowse sections +
En brefAt a glance
En bref
Problème — Un robot mobile autonome n'est vraiment autonome que s'il sait à la fois se déplacer et se recharger seul. L'accostage précis sur sa station de recharge sans fil est le maillon qui ferme cette boucle — et c'est de loin le plus difficile : traverser une pièce avec 20 cm de marge est facile, s'arrêter devant un chargeur au millimètre près et au bon angle ne l'est pas.
Approche — Ma mission portait sur le robot physique, mais le matériel n'était pas prêt et la base logicielle incomplète. J'ai donc commencé en simulation (Gazebo + Nav2), puis remis en service un vrai robot, lui ai donné une navigation autonome, et y ai enfin porté l'accostage — de bout en bout, du firmware au comportement autonome.
Résultat — Un robot qui, au départ, ne roulait même pas droit, sait désormais cartographier son environnement, se localiser, se déplacer seul en évitant les obstacles, et s'accoste sur un faisceau de marqueurs imprimés avec une ligne d'approche stable. En simulation, le dock est atteint à ~1–2 cm de justesse latérale et ~1° d'angle. J'ai aussi rédigé une publication technique publique sur la démarche.
At a glance
Problem — An autonomous mobile robot is only truly autonomous if it can both move and recharge on its own. Precise docking onto its wireless charging station closes that loop — and it's by far the hardest part: crossing a room with 20 cm of margin is easy, stopping in front of a charger within a millimetre and at the right angle is not.
Approach — My mission was about the physical robot, but the hardware wasn't ready and the software base was incomplete. So I started in simulation (Gazebo + Nav2), then recommissioned a real robot, gave it autonomous navigation, and finally brought the docking onto it — end to end, from firmware to autonomous behaviour.
Result — A robot that couldn't even drive straight at the start now maps its environment, localizes itself, drives autonomously while avoiding obstacles, and docks onto a printed marker bundle with a stable approach line. In simulation the dock is reached within ~1–2 cm laterally and ~1° in yaw. I also wrote a public technical article on the engineering approach.
Stage d'ingénieur robotique chez Botshare, un studio de R&D robotique basé à Berlin (au MotionLab). Botshare développe OpenAMRobot, une plateforme open-source qui rassemble les briques d'un robot mobile autonome — navigation, accostage, recharge — en paquets réutilisables, construits sur les outils standards de la robotique moderne : ROS2, Nav2, Gazebo, SLAM Toolbox et marqueurs visuels (AprilTags).
Les conditions ont façonné ma façon de travailler : projet open-source (progresser en intégrant mon travail dans une base partagée, pas en codant dans mon coin), robot hérité d'un projet précédent (auditer un matériel que je n'avais pas conçu avant de lui faire confiance), et petite équipe où j'ai travaillé en grande autonomie, encadré par mon tuteur.
Mon travail est intégré dans les dépôts publics de la plateforme — openamr-platform-sw (logiciel), openamr-platform-fw (firmware) et openamr-platform-hw (hardware) — où je figure parmi les contributeurs.
Encadrant : Oleksii « Alex » Reznichenko — Botshare · MotionLab Berlin.
Robotics engineering internship at Botshare, a robotics R&D studio based in Berlin (at MotionLab). Botshare develops OpenAMRobot, an open-source platform gathering the building blocks of an autonomous mobile robot — navigation, docking, charging — into reusable packages built on the standard tools of modern robotics: ROS2, Nav2, Gazebo, SLAM Toolbox and visual markers (AprilTags).
The conditions shaped how I worked: an open-source project (progress by integrating my work into a shared base, not coding in isolation), a robot inherited from an earlier project (audit hardware I hadn't designed before trusting it), and a small team where I worked largely on my own, supervised by my mentor.
My work is integrated into the platform's public repositories — openamr-platform-sw (software), openamr-platform-fw (firmware) and openamr-platform-hw (hardware) — where I am listed among the contributors.
Supervisor: Oleksii "Alex" Reznichenko — Botshare · MotionLab Berlin.
Volet 1 · Remettre le robot en marche (hardware & firmware)Part 1 · Bringing the robot back to life (hardware & firmware)
Volet 1 · Remettre le robot en marche (hardware & firmware)
Le robot ne fonctionnait pas : aucun firmware exploitable, et surtout il refusait de rouler droit — la roue droite s'emballait et le robot déviait. Architecture : un Raspberry Pi 5 (haut niveau, ROS2 Jazzy) relié à un microcontrôleur Teensy 4.0 (boucle temps réel : encodeurs, IMU, contrôle moteur) via micro-ROS.
L'enquête (roue folle) — Plutôt que de changer des pièces au hasard, j'ai isolé le problème en utilisant la roue gauche (qui marchait) comme témoin, et en instrumentant le firmware pour comparer commande et mesure de chaque roue. La première piste — les potentiomètres du driver — semblait plausible… mais en boucle ouverte, la vitesse mesurée de la roue droite était erratique. Le problème n'était pas dans la commande, mais dans la mesure : l'encodeur magnétique s'était décentré de son aimant. La mesure faussée était réinjectée dans la boucle, qui sur-corrigeait et emballait la roue. Une faute de mesure déguisée en faute de contrôle. Re-centrer l'encodeur a résolu la cause profonde.
La base fiable — J'ai ensuite reconstruit et réglé le firmware : PID par roue avec anti-windup, télémétrie de debug et mode test en boucle ouverte laissés dans le système, watchdog coupant les moteurs si les commandes cessent d'arriver, et l'interface standard attendue par Nav2 (/cmd_vel, /odom, /imu/data, /scan, arbre TF) — le robot devient, du point de vue de Nav2, une plateforme différentielle standard.
Part 1 · Bringing the robot back to life (hardware & firmware)
The robot didn't work: no usable firmware, and above all it refused to drive straight — the right wheel ran away and the robot veered off. Architecture: a Raspberry Pi 5 (high level, ROS2 Jazzy) connected to a Teensy 4.0 microcontroller (real-time loop: encoders, IMU, motor control) over micro-ROS.
The investigation (runaway wheel) — Rather than swapping parts at random, I isolated the problem using the working left wheel as a witness, and instrumented the firmware to compare each wheel's command vs. measurement. The first lead — the driver potentiometers — looked plausible… but in open loop, the right wheel's measured speed was erratic. The problem wasn't in the command, but in the measurement: the magnetic encoder had shifted off its magnet. The faulty reading was fed back into the loop, which over-corrected and made the wheel run away. A measurement fault disguised as a control fault. Re-centring the encoder fixed the root cause.
The reliable base — I then rebuilt and tuned the firmware: per-wheel PID with anti-windup, debug telemetry and an open-loop test mode kept in the running system, a watchdog stopping the motors if commands stop arriving, and the standard interface Nav2 expects (/cmd_vel, /odom, /imu/data, /scan, TF tree) — the robot becomes, from Nav2's point of view, a standard differential-drive platform.
Volet 2 · Navigation autonomePart 2 · Autonomous navigation
Volet 2 · Navigation autonome
Sur cette base fiable, j'ai bâti toute la pile de navigation, en repartant de zéro sur le matériel :
- Localisation — filtre de Kalman étendu (EKF) fusionnant odométrie et centrale inertielle. Détail honnête : sur cette IMU, seul l'axe de lacet du gyroscope était fiable (quaternion invalide, accéléromètre biaisé) — j'ai donc délibérément exclu le reste et construit le filtre autour de ce seul axe fiable, en configuration planaire. Le gain est ciblé : couper la dérive de cap dans les virages, là où les roues glissent. Couplé à AMCL (localisation Monte-Carlo sur la carte LiDAR) pour annuler la dérive absolue.
- Cartographie & évitement — SLAM Toolbox, puis Nav2. Le correctif le plus décisif : la forme réelle du robot. Il était configuré avec une empreinte circulaire trop petite ; il fonçait dans des obstacles qu'il voyait, car seul son centre était testé. Je l'ai remplacée par l'empreinte octogonale réelle décentrée (l'axe des roues n'est pas au centre du corps) et testée à chaque pas → évitement de tout le corps.
- Perception — filtre masquant les retours du LiDAR sur le corps du robot lui-même, et calibration caméra (damier) pour l'accostage.
Deux debugs marquants : un verrou d'accélération (le robot refusait de tourner, la vitesse plafonnant sous le seuil de démarrage des moteurs) et un biais gyro au repos (~−0,31 rad/s pris pour une vraie rotation par l'EKF, corrigé par une procédure de calibration à l'allumage). Un filtre de Kalman n'est honnête que si le capteur qu'on lui dit de croire l'est.
Part 2 · Autonomous navigation
On this reliable base, I built the whole navigation stack from scratch on the hardware:
- Localization — an Extended Kalman Filter (EKF) fusing odometry and IMU. An honest caveat: on this IMU, only the gyroscope's yaw axis was trustworthy (invalid quaternion, biased accelerometer) — so I deliberately excluded the rest and built the filter around that one reliable axis, in a planar configuration. The gain is targeted: killing heading drift in turns, exactly where the wheels slip. Paired with AMCL (Monte-Carlo localization on the LiDAR map) to cancel absolute drift.
- Mapping & avoidance — SLAM Toolbox, then Nav2. The single most consequential fix: the robot's real shape. It was configured with an undersized circular footprint; it drove into obstacles it saw, because only its centre was checked. I replaced it with the true off-centre octagonal footprint (the wheel axis isn't at the centre of the body) tested at every step → whole-body avoidance.
- Perception — a filter masking the LiDAR returns hitting the robot's own body, and camera calibration (checkerboard) for docking.
Two instructive debugs: an acceleration deadlock (the robot refused to turn, its speed capped below the motors' stick-slip threshold) and a gyro bias at rest (~−0.31 rad/s taken for a real rotation by the EKF, fixed with a boot-time calibration procedure). A Kalman filter is only as honest as the sensor it's told to trust.
Volet 3 · Accostage de précision par visionPart 3 · Vision-based precision docking
Volet 3 · Accostage de précision par vision
Le cœur du stage. La précision requise est imposée par le chargeur, pas par le robot : après avoir comparé quatre familles de chargeurs sans fil du commerce, j'ai fixé une cible de conception de ±10 mm de position et ±2° d'angle.
Le séquenceur — j'ai condensé une première version fragile à sept phases en un pipeline propre à quatre phases : Nav2 amène le robot en zone d'approche, il scanne et centre le marqueur, se met perpendiculaire, puis avance en suivant la ligne d'approche par pure-poursuite.
L'orientation, résolue par la géométrie — un seul marqueur ne donne jamais une orientation fiable (l'axe faible d'un tag plan). Ma solution : un faisceau de 3 AprilTags avec les deux extérieurs espacés de 90 cm — la droite qui les relie donne directement la direction du dock. C'est la géométrie de la large base qui rend l'orientation stable, pas le filtrage. Estimation rendue centrée caméra et observée des deux côtés pour annuler le biais de solvePnP.
Les deux vrais problèmes étaient systémiques, pas algorithmiques — et c'est là que j'ai le plus appris :
- Un asservissement visuel qui oscillait semblait un correcteur mal réglé. Aucun réglage de gain ne le calmait. La mesure a tranché : les détections AprilTag arrivaient avec 250–700 ms de retard. La cause n'était pas le contrôle mais le budget CPU : le Raspberry Pi tournait la pile Nav2, la caméra et le détecteur pleine résolution à la fois (charge ×2). J'ai composé caméra + détecteur en un seul process zéro-copie, plafonné la caméra à 15 fps, et mis Nav2 en pause pendant l'approche finale. La latence est tombée à ~1 image, et le même correcteur qui oscillait s'est mis à suivre proprement. Un asservissement visuel ne vaut que la fraîcheur de ce qu'on lui donne.
- Une ligne de référence qui balayait avec le robot était un artefact de repère + latence. Je l'ai corrigée en ancrant l'approche dans le repère odométrique fixe (résolu à l'horodatage de chaque détection), au lieu de basculer entre repères. La ligne a cessé de balayer et est restée plantée sur le dock.
Part 3 · Vision-based precision docking
The heart of the internship. The required precision is set by the charger, not the robot: after surveying four families of commercial wireless chargers, I fixed a design target of ±10 mm position and ±2° yaw.
The sequencer — I condensed a brittle seven-phase first version into a clean four-phase pipeline: Nav2 brings the robot to a staging zone, it scans and centres the marker, aligns perpendicular, then advances along the approach line via pure-pursuit.
Orientation, solved by geometry — a single marker never gives a reliable orientation (the weak axis of a planar tag). My solution: a bundle of 3 AprilTags with the two outer ones spaced 90 cm apart — the line through them directly gives the dock's direction. It's the wide-baseline geometry that makes the orientation stable, not filtering. Estimation made camera-centric and observed from both sides to cancel the solvePnP bias.
The two real problems were systemic, not algorithmic — and that's where I learned the most:
- A visual servo that oscillated looked like a mistuned controller. No gain change calmed it. Measurement settled it: the AprilTag detections arrived 250–700 ms stale. The cause wasn't control but the CPU budget: the Raspberry Pi ran the full Nav2 stack, the camera and a full-resolution detector at once (×2 load). I composed camera + detector into a single zero-copy process, capped the camera at 15 fps, and paused Nav2 during the final approach. Latency fell to ~1 frame, and the same corrector that had oscillated now tracked cleanly. A visual servo is only as good as the freshness of what it's fed.
- A reference line that swept with the robot was a frame + latency artefact. I fixed it by anchoring the approach in the fixed odometry frame (resolved at each detection's own timestamp), instead of switching frames. The line stopped sweeping and stayed planted on the dock.
Ce que j'en retiensWhat I take away
Ce que j'en retiens
Ce stage m'a appris à prendre la responsabilité d'un système entier, de bout en bout — d'un capteur mal étiqueté sur un banc jusqu'à un comportement autonome dans une pièce — et à rester honnête sur la ligne entre ce qui est démontré et ce qui est seulement plausible. Le fil rouge : la robustesse prime sur la précision brute, et les problèmes les plus instructifs (latence, repères, capteurs qui mentent) sont souvent systémiques, pas algorithmiques.
J'ai formalisé cette démarche dans une publication technique publique, écrite en anglais pour le blog de Botshare — voir la fiche dédiée.
What I take away
This internship taught me to take responsibility for a whole system, end to end — from a mislabelled sensor on a bench to an autonomous behaviour in a room — and to stay honest about the line between what is demonstrated and what is merely plausible. The through-line: robustness over raw precision, and the most instructive problems (latency, frames, lying sensors) are often systemic, not algorithmic.
I formalized this approach in a public technical article, written in English for the Botshare blog — see the dedicated project.
Crédits — Matthieu Vinet (firmware, navigation, accostage). Contributeur des dépôts publics de la plateforme : travail développé, intégré via pull requests et merges sur openamr-platform-sw (logiciel), openamr-platform-fw (firmware) et openamr-platform-hw (hardware). Projet open-source OpenAMRobot · Encadrant : Oleksii « Alex » Reznichenko — Botshare · MotionLab Berlin. Contributeur occasionnel : Raj (fusion des environnements de simulation).
Credits — Matthieu Vinet (firmware, navigation, docking). Contributor to the platform's public repositories: work developed and integrated through pull requests and merges on openamr-platform-sw (software), openamr-platform-fw (firmware) and openamr-platform-hw (hardware). Open-source project OpenAMRobot · Supervisor: Oleksii "Alex" Reznichenko — Botshare · MotionLab Berlin. Occasional contributor: Raj (merging the simulation environments).