<aside> 💡

TLDR; We took a basic, uncalibrated rover (4-wheel differential drive) and integrated vision and control algorithms, building up to EKF-SLAM and path planning. Largely from scratch.

Oh, and we named him Webster.

No encoders, only motor commands and access to a camera. Mainly built on ROS2, OpenCV, and Python.

</aside>

EKF-SLAM experiment driving a square path (provided as a sequence of desired waypoints). Note, Webster isn’t provided any ground-truth data and estimates AprilTag locations on the fly — we show estimated landmark location w/ uncertainty (blue X) vs. ground-truth location (green +).

EKF-SLAM experiment driving a square path (provided as a sequence of desired waypoints). Note, Webster isn’t provided any ground-truth data and estimates AprilTag locations on the fly — we show estimated landmark location w/ uncertainty (blue X) vs. ground-truth location (green +).

Motor + Vision Calibration

Motor Calibration

Webster (our rover) only had access to motor commands with no encoders (open-loop motor control). So the first thing we did was calibrate rotation and distance based on motor commands.

Error following motor calibration (no visual information). Course was a stair-step pattern before returning to origin.

Error following motor calibration (no visual information). Course was a stair-step pattern before returning to origin.

One of the main issues was rotation — since we had no encoders or visual information, our calibration was highly reliant on the surface we calibrated to. For low-pile carpet (which we chose vs. a hard surface like linoleum), different carpet sections often had different slippage rates…

…so let’s give our boy some vision 👁️👄👁️

Vision Calibration + Naive SLAM

We then calibrated a monocular camera and used an AprilTag detector to determine positional information of AprilTags set out in the environment.

Positional belief-state (left) and 3D visualization in RViz (right) of Webster driving a triangle course with AprilTags. Whenever we see a new AprilTag, we set it’s location (permanently) using our current positional estimate. Localization is computed through a naive combination of position estimates from both motor-command and vision data.

Positional belief-state (left) and 3D visualization in RViz (right) of Webster driving a triangle course with AprilTags. Whenever we see a new AprilTag, we set it’s location (permanently) using our current positional estimate. Localization is computed through a naive combination of position estimates from both motor-command and vision data.

We see that incorporating visual information through AprilTags led to better performance (smaller distance errors, rotational error largely reduced) — though this was a simpler course.

image.png

But the key flaw with this implementation was how we propagated error. We set an AprilTag’s position upon first encounter and didn’t factor in uncertainty (as you do with a Kalman filter).

So if the camera has a bad reading, Webster’s localization gets totally derailed…

Extended Kalman Filter for SLAM

To improve our naive SLAM implementation, we incorporated an extended Kalman filter for SLAM. This required returning to calibration to measure uncertainty for both visual detection and motor command-based positional estimation.

We built out EKF-SLAM using NumPy and tied everything together in ROS2 — we now plot our AprilTag estimate locations (and uncertainty) and compare them against ground-truth.

EKF-SLAM with a desired octagonal path provided as a sequence of waypoints. Webster is started at (0,0) and isn’t given AprilTag locations — our estimated landmarks (blue X) with covariance uncertainty are shown vs. ground-truth (green +).

EKF-SLAM with a desired octagonal path provided as a sequence of waypoints. Webster is started at (0,0) and isn’t given AprilTag locations — our estimated landmarks (blue X) with covariance uncertainty are shown vs. ground-truth (green +).

We see that EKF-SLAM is a clear improvement from our naive SLAM implementation. EKF-SLAM is much more robust as well — it is less likely to have a run derailed from noisy measurements.