6static const char *
const TAG =
"motion";
8static void log_matrix(
const float m[9]) {
9 ESP_LOGCONFIG(TAG,
" Calibration matrix:");
10 ESP_LOGCONFIG(TAG,
" - [%9.6f, %9.6f, %9.6f]",
m[0],
m[1],
m[2]);
11 ESP_LOGCONFIG(TAG,
" - [%9.6f, %9.6f, %9.6f]",
m[3],
m[4],
m[5]);
12 ESP_LOGCONFIG(TAG,
" - [%9.6f, %9.6f, %9.6f]",
m[6],
m[7],
m[8]);
17static uint32_t hash_matrix(
const float m[9]) {
18 const uint8_t *bytes =
reinterpret_cast<const uint8_t *
>(
m);
20 for (
size_t i = 0; i <
sizeof(float) * 9; i++) {
32 if (this->
pref_.
load(&saved) && saved.base_hash == this->base_hash_) {
33 memcpy(this->
matrix_, saved.matrix,
sizeof(this->matrix_));
34 ESP_LOGI(TAG,
"Restored calibration from NVS");
36 ESP_LOGD(TAG,
"No matching saved calibration; using build-time matrix");
41 LOG_UPDATE_INTERVAL(
this);
46 ESP_LOGW(TAG,
"Cannot save calibration: no preference key set");
50 memcpy(pref.matrix, this->matrix_,
sizeof(pref.matrix));
53 ESP_LOGI(TAG,
"Saved calibration to NVS");
56 ESP_LOGW(TAG,
"Calibration save failed");
61 ESP_LOGI(TAG,
"Calibration reset to build-time matrix");
71 this->
map_axes_(motion_data.acceleration, raw_data.acceleration);
72 this->
map_axes_(motion_data.angular_rate, raw_data.angular_rate);
75 ESP_LOGV(TAG,
"Accel: [%.3f, %.3f, %.3f] g; Gyro: [%.3f, %.3f, %.3f] °/s", motion_data.acceleration[X_AXIS],
76 motion_data.acceleration[Y_AXIS], motion_data.acceleration[Z_AXIS], motion_data.angular_rate[X_AXIS],
77 motion_data.angular_rate[Y_AXIS], motion_data.angular_rate[Z_AXIS]);
83 ESP_LOGW(TAG,
"calibrate_level: failed to read sensor data");
91 float nx = mapped[X_AXIS];
92 float ny = mapped[Y_AXIS];
93 float nz = mapped[Z_AXIS];
94 float mag = std::sqrt(nx * nx + ny * ny + nz * nz);
96 ESP_LOGW(TAG,
"calibrate_level: acceleration magnitude too small (%.3f)", mag);
109 ESP_LOGI(TAG,
"Level calibration: already aligned");
119 float m[9] = {1, 0, 0, 0, -1, 0, 0, 0, -1};
120 memcpy(r,
m,
sizeof(r));
122 float f = 1.0f / (1.0f + nz);
123 r[0] = 1.0f - nx * nx *
f;
127 r[4] = 1.0f - ny * ny *
f;
136 memcpy(old, this->
matrix_,
sizeof(old));
137 for (
int i = 0; i < 3; i++) {
138 for (
int j = 0; j < 3; j++) {
139 this->
matrix_[i * 3 + j] = r[i * 3 + 0] * old[j] + r[i * 3 + 1] * old[3 + j] + r[i * 3 + 2] * old[6 + j];
143 ESP_LOGI(TAG,
"Level calibration applied (mapped accel: [%.3f, %.3f, %.3f])", mapped[X_AXIS], mapped[Y_AXIS],
152 ESP_LOGW(TAG,
"calibrate_heading: failed to read sensor data");
160 float mx = mapped[X_AXIS];
161 float my = mapped[Y_AXIS];
162 float h = std::sqrt(mx * mx + my * my);
164 ESP_LOGW(TAG,
"calibrate_heading: device must be tilted (XY magnitude %.3f too small)",
h);
171 float sign_mx = mx >= 0 ? 1.0f : -1.0f;
172 float cos_phi = sign_mx * mx /
h;
173 float sin_phi = sign_mx * my /
h;
178 memcpy(old, this->
matrix_,
sizeof(old));
180 this->
matrix_[0] = cos_phi * old[0] + sin_phi * old[3];
181 this->
matrix_[1] = cos_phi * old[1] + sin_phi * old[4];
182 this->
matrix_[2] = cos_phi * old[2] + sin_phi * old[5];
183 this->
matrix_[3] = -sin_phi * old[0] + cos_phi * old[3];
184 this->
matrix_[4] = -sin_phi * old[1] + cos_phi * old[4];
185 this->
matrix_[5] = -sin_phi * old[2] + cos_phi * old[5];
188 ESP_LOGI(TAG,
"Heading calibration applied (mapped accel: [%.3f, %.3f, %.3f])", mapped[X_AXIS], mapped[Y_AXIS],
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.", "2026.2.0") void set_retry(const std uint32_t uint8_t std::function< RetryResult(uint8_t)> && f
LazyCallbackManager< void(MotionData &)> motion_data_callback_
void map_axes_(float output[3], const float input[3]) const
ESPPreferenceObject pref_
bool calibrate_heading()
Assuming Y-axis rotation only, correct the heading so X/Y align correctly.
virtual bool update_data(MotionData &data)=0
bool calibrate_level()
Calibrate the matrix so the current reading maps to [0, 0, 1] (device flat).
void dump_config() override
void clear_calibration()
Restore the build-time (axis_map / transform_matrix) base, discarding calibration.
bool save_calibration()
Save the current matrix to NVS.
ESPPreferences * global_preferences
ESPPreferenceObject make_preference(size_t, uint32_t, bool)
bool sync()
Commit pending writes to flash.