Skip to main content

What is MotorBridge?

v0.1.3 Rust Core Python Binding MotorBridge is a unified motor control stack with pluggable vendor drivers and a C ABI for cross-language integration.

The Problem We Solve

Every motor vendor has a different protocol:
VendorProtocolCAN FormatControl Modes
Damiao (达妙)DM-J4310/4340CAN 2.0MIT, POS_VEL, VEL, FORCE_POS
RobStrideRobStride MITCAN 2.0MIT, Position, Velocity
MyActuatorRMDCAN 2.0Current, Position, Velocity
HighTorqueHT NativeCAN 2.0MIT, POS_VEL, VEL, FORCE_POS
HexfellowHexfellow MITCAN-FDMIT, POS_VEL, FORCE_POS
Without MotorBridge, you need to:
  • Learn 5+ different protocols
  • Maintain separate codebases per vendor
  • Rewrite control logic when switching motors
  • Build your own debugging tools

MotorBridge Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                          Your Application                            │
│                     (Python / Future: C++, ROS2)                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│    ┌─────────────────────────────────────────────────────────────┐  │
│    │                    Language Bindings                         │  │
│    │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │  │
│    │  │   Python     │  │   C++ (WIP)  │  │  ROS2 (WIP)  │      │  │
│    │  │   Binding    │  │   Binding    │  │   Node       │      │  │
│    │  └──────────────┘  └──────────────┘  └──────────────┘      │  │
│    └─────────────────────────────────────────────────────────────┘  │
│                                │                                     │
│                                ▼                                     │
│    ┌─────────────────────────────────────────────────────────────┐  │
│    │                       C ABI (FFI)                            │  │
│    │              libmotor_abi.so / .dylib / .dll                 │  │
│    │                                                              │  │
│    │  • motor_controller_new_socketcan()                         │  │
│    │  • motor_controller_add_damiao_motor()                      │  │
│    │  • motor_handle_send_mit()                                  │  │
│    │  • motor_handle_get_state()                                 │  │
│    └─────────────────────────────────────────────────────────────┘  │
│                                │                                     │
│                                ▼                                     │
│    ┌─────────────────────────────────────────────────────────────┐  │
│    │                     Rust Core                                │  │
│    │                                                              │  │
│    │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │  │
│    │  │ motor_core  │ │ motor_abi   │ │ motor_cli   │           │  │
│    │  │ (abstractions)│ (FFI layer) │ │ (CLI tools) │           │  │
│    │  └─────────────┘ └─────────────┘ └─────────────┘           │  │
│    │                                                              │  │
│    │  ┌───────────────────────────────────────────────────────┐ │  │
│    │  │                   Vendor Drivers                       │ │  │
│    │  │  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐│ │  │
│    │  │  │ Damiao │ │RobStride│ │MyActuat.│ │HighTorq.│ │Hexfellow││  │
│    │  │  │        │ │        │ │        │ │        │ │        ││ │  │
│    │  │  └────────┘ └────────┘ └────────┘ └────────┘ └────────┘│ │  │
│    │  └───────────────────────────────────────────────────────┘ │  │
│    └─────────────────────────────────────────────────────────────┘  │
│                                │                                     │
│                                ▼                                     │
│    ┌─────────────────────────────────────────────────────────────┐  │
│    │                     Transport Layer                          │  │
│    │                                                              │  │
│    │  ┌────────────┐  ┌────────────┐  ┌────────────┐            │  │
│    │  │ SocketCAN  │  │ SocketCAN-FD│  │  DM Serial │            │  │
│    │  │ (CAN 2.0)  │  │  (CAN-FD)  │  │   Bridge   │            │  │
│    │  └────────────┘  └────────────┘  └────────────┘            │  │
│    └─────────────────────────────────────────────────────────────┘  │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Project Structure

rust_dm/
├── motor_core/           # Core abstractions (CanBus, MotorDevice)
├── motor_abi/            # C ABI / FFI layer (cdylib + staticlib)
├── motor_vendors/        # Vendor-specific protocol implementations
│   ├── damiao/          # 达妙 motor protocol
│   ├── robstride/       # RobStride motor protocol
│   ├── myactuator/      # MyActuator RMD protocol
│   ├── hightorque/      # HighTorque native protocol
│   └── hexfellow/       # Hexfellow MIT protocol (CAN-FD)
├── bindings/
│   └── python/          # Python binding (ctypes-based)
├── motor_cli/           # Command-line utilities
├── integrations/
│   └── ws_gateway/      # WebSocket gateway for remote control
└── tools/
    └── factory_calib_ui/ # Factory calibration web UI

Why “Python Binding” Not “SDK”?

A binding is a thin wrapper that exposes a native library to another language via FFI (Foreign Function Interface).
┌─────────────────────────────────────────────────┐
│  Python Code                                    │
│  motor.send_mit(pos, vel, kp, kd, tau)          │
└───────────────────────┬─────────────────────────┘
                        │ ctypes call

┌─────────────────────────────────────────────────┐
│  C ABI (libmotor_abi.so)                        │
│  motor_handle_send_mit(ptr, pos, vel, kp, kd, tau)│
└───────────────────────┬─────────────────────────┘
                        │ native call

┌─────────────────────────────────────────────────┐
│  Rust Core                                      │
│  DamiaoMotor::send_mit_target(...)             │
└─────────────────────────────────────────────────┘
Key characteristics:
  • Logic lives in Rust, not Python
  • Python is a 1:1 mapping to C ABI functions
  • No duplicate implementation
  • Minimal overhead (direct FFI calls)
