# Controls and hardware map Model: Johnny 5 (Short Circuit) MOC. Seven motors across two Technic hubs. ## 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 | Drive forward / back | | Left stick X | Turn | | Right stick X | Head turn | | Right stick Y | Head tilt | | R2 | Body lift up (proportional) | | L2 | Body lift down (proportional) | | D-pad up / down | Left arm up / down | | Triangle / Cross | Right arm up / down | | L1 (held) | Precision mode, 40% drive | | R1 (held) | Full speed, 100% drive | | Circle | All stop | Default drive scale is 75%. Bluepad32 names buttons Xbox-style, so in the code `y()` is Triangle, `a()` is Cross and `b()` is Circle. `throttle()` is R2 and `brake()` is L2, both analog 0–1023. Why this layout: arcade drive on one stick keeps the other free for the head, which is the expressive part of this model. The analog triggers go to body lift because it is the heavy slow axis that benefits most from proportional feel. Arms are digital because they are pose-and-hold, not modulate. 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 = 50; 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`. --- Created by: Jess Rogerson (yelling commands at Claude.AI)