Reference simulator for the Open Robot Control Protocol (ORCP)
Project description
orcp-sim
Reference simulator for the Open Robot Control Protocol (ORCP).
orcp-sim emulates an ORCP-compliant motor controller on a virtual serial port
(PTY). Point any ORCP host — a terminal, the orcp Python
library, or a ROS 2 node — at the
device path it prints, and develop against the protocol with no hardware.
It implements ORCP v1.1 and runs a 100 Hz control loop with PID, a motor model, encoder quantisation, the mandatory safety system, and streaming telemetry.
Requirements
Python 3.9+. No third-party dependencies — standard library only. (PTY support is Unix-only: macOS and Linux.)
Install
# Run straight from a checkout — no install needed:
python3 -m orcp_sim
# …or install the `orcp-sim` command:
pip install -e .
orcp-sim
Usage
orcp-sim # Level 2 controller, auto-created PTY
orcp-sim --level 1 # Level 1 controller
orcp-sim --link /tmp/orcp # also create a symlink at this path
orcp-sim --vbat 11.1 # set simulated battery voltage
orcp-sim --estop # start with the e-stop active
On start it prints the serial device path:
ORCP Reference Simulator — proto ORCP/1.1, fw 1.1.0, Level 2
Serial device: /dev/ttys004
Connect with any serial terminal (e.g. screen /dev/ttys004 115200) and type
commands:
PING
<<< OK PONG t=1234
INFO
<<< OK INFO fw=1.1.0 hw=ORCP-SIM proto=ORCP/1.1 vendor=ORCP-Project model=reference-sim level=2 uuid=00SIMULATED00FF
PRESET NORMAL
<<< OK PRESET name=NORMAL timeout_ms=250 enable_required=1 hb_required=1 duty_limit=0.900
ENABLE ON
<<< OK ENABLE state=ON
WHEEL l=5.0 r=5.0
<<< OK WHEEL l=5.000 r=5.000
Conformance levels
The simulator emulates all conformance levels (ORCP spec §9); select one with
--level. The controller declares its level in the INFO response, exactly as
real hardware does, so a host can be tested against each tier by changing one
flag. Commands above the active level return ERR code=BAD_CMD.
| Level | --level |
Commands available |
|---|---|---|
| 1 — Basic | 1 |
PING CMD_VEL WHEEL STOP STATUS ENABLE PRESET (motion + mandatory safety) |
| 2 — Standard | 2 (default) |
Level 1 + INFO HB STREAM GET SET SAVE LOAD DEFAULTS (runtime config with persistence, heartbeat & e-stop monitoring, telemetry streaming) |
| 3 — Extended | 3 |
CAN binary encoding is not emulated over a PTY; behaves as Level 2 on this ASCII transport |
Notable v1.1 behaviours the simulator demonstrates:
WHEELdefaults to rad/s closed-loop velocity; open-loop duty is opt-in via the vendor extensionmode=DUTY.- Closed-loop commands are rejected with
ERR code=NO_FEEDBACKwhenkin.counts_per_rev=0(no-encoder platform). - Heartbeat monitoring is a Level 2+ feature: the full preset reports
hb_required=1at Level 2 andhb_required=0at Level 1, where the command timeout provides the dead-man. - Safety faults latch until
ENABLE ON;! FAULTand! WARNpush messages are emitted on transitions.
Profiles
A profile makes the simulator emulate a specific controller — its identity, config-key surface, vendor command modes, and push events — layered over the generic v1.1 core.
A profile is declarative data, not code. Exactly one profile — base, the
standard reference — is built into the core; every other profile (including
MC1) is a JSON data file. That keeps the simulator vendor-neutral: no
manufacturer is privileged in the core, and adding a device is a data change,
not a code change.
Select a bundled profile by name with --profile, or load your own file with
--profile-file:
| Profile | Ships as | What it emulates |
|---|---|---|
base (default) |
built into the core | Generic, fully-conformant ORCP v1.1 controller — the standard reference (15 standard §7 config keys). |
mc1 |
orcp_sim/profiles/mc1.json |
First Layer Robotics MC1: the full 42-key config surface, hw=MC1 / bl= in INFO, band-label battery, and the ! WARN AUX5V vendor push. |
orcp-sim --profile mc1 --ws 8765 # emulate an MC1 over WebSocket
orcp-sim --profile mc1 --aux5v-amps 6 # trip the 5V-rail warning (! WARN AUX5V)
The base profile is the pure standard reference and is kept free of any
vendor-specific surface.
Creating a profile (third-party vendors)
There are three ways to ship a profile, in increasing order of permanence — all use the same JSON format:
| Tier | How | Selector |
|---|---|---|
| Private / local | Keep your own JSON file anywhere | --profile-file acme.json |
| Bundled (contributed) | Add orcp_sim/profiles/acme.json and open a PR — a data change, reviewed and shipped in the next release |
--profile acme |
| Independent (planned) | A pip entry-point plugin, for profiles that need custom code | --profile acme |
MC1 is the worked example of the bundled tier — copy orcp_sim/profiles/mc1.json
and you have a vendor profile that ships first-class, exactly like it. For a
private profile:
orcp-sim --profile-file acme.json # emulate your controller
orcp-sim --profile-file acme.json --ws 8765 # …and serve it to a browser tool
The fields are:
| Field | Required | Meaning |
|---|---|---|
name |
yes | Short profile name (the --profile selector and the start-up banner) |
identity |
yes | INFO fields — must include hw, fw, level; optional vendor, model, and info_extra (e.g. {"bl": "1.0.0"}) |
config |
yes | Ordered [name, default, min, max] rows — drives GET/SET/GET ALL. Must include the config keys the core requires (the §7 essentials); add vendor keys freely |
int_keys |
no | Config keys rendered as integers (others as %.3f) |
wheel_modes |
no | Vendor WHEEL modes beyond rad/s, e.g. ["DUTY"] |
warns |
no | ! WARN <type> events the device emits, e.g. ["BATT"] |
battery |
no | STATUS battery field: "percent" (default) or "band" |
aux5v |
no | true to model a 5 V aux rail + ! WARN AUX5V |
A complete example is provided at
docs/example-profile.json — copy it and edit. The
loader validates on start-up and reports the common mistakes clearly (missing
field, malformed config row, or a dropped key the core requires).
Getting your profile bundled
To turn a private profile into a first-class --profile <name> that ships with
the simulator, contribute it back. The process:
- Write and validate it locally. Copy
docs/example-profile.json, edit it to match your controller, and prove it loads:orcp-sim --profile-file your-device.json # must start without error
Connect a host (a terminal, theorcplibrary, the web configurator) and confirmINFO,GET ALL, and aPRESET/WHEELexchange look right. Aim to mirror your shipping firmware'sGET ALLoutput exactly — same keys, same order, same defaults — so the profile is a faithful stand-in for the device. - Fork
orcp-protocol/orcp-simand add your file asorcp_sim/profiles/<name>.json. Use a short, unique, lowercasename(it becomes the--profileselector); don't touchbaseor another vendor's profile. - List it by adding a row to the profile table in this README.
- (Encouraged) Add a quick test in
tests/— e.g. assert your profile is discovered and reports the identity / key-count you expect (see themc1tests for the pattern). The loader already validates every bundled file on import, so a broken profile fails the suite. - Open a pull request. CI runs the test suite (which loads and validates
every
profiles/*.json). A maintainer reviews it as a data change — the bar is "does it accurately represent a real, shipping ORCP controller?". On merge it's in the next release and selectable as--profile <name>everywhere.
Because a bundled profile is pure data and the loader validates it on import,
accepting one is low-risk: it cannot run vendor code or affect the base
reference or any other profile.
Scope: a file profile describes a controller's declarative surface — identity, config keys, which standard behaviours are switched on. It cannot add genuinely new behaviour (custom telemetry physics, bespoke commands, new warn trigger logic); those live in the simulator core. A pip entry-point plugin mechanism for profiles that need custom code is a planned future direction.
Connecting from a browser (web configurator)
Browsers reach real boards over the Web Serial API (USB CDC) and cannot open a PTY, so to drive the simulator from a browser tool — such as the MC1 web configurator — run it over a WebSocket instead:
pip install 'orcp-sim[web]'
orcp-sim --ws 8765 # serve on ws://localhost:8765
The WebSocket carries the identical ORCP line protocol, so the host only needs a small transport switch (Web Serial for hardware, WebSocket for the simulator). See docs/websocket-transport.md for the full contract and a reference client.
Configuration persistence
SAVE/LOAD persist the standard configuration parameters (ORCP §7) to a JSON
file. By default this is orcp_sim_config.json in the system temp directory;
override with --config-file PATH. DEFAULTS restores factory values.
Tests
pip install -e ".[dev]"
pytest
The suite checks v1.1 compliance (response formats, error codes, level gating) and the dynamic safety behaviour (heartbeat/command-timeout faults, e-stop latching, streaming).
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file orcp_sim-0.1.0.tar.gz.
File metadata
- Download URL: orcp_sim-0.1.0.tar.gz
- Upload date:
- Size: 26.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dad3c18eb104f20e7c35784e756b415f6670119f03fff6417c8ed52d19b21a95
|
|
| MD5 |
26e5e89df8d48c829fe0868fe86307bf
|
|
| BLAKE2b-256 |
68a14a0a694d90c0fd65f08a27ad4b75cb52a075a6473b2ef2a89d518145714d
|
File details
Details for the file orcp_sim-0.1.0-py3-none-any.whl.
File metadata
- Download URL: orcp_sim-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d406ddd45c53e1a18b25a81531309ec4bb3a4feb67bd9d90da72d92459f69758
|
|
| MD5 |
89fca67567411e7feb13aeb73d89b3d1
|
|
| BLAKE2b-256 |
3a36927f4553234bcac7c94f6f3ba4f749bb9acd05d50c127a02f0be4b8323d1
|