The motor_abi crate compiles to a shared library:
# motor_abi/Cargo.toml
[lib]
crate-type = ["cdylib", "staticlib"]  # Dynamic + Static library
Python loads it via ctypes:
# abi.py
lib = ctypes.CDLL("libmotor_abi.so")

# Bind function signature
lib.motor_handle_send_mit.argtypes = [c_void_p, c_float, c_float, 
                                       c_float, c_float, c_float]
lib.motor_handle_send_mit.restype = c_int32

# Call it
lib.motor_handle_send_mit(motor_ptr, 0.5, 0.0, 30.0, 1.0, 0.0)
This is zero-copy for primitive types - floats and ints pass directly between Python and Rust.
AspectSDKBinding (MotorBridge)
Logic locationIn the SDK itselfIn Rust core
LanguagePure PythonRust + Python wrapper
PerformancePython overheadNear-native speed
Memory safetyPython GCRust ownership
Other languagesN/ASame ABI for C++, etc.
DeploymentPure PythonNeed native library
MotorBridge is a Binding because:
  • The “SDK” is the Rust core (motor_core + vendor drivers)
  • Python is just one interface to that core
  • Future: C++, ROS2 nodes will use the same ABI

Why Rust for the Core?

RequirementRust Advantage
Real-time controlNo garbage collection pauses
Memory safetyNo buffer overflows, use-after-free
Deterministic timingPredictable execution for control loops
Zero-cost abstractionsHigh-level code, low-level performance
Cross-platformLinux, macOS, Windows support
CAN integrationNative SocketCAN bindings

Core Components

Controller

Manages CAN interface and motor lifecycle:
from motorbridge import Controller

# SocketCAN (most common)
with Controller("can0") as ctrl:
    # ctrl manages the CAN socket
    # ctrl tracks all registered motors
    # ctrl handles cleanup on exit
    pass

# CAN-FD (for Hexfellow)
ctrl = Controller.from_socketcanfd("can0")

# DM Serial Bridge (达妙专用)
ctrl = Controller.from_dm_serial("/dev/ttyACM0", 921600)
Each Controller is bound to one vendor. You cannot mix Damiao and RobStride motors in the same Controller instance.

Motor

Handle to a single physical motor:
# Add a Damiao motor
motor = ctrl.add_damiao_motor(
    motor_id=0x01,      # Command CAN ID
    feedback_id=0x11,   # Feedback CAN ID  
    model="4340P"       # Motor model string
)

# Control commands
motor.send_mit(pos=0.5, vel=0.0, kp=30.0, kd=1.0, tau=0.0)

# Read state
state = motor.get_state()

Mode

Control mode determines how the motor responds:
from motorbridge import Mode

motor.ensure_mode(Mode.MIT, timeout_ms=1000)
ModeParametersUse Case
MITpos, vel, kp, kd, tauFull impedance control
POS_VELpos, vlimPosition with speed limit
VELvelPure velocity control
FORCE_POSpos, vlim, ratioForce-limited position

MotorState

Real-time feedback structure:
@dataclass
class MotorState:
    can_id: int          # Motor CAN ID
    arbitration_id: int  # CAN arbitration ID
    status_code: int     # Error/status code (0 = OK)
    pos: float           # Position (radians)
    vel: float           # Velocity (rad/s)
    torq: float          # Torque (Nm)
    t_mos: float         # MOSFET temperature (°C)
    t_rotor: float       # Rotor temperature (°C)

Transport Options

TransportVendorsConstructor
SocketCANAll except HexfellowController("can0")
CAN-FDHexfellow (required)Controller.from_socketcanfd("can0")
DM SerialDamiao onlyController.from_dm_serial("/dev/ttyACM0", 921600)

CLI Tools

The project includes command-line utilities:
# Scan for motors
motorbridge-cli scan --vendor all --channel can0

# Enable and test
motorbridge-cli run --vendor damiao --motor-id 0x01 --mode enable

# Dump registers
motorbridge-cli id-dump --motor-id 0x01 --rids 7,8,9,10

Integrations

WebSocket Gateway

Control motors over WebSocket (useful for browser/remote apps):
# Start gateway
cargo run -p ws_gateway

Motor Calibration

Tool for motor calibration routines:
python3 tools/factory_calib_ui/server.py --bind 0.0.0.0 --port 18100

Comparison with Alternatives

FeatureVendor LibrariesMotorBridge
Multi-vendor❌ One per vendor✅ Unified API
Protocol details❌ Exposed✅ Abstracted
Type safety⚠️ Varies✅ Full type hints
CLI tools❌ Usually none✅ Built-in
Real-time safe⚠️ Python GC✅ Rust core
Other languages❌ Python only✅ C ABI for any language
Documentation⚠️ Varies✅ Comprehensive

Quick Start

1

Install Python Package

pip install motorbridge
2

Configure CAN Interface

sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
3

Run Your First Program

from motorbridge import Controller, Mode

with Controller("can0") as ctrl:
    motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")
    ctrl.enable_all()
    motor.ensure_mode(Mode.MIT, 1000)
    motor.send_mit(0.5, 0.0, 30.0, 1.0, 0.0)
    print("Motor running!")

What Can You Build?

Next Steps

Quick Start Guide

Get your first motor running in 5 minutes

API Reference

Complete API documentation

Tutorials

Step-by-step practical guides

Best Practices

Production-ready patterns