Connecting to real robot

Connecting to a real FOSSBot

IRiM and Fossbot4AI logos

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

  1. Connect your workstation to the lab Wi-Fi M321-Lab using <LAB_WIFI_PASSWORD>.

  2. Get the bridge (once per workstation):

git clone https://github.com/LRMPUT/fossbot-ros2-bridge.git
  1. 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.sh

The 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.py

Warning: 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.

  1. Start your lab container the same way as in the simulation labs:
bash start_container.sh

Both 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.

  1. 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. The ROS_DOMAIN_ID environment 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
  1. Confirm you can see the robot:
ros2 topic list
ros2 topic echo /fossbot/link_status --once

You 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_ID in this exact terminal and restart the daemon. If the topics are there but connected: false, the bridge cannot reach the robot: check that the robot is switched on, that you are on M321-Lab, and the hostname you passed in step 3.

  1. Enable the motors. Unlike in the simulator, the robot’s motors start disabled, and /cmd_vel is 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+C on 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

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.local

FOSSBot 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 both

Its 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.