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.
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
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 rc_car_actuator-0.1.0.tar.gz.
File metadata
- Download URL: rc_car_actuator-0.1.0.tar.gz
- Upload date:
- Size: 57.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4c26a570edc814b3c8112649139e60624a61955149516441b59e3006f780ad6
|
|
| MD5 |
1fe3e89596620462aad3b34e82865a4e
|
|
| BLAKE2b-256 |
7f9c6bf84f9c24fc466413ec53063eeb285246c3b06dd3ce80cb905023c022c0
|
File details
Details for the file rc_car_actuator-0.1.0-py3-none-any.whl.
File metadata
- Download URL: rc_car_actuator-0.1.0-py3-none-any.whl
- Upload date:
- Size: 42.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
386d8ea35506be1df898dbf44ba56aa0f4a9723498f9550c15ec528c3781ada4
|
|
| MD5 |
42f4685b8b29821e297cae79e22e73f6
|
|
| BLAKE2b-256 |
eb8ea33ac32e6cfaca329a04d29119bab2792eade9e1535c1d4c613df839b0a5
|