yaboPP电子
技术文章

如何解释IMU传感器数据,用于抵消考核:旋转矩阵创建

2019年4月23日经过马克·休斯

与imus一起工作可以疯狂的原因,但最害怕的是最害怕的人通常是数学。

与imus一起工作可以疯狂的原因,但最害怕的是最害怕的人通常是数学。

IMU数据是无用的,除非你知道如何解释它。

例如,BNO055是一个9DOF传感器,可以提供加速度、陀螺仪和磁力计数据,以及融合四元素指示从初始位置开始的绝对方向的数据。除非你能找到一种方法将IMU的参考系与一个固定的外部参考系联系起来,否则所有这些数据都是毫无用处的。

来自未经校准的传感器的数据是无用的。

一旦你弄清楚如何稳定惯性参考框架中的数据,就错位轴仍然可以对所有辛勤工作造成严重破坏。如果您不小心,您将结束计算多个运动轴之间混合的数据进行计算。

校准的传感器仍然需要与惯性引用对齐,以使数据真正有用。

您通常必须将传感器与惯性参考帧对齐,以便能够解释数据。

一旦你的传感器在惯性坐标系中对齐,你就可以对齐你的数据。

这样做的方法是具有旋转矩阵,其单个元素被三角函数或四元数填充。季倍是优选的,因为它们需要MCU的计算较少。

在本文中,我将描述一个旋转矩阵,并呈现用于在读取的目的中配置Bosch BNO055 IMU所需的一些数学。我正在使用这个imu,因为我从前一篇文章中有一个如何使用BNO055捕获数据

有兴趣的读者可能想知道博世用了这个imuBMX055。但是,这里呈现的数学应该适用于任何传感器系统。物品的重点是数学,而不是传感器。

无论您使用哪种传感器,您必须在每次使用之前根据制造商的数据表校准设备。有时校准需要外部EEPROM。

旋转矩阵

在三维空间中移动一个矢量可能是一件复杂的事情。一种常见的技术是围绕固定轴进行连续旋转来旋转向量。

在一次旋转中重新确定矢量方向的最简单方法是使用旋转矩阵。3×3矩阵包含了在不使用三角函数的情况下在一次旋转中移动矢量所需的所有信息。

上述重力矢量(橙色)围绕单轴(绿色)旋转,以位于负Z轴(蓝色)

您可以通过搜索“欧拉角“或通过阅读我以前的关于四元数的文章

在下面的gif图中,你可以看到偏航、俯仰和滚转的顺序旋转,每一个旋转都需要特定的轴方向来实现正确的功能。当一个运动可以被多个旋转描述时,万向节锁是可能的。

偏航,沥青和卷的轮换

卷,沥青和偏航旋转是流行的,但最终数学上有缺陷。

使用滚转、俯仰和偏航的麻烦是,它是笨重的,利用三角学和受制于万向节锁定。三角函数在微处理器中需要数百个时钟周期,这会对代码的性能产生负面影响。只要有可能,代码应该使用更简单的数学函数。

在单元球上呈现的三维向量可以旋转到任何绕固定轴的单个旋转的任何新位置。它更快,只需要添加,减去,划分和乘法的基本计算。

但是,在开始编程之前,它确实要求您进行一些数学。

示例方向配置:Bosch BNO055

所以这是我们将通过的场景。BNO055位于足球内,它已打开,数据从EEPROM存储器写入校准寄存器,该设备坐在房间的某个地方。我们真的不知道方向是什么,所以我们关闭设备的任何数据都可以指向任何方向。

我们将创建一个旋转矩阵,该旋转矩阵对准传感器数据,使得重力点在负Z轴的方向上。稍后,我们可以将磁性北方对准沿x轴铺平。

BNO055输出一个重力矢量。如下图所示,重力矢量总是指向下。我们将找到数学上旋转传感器所需的矩阵,使重力矢量沿着负z轴。

一个重力矢量的渲染。动画圈表示对应的正旋转方向右手规则

作为一个备注,如果传感器未输出重力矢量,我们可以简单地从加速度计的三个轴读取数据并执行类似的步骤。但是,我们将不得不对可变分配更加小心。

