Damiao Omnidirectional AGV Base — DBUS Protocol & Teleop Guide

Complete guide to connecting, commanding, and integrating the Damiao 4-wheel omnidirectional AGV base using the DBUS serial protocol, the Python dami_agent bridge, and the Fearless Platform.

Device: Damiao AGV (达妙) Drive: 4-wheel omnidirectional (4WS4WD) Interface: UART5, 100000 baud, 8E2 Protocol: DBUS/SBUS-style 18-byte frames Agent: dami_agent
Mobile Base Omnidirectional DBUS/SBUS UART Serial WebSocket Teleop 4WS4WD

1. Overview

The Damiao AGV (达妙 AGV) is a four-wheel omnidirectional mobile base with independent steering and drive on all four wheels (4WS4WD configuration). Its omnidirectional kinematics — using Mecanum or omni wheels — allow the base to move laterally, diagonally, and rotate in place without any turning radius constraint. This makes it well-suited for manipulation tasks in cluttered environments, mobile manipulation data collection, and whole-body teleoperation setups where precise base positioning is required.

The AGV's open-source firmware communicates via its main controller's UART5 interface (pin PD2, RX), accepting RC receiver-style DBUS/SBUS control frames at 100000 baud with 8 data bits, even parity, and 2 stop bits (8E2). The dami_agent.py bridge script connects a PC via USB-to-TTL adapter to this UART, translates high-level platform commands (move, stop, goal) into properly encoded 18-byte DBUS frames, and forwards them at a configurable control rate — all without modifying the AGV firmware.

The agent simultaneously maintains a WebSocket connection to the Fearless Platform, enabling real-time teleoperation from the browser UI, telemetry reporting, command timeout safety stops, and episode recording for mobile manipulation datasets.

2. Full Specifications

PropertyValue
VendorDamiao (达妙)
Drive configuration4-wheel omnidirectional (4WS4WD)
Wheel typeMecanum or omni wheels
Control interfaceUART5 on main controller (pin PD2, RX)
Baud rate100000
Serial framing8 data bits, even parity, 2 stop bits (8E2)
ProtocolDBUS/SBUS-style RC frame (18 bytes)
Channelsch0–ch3 (11-bit, 0–2047, center 1024) + ch4 (center, unused for AGV) + s0/s1 switches
Channel → velocity mappingVx = sign(ch3 − 1024), Vy = sign(ch2 − 1024), Vw = sign(−(ch0 − 1024))
Amplitude parameter--amp default 660, range 250–900 (offset from 1024)
Control rate30 Hz (configurable with --control-hz)
Telemetry rate8 Hz (configurable with --telemetry-hz)
Command timeout300 ms (configurable with --cmd-timeout-ms); AGV stops automatically
Platform device typemobile_base
Platform capabilities["mobile_base", "agv", "telemetry"]
Agent moduledami_agent
Backend WebSocket URLws://localhost:8000 (default)
Mock modeYes (--mock); serial port not opened, full WebSocket pipeline active

3. Quick Start

  1. Install dependencies.
    pip install pyserial websockets
  2. Connect the USB-to-TTL adapter. Wire the adapter's TX pin to the AGV main controller's UART5_RX (PD2). Connect GND. Do NOT connect the adapter's RX or 5V to the AGV. Confirm the port appears:
    ls /dev/ttyUSB*   # Linux
  3. Create a teleop session on the platform. Open platform.roboticscenter.ai, navigate to the Teleop section, and create a new session. Copy the session ID (format: RC-XXXX-XXXX).
  4. Launch the AGV agent.
    python3 dami_agent.py \
      --session RC-XXXX-XXXX \
      --serial-port /dev/ttyUSB0 \
      --backend ws://localhost:8000
    The agent connects to the platform, registers the AGV node, and begins the control loop at 30 Hz.
  5. Drive from the browser. Open the session URL in your browser. Use the directional controls to send move commands. The AGV responds within one control-loop tick (33 ms at default 30 Hz).
Test without hardware first. Run python3 dami_agent.py --session RC-XXXX-XXXX --mock to verify the full command pipeline end-to-end without an AGV or serial connection.

