Connecting to real robot
Connecting to a real FOSSBot

This page describes how to connect your workstation to a physical FOSSBot so that the ROS 2 tools you already use in simulation talk to the real robot instead. Other labs link here wherever they say “connect to the robot”. Follow the steps once, confirm you can see the robot’s topics, then return to the lab you came from.
The robot itself does not run ROS. It runs a small program, the
agent, that reads its sensors and drives its motors. On
your workstation you run the FOSSBot ROS 2
bridge, which talks to the agent over Wi-Fi and publishes the
same topics as the simulator (/cmd_vel, /odom,
/scan, /camera/image_raw, and so on). Your own
nodes and the lab tools then use those topics exactly as they used the
simulator’s. You do not launch a simulator.
Connection details
| Setting | Value |
|---|---|
| Wi-Fi network (SSID) | M321-Lab |
| Wi-Fi password | <LAB_WIFI_PASSWORD> (ask your instructor) |
| Bridge repository | https://github.com/LRMPUT/fossbot-ros2-bridge |
| Command topic | /cmd_vel |
Each robot has its own hostname and its own
ROS_DOMAIN_ID:
| Robot | Hostname (FOSSBOT_HOST) |
ROS_DOMAIN_ID |
Status |
|---|---|---|---|
| FOSSBot 1 | fossbotrpi1.local |
1 |
ready |
| FOSSBot 2 | fossbotrpi2.local |
2 |
not yet set up with the bridge |
Use the row for the robot you were given in every command below.
Your workstation needs Linux, Docker and Docker Compose. The
.local names above also need a running Avahi service on the
workstation; FOSSBOT_MDNS=1 lets the bridge container use
it. If Avahi is unavailable, ask the instructor for the robot’s current
IP address, use that as FOSSBOT_HOST, and omit
FOSSBOT_MDNS=1. The IP may change when the robot
reconnects.
The PC container fossbot_bridge provides ROS 2 Jazzy.
The robot’s fb container runs only the hardware agent;
students run their ROS commands in fossbot_bridge or in
their lab container with the matching ROS_DOMAIN_ID.
Steps
Connect your workstation to the lab Wi-Fi
M321-Labusing<LAB_WIFI_PASSWORD>.Get the bridge (once per workstation):
git clone https://github.com/LRMPUT/fossbot-ros2-bridge.git- Start the bridge for your robot. In a new terminal, with your robot’s values from the table:
cd fossbot-ros2-bridge
ROS_DOMAIN_ID=1 FOSSBOT_MDNS=1 FOSSBOT_HOST=fossbotrpi1.local ./run.shThe first run builds a Docker image and takes several minutes. The script then opens a shell inside the bridge container. There, start the bridge and leave this terminal open — closing it stops the bridge:
ros2 launch fossbot_bridge bringup.launch.pyWarning: Only one workstation may run the bridge for a given robot. A second bridge pointed at the same robot steals its telemetry and fights over its motors. Agree in your group who runs it.
- Start your lab container the same way as in the simulation labs:
bash start_container.shBoth containers run with --network=host, so the topics
the bridge publishes are visible in your lab container. Do
not launch the simulator; the bridge is the source of
the topics now.
- Select your robot with
ROS_DOMAIN_ID. ROS 2 nodes have no central master; they discover each other automatically over the network. By default, every ROS 2 node on the same network is visible to every other one. In a room full of laptops on the same Wi-Fi, that means your commands could drive a neighbouring group’s robot, and theirs could drive yours. TheROS_DOMAIN_IDenvironment variable, a small integer (0 to 232, default 0), partitions the network into independent groups: nodes only see other nodes that share the same id. The bridge already uses your robot’s id (you set it in step 3). Run this in every terminal of your lab container:
export ROS_DOMAIN_ID=1
ros2 daemon stop ; ros2 daemon start- Confirm you can see the robot:
ros2 topic list
ros2 topic echo /fossbot/link_status --onceYou should see the same topic names as the simulator
(/cmd_vel, /odom, /scan), and
link_status should report connected: true.
Warning: If the topic list is empty, your terminal is not on the bridge’s domain: re-check
ROS_DOMAIN_IDin this exact terminal and restart the daemon. If the topics are there butconnected: false, the bridge cannot reach the robot: check that the robot is switched on, that you are onM321-Lab, and the hostname you passed in step 3.
- Enable the motors. Unlike in the simulator, the
robot’s motors start disabled, and
/cmd_velis ignored until you enable them:
ros2 service call /fossbot/enable_motors std_srvs/srv/SetBool "{data: true}"The robot also stops by itself if no /cmd_vel message
arrives for half a second, so a crashed or closed node cannot leave it
driving. To disable the motors again, call the same service with
data: false.
Warning: A real robot moves. Before you send any command, clear the space around the robot, place it on the floor or a wide table away from edges, keep the speeds small, and know how to stop it (
Ctrl+Con whatever is publishing, then publish a single zero-velocity command on the command topic, or disable the motors as above).
Expected result: ros2 topic list shows
the robot’s topics, link_status reports
connected: true, and after enabling the motors the robot
responds to /cmd_vel. You can now run the robot steps of
the lab you came from, using the same commands you used in
simulation.
If something does not work
- The robot does not move. Enable the motors (step 7). Check that your publisher uses the command topic from the table.
- The robot switches itself off while driving. The
battery is low; motor current makes the supply sag until the robot
resets. Tell your instructor.
ros2 topic echo /fossbot/battery --onceshows the supply voltage; below about 4.7 V the robot is close to resetting. - Odometry looks wrong after pushing the robot by hand. The wheel encoders cannot tell direction, so they always count in the commanded direction. Move the robot only with commands while measuring.
- Keyboard driving: run the line below in a new
terminal, then press
eto enable the motors andw/a/s/dto drive:
docker exec -it fossbot_bridge bash -lc 'source /ws/install/setup.bash && ros2 run fossbot_bridge teleop'For instructors: maintaining the robots
Students never need to log in to a robot: the agent starts at boot. To maintain one, use the bridge repository’s scripts from your own workstation. Full instructions are in the bridge’s README.
| Robot | SSH login | Agent directory | Notes |
|---|---|---|---|
| FOSSBot 1 | admin@fossbotrpi1.local |
~/dev |
Provisioned before the scripts defaulted to ~/fossbot,
so set FOSSBOT_DIR=dev. Camera stack built. HTTP clock sync
installed (M321-Lab blocks NTP, and the Pi has no RTC
battery). |
The SSH password is held by the lab administrator and is deliberately
not stored in this repository; install your key with
ssh-copy-id and the scripts need no password.
Restart the agent after updating the bridge repository:
FOSSBOT_USER=admin FOSSBOT_DIR=dev scripts/restart_agent.sh fossbotrpi1.localFOSSBot 1’s motors are wired with both directions reversed. That is
stored in its ~/dev/agent_config.json (already installed)
and kept on every redeploy. If you reprovision the robot or replace that
file, pass --invert both again — without it the robot
drives backwards and turns the wrong way:
FOSSBOT_USER=admin FOSSBOT_DIR=dev scripts/restart_agent.sh fossbotrpi1.local --invert bothIts motor feedforward is not yet calibrated: repeated floor runs gave inconsistent fits, so the defaults are in use.
Each robot’s ROS_DOMAIN_ID is its number. When adding a
robot, give it hostname fossbotrpi<N>.local and add a
row to both tables above with ROS_DOMAIN_ID
<N>.
FOSSBot 1 wheel calibration status
The calibration attempt on 2026-10-01 was stopped when the robot’s battery died. No motor parameters were changed.
With the wheels suspended, a 20% command measured left/right forward speeds of 0.299/0.230 m/s and reverse speeds of 0.294/0.247 m/s. This suggests the right motor is slower, but suspended measurements do not include floor load and were not used to set coefficients.
On the floor, the 8–25% sweep produced little or no movement. At 30%, measured left/right speeds were 0.106/0.078 m/s; at 35%, 0.167/0.133 m/s. The subsequent 40% run lost telemetry and the agent stopped responding; the battery was then found dead. Treat these as incomplete measurements, not a calibration. Recharge the robot and repeat a controlled floor test before changing per-motor feedforward settings.