AI Teammate ROS2 Device Bridge
Project description
AI Teammate Robot Bridge
Connects ROS2 robots to the AI Teammate platform via WebSocket + MQTT.
Features
- rclpy native — Direct DDS participation, no rosbridge required
- Dual telemetry — MQTT (primary, 1Hz) + WebSocket (fallback)
- Auto-detection — cmd_vel, camera, IMU, LiDAR topics discovered at startup
- Camera streaming — RealSense / USB camera auto-detect, on-demand JPEG streaming
- SLAM mapping — Trajectory collection (5Hz, 5cm spacing) + WiFi fingerprint auto-collection
- WiFi fingerprinting — Save/localize/list fingerprints with mobile AP blocklist
- Plugin architecture — Optional AMR Skills for 54+ robot commands
- Auto-reconnect — WebSocket + MQTT reconnection with exponential backoff
- Simulator mode — Works without ROS2 for development/testing
- systemd ready — Auto-restart, boot start with linger
Quick Install (Recommended)
curl -sL "https://ai-teammate.net/api/b2b/install/MY-ROBOT-01?key=YOUR_API_KEY" | bash
This single command will:
- Detect ROS2 and auto-configure topics
- Install bridge from PyPI + AMR skills (pre-built binary)
- Configure MQTT telemetry
- Register device with cloud gateway
- Create systemd service (auto-restart + boot start)
Get your API key from Control Tower > Devices > + button.
Step-by-Step Setup Guide
Prerequisites
- Robot PC: Ubuntu 22.04 + ROS2 Humble (or Jazzy)
- Robot hardware bringup running (motors, LiDAR, IMU topics publishing)
- Internet connection (WSS + MQTT to ai-teammate.net)
Step 1. Get API Key
- Open Control Tower
- Go to Devices tab > click + button
- Enter a Device ID (e.g.
my-robot-01) and copy the generated API Key (dk_...)
Step 2. Run Install Script
SSH into the robot and run:
curl -sL "https://ai-teammate.net/api/b2b/install/my-robot-01?key=dk_YOUR_API_KEY" | bash
The script automatically:
- Detects ROS2 and discovers topics (cmd_vel, odom, imu, lidar, camera)
- Installs bridge from PyPI + optional AMR skills binary
- Generates
.envandsensors.yamlwith auto-detected topic names - Configures MQTT telemetry
- Registers device with cloud gateway
- Sets up sudoers for shutdown/reboot (NOPASSWD)
- Creates systemd service with boot-start enabled
For networks with a proxy:
curl -sL "..." | bash -s -- --proxy=http://proxy:8080
Step 3. Verify Installation
# Check service status
systemctl --user status ai-teammate-bridge
# Watch live logs
tail -f ~/ai-teammate-bridge/bridge.log
# Review detected config
cat ~/ai-teammate-bridge/.env
cat ~/ai-teammate-bridge/sensors.yaml
Step 4. Verify in Control Tower
- Open Control Tower > Devices tab
- Robot should show as connected with green indicator
- Click the robot > Health section should show IMU, odom, lidar as OK
- SLAM tab should display sensor data
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
sensor: no data (never received) |
Topic name mismatch | Run ros2 topic list to find actual names, update ~/ai-teammate-bridge/.env, then systemctl --user restart ai-teammate-bridge |
| SHUTDOWN/REBOOT not working | Missing sudoers | echo "$USER ALL=(ALL) NOPASSWD: /usr/sbin/shutdown, /usr/sbin/reboot" | sudo tee /etc/sudoers.d/ai-teammate-bridge && sudo chmod 440 /etc/sudoers.d/ai-teammate-bridge |
| Bridge not starting after reboot | Linger not enabled | loginctl enable-linger $USER |
| WS connection failed | Firewall/proxy | Test with curl https://ai-teammate.net/api/health, use --proxy flag if needed |
ros2: command not found in service |
ROS2 env not sourced | Ensure /etc/env.sh exists and sources ROS2 setup, or add source /opt/ros/humble/setup.bash to service ExecStart |
Manual Topic Override
If auto-detection picks the wrong topic:
# Check what's actually publishing
ros2 topic list | grep -E 'odom|imu|scan|cmd_vel'
# Edit .env
vi ~/ai-teammate-bridge/.env
# Example: ODOM_TOPIC=/base_controller/odom
# Restart
systemctl --user restart ai-teammate-bridge
Common non-standard topic names:
| Sensor | Standard | Variants |
|---|---|---|
| Odometry | /odom |
/base_controller/odom, /odometry/filtered, /wheel/odometry |
| IMU | /imu/data |
/imu/data_raw, /camera/imu, /front_lidar/imu |
| LiDAR | /scan |
/scan_filtered, /front_lidar/scan |
| cmd_vel | /cmd_vel |
/base_controller/cmd_vel_unstamped, /cmd_vel_mux/input/teleop |
Manual Install
pip3 install ai-teammate-ros2-bridge
Configuration
mkdir -p ~/ai-teammate-bridge && cd ~/ai-teammate-bridge
ai-teammate-bridge init
# → Creates .env with interactive prompts
# Or manually:
cat > .env << EOF
DEVICE_ID=my-robot-01
GATEWAY_URL=wss://ai-teammate.net/gw
API_KEY=dk_YOUR_API_KEY
CONNECTION_MODE=rclpy
STATUS_REPORT_INTERVAL=1.0
CMD_VEL_TOPIC=/cmd_vel
IMU_TOPIC=/imu/data
ODOM_TOPIC=/odom
SCAN_TOPIC=/scan
MQTT_BROKER=ai-teammate.net
MQTT_PORT=1883
MQTT_USER=robot_bridge
MQTT_PASS=mqtt_r0b0t_2026
EOF
Run
# Source ROS2 environment first
source /opt/ros/humble/setup.bash
ai-teammate-bridge
Environment Variables
| Variable | Default | Description |
|---|---|---|
DEVICE_ID |
required | Unique device identifier |
GATEWAY_URL |
required | Device Gateway WebSocket URL |
API_KEY |
required | Device API key (dk_xxx) |
CONNECTION_MODE |
rclpy |
rclpy for ROS2, simulator for testing |
STATUS_REPORT_INTERVAL |
1.0 |
Sensor update interval (seconds) |
CMD_VEL_TOPIC |
/cmd_vel |
ROS2 velocity command topic |
IMU_TOPIC |
/imu/data |
IMU subscription topic |
ODOM_TOPIC |
/odom |
Odometry subscription topic |
SCAN_TOPIC |
/scan |
LiDAR scan topic |
MQTT_BROKER |
(empty=disabled) | MQTT broker hostname |
MQTT_PORT |
1883 |
MQTT broker port |
MQTT_USER |
robot_bridge |
MQTT username |
MQTT_PASS |
(empty) | MQTT password |
Architecture
Robot Cloud (ai-teammate.net)
┌──────────────────────┐ ┌─────────────────────┐
│ ai-teammate-bridge │ │ Device Gateway │
�� (CLI entry point) │ │ (port 8003) │
│ │ │ │
│ ���────────────────┐ │ WSS │ /ws/{device_id} │
│ │ ws_client.py │──┼────────▶│ commands ◀────── │──▶ Control Tower
│ │ DeviceBridge │◀─┼────────│ responses │
│ └────────────────┘ │ │ │
│ │ MQTT │ Mosquitto (1883) │
│ ┌────────────────┐ │────────▶│ telemetry │
│ │ MQTT publisher │ │ │ position │
│ └────────────────┘ │ │ health │
│ │ └─────────────────────┘
│ ┌────────────────┐ │
│ │ ros2_node.py │ │ ROS2 DDS (no rosbridge)
│ │ ├─ cmd_vel pub│ │
│ │ ├─ IMU sub │ │
│ │ ├─ odom sub │ │
│ │ ├─ scan sub │ │
│ │ ├─ camera sub │ │ on-demand (auto-stop 30s)
│ │ └─ TF listener│ │ map→base_footprint (5Hz)
│ └────────────────┘ │
│ │
│ ┌────────────────┐ │
│ │ Skills (opt) │ │ ai-teammate-ros2-skills
│ │ 54+ commands │ │ (pre-built .so binary)
│ └────────────────┘ │
└──────────────────────┘
Communication Channels
| Channel | Data | Direction | Frequency |
|---|---|---|---|
| WebSocket | Commands, responses | Bidirectional | On-demand |
| WebSocket | Camera frames | Robot → Cloud | 2-5 FPS (on-demand) |
| WebSocket | SLAM map + trajectory | Robot → Cloud | Every 5s during mapping |
| MQTT | Telemetry (IMU, battery) | Robot → Cloud | 1 Hz |
| MQTT | Position (x, y, theta) | Robot → Cloud | 1 Hz (retained) |
| MQTT | Health alerts | Robot → Cloud | On-event (retained) |
Package Structure
ai_teammate_ros2_bridge/
├── cli.py # Entry point: ai-teammate-bridge command
├── config.py # Shared state (_ros2_cache), env loading, MQTT config
├── ws_client.py # DeviceBridge class, WS + MQTT event loop, health checks
├── device_bridge.py # Command handlers (SLAM, camera, nav, fingerprint, etc.)
├── ros2_node.py # rclpy spin thread, ROS2 subscriptions, TF listener
├── sensors.py # Sensor data aggregation, battery fallback
├── sensors_config.py # Hardware abstraction (sensors.yaml)
├── lan_server.py # LAN WebSocket server for local clients
└── utils.py # Input sanitization helpers
Systemd Service
The install script creates a systemd service automatically. For user-level services, the unit uses After=basic.target (not network-online.target, which is unavailable in user scope).
# System-level (if sudo available)
sudo systemctl status ai-teammate-bridge
sudo systemctl restart ai-teammate-bridge
sudo journalctl -u ai-teammate-bridge -f
# User-level (no sudo, with loginctl enable-linger)
systemctl --user status ai-teammate-bridge
systemctl --user restart ai-teammate-bridge
Command Dispatch
Commands from the cloud are dispatched in two tiers:
- Bridge-first commands — Camera commands (
CAPTURE_IMAGE,CAMERA_CAPTURE,START_CAMERA_STREAM,STOP_CAMERA_STREAM) always go todevice_bridge.pyfirst because they require access to the sharedconfig._ros2_cache. - Skills-first — All other commands try the optional
ai-teammate-ros2-skillsplugin first. If the plugin returnsunknown_command, the bridge falls back todevice_bridge.py.
SLAM Commands
| Command | Description |
|---|---|
SLAM_START |
Launch slam_toolbox, begin trajectory + WiFi fingerprint collection |
SLAM_STOP |
Stop SLAM, return trajectory/fingerprint counts |
SLAM_SAVE |
Save map, auto-link fingerprints to nearby locations, detect mobile APs |
During SLAM mapping, the bridge automatically:
- Collects trajectory points at 5Hz with 5cm minimum spacing (via TF listener)
- Scans WiFi fingerprints every 5s with 50cm minimum displacement
- On
SLAM_SAVE: links fingerprints to saved locations within 1.5m as"predicted"source - Detects mobile APs (same BSSID at distant locations) and adds them to
wifi_blocklist.json
WiFi Fingerprint Commands
| Command | Description |
|---|---|
SAVE_FINGERPRINT |
Save WiFi scan at current pose. source: verified (default) or predicted |
LIST_FINGERPRINTS |
List all saved fingerprints with pose and AP count |
LOCALIZE_FINGERPRINT |
Match current WiFi scan against saved fingerprints (filters blocked BSSIDs) |
Location Commands
| Command | Description |
|---|---|
SAVE_LOCATION |
Save named location. Supports explicit x, y params (map pin) or uses current robot pose |
Camera (On-Demand)
Camera subscriptions are created on-demand and auto-stop after 30s of inactivity to save CPU (~10% reduction). Camera health is excluded from the all_ok flag and alert system — it only reports status when actively streaming.
Capture flow: start_camera() is always called first, then a 10s wait for a fresh frame before capturing.
Supported Platforms
| Platform | Architecture | Python | ROS2 |
|---|---|---|---|
| Ubuntu 20.04+ | x86_64 | 3.10, 3.12 | Humble, Jazzy |
| Ubuntu 20.04+ | aarch64 (Jetson, RPi4+) | 3.10, 3.12 | Humble, Jazzy |
| Any Linux | x86_64/aarch64 | 3.10+ | Simulator mode (no ROS2) |
Requirements
- Python 3.10+
- ROS2 Humble or Jazzy (optional — simulator mode works without)
- Internet access to ai-teammate.net (WSS + MQTT)
Changelog (v2.6.14 — v2.6.24)
v2.6.24
- feat(radio): Mobile AP detection — same BSSID seen at distant locations during SLAM is auto-blocklisted in
wifi_blocklist.json - feat(place):
SAVE_LOCATIONsupports explicitx,ycoordinates (map pin placement vs robot pose) - feat(place):
SLAM_SAVEauto-links collected fingerprints to nearby saved locations as"predicted"source
v2.6.23
- feat(slam): Auto-collect WiFi fingerprints during SLAM mapping (5s interval, 50cm min displacement)
v2.6.22
- feat(slam): Collect trajectory during mapping via TF listener (5Hz, 5cm spacing), include in map upload metadata
v2.6.21
- fix(slam): Send initial SLAM map on WS connect regardless of age; flag-based dedup instead of age-only check
v2.6.20
- fix(stream):
camera_streamandfollow_stateuse sharedconfig._ros2_cacheinstead of local cache
v2.6.19
- fix(camera): Route camera commands (
CAPTURE_IMAGE,CAMERA_CAPTURE,START_CAMERA_STREAM,STOP_CAMERA_STREAM) to bridge first, skip skills — camera needs shared config cache
v2.6.18
- fix(camera): Always call
start_camera()+ 10s wait for fresh frame before capture
v2.6.17
- fix(camera): Use shared
config._ros2_cacheforCAPTURE_IMAGEinstead of local cache
v2.6.16
- fix(camera): Check frame presence instead of
_camera_activeflag for capture readiness
v2.6.15
- fix(camera): Improved
capture_image— checkstart_cameraresult, 5s wait, better logging
v2.6.14
- fix(health): Camera (on-demand) excluded from
all_okand health alerts — only reports when active
License
MIT - MobioLabs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ai_teammate_ros2_bridge-2.6.30.tar.gz.
File metadata
- Download URL: ai_teammate_ros2_bridge-2.6.30.tar.gz
- Upload date:
- Size: 70.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b05f5982d350a51bb94be2519ef73a1fbd0b2b0cb7d7dc69df1154f6f5079c1a
|
|
| MD5 |
271a9a0d85ef484c947a90d19c0ae894
|
|
| BLAKE2b-256 |
d34127520629757ef701c27e14b7fd7346110ce151f97d108cfa30031ccf9ba4
|
File details
Details for the file ai_teammate_ros2_bridge-2.6.30-py3-none-any.whl.
File metadata
- Download URL: ai_teammate_ros2_bridge-2.6.30-py3-none-any.whl
- Upload date:
- Size: 71.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e17e48ed38ea4f8d76efe5ba71af0644530f285324e64c9c7156c68b5b445dd2
|
|
| MD5 |
3717e6a807cb7c9fcc43e8e72c827419
|
|
| BLAKE2b-256 |
c909448b752bc421617c330e0314bf7f7f43a50a79fdabed73217595c919be17
|