Docs Get started Workspace repo
Docs menu

Set up the workspace

Clone the car workspace onto a Jetson, install its dependencies, build it, and confirm the car and its hardware are found.

Both cars already have a built workspace at ~/racerbot-ws, cloned from the one workspace repository both cars share. Follow this page to set up a new Jetson, to rebuild after a fresh clone, or to understand what the existing install contains. Run every command on the Jetson.

Requirements

  • A Jetson Orin Nano Super with JetPack 7.2 and Ubuntu 24.04.
  • ROS 2 Jazzy installed natively, with rosdep initialized.
  • CUDA at /usr/local/cuda, which JetPack installs. Only range_libc needs it.
  • Network access to GitHub.

1. Clone with submodules

Both cars clone the same repository, Racerbot-Car-Workspace. Several packages are Git submodules: particle_filter, range_libc, transport_drivers, the team repositories racerbot_a and racerbot_b, web_dashboards, and realsense-ros. realsense-ros is car 2’s camera driver and needs Intel’s librealsense to build, so car 1 leaves it uninitialized. An empty src/realsense-ros folder is skipped by the build.

Car 2, or any computer with librealsense installed:

git clone --recurse-submodules https://github.com/sfu-racerbot/Racerbot-Car-Workspace.git ~/racerbot-ws

Car 1:

git clone https://github.com/sfu-racerbot/Racerbot-Car-Workspace.git ~/racerbot-ws
cd ~/racerbot-ws
git submodule update --init --recursive src/particle_filter src/range_libc src/transport_drivers src/racerbot_a src/racerbot_b src/web_dashboards

If the submodule folders exist but are empty, the submodules were never initialized. Run the git submodule update line above on car 1, or this on car 2:

cd ~/racerbot-ws
git submodule update --init --recursive

Then run the set-up script once in the new clone:

cd ~/racerbot-ws
tools/dev/setup_clone.sh

It installs the workspace’s pre-commit hook, which refuses a commit that adds a file over 95 MiB, and prints the car this machine is: rb1 on car 1, rb2 on car 2, or dev box: set RACERBOT_CAR for the simulator on a computer that is not a registered car. A Jetson that prints an unknown serial error is not in machines.yamlGitHub yet; add its serial there before driving it, as docs/car-profiles.mdGitHub describes. On a development computer, choose the car in every terminal instead:

export RACERBOT_CAR=rb1

f1tenth_system is a copy of the upstream repository with local fixes committed on top, vendored rather than a submodule, so it arrives with a normal clone. Read docs/git-setup.mdGitHub before pulling upstream changes into it.

2. Install dependencies

rosdep reads every package’s package.xml and installs the system packages they declare, including slam_toolbox from apt.

source /opt/ros/jazzy/setup.bash
cd ~/racerbot-ws
rosdep install --from-paths src --ignore-src -r -y

3. Build

source /opt/ros/jazzy/setup.bash
cd ~/racerbot-ws
colcon build --symlink-install --parallel-workers 1

The build is working when it ends with Summary: N packages finished and no failed count. Warnings are normal. A full build takes several minutes. --parallel-workers 1 builds one package at a time, because a parallel build can run out of the Jetson’s 8 GB of memory.

--symlink-install links the Python, launch and YAML files into install/ instead of copying them, so edits to those files take effect at the next launch without a rebuild. A workspace built without it holds copies, and an edit to a YAML in src/ changes nothing until the package is rebuilt. A rebuild is still needed after changing package.xml, setup.py or C++ code, or after adding or removing files. While working on one package, build only that package:

colcon build --symlink-install --packages-select gap_follow

If the build state becomes confusing, delete the generated folders and rebuild. build/, install/ and log/ contain only build output.

rm -rf build install log && colcon build --symlink-install --parallel-workers 1

4. Build the GPU ray caster

particle_filter localizes the car by asking range_libc what the LiDAR would see from each candidate pose. colcon does not build range_libc’s Python module, and particle_filter’s configuration requires the CUDA version. Build it once by hand. It installs into the user’s Python packages and survives later workspace rebuilds.

source /opt/ros/jazzy/setup.bash
export PATH=/usr/local/cuda/bin:$PATH
cd ~/racerbot-ws/src/range_libc/pywrapper
rm -rf build RangeLibc.cpp
WITH_CUDA=ON python3 setup.py install --user

