Tutorial: Connect Robot Vacuum Cleaner to ROS 2 – Proscenic M6 Pro

Turn a Proscenic M6 Pro robot vacuum into a ROS 2 robot: root it over ADB, flash the open-source SangamIO firmware, and bridge its LiDAR, odometry and motors into ROS 2 Jazzy as /scan, /odom and /cmd_vel.

A robot vacuum is one of the cheapest ways to get a real mobile robot: differential-drive motors with wheel encoders, a spinning 360° LiDAR, an IMU, bumpers, cliff sensors and a battery — all for the price of an appliance. In this tutorial we turn a Proscenic M6 Pro into a ROS 2 robot. By the end, the vacuum’s LiDAR, odometry, IMU and motors show up as standard ROS 2 topics like /scan, /odom and /cmd_vel that you can drive, visualize in RViz, and run SLAM or Nav2 on.

Proscenic M6 Pro robot vacuum standing on the floor
Our Proscenic M6 Pro — about to become a ROS 2 robot.

Heads up — this is an advanced, experimental project. Rooting the vacuum and replacing its firmware voids the warranty, can brick the device, and relies on community reverse-engineering. Do it only on a unit you’re happy to tinker with, and at your own risk.

Huge credit to codetiger’s VacuumTiger project, which reverse-engineered the Proscenic / 3irobotix CRL-200S hardware and wrote the open-source on-device firmware (SangamIO, DhruvaSLAM, Drishti) we deploy here. The ROS 2 bridge is remake.ai’s vacuum_ros2_bridge.

What you’ll need

  • A Proscenic M6 Pro (built on the 3irobotix CRL-200S platform — Allwinner SoC running TinaLinux). Other CRL-200S-based vacuums are similar.
  • A micro-USB cable — the M6 Pro exposes ADB on its USB port, so no soldering or teardown is required.
  • A PC with Ubuntu 24.04 (native install recommended for the ROS 2 side). Windows 10/11 users can do the rooting and firmware build under WSL2.
  • ROS 2 Jazzy on the Ubuntu side.
  • ADB (Android platform-tools) and the Rust toolchain with an ARM cross-compiler (to build the firmware).

How the pieces fit together

Two small programs do all the work:

  • On the vacuum — SangamIO: a tiny daemon (part of VacuumTiger) that talks to the GD32 motor controller and the LiDAR over the robot’s internal serial ports, and exposes everything over TCP port 5555.
  • On your PC — vacuum_ros2_bridge: a ROS 2 Jazzy node that connects to SangamIO over your network and republishes the data as ROS 2 topics, services and TF.
Proscenic M6 Pro (SangamIO, TCP 5555)  <-->  Wi-Fi / LAN  <-->  PC (vacuum_ros2_bridge)  <-->  ROS 2

Step 1 — Get a root ADB shell

The M6 Pro conveniently exposes an Android Debug Bridge (ADB) interface on its micro-USB port, with root access out of the box. Plug the vacuum into your PC with a micro-USB cable and pick your OS below.

Windows

Download the Android platform-tools, unzip them to a folder such as C:\Users\you\adb, then in PowerShell:

cd C:\Users\you\adb
.\adb.exe devices

You should see your vacuum listed with a serial number:

List of devices attached
20080411        device

Open a shell on the vacuum (you’ll land on its TinaLinux system as root):

.\adb.exe shell

Ubuntu

sudo apt update
sudo apt install adb        # or: android-tools-adb android-tools-fastboot
adb version
adb kill-server
sudo adb start-server
adb devices
adb shell

Make the root shell stick

By default the ADB shell can drop into a bare-bones environment. Install a proper root login profile so every adb shell gives you a full root shell. On your PC, create a file named adb_shell containing:

#!/bin/sh
export ENV='/etc/adb_profile'
exec /bin/sh "$@"

Then make it executable and push it onto the vacuum:

chmod +x adb_shell
adb push ./adb_shell /bin/adb_shell

If your unit has a root password set, clear it from inside the vacuum’s shell so SSH and console login work without prompting:

