← All skills

Skill

Motion capture

Camera systems that track objects to a fraction of a millimeter, used as ground truth. I checked OpenDubs's odometry and ARUW's Odin localization against it.

3 log entries2 projects

Advanced Robotics at UWBest example

A test platform against motion capture

Code

Also shows: Experiment designPython

The sentry localizes with an Odin1, a lidar-inertial sensor that relocalizes into a prebuilt map. Before the team decided whether the whole localization system could rely on it alone, we wanted to know how accurate it is and where it is weak. So I built a test platform that measures it against the motion capture room, whose OptiTrack tracks the robot to a fraction of a millimeter. It starts and stops the sensor, records every run, guides whoever is driving with live mocap feedback, and can also drive the robot itself through the Jetson and the robot's controller, with a watchdog and speed caps. A campaign day runs a fixed protocol: calibration spins, a mapping drive, figure-8 laps at set speeds, ten-minute holds, back-and-forth motion to measure latency, cold starts, and outages where someone covers the sensor.

Diagram of the system: motion capture and the Odin1 sensor feed the characterization scripts, which record every run and write a report; in autonomous mode they send chassis velocities over UDP to the Jetson, which forwards them over UART to the sentry's motor control board
The three parts, and the default human-driven mode.
Bar timeline of day 1: preflight 8 minutes, calibration 3, mapping 5, figure-8 laps 6, holds 41, latency 3, cold starts 16, outages 11; 93 minutes in all
Day 1, step by step, from the campaign's time estimate.

OpenDubs

Optical flow odometry, checked against mocap

micro-ROS bridgeMocap package

Before the base could navigate, it had to know where it was. The first source was optical flow: a sensor that watches the floor slide past. I brought it up over micro-ROS and fed it into ArduPilot's EKF alongside the IMU of the Pixhawk the base ran at the time. It only read sensibly within about 10 cm of the floor, so it sits low, lit by its own LED.

To tell whether it worked, I needed ground truth. The lab's motion capture tracks the robot more precisely than anything you could measure by hand, so I wrote the package that brings it into ROS: the EKF's estimate and the mocap pose land in one bag on one clock, and every run can be compared with the truth point by point. The first runs showed why that mattered: driving 5.5 m, the estimate stayed within 0.74 m of mocap, but spinning in place sent it 155 m off. Once teammates found the sensor's mounting missing from the config, I tuned the flow gain against mocap, run by run, until the estimate stayed within 5 mm of motion capture.

Top-down chart of a simulated drive: with the sensor's mounting missing from the config, the estimate heads 10 meters sideways while the robot drives 6 meters forward and back; with the mounting fixed, it follows the true path
In simulation (ArduPilot SITL, flow only, the sensor 10 cm off the floor): with the mounting missing from the config, driving forward reads as driving sideways.
Chart of simulated position error over time for three configurations: mounting missing, up to about 11 meters; mounting fixed, about 1 meter; flow gain tuned, about half a meter
The same simulated run, error over time for each config. On the robot, against mocap, the tuned estimate stayed within 5 mm.

Advanced Robotics at UW

An error model for the Odin

Analysis code

Also shows: State estimationExperiment designPython

The question wasn't how accurate the Odin is but whether the sentry could rely on it alone, and one accuracy number can't answer that: the nav stack needs to know how the error behaves, whether it grows, and what happens when something goes wrong. So I designed the October 3 campaign around those questions (figure-8 laps, a long hold, repeated relocalizations and covered-sensor trials, all against mocap) and fit a small model to it: the true pose, plus an offset drawn each time the Odin relocalizes into its map, plus first-order Gauss-Markov noise: correlated over time, but decaying.

poseout(t)=posetrue(t−τd)⊕ε(t),τd≈0
ε(t)=R(ψ)Tbk+η(t)
bk∼N(0, diag(σb2)),per relocalizationk
ηi[n+1]=aiηi[n]+σi1−ai2wi[n]
ai=e−Δt/τc,i,Δt=0.1s

Splitting the error this way was the key decision. The offset from each relocalization turned out to be the largest term, which one overall noise figure would have blurred, and modelling the noise as decaying showed the error stays bounded instead of drifting. To check the model wasn't just describing the data it was fit to, I refit it without one session, simulated it many times along that session's real path (a Monte Carlo check), and asked whether the real error fell where the simulations said it would. It did: its real error there, 5.1 cm horizontal and under half a degree, matched the prediction on all six axes (roll came in just under its predicted range, still within the test). That made the recommendation clear: the Odin can be the sentry's only localization, kept on the turret major, where it swivels independently of the turret and the chassis. We tried it in several mount locations and found the occlusions made little difference. The nav stack only has to handle a rare wrong relocalization, and the output pausing while the sensor is covered.

Depth image from the Odin, colored from yellow for near to purple for far, in its round fisheye frame: a wall close by on the left, a person sitting in a chair, and boxes and furniture across the room
What the Odin sees: a depth image from its recordings, near in yellow and far in purple.
Chart: for each axis, the Odin's real error on a held-out session as a dot against the model's predicted range as a bar; along-track, cross-track and vertical position, and roll, pitch and yaw
The hold-out check: the model, refitted without one session, predicts that session's error. Every axis passes; roll comes in just under its predicted range.