All projects
Carnegie Autonomous Racing2021 — 2023

GraphSLAM for an Autonomous Race Car

Led the SLAM team building the mapping and localization stack for North America's first autonomous Formula Student race car.

Path Planning & SLAM Team Lead

Team led
5 engineers
Milestone
1st NA autonomous lap
C++PythonROSPose-graph optimization

Carnegie Autonomous Racing designs, builds, and races the first-ever North American autonomous Formula Student car. I led the path-planning and SLAM team working on the map and localization stack that downstream planning depended on.

Problem

To race autonomously, the car has to build a map of a track it has never seen and localize itself within that map in real time — accurately enough to plan and follow a racing line at speed.

That is difficult because every input is noisy. Odometry drifts as the car moves, cone detections arrive through a perception pipeline, and local mistakes compound quickly on a closed course. A small localization error can turn into a bad map, and a bad map can become an unsafe racing line.

The core question was: how do we make the car's estimate globally consistent while it is still discovering the track?

GraphSLAM pipeline

Turning noisy laps into a map the race car can trust

Click through the stages to see how odometry, cone landmarks, loop closures, and graph optimization work together before the planner commits to a racing line.

Pose graph optimization
Error: 42%Loop closures: 0Racing line pending

Cone detections to landmarks

GraphSLAM starts before the graph: cones have to become coordinates.

The perception stack detects cones in the camera frame, estimates their relative depth/range, and transforms those observations from the car frame into the map frame. GraphSLAM can then treat each cone as a landmark constraint instead of a loose pixel detection. Those landmarks are also what make loop closures possible when the car recognizes a previously seen section of track.

Detect

2D cone box

Estimate

range + bearing

Transform

map coordinate

Pipeline

This is the handoff from perception to SLAM: pixels become relative cone measurements, then those measurements become graph constraints and place-recognition cues.

camera view: detections + depthmap frame: landmarksz=11.4mz=14.8mz=7.9mz=6.3mcamera to car to map transformlandmark constraints

Optimization evidence

The graph matters because it changes the geometry of the map.

Ground truth gives the target structure. Noisy odometry shows how drift distorts the track. After loop closures and pose graph optimization, the estimate settles back toward a coherent loop that planning can use.

Loop closure performance

The first few loop closures do the most work.

In simulation, adding loop closures sharply reduced mean squared error. Each loop-closure count was evaluated across 100 simulations, then averaged. Once the optimizer has enough global constraints, additional closures refine the map more gradually.

Mean squared error across 100 simulations per loop-closure count
0 loop closures30 loop closureshigh MSElow MSErapid correction

Ground truth

Reference track
The clean loop the estimate should recover.

Noisy

Sensor estimate
Odometry drift and perception noise stretch the map open.

Optimized

GraphSLAM output
Loop-closure constraints pull the trajectory into shape.

Approach

I led a team of five developing the car's GraphSLAM system and integrating it with the rest of the autonomy stack. The core abstraction was a pose graph: car poses became nodes, and odometry plus cone observations became constraints the optimizer could reason over.

The hard part was turning local observations into global consistency. When the car revisited a previously seen section of track, matching cone landmarks created loop closures: long-range constraints between the current pose and earlier poses. Those constraints told the optimizer that the trajectory should close consistently instead of drifting open.

Pose graph optimization then distributed error across the full trajectory. Rather than trusting any single noisy measurement, the system searched for the most consistent map and car state estimate given all constraints. That optimized map became the input the path planner used to generate a racing line.

My role was both technical and organizational: leading implementation across the SLAM team, debugging the planner that consumed our map, and making sure our work integrated cleanly with perception, controls, and track-testing workflows.

Result

In May 2023, the car completed the first autonomous lap in North American history at New Hampshire Motor Speedway — the path planner and SLAM stack working end to end on track.

Track test

From graph constraints to an autonomous lap

The algorithmic work only mattered if the full stack could hold together on track: perception detecting cones, SLAM maintaining a map, planning choosing a line, and controls executing it.

Carnegie Autonomous Racing running through the cone-marked course during track testing. The same map/localization loop described above feeds the planner that decides where the car should go next.

The experience taught me how different real robotics feels from isolated algorithms. Progress came from making noisy systems cooperate under track-day constraints: perception had to produce usable cone landmarks, SLAM had to turn them into a consistent map, planning had to trust that map, and controls had to execute the line. The code remains proprietary to Carnegie Autonomous Racing.