Skip to main content

rc-car-actuator

A wire-controlled RC car drive actuator for robot-md-gateway.

The design in one sentence

Motion is a lease, not a command: execute() writes the setpoint, extends a deadman lease, and returns immediately — the car stops when the lease expires, not when anyone waits for it.

duration_s is how long the lease lasts, not how long the call sleeps. If the call slept for the duration it would hold the request path for the whole motion, and the next request — the one saying "stop" — would queue behind the motion it was meant to cancel.

Three states, and conflating the first two is the bug this contract is written against: an explicit 0 is a zero-length lease, which is a STOP; an absent duration_s is "no opinion" and takes the deadman's short default (400 ms); a stated number is granted as asked, up to the 2.0 s ceiling. A published manifest must therefore never give duration_s a schema default — the default a model copies would be the one number that stops the car while the receipt says it drove. Mark it required and make callers say what they want.

The lease a receipt reports is the lease the deadman enforces

drive.set returns lease_s and stops_at_monotonic, the gateway signs them, and someone will later rely on them. So they are read back from the watchdog after it grants the lease rather than computed beside it, and every bound is applied in the watchdog itself:

bound value applies when
per-command ceiling MAX_LEASE_S = 2.0 s any single command, however long it asks for
no-duration default DEFAULT_TIMEOUT_S = 0.4 s a command that states no duration
remaining motion budget the envelope's whenever it is the tighter bound

lease_cut_by names which one did the cutting, and stop_detect_within_s (one watchdog tick, 50 ms) is the honest error bar: expiry is detected by polling, so the wheels go neutral in [stops_at_monotonic, + one tick] — never before the promised instant. drive.stop, drive.envelope.revoke and the e-stop outrank any live lease and take effect at once.

This is written down because it was once false. The driver reported lease_s: 2.0 while a fixed 0.4 s timeout stopped the car — safe by accident, and a signed untruth about when a vehicle stops. Every test asserted the reported number and none timed the vehicle, which is exactly how it shipped.

Safety status: NOT ROAD READY

The deadman is a Python thread on Linux. It covers a locked phone, a crashed app, dropped Wi-Fi, and a hung gateway, because it does not share a thread with the request path.

It does not cover the kernel stalling, this process being SIGKILLed, or the Pi browning out — and a brownout is most likely exactly when the motor draws current.

The authoritative stop must be a lease that expires in firmware, on an MCU between the Pi and the ESC, which survives Linux dying entirely. Until that exists, run this with the wheels off the ground.

PWMDrive has never been connected to a vehicle. Its pulse widths are the standard hobby-RC values and must be checked against the actual ESC first.

The envelope: one approval, many commands

A phone driving a car sends commands at 20 Hz. Approving each one is absurd; approving none means the vehicle moves on nobody's authority. So the unit of approval is not a command, it is an envelope: a bounded budget of motion a human authorises once, which every subsequent command draws down.

bound why it exists
motion_budget_s Seconds the wheels may actually turn — the real currency, since it decides how far the car can get.
window_s Wall-clock lifetime, so an unused approval from this morning is not still live tonight.
max_throttle "Around the house" and "in the yard" deserve different ceilings, and the approver knows which they meant.

The budget only ever decreases. There is no renew, extend, or top-up — more motion requires a new approval. An envelope the spender could extend would authorise nothing.

Charging is by elapsed motion, not commands issued or leases granted. Per-lease billing would be catastrophic: at 20 Hz with a 0.5 s lease, one second of driving would be billed as ten. Idling and steering a stationary car are free.

A granted lease is capped by the remaining budget, so the deadman that already stops the car when a lease ends also stops it when the budget runs out — one mechanism rather than two racing ones.

Every motion receipt carries its envelope_id, so a signed record of the car moving traces back to the human decision that permitted it.

Capabilities

tool tier effect
drive.envelope.open actuate Approve a budget. This IS the approval, so it needs the same tier as moving.
drive.envelope.revoke read Withdraw approval and stop the car.
drive.set actuate Set throttle/steering, draw on the budget, extend the lease. Returns immediately. Refused with no open envelope.
drive.stop read Stop now.
status.report read Throttle, steering, lease in force and remaining, budget remaining, e-stop state.

drive.stop and drive.envelope.revoke require only the read tier: a stop that can be refused is not a stop, and there is no failure mode where refusing to halt a moving vehicle is safer.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rc_car_actuator-0.1.1.tar.gz (61.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rc_car_actuator-0.1.1-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

Details for the file rc_car_actuator-0.1.1.tar.gz.

File metadata

  • Download URL: rc_car_actuator-0.1.1.tar.gz
  • Upload date:
  • Size: 61.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for rc_car_actuator-0.1.1.tar.gz
Algorithm Hash digest
SHA256 08489256438b4ade5f2a946b717244d72e7f9b2a3e039cdfa44b14800b0e6773
MD5 0e502291f8a0f2309d9ff5d19d3cdc61
BLAKE2b-256 6b7669e5084ec28f1c5bb5882402857d43628b05e91690c77bc9d5606400be14

See more details on using hashes here.

File details

Details for the file rc_car_actuator-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for rc_car_actuator-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5ae0abcd4efd4f274b325c30a305cb54526e73fd0c9a10aaa3b5e0b7132b392a
MD5 858677303257d8be3c130fdb28ad812d
BLAKE2b-256 7d6a58bb7990cc98d4c98a6a1a39a2f751113790be7e5b1720a538245a59ecf1

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page