一个物体在空间中的存在可以从两个维度描述:一方面是在什么位置,这可以由其所在坐标$${x,y,z}$$来描述;另一方面是处于什么姿态(orientation),例如它是倾斜的还是正的。要知道一个物体在空间的位置是困难的,需要借助外在测量系统,例如GPS利用24颗卫星定位一个物体在地球上的经纬度和海拔。即便有GPS,要知道物体在室内的位置还是不行,需要相应的室内定位技术。扯远了,室内定位以后再说。要知道一个物体的姿态,相对容易一些,这可以借助惯性传感器(inertial sensor)。
惯性传感器通常指代下面三个具体的传感器:
- 加速度计(accelerometer):测量三轴加速度,单位$$m/s^2$$;
- 陀螺仪 (gyroscope):测量绕三轴旋转的角速度,单位是$$degree/s$$;
- 磁力计(magnetometer):测量三轴磁力的大小,单位是$$tesla$$;
惯性传感器的应用非常广泛,几乎遍及所有的智能硬件设备(如手机、手环等)。它能用于姿势识别,如apple watch自动识别用户是否正在看表;zepp捕捉网球、棒球姿势辅助训练;手环识别走路、跑步、骑车等等。这些看似神奇的应用都基于惯性传感器,以后有机会再深入讨论这些算法。
怎么才能测量一个物体的姿态呢?首先我们必须假定该物体与惯性传感器之间是刚体连接的,这样通过读取惯性传感器的值就能推测物体的姿态。加速度计可以用来测量物体的倾斜。如果物体处于静止状态,因为我们知道重力的方向总是向下的,这是非常容易做到的。如果物体静止,测量到的加速度方向就是重力的方向。此外,陀螺仪也可以用来计算物体的姿态。假定已知物体的初始姿态,那么我们将物体沿三轴旋转的角速度积分,就知道物体的姿态了。
但实际情况比这复杂。物体可能处于运动状态,而陀螺仪读数有严重的漂移,使得姿态估计并不容易。现有的主流思路是结合加速度计和陀螺仪,根据两者的读数分别估算物体姿态,然后依据某种方法将两方面融合起来。其中的算法细节,没有比这篇文章讲得更清楚的了,感兴趣的话可以好好读一遍(A practical approach to Kalman filter and how to implement it),中文翻译)。
Demo采用Arduino和SparkFun 9Dof Sensor Stick。连接和代码借鉴这篇文章,讲得比较详细,照着做一遍就行了,代码参考这里。在上面代码的accelerometer_norm和gyro_comp需要用到两个数组,需要在校准中获得。
传感器得到的原始读数无法直接使用。例如加速度计在水平静止时的读数可能是$$ x=0, y=0, z=-211$$,这里的211其实是g的大小,而我们需要把这个值与g对应起来。对应上面的代码,accelerometer_norm[2]就应该是211。同理,需要找到x轴、y轴与g的对应关系。将传感器的x轴、y轴与水平面垂直静止放置(即分别使x轴、y轴朝上),得到的读数分别对应accelerometer_norm[0]和accelerometer_norm[1]。陀螺仪的校准与加速度计不同。陀螺仪的问题在于即使处于静止状态,各个轴角速度一般都不为0,这是明显错误的。所以简单的做法是把传感器静止放置,记录陀螺仪各个轴角速度测量值,例如$$ x=5, y=30, z=-10$$,那么对应的gyro_comp[3] = {-5, -30, 10}。需要注意的是,这里的校准是非常粗糙的,也并不能完全消除误差,而实际的误差模型非常复杂,如果需要得到更加精确的测量结果还需要更加复杂的校准过程。
姿态恢复采用开源项目。这个项目本来是针对xio自产的传感器设备,为了接入自己的设备需要做一些修改。只需要修改program.cs。
建议安装Arduino IDE则不需要安装额外的驱动了。
改变传感器的姿态可以从Visual Studio执行的项目中看到下面的画面: