Skip to main content

Quickstart

Prerequisites

Before starting, ensure:
  • motorbridge installed (pip install motorbridge)
  • CAN interface configured (see Install)
  • Motor connected and powered on
  • Known motor ID and feedback ID

30-Second Minimal Example

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)

    # Send position command
    motor.send_mit(pos=0.5, vel=0.0, kp=20.0, kd=1.0, tau=0.0)

    # Read state
    print(motor.get_state())

Step-by-Step Walkthrough

1. Import the SDK

from motorbridge import Controller, Mode, MotorState
from motorbridge.errors import CallError, MotorBridgeError

2. Create Controller

The controller manages the CAN interface and motor handles:
# SocketCAN (most common)
ctrl = Controller("can0")

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

# DM Serial bridge (for Damiao)
# ctrl = Controller.from_dm_serial("/dev/ttyACM0", 921600)

3. Add Motor

Create a motor handle with vendor-specific parameters:
# Damiao motor
motor = ctrl.add_damiao_motor(
    motor_id=0x01,      # Command CAN ID
    feedback_id=0x11,   # Feedback CAN ID
    model="4340P"       # Motor model string
)
motor_id and feedback_id are motor-specific. Use motorbridge-cli scan to discover them.

4. Enable and Set Mode

# Enable motor output (apply power)
ctrl.enable_all()

# Switch to MIT control mode with 1-second timeout
motor.ensure_mode(Mode.MIT, timeout_ms=1000)

5. Send Commands

# MIT mode: full control over position, velocity, stiffness, damping, torque
motor.send_mit(
    pos=1.0,    # Target position (radians)
    vel=0.0,    # Target velocity (rad/s)
    kp=30.0,    # Position stiffness
    kd=1.0,     # Velocity damping
    tau=0.0     # Feedforward torque (Nm)
)

# Position-velocity mode: simpler interface
# motor.send_pos_vel(pos=1.0, vlim=2.0)

# Velocity mode: speed control only
# motor.send_vel(vel=1.5)

# Force position mode: compliant position control
# motor.send_force_pos(pos=1.0, vlim=2.0, ratio=0.3)

6. Read Motor State

import time

# Request fresh feedback
motor.request_feedback()

# Read cached state (may be None if no feedback yet)
state = motor.get_state()

if state:
    print(f"Position: {state.pos:.3f} rad")
    print(f"Velocity: {state.vel:.3f} rad/s")
    print(f"Torque: {state.torq:.3f} Nm")
    print(f"MOS Temperature: {state.t_mos:.1f} °C")
    print(f"Rotor Temperature: {state.t_rotor:.1f} °C")
else:
    print("No feedback received yet")

7. Clean Up

# Disable motor
motor.disable()

# Close resources (automatic with context manager)
motor.close()
ctrl.close()

Complete Control Loop Example

import time
from motorbridge import Controller, Mode

# Context manager ensures proper cleanup
with Controller("can0") as ctrl:
    motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")

    # Enable and set mode
    ctrl.enable_all()
    motor.ensure_mode(Mode.POS_VEL, timeout_ms=1000)

    # Control loop
    dt_s = 0.02  # 20ms period = 50Hz
    target_pos = 1.0  # radians

    for i in range(100):
        t0 = time.time()

        # Send command
        motor.send_pos_vel(pos=target_pos, vlim=1.0)

        # Read state
        state = motor.get_state()
        if state:
            print(f"#{i:03d} pos={state.pos:+.3f} vel={state.vel:+.3f}")

        # Maintain loop timing
        elapsed = time.time() - t0
        if elapsed < dt_s:
            time.sleep(dt_s - elapsed)

Multi-Motor Control

from motorbridge import Controller, Mode

with Controller("can0") as ctrl:
    # Add multiple motors
    motor1 = ctrl.add_damiao_motor(0x01, 0x11, "4340P")
    motor2 = ctrl.add_damiao_motor(0x02, 0x12, "4340P")

    # Enable all at once
    ctrl.enable_all()

    # Set modes individually
    motor1.ensure_mode(Mode.MIT, 1000)
    motor2.ensure_mode(Mode.MIT, 1000)

    # Control each motor
    motor1.send_mit(0.5, 0.0, 20.0, 1.0, 0.0)
    motor2.send_mit(-0.5, 0.0, 20.0, 1.0, 0.0)

Error Handling

from motorbridge import Controller, Mode
from motorbridge.errors import CallError, MotorBridgeError

try:
    with Controller("can0") as ctrl:
        motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")
        ctrl.enable_all()
        motor.ensure_mode(Mode.MIT, 1000)

        for i in range(100):
            try:
                motor.send_mit(0.5, 0.0, 20.0, 1.0, 0.0)
            except CallError as e:
                print(f"Command failed: {e}")
                # Optionally continue or break

except MotorBridgeError as e:
    print(f"Motor bridge error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

CLI Quick Reference

After pip install, use the CLI for quick testing:
# Scan for motors
motorbridge-cli scan --vendor all --channel can0 --start-id 1 --end-id 32

# Run motor in MIT mode
motorbridge-cli run \
    --vendor damiao \
    --channel can0 \
    --model 4340P \
    --motor-id 0x01 \
    --feedback-id 0x11 \
    --mode mit \
    --loop 100 \
    --dt-ms 20 \
    --pos 1.0 \
    --kp 30.0 \
    --kd 1.0

# Read Damiao registers
motorbridge-cli id-dump \
    --vendor damiao \
    --channel can0 \
    --motor-id 0x01 \
    --feedback-id 0x11 \
    --rids 7,8,9,10,21,22,23

Vendor-Specific Examples

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)

Next Steps