4. DBUS Protocol

The Damiao AGV firmware expects standard DBUS/SBUS RC receiver frames on its UART5 input. The agent encodes velocity commands as RC joystick values in this format without any firmware modification required.

18-byte frame layout

BytesContentNotes
0–5ch0, ch1, ch2, ch3 packed (11-bit each)Little-endian bit-packing; 44 bits total occupying 48 bits
5 (high nibble)s0 (bits [5:4]), s1 (bits [7:6])Switch states; fixed at 1/1 (center) for AGV use
6–15Mouse and keyboard fieldsZeroed for AGV; not parsed by AGV firmware
16–17ch4 (11-bit)Fixed at center (1024); not used for AGV motion

The 11-bit channels are packed consecutively starting from bit 0 of byte 0:

# bit-packing of ch0..ch3 into bytes 0..5
b[0] =  ch0 & 0xFF
b[1] = (ch0 >> 8 & 0x07) | ((ch1 & 0x1F) << 3)
b[2] = (ch1 >> 5 & 0x3F) | ((ch2 & 0x03) << 6)
b[3] =  ch2 >> 2 & 0xFF
b[4] = (ch2 >> 10 & 0x01) | ((ch3 & 0x7F) << 1)
b[5] =  ch3 >> 7 & 0x0F    # upper nibble: switch bits

# ch4 in bytes 16..17
b[16] = ch4 & 0xFF
b[17] = ch4 >> 8 & 0x07

Channel-to-velocity mapping

The AGV firmware's Control_Task decodes channels as follows. The agent must invert this mapping when encoding velocity commands:

ChannelFirmware interprets asAgent encodes fromFormula
ch0Yaw (rotation)vw (angular velocity)ch0 = 1024 + (-vw) × amp
ch1UnusedFixed at 1024
ch2Lateral (Y)vych2 = 1024 + vy × amp
ch3Forward (X)vxch3 = 1024 + vx × amp

Channel values are clamped to [0, 2047]. At center (1024 on all channels), the AGV holds position. The amp parameter (default 660) sets the magnitude of deflection from center — higher values produce faster motion. The agent accepts vx, vy, and vw as discrete sign values (−1, 0, +1) from the platform command messages.

Serial framing critical. The UART5 must be configured as 100000 baud, 8E2 (8 data bits, even parity, 2 stop bits). A common mistake is opening the port as 8N1 (no parity, 1 stop bit). Even though both sides appear to connect, the AGV firmware will silently ignore or misparse frames at the wrong framing. Use pyserial.PARITY_EVEN and STOPBITS_TWO.

5. SDK / Python Usage

The dami_agent.py script is the primary interface between the Fearless Platform and the AGV hardware. It runs two async loops — a control loop and a telemetry loop — inside a single WebSocket session.

Agent CLI reference

FlagDefaultDescription
--backendws://localhost:8000Platform WebSocket base URL
--session(required)Teleop session ID
--node-idhostnameAGV node identifier in the session
--serial-port/dev/ttyUSB0USB-to-TTL adapter device path
--telemetry-hz8.0Frequency to send telemetry to platform
--control-hz30.0DBUS frame output rate (Hz)
--cmd-timeout-ms300Auto-stop if no command received within this window
--amp660Joystick amplitude (500–760 recommended)
--invert-xfalseFlip forward/backward direction
--invert-yfalseFlip left/right direction
--invert-zfalseFlip rotation direction
--mockfalseSkip serial port; validate command pipeline only

Sending commands programmatically

The agent receives platform commands as JSON messages over its WebSocket. You can send commands from any platform client or script using the session WebSocket. Supported command types:

# Move forward along X axis
{"type": "move", "axis": "x", "dir": 1}

# Move laterally right (Y axis)
{"type": "move", "axis": "y", "dir": 1}

# Rotate counter-clockwise (Z axis)
{"type": "move", "axis": "z", "dir": -1}

# Stop all motion immediately
{"type": "stop"}

# Goal-based delta movement (x, y, yaw)
{"type": "goal", "delta": {"x": 0.5, "y": 0.0, "yaw": 0.0}}

