# Mars Rover Autonomy

> Autonomy software for Yale's Mars rover: a mission coordinator that drives Nav2 navigation, tested in Gazebo simulation.

Autonomy Lead · Yale Mars Rover Team · Sep 2026 to now · tested in Gazebo simulation

## Results

- 91 mission coordinator tests, CI green
- 0.11 m goal error on a simulated Nav2 run with fused localization
- < 1 m startup error after the GPS race fix (was km)
- 9 infrastructure PRs merged to main

## The problem

For University Rover Challenge 2027 the rover has to run two autonomy missions on its own. Commands can arrive at the wrong moment, navigation can fail or be cancelled, and old results can show up late. A new student team also needed a shared, reproducible ROS environment before anyone could test autonomy at all.

## What I built

- A ROS 2 mission coordinator for both missions: an explicit transition table, command guards, stop, abort, timeout and human takeover, and rejection of stale results, with 91 package tests.
- A Nav2 adapter that reports arrival only on successful navigation and waits for a cancel to finish before sending a replacement goal.
- A diagnosis and fix for a localization startup race (GPS arriving before the datum was set): a pinned, patch-verified build with a regression test that forces GPS to arrive first.
- Team infrastructure, merged: a multi-architecture ROS Jazzy dev container (ARM64 and x86-64), GitHub Actions build and test on every PR, and architecture docs.

## The hard part

A localization bug that only showed up sometimes. In fresh simulation runs the fused position of a rover sitting still could start kilometres away, and a successful retry hid the bug. I traced it to robot_localization: a GPS fix that arrived before the datum was set got projected from the default origin and cached. I pinned the package with a five-line guard, made the installer verify the exact revision and patch, and added a test that forces GPS to arrive first. Every startup position then stayed within 1 m of the origin.

## How it fits together

- Mission commands -> Mission coordinator (start, stop)
- Mission coordinator -> Nav2 adapter (mission step)
- Nav2 adapter -> Nav2 (map goal)
- Nav2 -> Simulated rover (velocity)
- Simulated rover -> Fused localization (odom, GPS)

Parts David built: Mission coordinator, Nav2 adapter.

The coordinator only trusts results tagged with the current goal, so a late answer from a cancelled goal can never end a mission. I integrated the coordinator with fused localization and fixed its startup race.

## Decisions

- An explicit transition table instead of nested conditionals, so every state change is written down once and tested.
- Every result carries the goal it belongs to, and anything for an old goal is ignored, so a late answer can't end the wrong mission.
- A replacement goal waits for the cancel to finish, so Nav2 is never driving toward two goals at once.

Tech: ROS 2, Nav2, Python, Gazebo, Docker

Page: https://davidantwi.vercel.app/work/mars-rover-autonomy
