Skip to main content

API: Mode and State

Mode Enum

The Mode enum defines the available control modes for motors.

Import

from motorbridge import Mode

Definition

class Mode(IntEnum):
    MIT = 1
    POS_VEL = 2
    VEL = 3
    FORCE_POS = 4

Mode Descriptions

ModeValueDescriptionUse Case
MIT1Full impedance controlPrecise position/torque control with adjustable stiffness
POS_VEL2Position with velocity limitSimple position control with speed limit
VEL3Pure velocity controlContinuous rotation, speed control
FORCE_POS4Compliant position controlForce-limited position control

Mode Details

Mode.MIT

MIT mode provides full impedance control with independent control over:
  • Position target
  • Velocity target
  • Position stiffness (Kp)
  • Velocity damping (Kd)
  • Feedforward torque
Command: motor.send_mit(pos, vel, kp, kd, tau) Best for:
  • Legged robots requiring compliant control
  • Arms with variable stiffness
  • Haptic feedback applications
Example:
motor.ensure_mode(Mode.MIT, 1000)
motor.send_mit(
    pos=1.0,    # Target position (rad)
    vel=0.0,    # Target velocity (rad/s)
    kp=30.0,    # Position stiffness (Nm/rad)
    kd=1.0,     # Velocity damping (Nm·s/rad)
    tau=0.0     # Feedforward torque (Nm)
)

Mode.POS_VEL

Position control with velocity limit. Motor moves to target position at limited speed. Command: motor.send_pos_vel(pos, vlim) Best for:
  • Simple point-to-point motion
  • Applications needing speed limits
  • Beginner-friendly control
Example:
motor.ensure_mode(Mode.POS_VEL, 1000)
motor.send_pos_vel(
    pos=2.0,    # Target position (rad)
    vlim=1.5    # Velocity limit (rad/s)
)

Mode.VEL

Pure velocity control. Motor runs at commanded velocity indefinitely. Command: motor.send_vel(vel) Best for:
  • Conveyor belts
  • Wheels and drivetrains
  • Speed-controlled applications
Example:
motor.ensure_mode(Mode.VEL, 1000)
motor.send_vel(vel=2.0)  # 2 rad/s

# Stop motor
motor.send_vel(vel=0.0)

Mode.FORCE_POS

Compliant position control with force ratio. Motor moves to position but limits applied force. Command: motor.send_force_pos(pos, vlim, ratio) Best for:
  • Grippers with force control
  • Contact tasks
  • Safety-critical applications
Example:
motor.ensure_mode(Mode.FORCE_POS, 1000)
motor.send_force_pos(
    pos=1.0,    # Target position (rad)
    vlim=1.0,   # Velocity limit (rad/s)
    ratio=0.3   # Force ratio (0.0-1.0)
)

Vendor Mode Support

VendorMITPOS_VELVELFORCE_POS
Damiao
RobStride
MyActuator
HighTorque
Hexfellow
Attempting to use an unsupported mode will raise a CallError or ValueError.

MotorState Dataclass

MotorState is an immutable dataclass containing motor feedback data.

Import

from motorbridge import MotorState

Definition

@dataclass(frozen=True)
class MotorState:
    can_id: int
    arbitration_id: int
    status_code: int
    pos: float
    vel: float
    torq: float
    t_mos: float
    t_rotor: float

Field Descriptions

FieldTypeUnitDescription
can_idintMotor CAN ID
arbitration_idintCAN arbitration ID of feedback frame
status_codeintMotor status/error code (vendor-specific)
posfloatradMotor position
velfloatrad/sMotor velocity
torqfloatNmMotor torque (estimated)
t_mosfloat°CMOSFET temperature
t_rotorfloat°CRotor temperature

Usage Example

from motorbridge import Controller, Mode

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

    # Request feedback
    motor.request_feedback()

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

    if state is not None:
        # Access fields
        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 Temp: {state.t_mos:.1f} °C")
        print(f"Rotor Temp: {state.t_rotor:.1f} °C")
        print(f"Status: 0x{state.status_code:02X}")

        # Check for temperature warning
        if state.t_mos > 80.0 or state.t_rotor > 80.0:
            print("WARNING: High temperature!")
    else:
        print("No feedback received")

Status Code Interpretation

Status codes are vendor-specific. Common patterns:

Damiao Status Codes

CodeMeaning
0Normal operation
1Over-voltage
2Under-voltage
3Over-current
4MOSFET over-temperature
5Rotor over-temperature
6Communication timeout

Checking Status

state = motor.get_state()
if state and state.status_code != 0:
    print(f"Motor error: status=0x{state.status_code:02X}")
    motor.clear_error()

Retry Pattern for State Reading

Since feedback is asynchronous, implement a retry pattern:
import time

def get_state_with_retry(motor, max_attempts=10, delay=0.05):
    """Get motor state with retry on None."""
    for attempt in range(max_attempts):
        motor.request_feedback()
        state = motor.get_state()
        if state is not None:
            return state
        time.sleep(delay)
    return None

# Usage
state = get_state_with_retry(motor)
if state:
    print(f"Got state: pos={state.pos:.3f}")
else:
    print("Failed to get state after retries")

Complete Example

import time
from motorbridge import Controller, Mode, MotorState

def print_state(state: MotorState, prefix: str = ""):
    """Pretty print motor state."""
    print(f"{prefix}pos={state.pos:+7.3f} rad | "
          f"vel={state.vel:+6.3f} rad/s | "
          f"torq={state.torq:+5.2f} Nm | "
          f"t_mos={state.t_mos:5.1f}°C | "
          f"status=0x{state.status_code:02X}")

with Controller("can0") as ctrl:
    motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")

    # Enable motor
    ctrl.enable_all()
    motor.ensure_mode(Mode.POS_VEL, 1000)

    # Control loop with state monitoring
    target_pos = 0.0

    for i in range(100):
        # Sinusoidal position target
        target_pos = 1.0 * (1.0 - (i / 50.0) if i < 50 else (i - 50) / 50.0)

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

        # Read state
        motor.request_feedback()
        state = motor.get_state()

        if state:
            print_state(state, prefix=f"#{i:03d} ")

            # Safety check
            if state.t_mos > 85.0:
                print("WARNING: MOSFET overheating!")
            if state.status_code != 0:
                print(f"ERROR: status=0x{state.status_code:02X}")

        time.sleep(0.02)

    motor.disable()

See Also