Firmware simulation, Unity project, and sim-verified robot fixes

Simulation
- sim/: the unchanged robot firmware compiled into hexapod_sim.dll
  against PC stand-ins (Arduino, Servo, Wire + register-level MPU6050,
  RF24 with matching-config radio), a kinematic body model (support
  plane + planted-foot odometry) that also drives the simulated IMU,
  and a headless smoke test (sim_smoke). build.ps1 builds and tests.
- Hexapod_Simulation_Unity/ folded in (history kept in a bundle
  outside the repo). Assets/HexapodSim loads the DLL, drives the
  existing leg rig, and offers joystick / keyboard / robot-serial
  input plus a test panel.

Robot (all found or confirmed in the simulation)
- Config.h geometry taken from the Unity model.
- IK femur elevation sign, gait stance direction, body pose
  rotation direction, yaw lever arm.
- Stance feet integrated from the current command; gait restarts at
  mid-stance; heading integrates the applied turn rate, only while
  walking.
- Leg clearance and reach checks (Limits::feetFeasible); walk command
  and body pose scaled as a whole, pose scale rate-limited, planted
  feet guarded so the body never snaps or legs collide.
- Robot-gyro self-leveling as an integrator.
- Heading mode: steering relative to the body; S walks backward.
- Standing height from the remote (STANCE_HEIGHT_RANGE_MM).

Protocol v3 (reflash both boards)
- CmdPacket gains body_height (22 bytes).

Remote
- Height slider (Nextion hHeight/nHeight, serial [ ]).
- Fixed unspecified I2C read order in RemoteIMU.

LEGACY/: owner's old Nextion HMI and remote hardware assets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-09-29 00:37:12 +02:00
1 parent 91dac16fca
commit 935526eab5
145 files changed
+431258 -114

No files matched your search

+120
View File
@@ -0,0 +1,120 @@
# Firmware simulation (software-in-the-loop)
This folder compiles the **unchanged** robot firmware (`robot/*.cpp` plus
`robot.ino`) into a Windows DLL. The Unity project
(`Hexapod_Simulation_Unity/`) runs that DLL, so the code you test in the
simulation is exactly the code you flash to the Teensy. `robot/` has no
`#ifdef SIM` anywhere.
```
robot/ (unchanged) ──► PlatformIO + Teensy core ──► Teensy 4.0 firmware
└─► CMake + g++ + sim/shim/ ──► sim/build/hexapod_sim.dll ──► Unity
```
## How it works
`shim/` provides PC stand-ins for the only hardware the firmware touches:
| Firmware uses | Simulated as |
|---|---|
| `Servo::writeMicroseconds()` | the pulse stored per pin, decoded back to angles with `Config.h`'s `SERVO_US_*` |
| `Wire` + MPU6050 registers | a register-level fake MPU6050 at 0x68, fed from the simulated body's tilt and rotation |
| `RF24` | a simulated radio: packets are received only if channel, address, data rate and **payload size** match, and the RX FIFO holds 3 |
| `millis()` / `micros()` / `Serial` | a simulated clock that Unity advances, and captured serial I/O |
`robot_ino.cpp` compiles `robot.ino` itself and exposes read-only views of
its globals (state machine, heading, IMU filter, gait phase) for status
display. `HexapodSimApi.h` is the C API. Its forward kinematics is written
separately from `robot/Kinematics.cpp` on purpose, so it can catch IK
mistakes.
## Build
Needs a 64-bit g++ and CMake. Strawberry Perl's `C:\Strawberry\c\bin` has
g++, cmake and ninja, and the script falls back to it automatically. From
the repo root in PowerShell:
```
.\sim\build.ps1 # configure (first time) + build + smoke test
.\sim\build.ps1 -NoTest # build only
.\sim\build.ps1 -Clean # rebuild from scratch
```
To run the steps by hand, use separate lines. Windows PowerShell 5.1 has
no `&&`:
```
cmake -S sim -B sim\build -G Ninja
cmake --build sim\build
.\sim\build\sim_smoke.exe
```
Rebuild after any change in `robot/` or `shared/`. In Unity, press **Play**
(or **Reload firmware** in the panel) to pick up the new DLL. Unity copies
the DLL before loading it, so it never locks the build output and you
don't need to restart the editor.
## Headless smoke test (`tests/sim_smoke.cpp`)
It drives the firmware the way the remote would and checks:
- disarmed at power-on,
- arm lands in SIT,
- stand reaches STAND,
- **IK gives valid solutions and the feet end up at `STANCE_HEIGHT`**,
- `FLAG_WALK` leads to WALKING,
- **`+vx` moves the body forward**,
- link loss disarms,
- a wrong-size packet is ignored,
- the serial harness still works.
## Using it in Unity
Open `Hexapod_Simulation_Unity` and press Play in `Main.unity`. No scene
edits are needed: `HexapodSimBootstrap` adds a `HexapodSimulation` object,
disables the old movement scripts (`Walk`, `RotationControl`, `Leg`,
`HandleHoystick`), and binds the existing leg rig by name (`Leg` → `hip1`
/ `Hip2` / `Knie`). The on-screen panel (F1 toggles it) offers three input
sources:
- **Joystick:** the real remote as a USB controller, on input axes
`"1"`–`"6"` like the old `HandleHoystick`. Axis assignment and inversion
are set on the `SimRemote` component. The panel shows the raw axes so you
can fix them.
- **Keyboard:** test without a remote. WASD walks, Q/E turns, IJKL + U/O
drive the right stick, 1–7 flip the toggles, Backspace disarms, +/-
change speed.
- **Robot serial:** no radio at all. Keystrokes go to `robot.ino`'s own
`TEST_SERIAL_INPUT` harness.
The panel also has every remote toggle, the speed slider, simulated
handset tilt (remote gyro), a **ground tilt** slider (to test the robot
gyro), and live firmware state, joint angles, foot contact, the packet on
air and robot serial output.
The body moves **kinematically**, computed in the DLL (`SimBody.cpp`), so
Unity shows what the smoke test checks:
- The body rests on the support plane of its feet, the plane all feet are
on or above.
- Grounded feet don't slide.
- The simulated MPU6050 reads that body's tilt and rotation rate.
The sphere at each foot (`Point`) is placed by the DLL's forward
kinematics. If it doesn't sit on the tibia tip, the rig and `Config.h`
disagree.
Setup that lives in the Inspector on `HexapodSimulation`:
- `forwardAxis`: robot forward = Unity −X by default, taken from the old
scene's `invertForLeftLeg` naming.
- `unitsPerMm`: 0.1, since the model is in cm.
- `kneeRestDeg`: −90, the rig's knee pose at rotation 0.
For a custom setup instead of the bootstrap, add a `HexapodSimulation`
component to the scene yourself.
## What is not simulated
- Physics (mass, falling, slipping, servo torque and speed).
- Servo calibration. The sim decodes pulses with `Config.h`'s single
`SERVO_US_AT_0DEG` / `SERVO_US_PER_DEG`, i.e. what the firmware *intends*,
not per-servo offsets or directions.
- The remote firmware. `SimRemote.cs` mirrors its packet rules instead.