rtimulib的报告

为什么螺距仅在-90度到+90度之间变化?

这是一个常见的问题,所以我想就为什么为什么音高至少在RTIMULib(2)中说出不同的滚动和偏航特性有所疑问。我之所以这样说是因为其他软件可能有不同的约定,并且不一定总是与其他两个软件不同的音调轴。

RTIMULib(2)使用的约定是,滚动和偏航在-180度至+180度之间变化,而俯仰在-90度至+90度之间变化。为什么俯仰角也不会在-180度和+180度之间变化?这是因为球面完全由这些范围表示,因此所有三个轴都不必具有整个范围。

以IMU处于零侧倾和偏航并且俯仰从零稳定地增加的情况为例。当它刚好超过直线时,滚动和偏航将改变180度,以反映它已经超过了垂直方向。这种不连续是令人不愉快的,但确实可以正确表示姿势。这些不连续性是为什么在任何可能的情况下都使用四元数并且仅在绝对必要时才求助于Euler角的好主意的原因。

举一个具体的例子,假设一个IMU与地面平行并面朝北,与垂直线成45度角,其俯仰角可认为是135度。这可以描述为具有0的滚动,135度的俯仰和0的偏航。可替代地,这可以被认为具有180度的滚动,45度的俯仰和180度的偏航。这两个姿势是相同的,并且是混叠的一种形式。同样,有两种方式为每个姿势形成四元数。始终可以从一种转换为另一种,如果应用程序需要,可以这样做。

有关值范围的更多信息,请在Wikipedia条目中查看Euler角。我可能还应该提到使螺距精确达到-90度或+90度有多么困难。这主要是因为它是一个奇异点(实际上是两个奇异点),并且在该点的任一侧上的螺距都较小。查看俯仰角是如何从基础四元数推导的:

vec.setY(asin(2.0 * (m_data[0] * m_data[2] - m_data[1] * m_data[3]))); 

m_data是代表IMU姿态的标准化四元数。例如,为了使asin()结果为+90度,此部分:

m_data[0] * m_data[2] - m_data[1] * m_data[3] 

必须完全等于0.5,并且只有在一切正确的情况下才会发生这种情况。由于存在校准误差,传感器之间的非正交轴,未对齐的轴以及使用MEMS IMU时难以完全消除的东西之类的问题,滤波器可能无法可靠地输出代表恰好+ / 90度的间距。

对于那些感兴趣的人,实际尝试一下是一个值得尝试的实验。它需要使用试错法将IMU移至很小的距离,以最大程度地提高音调。如果幸运的话,您实际上可能会看到+/- 90度!

使用四元数校正IMU安装偏移

RTIMULib支持校正任意,非标准的,坐标轴对齐的IMU方向。但是,在设备中安装IMU通常并不完全完美,这可能会导致每个轴偏移几度。但是,使用四元数来更正此错误非常容易。

为此,必须通过将设备放置在其参考位置并存储融合的四元数–fusionQPose来捕获偏移方向。我们将此称为referenceQPose。然后,每次使用IMU的融合结果时,只需将FusionQPose乘以referenceQPose的共轭即可:

correctedQPose = referenceQPose.conjugate() * fusionQPose; correctedQPose.toEuler(correctedPose); 

就这么简单。

将多个IMU与RTIMULib一起使用

RTIMULib应用程序的典型初始化部分如下所示:

RTIMUSettings *settings = new RTIMUSettings("RTIMULib"); RTIMU *imu = RTIMU::createIMU(settings); if ((imu == NULL) || (imu->IMUType() == RTIMU_TYPE_NULL)) { printf("No IMU found"); exit(1); } imu->IMUInit(); 

要使用多个IMU,只需执行以下操作即可:

// create settings0 and imu0  RTIMUSettings *settings0 = new RTIMUSettings("RTIMULib0");  // IMU type, bus and address and other interface parameters // along with any associated pressure sensor address and type  // can be overridden in the settings object here.  RTIMU *imu0 = RTIMU::createIMU(settings0); if ((imu0 == NULL) || (imu0->IMUType() == RTIMU_TYPE_NULL)) { printf("No IMU found"); exit(1); } // This is an opportunity to manually override any other settings // set up IMU  imu0->IMUInit();  // create settings1 and imu1  RTIMUSettings *settings1 = new RTIMUSettings("RTIMULib1");  // IMU type, bus and address and other interface parameters // along with any associated pressure sensor address and type  // can be overridden in the settings object here.  RTIMU *imu1 = RTIMU::createIMU(settings1); if ((imu1 == NULL) || (imu1->;IMUType() == RTIMU_TYPE_NULL)) {  printf("No IMU found");  exit(1);  }  // This is an opportunity to manually override any other settings // set up IMU  imu1->;IMUInit(); 

初始化完成后,只需按常规轮询imu0和imu1。上面的代码将创建RTIMULib0.ini文件和RTIMULib1.ini文件。如果您只运行该程序而这些程序不存在,则RTIMULib将依次创建每个文件并尝试自动检测IMU。现在,两个文件都将设置为相同的IMU(找到的第一个),因此必须手动编辑其中一个文件才能使用第二个IMU。替代方法是将代码放在对createIMU的调用之前,该代码将修改settings1对象中的相应变量。这将阻止自动检测运行,并使用提供的类型,总线和地址信息。

