Files
mangavalkandClaude Opus 5.5 5ff85c4eb8 Robot: Teensy 3.6 with the old robot's servo wiring and calibration
- LEGACY/Hexapod_Teensy/: old robot sketch (reference only).
- platformio.ini: robot env targets teensy36 (owner-confirmed board).
- Config.h: per-servo SERVOS table (pin, pulse at 0 deg, signed
  us/deg, pulse limits) built from the old sketch's pins, ranges, trims
  and the old Unity servo directions. Rear-left/front-left coxa offsets
  set to 0: the owner re-horns those two servos (the old +-90 left them
  at the end of travel; the sim showed them clamping).
- ServoDriver: 18 servos on hardware PWM (50 Hz, 16-bit); the Teensy 3.6
  Servo library stops at 12.
- Radio on CE 39 / CSN 15 with SPI SCK on pin 14.
- sim: analogWrite/PWM shims, pulses decoded through SERVOS (API v6).
- Docs: CLAUDE.md, READMEs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 15:53:55 +02:00

89 lines
4.4 KiB
C

#pragma once
// C API of hexapod_sim.dll: the unchanged robot firmware running against
// simulated hardware. Consumed by Unity (Assets/HexapodSim/HexapodSimNative.cs)
// and by the headless test (tests/sim_smoke.cpp).
//
// Conventions: robot body frame, mm and degrees - +X forward, +Y left, +Z up
// (same as shared/HexapodProtocol). Per-leg arrays are [leg][joint or xyz]
// flattened, leg order as in robot/Config.h, joints coxa/femur/tibia.
//
// One robot per loaded DLL: its globals are the firmware's globals. To reset
// the robot, unload and reload the DLL (Unity does this on every Play).
#include <stdint.h>
#ifdef _WIN32
#define HXSIM_API extern "C" __declspec(dllexport)
#else
#define HXSIM_API extern "C" __attribute__((visibility("default")))
#endif
// Bump whenever a signature or struct below changes; the C# side checks it.
#define HXSIM_API_VERSION 6
#define HXSIM_NUM_LEGS 6
// All fields 4 bytes wide so C# can mirror this with LayoutKind.Sequential.
typedef struct {
int32_t num_legs;
float mount_x_mm[HXSIM_NUM_LEGS];
float mount_y_mm[HXSIM_NUM_LEGS];
float mount_angle_deg[HXSIM_NUM_LEGS];
float coxa_mm, femur_mm, tibia_mm;
float stance_radius_mm, stance_height_mm;
float coxa_min_deg, coxa_max_deg;
float femur_min_deg, femur_max_deg;
float tibia_min_deg, tibia_max_deg;
float control_hz;
float leg_clearance_mm; // LEG_CLEARANCE_MM: minimum gap between neighbouring legs' segments
float stance_height_range_mm; // CmdPacket.body_height +-1000 moves the height by this much
} HxGeometry;
typedef struct {
int32_t robot_state; // 0 DISARMED, 1 SIT, 2 STAND, 3 WALKING
float sit_stand_blend; // 0 sit .. 1 stand
int32_t link_ok; // Comms::linkOk()
float heading_deg; // robot.ino's open-loop heading estimate
float imu_roll_deg; // RobotIMU filter output
float imu_pitch_deg;
int32_t imu_enabled; // robot-gyro toggle as the robot sees it
uint32_t sim_time_ms;
uint32_t control_ticks; // loop() passes that ran the control step
int32_t stance_mask; // bit i = leg i in stance per the gait engine
float pose_reach_scale; // 1 = full commanded body pose; less = scaled down to what the legs can reach
float twist_scale; // 1 = walk command as sent; less = slowed to a stride the legs can take
float stance_height_mm; // current (rate-limited) standing height: feet below hips
} HxStatus;
HXSIM_API int32_t hxsim_api_version(void);
HXSIM_API int32_t hxsim_packet_size(void); // sizeof(CmdPacket) as compiled
HXSIM_API void hxsim_get_geometry(HxGeometry* out);
// Hardware present at power-on. Call before hxsim_start().
HXSIM_API void hxsim_set_radio_present(int32_t present);
HXSIM_API void hxsim_set_imu_present(int32_t present);
HXSIM_API void hxsim_start(void); // runs setup() once
// Advances simulated time by dt_us, calling loop() every HXSIM_LOOP_PERIOD_US
// like the real busy loop (loop() itself holds the CONTROL_HZ rate).
HXSIM_API void hxsim_step(uint32_t dt_us);
// Inputs
HXSIM_API void hxsim_radio_send(const uint8_t* bytes, int32_t len); // one packet on air
HXSIM_API void hxsim_set_ground_tilt(float roll_deg, float pitch_deg); // tilt the world (robot-gyro tests)
// The MPU6050 is normally fed from the kinematic body model (SimBody.cpp).
// Calling this overrides it with fixed readings from then on.
HXSIM_API void hxsim_set_imu(float ax_g, float ay_g, float az_g,
float gx_dps, float gy_dps, float gz_dps);
HXSIM_API void hxsim_serial_input(const char* bytes, int32_t len); // TEST_SERIAL_INPUT keys
// Outputs
HXSIM_API int32_t hxsim_serial_output(char* out, int32_t cap); // drains robot Serial prints
HXSIM_API void hxsim_get_servos(int32_t* us_18, int32_t* attached_18, uint32_t* writes_18);
HXSIM_API void hxsim_get_joints_deg(float* deg_18); // servo pulses decoded through Config.h's per-servo SERVOS table
HXSIM_API void hxsim_get_feet_mm(float* xyz_18); // forward kinematics of those angles, body frame
HXSIM_API void hxsim_get_status(HxStatus* out);
// Kinematic body (SimBody.cpp): the body rests on the support plane of its
// feet and grounded feet don't slide. World frame = robot frame at power-on,
// ground at z = 0. Any pointer may be null.
HXSIM_API void hxsim_get_body(float* pos_mm_3, float* quat_wxyz_4, float* yaw_deg, int32_t* contact_mask);