Open-source mobile robot for laboratory automation and SBS plate handling.
- Overview
- System Architecture
- Deployment of a New Robot
- Docker Installation (recommended)
- Local Installation (advanced)
- How to Run
- ROS 2 Interfaces
- Project Structure
- Improvements & Roadmap
- License
The Swiss CAT+ 2D-drone is an open-source mobile robot platform developed at the SwissCAT+ laboratory for laboratory automation.
Built to transport SBS-format plates along a dedicated track on top of the lab, the 2D-drone provides a robust foundation for developing and deploying modular, automated workflows in research and production environments.
The robot localizes itself using a top-mounted camera that detects a network of ArUco markers placed above the track, enabling precise and repeatable navigation without external localization systems.
The EM_fleetmanager coordinates multiple 2D-Drones, manages map and marker deployment, and ensures synchronized operation across the SwissCAT+ laboratory.
A markerless visual SLAM module is currently in development and will extend the 2D-Drone’s capabilities beyond track-based navigation to more general indoor environments in upcoming releases.
The EM_onrobot repository contains the complete software and hardware resources required to build, configure, and
deploy the 2D-Drone
- Controls the two DYNAMIXEL XC430-W150 differential-drive motors.
- Reads and compute encoder odometry directly through the Dynamixel SDK.
- Collects IMU data from the Bosch BNO055 sensor.
- Runs an Extended Kalman Filter (EKF) to fuse IMU and wheel odometry.
- Uses the camera with ArUco markers for drift correction in odometry (map correction).
- Publishes ROS 2 topics for robot localization and subscribes to
/cmd_velfor motion commands.
- Includes the 3D-printable mechanical design of the robot’s case (recommended material: PLA) :
- EdyMobileAssembly contains the full CAD for SolidWorks
- EdyMobileURDFAssembly contains the CAD ready for URDF export
- EdyMobile_URDF_screencast_ROS contains the URDF
- Edymobile_STL_And_BambuPrintables contains the STL files and a read-to-print file for bamboo lab PS1
- Provides the electrical schematics for wiring and integration.
- Supports containerized deployment with Docker for easy setup and reproducibility.
- OS: Ubuntu 22.04 (on Raspberry Pi OS 64-bit for Raspberry Pi 5)
- ROS 2: Humble
- Docker image (recommended):
ghcr.io/swisscatplus/em_onrobot/em_robot:latest - Dependencies (local runs): see Local Installation
-
Hardware
- Raspberry Pi 5
- 2x DYNAMIXEL Motors (XC430-W150)
- DYNAMIXEL U2D2 Power Hub
- DYNAMIXEL U2D2
- 2x Pololu Scooter/Skate Wheel 70×25mm - Black (3272)
- Bosch BNO055 IMU Adafruit Board (2472)
- Raspberry Pi Camera Module 3 Wide
- Bosch Professional GBA 18V (5AH recommended)
- Converter DC/DC to 5V (DTJ1524S05)
- Converter DC/DC to 12V (DTJ1524S12)
- 3D printed Mobile Robot Case
-
Software
- OS installed on the RPi5 (recommended : Raspberry pi OS using Imager software)
- ROS 2 packages (all inside Docker):
em_robot→ motor control and odometrybno055→ IMU driver (Thesrc/bno055package in this repository is a modified version of the originalflynneva/bno055code, adapted to work with this application.)em_robot_srv→ service definitions
- Mount and wire the robot according to the CAD and Electrical Schematics
- Insert the fully charged battery into the back holder
- Wait some time for the Raspberry Pi to initialize
- Place the RPi within Wi-Fi range.
- Ensure PC and RPi are on the same network.
- For that, configure a static IP on the RPi which should be the same as the one found in fastdds.xml (for example : 192.168.0.101)
- Match the ROS_DOMAIN_ID on both PC and RPi (default =
10):Or in the Dockerfile:echo "export ROS_DOMAIN_ID=10" >> ~/.bashrc
ENV ROS_DOMAIN_ID=10
-
SSH into the RPi:
ssh <rpi-name>@<robot-ip>
-
Install Docker on the RPi:
sudo apt-get update sudo apt-get install ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo groupadd docker sudo gpasswd -a $USER docker newgrp docker docker run hello-world
-
Pull the container image:
docker pull ghcr.io/swisscatplus/em_onrobot/em_robot:latest
-
Run the container:
./deploy.sh
Running outside Docker is not the primary workflow, but it is possible.
From the Dockerfile, the required local dependencies are:
sudo apt update
sudo apt install python3-smbus i2c-tools python3-devpip install smbus2Make sure you have ROS 2 Humble installed with colcon and build tools.
Then build the workspace:
cd ros2_ws
colcon build --packages-select em_robot em_robot_srv bno055-
Connect to the RPi:
ssh <rpi-name>>@<robot-ip>
-
Start the container:
./deploy.sh
-
Test movement:
Important: This is a two-wheeled differential drive robot. That means it can only move using:
- Linear X → forward/backward motion (both wheels turning in the same direction).
- Angular Z (yaw) → rotation on the spot or turning (wheels turning at different speeds).
All other fields (
linear.y,linear.z,angular.x,angular.y) are ignored.You have two options for testing:
-
Direct velocity commands (use with caution):
You can publish a velocity command directly, but be aware that the robot will keep moving until you explicitly send another command with zero velocity. For example:
ros2 topic pub /cmd_vel geometry_msgs/Twist "linear: x: 0.3 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 0.5"
To stop the robot, send the same command again but with all values set to
0.0. -
Safer option: use teleop:
The recommended way to test is to use the teleop_twist_keyboard package. This allows you to control the robot interactively from your PC with the keyboard:
ros2 run teleop_twist_keyboard teleop_twist_keyboard
You can also connect a gaming controller and map the joystick to publish commands on
/cmd_velfor smoother and safer manual control.
| Topic | Type | Description |
|---|---|---|
/left_ticks_counts |
std_msgs/Int16 |
Encoder ticks from left wheel |
/right_ticks_counts |
std_msgs/Int16 |
Encoder ticks from right wheel |
/bno055/imu |
sensor_msgs/Imu |
Orientation and acceleration from BNO055 |
/edi/cam |
geometry_msgs/PoseWithCovarianceStamped |
Pose correction from camera + ArUco markers |
/cmd_vel |
geometry_msgs/Twist |
Input velocity command for differential drive |
EM_onrobot/
├── Dockerfile # Build instructions for em_robot image
├── Dockerfile.base # Base image with ROS 2 and dependencies
├── entrypoint.sh # Container entrypoint script
├── fastdds.xml # Fast DDS configuration
├── src/
│ ├── em_robot/ # Main robot package (motors, camera, odometry)
│ ├── em_robot_srv/ # ROS 2 service definitions
│ ├── bno055/ # External Bosch BNO055 driver
│ └── test.py # Example script
├── images/logo.png
└── README.md
- Expand documentation with troubleshooting and advanced usage examples.
This project is licensed under the MIT License.
It also includes code from flynneva/bno055, which is licensed under the BSD 3-Clause License.