重力矢量代码

以下代码从BNO055读取重力矢量

#include  #include  #include  #include  / *该程序是Adafruit BNO055 Rawdata.ino的删节版本,安装了Adafruit BNO055图书馆。由Mark Hughes修改的程序for Allaboutcircues.com文件→示例→Adafruit BNO055→Arduino上的原始数据连接UNO ========================================================================= scl到模拟5 |SDA为模拟4 |VDD到3.3V DC |GND到共同的地面* / #define bno055_samplerve_delay_ms(100)//数据请求之间的延迟adafruit_bno055 bno = adafruit_bno055();//基于ADAFRUIT_BNO055库VOID SETUP(VOID){SERIAL.BEGIN(115200);创建传感器对象BNO;//开始串口通信if(!bno.begin())//初始化传感器通信{serial.print(“ooops,未检测到bno055 ...检查您的接线或i2c addr!”);延迟(1000);bno.setextcrystaluse(true); // Use the crystal on the development board } void loop(void) { imu::Vector<3> gravity = bno.getVector(Adafruit_BNO055::VECTOR_GRAVITY); Serial.print("gX: ");Serial.print(gravity.x()); Serial.print("\t"); Serial.print("gY: ");Serial.print(gravity.y()); Serial.print("\t"); Serial.print("gZ: ");Serial.print(gravity.z()); Serial.print("\t"); Serial.println(""); } ------ Output ------- gX: 0.59 gY: 9.15 gZ: -3.47

由于地球表面附近的重力引起的加速度约为9.801米/平方米。传感器读取9.15在Y方向上表示传感器几乎倾斜(如下所示)。我们的目标是使重力0的x和y组件和重力的z分量接近9.8。

下面您可以看到传感器方向的渲染图,由深蓝色指针表示。右边是创业公司的定位。左边是更接近理想的方向,负z轴平行于重力矢量。

左:启动时传感器方向。对:接近理想的传感器方向。

确定将传感器旋转到正确位置所需的旋转矩阵需要一些数学。首先,必须归一化传感器和目标向量的载体。这是使方程可以解决的必要条件。没有规范化,术语变得非常笨拙,涉及虚构的术语和共轭。在我的机器上,它出现在大约14个字体上大约4页。

归一化给出了仅具有方向的载体 - 归一化向量的长度是一个。为了标准化,将每个组件划分每个组件的平方和的平方根。由实际传感器数据进行的示例如下所示。

$$ \ hat {a} = \ left \ {\ frac {a_x} {\ sqrt {a_x ^ 2 + a_y ^ 2 + a_z ^ 2}} \; \ hat {x},\ frac {a_y} {\ sqrt{A_X ^ 2 + A_Y ^ 2 + A_Z ^ 2}}}\ hat {y},\ frac {a_z} {\ sqrt {a_x ^ 2 + a_y ^ 2 + a_z ^ 2}}}}}} \; \ hat {z} \ light \}%0 $$

$$ \帽子{A} = \左\ {\压裂{0.59} {\ SQRT {0.59 ^ 2 + 9.15 ^ 2 +( - 3.47)^ 2}} \; \帽子{X},\压裂{9.15}{\ sqrt {0.59 ^ 2 + 9.15 ^ 2 +( - 3.47)^ 2}}}\ hat {y},\ frac {-3.47} {\ sqrt {0.59 ^ 2 + 9.15 ^ 2 +( - 3.47)^ 2}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}。

$$ \ hat {a} = \ left \ {0.061 \; \ hat {x},0.933 \;\ hat {y},-0.354 \; \ hat {z} \ rick \} $$

由于我们将目标矢量选择为负Z轴,因此我们不必经历归功化它的麻烦。

$$ \ hat {g} = \ left \ {0 \;\ hat {x},0 \;\ hat {y},-1 \; \ hat {z} \ light \}%0 $$

矢量数学

点产品

要确定投影到矢量g的载体A的一部分,请使用点产品。

$$ \ hat {a} \ cdot \ hat {g} = \ left |一个\右手|\左手|G \右| COS(\ THETA)$$

为了找到它们之间的角度,重新排列方程以解决θ。

