34 : spi_device_(spi_device), gpio_cs_(gpio_cs), gpio_int_(gpio_int) {
35 assert(spi_device_ && gpio_cs_ && gpio_int_);
43 calibrate_thread_ = std::thread(&Mpu9250::CalibrateThreadTask,
this);
47 if (calibrate_thread_.joinable()) {
48 calibrate_thread_.join();
52 void CalibrateThreadTask() {
54 auto start_time = std::chrono::steady_clock::now();
55 std::chrono::microseconds period_us(1000);
56 std::chrono::steady_clock::time_point next_time =
57 std::chrono::steady_clock::now();
59 double gyro_offset_x = 0, gyro_offset_y = 0, gyro_offset_z = 0;
60 static bool cali_done =
false;
63 std::this_thread::sleep_for(std::chrono::seconds(UINT32_MAX));
68 if (std::fabsf(gyro_delta_.x) > 0.005 ||
69 std::fabsf(gyro_delta_.y) > 0.005 ||
70 std::fabsf(gyro_delta_.z) > 0.01) {
71 next_time += period_us;
72 std::this_thread::sleep_until(next_time);
76 auto now = std::chrono::steady_clock::now();
77 if (now - start_time > std::chrono::seconds(5) &&
78 now - start_time < std::chrono::seconds(30)) {
80 gyro_offset_x += gyro_.x;
81 gyro_offset_y += gyro_.y;
82 gyro_offset_z += gyro_.z;
85 if (now - start_time > std::chrono::seconds(35) && cali_done ==
false) {
87 static_cast<float>(gyro_offset_x /
static_cast<double>(counter));
89 static_cast<float>(gyro_offset_y /
static_cast<double>(counter));
91 static_cast<float>(gyro_offset_z /
static_cast<double>(counter));
93 if (std::fabsf(bias_x) > 0.005 || std::fabsf(bias_y) > 0.005 ||
94 std::fabsf(bias_z) > 0.005) {
95 gyro_bias_.x += bias_x;
96 gyro_bias_.y += bias_y;
97 gyro_bias_.z += bias_z;
99 std::cout <<
"Calibration data saved\n";
101 std::cout <<
"No need to calibrate\n";
104 std::cout <<
"Calibration completed\n";
107 next_time += period_us;
108 std::this_thread::sleep_until(next_time);
122 data_callback_ = callback;
134 std::this_thread::sleep_for(std::chrono::milliseconds(100));
138 std::cout << std::format(
"MPU9250 initialized. WHO_AM_I: 0x{:02X}\n",
141 if (who_am_i != 0x71 && who_am_i != 0x68 && who_am_i != 0x70) {
143 std::format(
"Error: MPU9250 connection failed (WHO_AM_I: 0x{:02X})",
165 spi_device_->
WriteRegister(gpio_cs_, I2C_MST_DELAY_CTRL, 0x01);
187 std::this_thread::sleep_for(std::chrono::milliseconds(10));
191 std::this_thread::sleep_for(std::chrono::milliseconds(10));
198 std::array<uint8_t, 14> data{};
200 spi_device_->ReadRegisters(gpio_cs_, ACCEL_XOUT_H, &data[0], 14);
202 constexpr float ACCEL_SCALE = 16.0f / 32768.0f * 9.80665f;
203 constexpr float GYRO_SCALE = 2000.0f / 32768.0f * M_PI / 180.0f;
205 uint8_t* accel_data = &data[0];
206 uint8_t* temperature_data = &data[6];
207 uint8_t* gyro_data = &data[8];
209 accel_.z =
static_cast<float>(
210 static_cast<int16_t
>((accel_data[0] << 8) | accel_data[1])) *
212 accel_.y = -
static_cast<float>(
213 static_cast<int16_t
>((accel_data[2] << 8) | accel_data[3])) *
215 accel_.x =
static_cast<float>(
216 static_cast<int16_t
>((accel_data[4] << 8) | accel_data[5])) *
219 temperature_ =
static_cast<float>(
static_cast<int16_t
>(
220 (temperature_data[0] << 8) | temperature_data[1])) /
224 float gyro_z =
static_cast<float>(
static_cast<int16_t
>((gyro_data[0] << 8) |
228 float gyro_y = -
static_cast<float>(
static_cast<int16_t
>(
229 (gyro_data[2] << 8) | gyro_data[3])) *
232 float gyro_x =
static_cast<float>(
static_cast<int16_t
>((gyro_data[4] << 8) |
237 gyro_delta_.x = gyro_x - gyro_.x;
238 gyro_delta_.y = gyro_y - gyro_.y;
239 gyro_delta_.z = gyro_z - gyro_.z;
245 if (data_callback_) {
246 data_callback_(accel_, gyro_);
254 float accel_intensity = std::sqrt(
255 accel_.x * accel_.x + accel_.y * accel_.y + accel_.z * accel_.z);
256 std::cout << std::format(
257 "Acceleration: [X={:+.4f}, Y={:+.4f}, Z={:+.4f} | Intensity={:+.4f}] | "
258 "Gyroscope: [X={:+.4f}, Y={:+.4f}, Z={:+.4f}] | Temperature: {:+.4f} "
260 accel_.x, accel_.y, accel_.z, accel_intensity, gyro_.x, gyro_.y,
261 gyro_.z, temperature_);
278 std::ofstream file(
"cali_data.bin", std::ios::binary);
280 std::cerr <<
"Error: Unable to open cali_data.bin for writing.\n";
283 file.write(
reinterpret_cast<const char*
>(&gyro_bias_),
sizeof(gyro_bias_));
285 std::cout <<
"Calibration data saved successfully.\n";
292 std::ifstream file(
"cali_data.bin", std::ios::in | std::ios::binary);
295 <<
"MPU9250 calibration file not found. Using default values.\n";
300 file.seekg(0, std::ios::end);
301 std::streamsize file_size = file.tellg();
302 file.seekg(0, std::ios::beg);
304 if (file_size !=
sizeof(gyro_bias_)) {
306 <<
"Error: MPU9250 calibration file size mismatch. Using default "
309 gyro_bias_ = {0, 0, 0};
314 file.read(
reinterpret_cast<char*
>(&gyro_bias_),
sizeof(gyro_bias_));
318 if (std::abs(gyro_bias_.x) > 1.0f || std::abs(gyro_bias_.y) > 1.0f ||
319 std::abs(gyro_bias_.z) > 1.0f || std::isnan(gyro_bias_.x) ||
320 std::isnan(gyro_bias_.y) || std::isnan(gyro_bias_.z) ||
321 std::isinf(gyro_bias_.x) || std::isinf(gyro_bias_.y) ||
322 std::isinf(gyro_bias_.z)) {
324 <<
"Error: MPU9250 invalid calibration data detected. Resetting to "
326 gyro_bias_ = {0, 0, 0};
328 std::cout <<
"MPU9250 calibration data loaded successfully: "
329 <<
"X=" << gyro_bias_.x <<
", "
330 <<
"Y=" << gyro_bias_.y <<
", "
331 <<
"Z=" << gyro_bias_.z <<
"\n";
339 static constexpr uint8_t PWR_MGMT_1 = 0x6B;
340 static constexpr uint8_t PWR_MGMT_2 = 0x6C;
341 static constexpr uint8_t CONFIG = 0x1A;
342 static constexpr uint8_t SMPLRT_DIV = 0x19;
343 static constexpr uint8_t GYRO_CONFIG = 0x1B;
344 static constexpr uint8_t ACCEL_CONFIG = 0x1C;
345 static constexpr uint8_t ACCEL_CONFIG_2 = 0x1D;
346 static constexpr uint8_t ACCEL_XOUT_H = 0x3B;
347 static constexpr uint8_t GYRO_XOUT_H = 0x43;
348 static constexpr uint8_t USER_CTRL = 0x6A;
349 static constexpr uint8_t INT_PIN_CFG = 0x37;
350 static constexpr uint8_t INT_ENABLE = 0x38;
351 static constexpr uint8_t I2C_MST_CTRL = 0x24;
352 static constexpr uint8_t I2C_MST_DELAY_CTRL = 0x67;
353 static constexpr uint8_t I2C_SLV0_CTRL = 0x27;
357 static constexpr uint8_t AK8963_CNTL2_REG = 0x0B;
358 static constexpr uint8_t AK8963_CNTL2_SRST = 0x01;
371 float temperature_ = 0;
376 std::thread calibrate_thread_;