The build is working when the output contains Compiling with CUDA support and lines ending in for 'sm_87', the Orin’s GPU architecture. It takes about two minutes. Then confirm the GPU version is the one Python loads:

cd ~/racerbot-ws
python3 -c "import range_libc; print(range_libc.SHOULD_USE_CUDA)"

It prints True when the build used CUDA. False means the build fell back to the CPU version, and particle_filter fails on its first scan. The full measurements are in docs/gpu-acceleration.mdGitHub.

5. Install the MPC solver (optional)

The MPC steering law needs the osqp solver. The other three steering laws do not.

pip install --user --break-system-packages osqp==1.1.3
python3 -c "import osqp; print(osqp.__version__)"

The second command prints 1.1.3. --break-system-packages is needed because Ubuntu 24.04 protects the system Python, and --user keeps the package in the home folder.

6. Check the IMU calibration

imu_bridge reads each IMU’s mount rotation and calibration from the car’s profile, cars/rb1/imu/Car 1 or cars/rb2/imu/Car 2, and the BNO085 bridge and calibration tools from tools/imu_calibration/GitHub. Both arrive with the clone, so no separate repository is needed. Car 2’s mount yaw and BNO085 position are not measured yet; see IMU fusion before turning on any feature that uses the IMU’s forward axis.

7. Set up device access

The VESC, the car 1 LiDAR, the gamepad, car 1’s webcam and each car’s BNO085 need a fixed device name or a group membership. The udev rules live in /etc/udev/rules.d/, outside the repository; copies of car 1’s are in tools/udev/GitHub.

Device setup
Car 1Car 2
VESC99-vesc.rules: /dev/sensors/vesc for USB ID 0483:574099-vesc.rules: /dev/sensors/vesc for USB ID 0483:5740
LiDAR99-hokuyo.rules: /dev/sensors/hokuyo for USB ID 15d1:0000NetworkManager profile hokuyo: static 192.168.0.15/24 on enP8p1s0
Groupsinput (gamepad), video (webcam), i2c (BNO085), dialoutinput (gamepad), i2c (BNO085), dialout

After adding or editing a udev rule, apply it without rebooting:

sudo udevadm control --reload-rules && sudo udevadm trigger

Add a user to a group, then log out and back in. Group membership only applies to sessions started afterwards.

sudo usermod -aG input,video,i2c,dialout $USER

8. Check the result

Source both setup files, start bringup, and run the doctor in a second terminal.

Terminal 1:

source /opt/ros/jazzy/setup.bash
source ~/racerbot-ws/install/setup.bash
ros2 launch f1tenth_stack bringup_launch.py

Terminal 2:

source /opt/ros/jazzy/setup.bash
source ~/racerbot-ws/install/setup.bash
ros2 run racerbot_doctor doctor

The setup is complete when the doctor’s first line names this car (Car rb1 or Car rb2) and its last line reads 0 FAIL. See the pre-run checklist for what each check means.

Troubleshooting

Symptom Cause Fix
Package 'gap_follow' not found The terminal has not sourced install/setup.bash, or the build failed. Source both setup files in that terminal. Check the build summary for failed.
A build dies with no useful error, or the Jetson freezes The build ran out of memory. Rebuild with --parallel-workers 1.
ModuleNotFoundError: No module named 'range_libc' Step 4 was skipped, or ~/.local was cleaned. Run step 4.
importlib.metadata.PackageNotFoundError when a node starts A partial or mixed install for that package. rm -rf build/<pkg> install/<pkg>, then rebuild it.
Permission denied on /dev/sensors/vesc or /dev/input/js0 The user is missing a group, or the session predates the group change. Step 7, then log out and back in.
A launch stops with CarMismatchError RACERBOT_CAR names the other car on a registered Jetson. unset RACERBOT_CAR in that terminal, then relaunch.
A launch stops with UnknownCarError The Jetson’s serial is not in machines.yaml, or RACERBOT_CAR is unset on a development computer. Register the serial, or set RACERBOT_CAR=rb1 or rb2 on a development computer.
The build fails in realsense2_camera on car 1 src/realsense-ros was initialized, and librealsense is not installed. git submodule deinit -f src/realsense-ros, then rebuild.

Checked against workspace commit 556284c.