The goal command degrades the continuous delta to a discrete direction sign, matching the agent's discrete velocity model. For smooth continuous control, send repeated move commands at the desired rate and stop when the target is reached.

Shutdown safety

On agent exit (Ctrl+C or WebSocket close), the agent sends three center-position DBUS frames (all channels at 1024) separated by 30 ms delays before closing the serial port. This ensures the AGV firmware receives the stop signal even if the final command was a movement.

6. Platform Integration

The agent connects to /api/teleop/ws on the Fearless Platform backend and registers the AGV as a robot node. The WebSocket handshake:

{
  "role": "robot",
  "session_id": "RC-XXXX-XXXX",
  "member_id": "dami-agv-node",
  "node_id": "dami-agv-node",
  "node_role": "robot",
  "device_type": "mobile_base",
  "capabilities": ["mobile_base", "agv", "telemetry"],
  "source_host": "hostname"
}

Telemetry format

The agent sends telemetry at the configured --telemetry-hz rate. The joints field reuses the generic telemetry structure to carry the discrete velocity command state:

{
  "type": "telemetry",
  "member_id": "dami-agv-node",
  "joints": {
    "vx_cmd": 1.0,    // current commanded X velocity sign
    "vy_cmd": 0.0,
    "vw_cmd": 0.0
  },
  "feedback": {
    "connected": true,
    "robot_model": "dami_agv_4ws4wd",
    "transport": "serial_dbus",
    "serial_port": "/dev/ttyUSB0",
    "amp": 660,
    "cmd_timeout_ms": 300
  },
  "ts": 1743680400123
}

Latency ping/pong

The platform sends periodic ping_latency messages. The agent responds with pong_latency immediately, preserving the original ts and id fields. The platform uses these round trips to display round-trip latency in the teleop session header.

Episode recording

When a recording session is active on the platform, all telemetry frames from the AGV node are archived alongside other session nodes (arm, cameras, tactile sensors). The resulting JSONL archive captures the complete mobile manipulation trajectory, including base velocity commands and timing, enabling full replay and training data extraction.

WebSocket keepalive. If no message is received from the platform for 45 seconds, the agent sends a {"type": "ping"} message to keep the connection alive. If the connection closes, the control loop continues running and the AGV will auto-stop after cmd_timeout_ms — it will not run uncontrolled.

7. Troubleshooting

Symptom Likely Cause Fix
pyserial.SerialException on open Port busy, wrong path, or permission denied Check ls /dev/ttyUSB*. Add user to dialout group: sudo usermod -aG dialout $USER then log out and back in. Pass the correct port with --serial-port /dev/ttyUSBX.
AGV does not move on command Wrong serial framing (8N1 instead of 8E2), wrong baud rate, or TX/RX wired incorrectly Confirm pyserial is opened with PARITY_EVEN, STOPBITS_TWO, baudrate=100000. Verify the USB-to-TTL TX pin goes to AGV UART5_RX (PD2). Do NOT connect RX-to-TX in loopback.
AGV moves briefly then stops Command timeout triggering (default 300 ms) The platform is not sending commands fast enough. Check network latency. Increase --cmd-timeout-ms to 500–1000 ms for high-latency links. Ensure the browser teleop panel is actively sending commands.
AGV moves in wrong direction Axis inversion needed for physical installation orientation Use --invert-x, --invert-y, or --invert-z flags to correct orientation without firmware changes. Test each axis individually first.
Agent connects but platform shows no telemetry Session ID mismatch or WebSocket handshake not completing Confirm the session ID passed to --session is active in the platform. Check the agent output for "ready" after the handshake. If it prints "handshake failed", the session may have expired — create a new one.
Still stuck? Contact SVRC support with the output of python3 dami_agent.py --mock --session test-session and your serial port path. Include the USB-to-TTL adapter model.
New to robotics? Learn mobile base control, ROS 2 navigation, and teleop fundamentals at the SVRC Robotics Academy before integrating hardware.
Have a question? Ask the community or contact support with the output of dami_agent.py --mock.

Ready to build a mobile manipulation system?

Register on the platform, connect your AGV, and start collecting whole-body teleoperation demonstrations.