Autonomy code for the Columbia University Robotics Club F1TENTH platform.
This repo has two ROS 2 workspaces:
f1tenth_ws: hardware workspace for the real carsim_ws: simulation workspace forf1tenth_gym_ros
The guiding rule is:
- hardware- and simulator-specific packages live in their own workspace
- shared team-owned autonomy packages live once in
f1tenth_ws/src sim_ws/srcshould symlink shared packages instead of duplicating them
Today that means:
f1tenth_ws/src/
f1tenth_system/ # vendor, driver, bringup, teleop, and hardware stack
localization/ # mapping and map-frame localization output
planning/ # shared planner and path follower
planner_web_ui/ # shared lightweight browser UI for planning
sim_ws/src/
f1tenth_gym_ros/ # simulator bridge and simulator-specific launch/config
planning # symlink to ../../f1tenth_ws/src/planning
planner_web_ui # symlink to ../../f1tenth_ws/src/planner_web_ui
f1tenth_system is the low-level system stack. It owns packages such as:
f1tenth_stackackermann_muxteleop_toolsvesc
These packages bring up the real car, publish raw sensors, and accept low-level drive commands.
localization, planning, and planner_web_ui are team-owned autonomy packages. They sit beside f1tenth_system because they are consumers of the hardware stack, not part of the hardware stack itself.
The main autonomy-facing pose contract is:
/localization/poseasgeometry_msgs/PoseWithCovarianceStamped
Both real and simulated flows publish that same topic:
- real car:
- SLAM Toolbox mapping mode publishes
/pose, whichlocalizationrelays to/localization/pose - AMCL localization mode publishes
/amcl_pose, whichlocalizationrelays to/localization/pose
- SLAM Toolbox mapping mode publishes
- simulation:
f1tenth_gym_rospublishes the exact ground-truth map pose directly to/localization/pose
planning subscribes to /localization/pose in both workspaces, so planning code does not need separate real/sim pose topic names anymore.
Lower-level motion topics still exist and are intentionally separate from the autonomy pose contract:
- real car:
/odom - sim:
/ego_racecar/odom
Build each workspace from its own root:
cd ~/Desktop/f1tenth_ws
source /opt/ros/humble/setup.bash
colcon buildcd ~/Desktop/sim_ws
source /opt/ros/humble/setup.bash
colcon buildIf you change Python or C++ code, rebuild the affected workspace. If you only change launch or YAML files, relaunching is usually enough.
Bring up the real car stack:
cd ~/Desktop/f1tenth_ws
source /opt/ros/humble/setup.bash
source install/setup.bash
ros2 launch f1tenth_stack bringup_launch.pyRun mapping on the real car:
cd ~/Desktop/f1tenth_ws
source /opt/ros/humble/setup.bash
source install/setup.bash
ros2 launch localization mapping.launch.py mode:=mappingRun map-based localization on the real car:
cd ~/Desktop/f1tenth_ws
source /opt/ros/humble/setup.bash
source install/setup.bash
ros2 launch localization mapping.launch.py mode:=localization map_file:=maps/map_1761949489.yamlRun the simulator:
cd ~/Desktop/sim_ws
source /opt/ros/humble/setup.bash
source install/setup.bash
ros2 launch f1tenth_gym_ros gym_bridge_launch.pyRun planning in either workspace:
ros2 launch planning planning.launch.pyThe planner package includes both config/real.yaml and config/sim.yaml. Both consume /localization/pose, so the same launch flow works in either workspace unless you explicitly override config_file.
Run lightweight map-based pathplanning in sim with the browser UI instead of Foxglove:
./scripts/pathplanning_sim.sh --map SpielbergRun the same lightweight UI against the real-car localization/planning stack:
./scripts/pathplanning_real.sh --map f1tenth_ws/src/localization/maps/map_1761949489.yamlBoth scripts:
- auto-detect whether to run natively or in the Docker ROS container
- optionally rebuild the relevant workspace
- launch planning plus the browser UI on http://localhost:8081
- use the same click-to-goal workflow by publishing to
/planner/goal_pose
When native ROS 2 Humble is available, the scripts run directly on the host. Otherwise they fall back to the ubuntu Docker service. You can override the choice with --runtime native or --runtime docker.
The real-car script assumes the low-level hardware stack is already running. The sim script reuses or bootstraps sim_ws/.venv before launch so the upstream f1tenth_gym Python dependencies are present in both native and Docker runs. The regular gym_bridge_launch.py still supports Foxglove and now accepts map_path:=... plus start_foxglove_bridge:=false when you want to customize it directly.