Document power options and the power-loss failsafe gap

Adds bench vs model power arrangements, the both-USB-plus-5V-jumper
hazard, current budget, diode drop margin, and a deliberate test for the
case the 400ms failsafe cannot cover.
This commit is contained in:
2026-09-09 19:35:08 +10:00
parent 9dd74d9d60
commit 6c476afb08
+55 -4
View File
@@ -29,21 +29,70 @@ a lot more ways to be wrong.)
* 2x ESP32 dev boards. Both must be the **original ESP32** (WROOM/WROVER).
S3, C3, C6 and H2 have no Bluetooth Classic, so a PS4 pad will not pair.
* 3 jumper wires.
* 3 jumper wires, or 4 if you daisy-chain power.
```
Board A (Bluepad32) Board B (Legoino)
GPIO17 TX -------------> GPIO16 RX
GPIO16 RX <------------- GPIO17 TX
GND -------------- GND <- do not skip this one
5V -------------- 5V <- only in the model setup, see below
```
TX goes to RX, not TX to TX. If nothing arrives, that swap is the first thing
to check.
Power both from the same supply if you can. Separate USB bricks are fine as long
as the grounds are tied together — without a common ground the UART has no
shared voltage reference and you get garbage or silence.
Without a common ground the UART has no shared voltage reference and you get
garbage or silence, so that wire is not optional even when both boards have
their own USB.
## Power
Two arrangements, and the choice matters more than it looks.
**Bench setup — separate USB, no 5V wire.** Both boards on their own USB cables.
You get both serial monitors and can reflash either board without unplugging
anything. Use this for everything up to step 5.
**Model setup — one supply, 5V jumper.** USB into board A, then a fourth wire
from **A's 5V pin to B's 5V pin** (labelled VIN on some boards). Ground is
already joined by the wire you have.
Use 5V to 5V, never 3.3V to 3.3V. Each board's onboard AMS1117 regulator makes
its own 3.3V, and tying the outputs together back-feeds one regulator from the
other.
**Never have both USB cables plugged in while the 5V wire is connected.** That
ties two host supplies together through your jumper. Some devkits have a Schottky
diode on VBUS that prevents it, plenty do not, and you cannot tell by looking.
Pull the 5V jumper before plugging in a USB cable to reflash.
**Current budget.** An ESP32 idles around 80-120mA and peaks at a few hundred mA
on Bluetooth transmit. Two of them off one USB 2.0 port sits right at the 500mA
that port promises. It usually works, but a marginal supply shows up as random
reboots that look exactly like a software fault. A 1A+ charger or power bank
removes the doubt.
**Diode drops.** Many boards put a diode between VBUS and the 5V pin, so board
A's 5V pin sits nearer 4.7V. Through board B's own diode you are at maybe 4.4V
into a regulator wanting roughly 1.1V of headroom. It works, but the margin is
thin. If you are running off a power bank anyway, prefer separate leads to each
board's 5V pin over chaining B off A — same wire count, no stacked drops.
## Test the power-loss case deliberately
The 400ms failsafe in `receiver.ino` only fires if the receiver is *running*. If
board B loses power mid-command — and on a shared supply that now happens
whenever board A does — the failsafe cannot fire, and whether the motors stop is
left to the hub's own behaviour on BLE disconnect.
Find that out on purpose rather than by accident. Set a track running slowly,
pull power from board B, and watch what the motor does. If it keeps running you
want a physical switch on the hubs within arm's reach before driving this
anywhere interesting.
Worth doing the same test by pulling the UART wire instead — that path *does*
hit the failsafe, and confirming it works takes ten seconds.
## Step by step
@@ -142,6 +191,8 @@ stops all motors if nothing valid arrives for 400ms.
* **Nothing arrives at board B.** TX/RX swapped, or no common ground. Both are
silent failures.
* **Random reboots under load.** Supply, not software. See the current budget
above.
* **One hub connects, the other does not.** Legoino shares a single NimBLE
scanner. `receiver.ino` connects them strictly one at a time for this reason —
do not "optimise" that into two parallel `init()` calls.