# 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 ```cpp 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 port * `HUB_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()`: ```cpp 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)