如果两个或两个IMU都具有压力传感器,则自动检测会将找到的第一个压力传感器与找到的第一个IMU相关联。如果这不是所需的行为,那么也必须重写此行为。

请注意,两个IMU不必是相同的芯片或相同的总线-它们可以位于不同的I2C总线,不同的SPI总线或I2C和SPI上。并且可以支持的IMU总数没有限制(尽管必须考虑总线利用率和CPU负载等因素)。

为了校准磁力计和加速度计,可以正常使用RTIMUCal应用程序,但使用特定名称作为参数:

RTIMULibCal RTIMULib0 RTIMULibCal RTIMULib1 

这将在正确的.ini文件中设置校准数据。

这就是为什么尝试使用MEMS 9-dof IMU测量位置注定会失败的原因

我们大多数人都去过那里。我们有一个9 df MEMS IMU可以很好地测量姿势(即空间方向),然后尝试使用相同的硬件来跟踪位置变化似乎是一个好主意。这篇文章讨论了为什么我们所有人(据我所知)都失败了。

首先,让我们回顾一下数据融合如何与9 dof IMU一起工作以获取空间方向。一个9dof IMU具有三个传感器,每个传感器具有不同的作用:

  • 陀螺仪。在许多方面,这些实际上都是主要的传感器。它们以相对较低的噪声对方向变化提供了几乎瞬时的响应。由于它们输出角速度,因此必须相对于时间对输出进行(离散)积分以获得角度变化。但是,陀螺仪没有上下感-它们不包含绝对参考。他们只是感觉方向改变。

  • 加速度计。当使用IMU进行方向感测时,加速度计的作用主要是跟踪重力矢量的方向,因为已知该方向是向下的。当然,加速度计不仅对重力加速度敏感,而且还可以感应到每一个微小的干扰,并且固有地会产生噪声。但是,经过很好的滤波后,可以使用输出来保持对水平面的绝对参考,即它们为俯仰和横滚提供参考。他们没有提供有关偏航(航向)的信息。他们遇到的一个问题是,当IMU受到连续加速时(例如,在加速的运动车辆上或转弯的飞机上),基准会失真。

  • 磁力计。磁力计通过感测地球磁场来提供缺少的偏航参考。但是,他们真正要做的是感知几乎受任何事物影响的环境磁场-附近的磁铁,磁性材料,风的吹散方式等。

9-dof融合软件的任务是进行这三组测量(如果需要进行校正,则需要瞬时车速),并得出(主要是)正确的方向。

好的,这就是方向。现在,位置。要尝试使用IMU感测位置变化,您基本上必须做两件事:

  1. 删除重力矢量以保留剩余加速度。
  2. 对时间的剩余加速度进行二次积分以改变位置。

原则上很简单–可能出什么问题?好吧,基本上一切。一方面,这种基本假设一个时间步长(采样间隔)为恒定加速度的分段线性积分可能不会完全正确。鉴于需要对加速度进行双重积分,因此可能会导致严重误差。减去旋转的重力矢量以获得残余加速度的任何错误都会类似地引起位置大误差。加速度计中的噪声或不正确的校准也会导致错误。等等

因此,错误的来源很多。问题在于无法纠正它们。例如,假设IMU实际上处于静止状态,但是由于先前的错误,会留下较小的速度。即使残留加速度为零,代码也会认为IMU仍在移动,并相应地保持位置变化。基本上,整个过程很快就会分开!

有解决办法吗?很好地使用具有超级精确安装座和出色工程设计的超级杜军军用传感器(激光环陀螺仪等)会更好地工作。其他方法使用多个IMU并组合输出以尝试抵消各种错误。这确实有可能导致更好的性能,但可能仍然不够好。例如,MEMS陀螺仪不仅受旋转加速度的影响,还受线性加速度的影响。因此,需要将它们与振动隔离开来以抵消这种情况。

据我所知,使用MEMS IMU进行位置感测的唯一现实方法是拥有一个单独的绝对基准,该基准可以用来纠正错误并阻止发散。这与使用加速度计和磁力计校正陀螺仪角速度数据中的误差基本相同。问题是,如果存在这样的参考,为什么不只是将其用于位置感应?

将多个相同的IMU(或其他I2C设备)连接到单个I2C接口

在许多情况下,需要将多个I2C设备连接到单个处理器。智能手套和动作捕捉服就是几个例子。问题在于,通常无论如何对于IMU来说,只有两个I2C地址选项。使用SPI接口可以减少问题,因为无论如何每个设备都需要一条单独的选择线。即使没有足够的GPIO,一个简单的多路复用器芯片也会将几个GPIO扩展到更大的数量。使用多个I2C接口显然有帮助,但是大多数处理器只公开一两个。

如果I2C是唯一可用的选项,则有几种方法可以扩展可连接到适用于任何芯片的单个I2C接口的设备数量。所需要的是一种隐藏未被寻址的设备并使处理器仅与所需芯片对话的技术。