passwd -d root

Step 2 — Put the vacuum on Wi-Fi and enable SSH

So the robot can roam without a USB tether, get it onto your Wi-Fi and turn on its SSH server. Run these inside the vacuum’s shell (via adb shell):

cat > /etc/wifi/wpa_supplicant.conf << 'EOF'
update_config=1
ctrl_interface=/etc/wifi/sockets

network={
    ssid="YOUR_WIFI_SSID"
    psk="YOUR_WIFI_PASSWORD"
    key_mgmt=WPA-PSK
}
EOF

rm -f /etc/wifi/sockets/wlan0
killall wpa_supplicant
wpa_supplicant -B -i wlan0 -c /etc/wifi/wpa_supplicant.conf
udhcpc -i wlan0

# Note the vacuum's IP address:
ip addr show wlan0

Enable the Dropbear SSH server so you can reach the vacuum wirelessly:

/etc/init.d/dropbear start
/etc/init.d/dropbear enable
pidof dropbear

Dropbear uses legacy algorithms, so connect from your PC with a few extra options (replace <VACUUM_IP> with the address from above):

ssh -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -o MACs=+hmac-sha1 root@<VACUUM_IP>

You can now unplug the USB cable — the rest of the work happens over the network.

Step 3 — Build and deploy the SangamIO firmware

SangamIO is cross-compiled for the vacuum’s ARM CPU. Building needs a Linux toolchain — do this on Ubuntu, or in a WSL2 Ubuntu shell on Windows. First, install Rust and the ARM target:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
rustup target add armv7-unknown-linux-musleabihf

Install a musl ARM cross-compiler:

cd /opt
sudo wget https://musl.cc/armv7l-linux-musleabihf-cross.tgz
sudo tar xzf armv7l-linux-musleabihf-cross.tgz
echo 'export PATH="/opt/armv7l-linux-musleabihf-cross/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
cd /opt/armv7l-linux-musleabihf-cross/bin
sudo ln -s armv7l-linux-musleabihf-gcc armv7-unknown-linux-musleabihf-gcc

Clone VacuumTiger and build SangamIO:

sudo apt install protobuf-compiler
git clone https://github.com/codetiger/VacuumTiger.git
cd VacuumTiger/sangam-io
cargo build --release --target armv7-unknown-linux-musleabihf

Push the binary and its config onto the vacuum, and make it executable:

adb push target/armv7-unknown-linux-musleabihf/release/sangam-io /usr/sbin/sangamio
adb push sangamio.toml /etc/sangamio.toml
adb shell chmod +x /usr/sbin/sangamio

The default sangamio.toml is set up for the CRL-200S (serial ports /dev/ttyS3 for the motor controller and /dev/ttyS1 for the LiDAR, listening on 0.0.0.0:5555). You shouldn’t need to change it for an M6 Pro.

Step 4 — Start SangamIO on the vacuum

The stock firmware holds the serial ports open, so stop it first, then launch SangamIO (inside the vacuum’s shell):

killall robotManager AuxCtrl Monitor everest-server 2>/dev/null
RUST_LOG=info /usr/sbin/sangamio

You should see it initialize the motor controller and LiDAR and open its TCP server:

[INFO  sangam_io] Device: CRL-200S Vacuum Robot
[INFO  sangam_io::devices::crl200s] Opening GD32 port /dev/ttyS3
[INFO  sangam_io::devices::crl200s] Opening lidar port /dev/ttyS1
[INFO  sangam_io::devices::crl200s::gd32] GD32 responded - initialization successful
[INFO  sangam_io::devices::crl200s::lidar] Lidar motor started
[INFO  sangam_io::streaming] TCP server listening on 0.0.0.0:5555

Leave it running. (To run it in the background, append > /tmp/sangamio.log 2>&1 &; to start it automatically on boot, the VacuumTiger deployment guide includes an /etc/init.d/sangamio service script.) Your vacuum is now a robot server on TCP port 5555.

Step 5 — Install ROS 2 Jazzy and the bridge

