Skip to content

orcp-protocol/orcp-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

orcp

Python client library for the Open Robot Control Protocol (ORCP).

Communicate with ORCP-compliant motor controllers over USB serial or WiFi using a clean, Pythonic API.

Installation

pip install orcp

Quick start

from orcp import ORCP

with ORCP('socket://192.168.4.1:3333') as robot:
    robot.ping()
    robot.cmd_vel(v=0.2, w=0.0)   # 0.2 m/s forward
    import time; time.sleep(2)
    robot.stop()

Connection options

ORCP('/dev/cu.usbmodemXXXX')                  # USB serial (auto baud)
ORCP('/dev/cu.usbmodemXXXX', baudrate=115200)  # Explicit baud rate
ORCP('socket://192.168.4.1:3333')              # WiFi bridge

Teleop demo (orcp-drive)

orcp-drive is a keyboard tele-operation app — drive any ORCP controller around with the WASD/arrow keys. It's both a handy test tool and a worked example of the library: it uses CMD_VEL, the safety presets, the enable gate, a background heartbeat, and live telemetry streaming all together.

Install it (the teleop extra just adds curses support on Windows — macOS and Linux need nothing extra):

pip install "orcp[teleop]"

Run it against hardware, a WiFi bridge, or — with no hardware at all — the reference simulator:

orcp-drive /dev/cu.usbmodemXXXX        # USB (macOS; /dev/ttyACM0 Linux, COM3 Windows)
orcp-drive socket://192.168.4.1:3333    # WiFi / TCP

# No robot handy? Drive the simulator instead:
pip install orcp-sim
orcp-sim --link /tmp/orcp &             # terminal 1: a virtual ORCP controller
orcp-drive /tmp/orcp                    # terminal 2: drive it

Controls

Key Action
W / Forward
S / Reverse
A / Spin left
D / Spin right
Q / E Arc forward-left / forward-right
Space Stop
+ / - Increase / decrease speed
M Toggle SLOW ↔ NORMAL (NORMAL auto-enables and starts a background heartbeat)
R Re-enable the motors after a fault is cleared (sends ENABLE ON)
Esc Quit (always returns to a safe, stopped state)

Faults & recovery

The teleop shows the controller's active fault under the battery line (e.g. FAULT: ENCODER_STALL — press [R] to re-enable). Fault behaviour follows the ORCP safety model (spec §5): when the controller trips a fault it stops the motors and latches the fault — it does not silently auto-recover when the cause goes away. That's deliberate: a machine must not become ready-to-move again on its own.

Faults you may see on real hardware:

Fault Cause Recover by
ESTOP Emergency-stop loop opened Close the loop, then press R
ENCODER_STALL Driven against an obstacle (wheels commanded but can't turn) — this is motor protection, not a bug Back the robot off, then press R
OVERCURRENT_* Per-side current limit exceeded Reduce the load, then press R
LOWBATT Battery below the critical threshold Recharge, then press R
HEARTBEAT / TIMEOUT Host link / command flow lost in NORMAL Press R

To recover: clear the cause, then press R. That sends ENABLE ON, which clears recoverable faults and re-enables the motors — matching the ORCP spec (§5.3): "after the emergency stop is released the fault MUST persist until the host explicitly sends ENABLE ON; motors MUST NOT restart automatically." The same explicit-re-enable rule applies to every latched fault, not just e-stop. If R is rejected (e.g. the e-stop is still open), the status line tells you — fix the cause and try again.

The source — src/orcp/teleop.py — is a good read for how the pieces fit together. It's ~200 lines and uses only the public API documented below.

API reference

System

robot.ping()      # → True or raises ConnectionError
robot.info()      # → InfoResponse(fw, hw, proto, level, vendor, model, extra)
robot.status()    # → StatusResponse(preset, mode, enabled, fault, estop, vl, vr, vbat, battery, ...)

Motion

robot.cmd_vel(v=0.5, w=0.0)   # Unicycle: linear (m/s), angular (rad/s)
robot.wheel(l=5.0, r=5.0)     # Direct wheel velocities (rad/s)
robot.stop()                   # Immediate stop, never raises

Safety

robot.preset('SLOW')    # 30% power, auto-enabled, 1 s watchdog
robot.preset('NORMAL')  # 100% power, requires ENABLE ON + heartbeat
robot.enable()
robot.disable()
robot.heartbeat()                    # Single HB
robot.start_heartbeat(interval=0.1)  # Background thread, 100 ms interval
robot.stop_heartbeat()

Streaming telemetry

def on_telemetry(data):
    print(f"Left: {data.vl:.2f} rad/s, Right: {data.vr:.2f} rad/s")

robot.stream_on(rate=10, callback=on_telemetry)
robot.stream_off()

Configuration

kp = robot.get('pid.kp')         # single parameter
cfg = robot.get_all()            # → {name: value} for every parameter
robot.set('pid.kp', 0.08)
robot.save()      # Persist to flash
robot.load()      # Load from flash
robot.defaults()  # Factory reset

Push events

robot.on_fault(lambda e: print("FAULT:", e.code))          # ! FAULT <code>
robot.on_warn(lambda e: print("WARN:", e.type, e.fields))  # ! WARN <type> ...

Cached properties

robot.battery_voltage   # float | None  (volts)
robot.battery           # str | None    (band label "OK"/"LOW"/… or "80%")
robot.is_enabled        # bool | None
robot.fault             # str | None    (updated by STATUS and ! FAULT pushes)

Testing without hardware

Use MockTransport to test your code without a physical robot:

from orcp import ORCP
from orcp.transport import MockTransport

transport = MockTransport()
transport.queue_response('OK PING')
transport.queue_response('OK CMD_VEL')

with ORCP('mock://', _transport=transport) as robot:
    robot.ping()
    robot.cmd_vel(v=0.5, w=0.0)

Error handling

from orcp import CommandError, ConnectionError, TimeoutError

try:
    robot.cmd_vel(v=0.5, w=0.0)
except CommandError as e:
    print(f"Controller error: {e.code}{e.message}")
except TimeoutError:
    print("No response from controller")
except ConnectionError:
    print("Lost connection")

Development

git clone https://github.com/orcp-protocol/orcp-python
cd orcp-python
pip install -e ".[dev]"

pytest tests/
mypy src/orcp/
black src/ tests/
ruff check src/ tests/

Protocol

ORCP uses ASCII line-based messages:

Direction Format
Command COMMAND param=value\n
Success OK COMMAND field=value\n
Error ERR code=CODE msg="description"\n
Push ! TYPE field=value\n

See the ORCP specification for full details.

License

MIT — see LICENSE.

About

Python client library for the Open Robot Control Protocol (ORCP) — talk to ORCP-compliant motor controllers over USB serial or WiFi, plus the orcp-drive teleop demo.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages