#include "imu.hpp" #include #include #include #include #include #include YawTracker::YawTracker() : _fd(-1), _yaw(0), _unbounded_yaw(0), _gyro_z(0), _gyro_bias(0), _ready(false) {} bool YawTracker::begin(const char* device, int baud) { _fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); if (_fd < 0) { printf("[IMU] 无法打开 %s, 继续无IMU运行\n", device); _ready = false; return false; } termios opt; tcgetattr(_fd, &opt); cfsetispeed(&opt, B115200); cfsetospeed(&opt, B115200); opt.c_cflag |= (CLOCAL | CREAD); opt.c_cflag &= ~PARENB; opt.c_cflag &= ~CSTOPB; opt.c_cflag &= ~CSIZE; opt.c_cflag |= CS8; tcsetattr(_fd, TCSANOW, &opt); calibrate(); return true; } void YawTracker::calibrate(int samples) { float sum = 0; int valid = 0, fail = 0; for (int i = 0; i < samples && fail < 10; ++i) { int ret = _parseJY62(); if (ret > 0) { sum += _gyro_z; ++valid; fail = 0; } else { ++fail; } usleep(2000); } _gyro_bias = valid > 0 ? sum / valid : 0; _yaw = 0; _unbounded_yaw = 0; _ready = (valid > 10); if (!_ready) printf("[IMU] 校准失败 (仅 %d/%d 样本), 继续无IMU运行\n", valid, samples); } void YawTracker::update(float dt) { if (_parseJY62() <= 0) return; float gyro_filt = _gyro_z - _gyro_bias; if (std::fabs(gyro_filt) < 0.03f) gyro_filt = 0; // 死区 _unbounded_yaw += gyro_filt * dt; _yaw = _unbounded_yaw; while (_yaw > 180.0f) _yaw -= 360.0f; while (_yaw < -180.0f) _yaw += 360.0f; } int YawTracker::_parseJY62() { uint8 buf[11]; int total = 0; for (int tries = 0; total < 11 && tries < 20; ++tries) { int n = read(_fd, buf + total, 11 - total); if (n < 0) { usleep(2000); continue; } // EAGAIN, 等 2ms if (n == 0) break; total += n; } if (total < 11) return -1; for (int tries = 0; buf[0] != 0x55 && total > 10 && tries < 10; ++tries) { memmove(buf, buf + 1, 10); int n = read(_fd, buf + 10, 1); if (n <= 0) { usleep(1000); continue; } } if (buf[0] != 0x55) return -1; int16 gz = (buf[5] << 8) | buf[4]; _gyro_z = gz * (2000.0f / 32768.0f); // ±2000°/s return 1; }