Switch to your PC. Install ROS 2 Jazzy on Ubuntu 24.04 by following the official install guide, then clone and build the bridge in a colcon workspace:

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
git clone https://github.com/remakeai/vacuum_ros2_bridge

cd ~/ros2_ws
colcon build --packages-select vacuum_ros2_bridge
source install/setup.bash

WSL2 note: ADB and the firmware build work fine under WSL2, but ROS 2 networking to the vacuum is smoothest on a native Ubuntu install or a dedicated Linux PC.

Step 6 — Configure and launch the bridge

Point the bridge at your vacuum’s IP address (the one from Step 2). You can pass it on the command line:

ros2 launch vacuum_ros2_bridge bridge.launch.py robot_ip:=192.168.1.143

…or edit config/bridge_params.yaml and set robot_ip permanently. The default port (5555) matches SangamIO. If it connects, the bridge starts streaming topics immediately.

How LiDARs are used in self-driving robots?

Build a real LiDAR self-driving Arduino/ROS2 robot using our kit - with complete step-by-step instructions. No robotics experience necessary.

See the full robot kit →

Step 7 — See your vacuum in ROS 2

In another sourced terminal, confirm the topics are live:

ros2 topic list
ros2 topic echo /scan
ros2 topic echo /odom

If /scan is empty, make sure the LiDAR motor is spinning:

ros2 service call /set_lidar vacuum_ros2_bridge/srv/SetLidar "{enable: true}"

Drive it around with the keyboard:

sudo apt install ros-jazzy-teleop-twist-keyboard
ros2 run teleop_twist_keyboard teleop_twist_keyboard

…and even run the actual vacuum motor and brushes through ROS 2 services:

ros2 service call /set_actuator vacuum_ros2_bridge/srv/SetActuator "{component: 'vacuum', speed: 50}"
ros2 service call /set_actuator vacuum_ros2_bridge/srv/SetActuator "{component: 'main_brush', speed: 80}"

Here’s what the bridge exposes:

  • Published: /scan (LaserScan), /imu, /odom, /battery, /bumper, /cliff, /vacuum_status
  • Subscribed: /cmd_vel (drive), /actuator_cmd, /led_cmd
  • Services: /set_actuator, /set_led, /set_lidar
  • TF: odombase_linklaser

Step 8 — Where to go next

  • Visualize in RViz: set the fixed frame to odom and add a LaserScan display on /scan to watch the room appear.
  • Build a map (SLAM): the bridge publishes standard /scan and /odom, so slam_toolbox works out of the box: sudo apt install ros-jazzy-slam-toolbox.
  • Autonomous navigation: feed the map into Nav2. Fuse the IMU with robot_localization to tame wheel-odometry drift.
  • On-device SLAM: VacuumTiger also ships DhruvaSLAM and the Drishti visualizer that run on the vacuum itself — a fun alternative to the ROS 2 stack.

Troubleshooting

  • ADB device offline / not listed: adb kill-server then sudo adb start-server and reconnect the cable.
  • SangamIO can’t open /dev/ttyS3: the stock firmware is still running — killall AuxCtrl (and robotManager Monitor everest-server) to free the serial ports.
  • No /scan data: enable the LiDAR motor with the /set_lidar service and listen for it spinning up.
  • Bridge can’t connect: ping <VACUUM_IP>, confirm SangamIO is still running, and make sure the PC and vacuum are on the same subnet with TCP 5555 unblocked.
  • Odometry drifts: it’s wheel-encoder-only — fuse with the IMU via robot_localization for better localization.

Source code and credits

  • VacuumTiger by codetiger — on-device firmware (SangamIO, DhruvaSLAM, Drishti) and the CRL-200S reverse engineering this tutorial stands on.
  • VacuumRobot by codetiger — the underlying hardware/protocol research.
  • vacuum_ros2_bridge by remake.ai — the ROS 2 Jazzy bridge.

New to ROS 2 and robotics? Our build-a-robot crash course is a gentler place to start — no rooting required.

Leave a Reply

Your email address will not be published. Required fields are marked *