对陀螺仪 Z 轴角度的线性化处理

发布时间 2023-08-10 22:07:45作者: Sound_Sleep

多数陀螺仪 Z 轴方向角度变化如下图所示:

为方便进行 PID,需要对其进行线性化处理

观察图像不难发现,由于非线性是跳跃间断点造成的,所以间断点两端会存在巨大的数值跳变,这个跳变就是我们可以利用的地方

定义一个圈数变量,初值为0,每判定一次越界则圈数变量的值发生 1 的变化 。假设采样频率无限大,那么检测到角度发生了360°变化时就可以判定发生了越界,圈数就可以相应变化,这种理想条件下的伪代码可以写成:

int 圈数 = 0;

if(这一圈角度 - 上一圈角度 == -360) 圈数++;
else if(这一圈角度 - 上一圈角度 == 360) 圈数--;

处理后的角度 = 圈数 * 360 + 这一圈角度;

但是实际情况下受采样周期的限制,这一圈角度和上一圈角度采样点可能像下图中 G 和 H 一样,
可以看到 G 和 H 之间的角度差就小于 360°

可以发现采样周期角速度与判定界限之间满足一下关系式:

同时还要防止误触发,也就是正常旋转的时候不能记成圈数变化:

综合上面两个式子,angelBound 为 180° 的时候,可以适应 最大的角速度 和 最低的采样频率

完整源码如下:

每次传入当前的角度,就会返回线性化处理后的角度

double getLinearAngel(double angelNow){
  static double angelLast = 0;
  static int roundCount = 0;
  double err = angelNow - angelLast;

  if(err < -180)  roundCount++;
  else if (err > 180) roundCount--;

  angelLast = angelNow;

  return roundCount * 360 + angelNow;
}

在此基础上可以进行推广,所有图像类似于下图的数据都可以用这种方法进行线性化处理,记最大值为 max,最小值为 min,则最优界限为 (max + min)/2

代码也可以推广为:

double getLinearData(double dataNow){
  static double dataLast = 0;
  static int count = 0;
  double err = dataNow - dataLast;

  if(err < -BOUND)  count++;
  else if (err > BOUND) count--;

  dataLast = dataNow;

  return count * BOUND * 2 + dataNow;
}