Files

91 lines
2.3 KiB
C++

#include "imu.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <termios.h>
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;
}