$$ cos(\ theta)= \ frac {\ hat {a} \ cdot \ hat {g}} {\ left |一个\右手|\左手|G \右手|} $$

我们的矢量归一化已经过清。自| |和| g |两者都已经设置为一个,分母消失了。另外,由于G的X和Y组分为零,因此该等式迅速减少。

$$ cos(\ theta)= a_x \ cdot 0 + a_y \ cdot 0 \; + \; - 1 \ cdot a_z $$

因此,旋转角度仅取决于加速度的Z分量。

$ $ \θ= arccos (1 \ cdot A_z) $ $

交叉产品

确定旋转该角度的向量不是胆小的心脏。并不是特别困难,但它特别乏味。有几个步骤,很容易弄错。这是Mathematica Shine等节目 - 他们不会犯错误,除非他们的人工程序员告诉他们。下面是我告诉我使用单位向量之前的旋转矩阵

一旦你意识到可以对矩阵进行几种简化,它会很快减少到更容易管理的东西

在替代我们的原始值之后,我们的旋转矩阵将把我们的重力矢量旋转到负Z轴上。并且存在某些对称性,可以利用进一步降低计算复杂性。

基于重力矢量的该矩阵在启动时确定一次以获得相对于重力的取向。如果应用于未来的加速度读数,该矩阵将旋转值,以便无论如何安装传感器,负Z轴都会直接指向。当乘以任何加速度向量时(归一化与否)时,该旋转矩阵将旋转它。让我们来看看一个例子 - 并使用原始的重力矢量。

对于那些需要简单复习一下矩阵乘法的人来说,矩阵每一行的元素乘以列中的每个元素。重新排列组件后,结果被合计。

当所有人都说并完成时,结果如下:

在X方向和Y方向上都不完全为零,但已经很接近了。记住,在开始这段旅程时,我们只使用了两个小数点后的精度,X和Y的小数点后两个小数点后的读数都是0,而预期的结果是-9.801 m/s²。我认为这是一场胜利。

幸运的是,旋转罗盘读数使X或Y轴沿着磁性北方更简单,因为现在可以在Z轴周围旋转测量值。并且有足够的代码空间简化 - 临时变量可用于存储公共术语来加速代码执行。另外,可以使用对称性来减少冗余计算。

将θ= y / x的切线的值替换为矩阵提供旋转。You can align to the positive x-axis, the positive y-axis, the negative y-axis, or the negative x-axis by manipulating the right side of this equation (e.g., tan[θ] = -X/Y), or you can align to another angle (e.g., geographic north) by manipulating the left side of the equation (tan[θ+14°]=Y/X).

概括

需要在他们将运作的环境中校准IMUS。该校准的部分通常要求用户定义传感器在空间中定向的方式,并参考传感器所在的环境。本文演示了如何创建与加速度计数据对齐的任意旋转矩阵以及二维旋转。基于磁力计数据的矩阵。

结合的重力和磁力计旋转矩阵变换如上所示。

初始矩阵(重力和磁力计)可以乘以以创建应用于所有未来测量的单个旋转矩阵 - 确保您收集的数据可以稍后成功分析。

17日评论
  • j
    JMSayles. 2019年4月26日

    有人用这样的装置成功地控制了相对缓慢移动的小型车辆吗?

    像。 回复
    • 马克·休斯 2019年4月26日
      @jmsayles - 这不是执行死亡所需的代码(或数学)的整个代码(或数学),但它可能是人们最顽固的部分 - 因为这种旋转矩阵旋转x,y,z传感器的轴与地球上的北,南,东,西,上下和下游对齐。此时,您必须开始将旋转的加速度集成以获取速度并集成速度以获得位移。还有其他问题也可以解决。量化误差,虚假读数,饱和等......基本上 - 如果您有GPS信号 - 使用GPS信号,并且只依赖于GPS卫星不可见的终止。
      像。 回复
      • B.
        brown7278 2019年4月30日
        这是一件信息,如果您阅读本文,您将获得关于如何解释IMU传感器数据的整个指南,如果您仍然需要有关此信息,请访问https://errorcode0x.com/fix-epson-错误代码-0xf4 /。
        像。 回复