要永远记住的一件事是,您不能忽略信号的完整性。多个相同的传感器芯片通常意味着它们将位于不同的位置,因此会涉及到电缆的长度。如果注意优化上拉电阻值,则I2C可以成功地通过几英尺的电缆(我通常使用USB电缆进行这种连接)。

那么,如何解决有限的寻址问题呢?

  • 使用I2C开关。TI TCA9548A就是一个例子。这本身就是一个I2C设备,最多可以连接八个I2C设备(也有两个和四个端口选项)以及主I2C接口。本质上,处理器通过交换机芯片自己的I2C地址告诉交换机要激活哪个接口,然后处理器可以对选定的传感器芯片进行寻址,就像直接连接一样。所有八个设备可以位于相同的I2C地址。一个不错的方面是,连接到传感器的每条电缆都与其他电缆隔离。您最多可以连接八个开关,总共64个传感器!不确定是否有人真的想这样做。
  • 使用两个可用的I2C地址作为启用。这有点像为每个传感器选择单独的芯片。使用一组GPIO(或具有多路分配功能的GPIO获得更多选择线),将一条线连接到每个传感器芯片的地址选择输入。在正常操作中,除一条线外,所有线都处于高电平。因此,所有传感器都将位于一个地址,而另一个传感器仅位于一个地址。然后,处理器可以单独与该传感器通信,而不会影响其他传感器。该系统可能有效(我自己还没有尝试过),但是有一个明显的缺点。不同的传感器之间没有电气隔离。由于电缆增加了所有电容,这将使信号完整性成为一个真正的问题。如果不是不可能的话,加上终止将变得非常棘手。另外,每个传感器需要五根电线。
  • 使用模拟开关。这有点类似于第一种选择,除了(原则上)可以使用任何旧的模拟开关。这意味着来自处理器的SDA和SCL信号仅到达一台设备,并且每条电缆都被隔离。我没有尝试过–专用的I2C交换机似乎是一个更好的解决方案。

综上所述,我认为将太多的传感器连接到一个I2C接口只是一个坏主意-特别是对于高采样率IMU应用。一方面,接口的总带宽分配在同一接口上的所有设备之间。即使在400kHz,这也可能是一个很大的限制。另外,我已经多次提到信号完整性问题。奇怪的挂断和奇怪的数据很可能是电缆过多和端接不正确的结果。

那该怎么办?取决于应用程序,但我认为应该认真考虑仅将一个或两个传感器连接到低成本,电池供电的无线连接处理器,然后复制该传感器以获得所需的传感器总数。处理器本身不需要做任何非常复杂的事情-只需操作芯片并将原始数据发送回功能更强大的处理器即可。

使用四元数的磁力计倾斜补偿

有很多技术可以用来补偿磁力计的倾斜,但我使用的是基于四元数的技术,效果很好。它一直被用于RTIMULib的所有口味。倾斜补偿是必要的,因为磁力计正在以安装磁力计的对象的方向读取磁场,而所需的测量则在水平面中。实际上,需要撤消侧倾角和俯仰角,以使其看起来像磁力计是水平的。高侧倾角和俯仰角总是使事情变得复杂,但这正是四元数派上用场的地方。跳转后的代码片段说明了其工作原理…

首先需要的是侧倾和俯仰信息。此处使用的约定是,例如,如果设备是飞机,则x轴从飞行员的角度指向鼻子,y轴沿右翼指向,z轴指向直线下。因此,正的侧倾角表示右翼向下滚动,正的俯仰角表示机头朝上,而偏航角为正值表示机头向右旋转。

这是RTIMULIb中代码的版本:

RTQuaternion q;    // this is a quaternion derived from roll and pitch RTQuaternion m;    // this is the magnetometer data as a quaternion  // the first part constructs quaternion from roll and pitch  RTFLOAT cosX2 = cos(roll / 2.0f); RTFLOAT sinX2 = sin(roll / 2.0f); RTFLOAT cosY2 = cos(pitch / 2.0f); RTFLOAT sinY2 = sin(pitch / 2.0f);  q.setScalar(cosX2 * cosY2); q.setX(sinX2 * cosY2); q.setY(cosX2 * sinY2); q.setZ(-sinX2 * sinY2);  // now construct a quaternion from the magnetometer data m.setScalar(0); m.setX(mag.x()); m.setY(mag.y()); m.setZ(mag.z());  // perform the tilt compensation m = q * m * q.conjugate();  // calculate the yaw value yaw = -atan2(m.y(), m.x())); 

此代码段的输入为弧度的俯仰和横滚。这是从加速度计得出的。该代码的第一部分创建了一个四元数q来表示横摇和俯仰–带有正弦和余弦的所有东西就是您如何从Euler角度创建四元数(为此,偏航始终为0,因此该代码经过优化以反映)。

然后,将磁力计矢量放入四元数,准备进行倾斜补偿。魔术发生在最后一行。这是磁力计信息通过四元数从横摇和俯仰旋转的地方,成为倾斜补偿的版本(即,如果磁力计完全处于水平状态,您将获得的值)。最后一行是根据倾斜补偿磁力计读数生成偏航值的标准方法。

sitemap