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>
91 lines
4.4 KiB
C
91 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 5
|
|
|
|
#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;
|
|
int32_t servo_us_at_0deg;
|
|
int32_t servo_us_per_deg;
|
|
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 with Config.h constants
|
|
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);
|