4.7 KiB
Controls and hardware map
Model: Johnny 5 (Short Circuit) MOC. Seven motors across two Technic hubs.
Control scheme is tank drive: every input drives exactly one motor. Nothing is mixed, so a single stick can never command two motors at once.
Port map
| Hub | Address | Port | Function | Desired field |
|---|---|---|---|---|
| 0 | 90:84:2b:61:e6:8c |
A | Right track | rightTrack |
| 0 | B | Left track | leftTrack |
|
| 0 | D | Body lift | bodyLift |
|
| 1 | 90:84:2b:61:f2:d7 |
A | Head tilt | headTilt |
| 1 | B | Head turn | headTurn |
|
| 1 | C | Left arm | leftArm |
|
| 1 | D | Right arm | rightArm |
The sketch does not rely on this table — it is here for humans. At connect the hubs report their own inventory over notifications, so the serial log tells you what is actually plugged in:
hub0 port A : Technic Control+ LARGE motor (0x002E)
hub0 port B : Technic Control+ LARGE motor (0x002E)
hub0 port D : Technic Control+ XL motor (0x002F)
hub0 port 0x32 : hub RGB LED (0x0017)
...
Internal devices (LED on 0x32, battery voltage, current, IMU) report as
attached too. Anything not on A–D can be ignored.
Controls
| Input | Function |
|---|---|
| Left stick Y | Left track |
| Right stick Y | Right track |
| D-pad up / down | Head tilt |
| D-pad left / right | Head turn |
| R2 | Body lift up (proportional) |
| L2 | Body lift down (proportional) |
| Square / Circle | Left arm up / down |
| Triangle / Cross | Right arm up / down |
| L1 (held) | Precision mode, 40% track speed |
| R1 (held) | Full speed, 100% track speed |
| L1 + R1 together | All stop |
Default track scale is 75%. The stick X axes are unused.
Bluepad32 names buttons Xbox-style, so in the code x() is Square, b() is
Circle, y() is Triangle and a() is Cross. throttle() is R2 and brake()
is L2, both analog 0–1023.
Trade-offs in this layout:
- Tracks are independent. Turning means pushing one stick further than the other, like a skid-steer. Takes a minute to get used to, but you always know which motor you are commanding.
- The head is digital now, not proportional — d-pad has no analog travel, so
it runs at a fixed
HEAD_MAX. Drop that constant if it moves too fast to aim. - Body lift kept the triggers because they are the only remaining analog inputs, and it is the axis that benefits most from proportional control.
- D-pad diagonals will tilt and turn the head simultaneously. That is two motors from one thumb, but only when you deliberately press a diagonal.
To remap, set DEBUG_BUTTONS to 1 at the top of the sketch and press each
button — it prints the mask so you can match your pad's firmware exactly.
Power caps
static const int TRACK_MAX = 100;
static const int HEAD_MAX = 45;
static const int LIFT_MAX = 60;
static const int ARM_MAX = 45;
Everything except the tracks runs into a mechanical end stop. There is no position feedback in this code, so holding a direction against a stop stalls the motor — that means stripped gears or a browned-out hub, and the hub will not complain until it drops the BLE connection entirely. That is why the non-track caps are well below 100. Lower them further if an axis feels forceful, and do not hold a direction once the axis has stopped moving.
The real fix, worth doing once the travel of each axis is known: Control+ motors
have absolute encoders. Subscribe to position with Port Input Format Setup
(0x41), learn each axis's limits, and refuse to drive past them. That turns a
mechanical hazard into a software one.
Rate limiting
Two limits, both in driveMotor:
MOTOR_MIN_GAP_MS(100ms) per portHUB_MIN_GAP_MS(25ms) per hub, roughly 40 commands/sec
The second one exists because hub 1 has four motors on it. The per-port limit alone would let through up to 66 commands/sec to a single hub, which is more than these will absorb — you get stutter, then a dropped link. Stops are exempt from both and always go out immediately.
If motors feel laggy, lower MOTOR_MIN_GAP_MS before touching the hub limit.
If a hub drops out under heavy stick movement, raise HUB_MIN_GAP_MS.
Clearing stale pairings
Bluepad32 stores Bluetooth pairing keys in NVS, and reflashing the sketch does
not clear them. If you end up with a pad paired into more than one slot, or an
old device from a previous build still remembered, uncomment this in setup():
BP32.forgetBluetoothKeys();
Flash once, re-pair, then comment it out again — leaving it in means re-pairing on every boot. For a full wipe, Tools → Erase All Flash Before Sketch Upload → Enabled, upload once, then set it back to Disabled.
Created by: Jess Rogerson (yelling commands at Claude.AI)