WIP: checkpoint Wii native IMU and upstream IR bridge

Pause Wii pointing work with firmware 0.33-wii-trace installed. Preserve the pinned libogc IR pipeline, calibrated native IMU, software BOOTSEL, and standard camera sensitivity trial.

Tracking instability, tracking loss, and ineffective vertical movement remain unresolved. Level-2 camera filtering is not hardware-qualified. Nine targeted regression tests pass; firmware and persistent storage were verified after flashing.
This commit is contained in:
Joey Yakimowich-Payne 2026-09-11 17:05:54 -06:00
commit 9f6dddb790
41 changed files with 7990 additions and 150 deletions

View file

@ -0,0 +1,99 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Encode one native mode-0 IMU block. Inputs use the native-right body frame;
// quaternion wxyz rotates body vectors into the reference frame. Quaternion
// scale/sign do not matter. Finite acceleration saturates at signed Q28 limits.
// Invalid inputs leave output untouched; counter and elapsed must fit 12 bits.
bool probe_native_imu_pack(const float quaternion_wxyz[4], const float accel_g[3],
uint16_t counter_ticks, uint16_t elapsed_ticks,
int16_t temperature_raw, uint8_t output[30]);
#ifdef __cplusplus
}
struct ProbeNativeMotionSample {
bool accel_valid = false;
bool gyro_valid = false;
uint32_t accel_sequence = 0;
uint32_t gyro_sequence = 0;
uint32_t accel_us = 0;
uint32_t gyro_us = 0;
float accel_g[3]{};
float gyro_dps[3]{};
};
// Core 0 only. Call update even when sensors are unavailable, and consult ready
// before using the orientation. Sequence identities, not polling, admit samples;
// repeated sequences cannot refresh timestamps or contribute to calibration.
// Startup requires the user to rest the controller: constant rotation about
// gravity is indistinguishable from an unknown gyro bias without another sensor.
// Fresh near-1g acceleration corrects tilt drift after startup. Heading remains
// gyro-derived unless a reliable optical heading observation is supplied.
class ProbeNativeMotion {
public:
void reset();
void update(uint32_t now_us, uint32_t connection_generation,
const ProbeNativeMotionSample& sample);
// Call after update, using a full observed sensor-bar pair (never inferred).
// Positive optical yaw means aim-right, the negative reference-world turn.
// The first sample in each optical generation anchors the current heading;
// it supplies neither absolute world yaw nor an absolute console cursor.
void observe_optical_heading(uint32_t now_us, uint32_t reference_generation,
uint32_t sequence, uint32_t sample_us,
float yaw_radians, bool valid);
bool ready() const { return ready_; }
const float* quaternion() const { return quaternion_; }
const float* acceleration() const { return acceleration_; }
const float* bias() const { return bias_; }
private:
void invalidate();
void clear_candidate();
bool initialize_orientation();
bool integrate(const float gyro_dps[3], uint32_t elapsed_us);
bool correct_gravity(uint32_t elapsed_us);
bool normalize_orientation();
bool have_generation_ = false;
bool have_update_ = false;
bool seen_accel_sequence_ = false;
bool seen_gyro_sequence_ = false;
bool have_accel_ = false;
bool have_gyro_ = false;
bool candidate_ = false;
bool ready_ = false;
bool have_optical_generation_ = false;
bool seen_optical_sequence_ = false;
bool have_optical_reference_ = false;
bool have_optical_sample_ = false;
uint32_t connection_generation_ = 0;
uint32_t update_us_ = 0;
uint32_t accel_sequence_ = 0;
uint32_t gyro_sequence_ = 0;
uint32_t accel_us_ = 0;
uint32_t gyro_us_ = 0;
uint32_t candidate_us_ = 0;
uint32_t gyro_count_ = 0;
uint32_t accel_count_ = 0;
uint32_t optical_generation_ = 0;
uint32_t optical_sequence_ = 0;
uint32_t optical_sample_us_ = 0;
float optical_reference_radians_ = 0.0f;
float gyro_variation_ = 0.0f;
float accel_variation_ = 0.0f;
float quaternion_[4]{1.0f, 0.0f, 0.0f, 0.0f};
float acceleration_[3]{};
float gyro_dps_[3]{};
float bias_[3]{};
float mean_gyro_[3]{};
float mean_accel_[3]{};
float gravity_reference_[3]{};
};
#endif