Arduino和Python卡尔曼滤波对四元数进行姿态测定

在本文中,我将演示使用EKF(扩展卡尔曼滤波)对四元数确定姿态的实现,并说明将多个传感器数据融合在一起以使系统正常工作的必要性。

将要使用的传感器是陀螺仪,加速度计和磁力计。 Arduino用于从传感器读取数据,但是数据处理将在python中完成。 除此之外,我还使用Pygame创建了一个简单的显示器,以便更好地可视化结果。 我还将提供一种校准磁力计的简单方法,因为它们的读数会根据周围环境而变化很大。

绘制图形

在本节中,我们将创建可视化工具,以便了解问题并更直观地得出结果。

Python完整代码

注意:BoardDisplay代码引用了Wireframe代码,因此您需要将包含Wireframe.py的文件夹标记为源根。 您可以通过右键单击Pycharm中的文件夹,选择“将目录标记为”,然后选择“源根目录”来执行此操作。 如果您这样做正确,则该文件夹应标记为蓝色。

创建线框

为了在Pygame中显示对象,我们首先需要完全定义其坐标。 为简单起见,我将显示一个矩形块来模仿我正在使用的板,因此我们要做的就是定义该块的6个面。 我们将分3个步骤进行操作。 首先,我们将有一个名为“节点”的类来定义点的xyz坐标,然后我们将有另一个名为“ Face”的类,它使用4个“节点”来定义矩形块的面。 然后,我们将有最后一个名为“ Wireframe”的类,它存储了多维数据集的信息,并且还充当了Pygame显示代码和后端计算代码之间的接口。

当我们开始谈论四元数时,后端计算部分将出现在第3部分中,因此,现在,我们仅专注于在Pygame中显示块。下面是上述3个类的代码。

代码略

我还创建了一些方便的功能来记录日志。 这有助于确保我们将信息正确插入到类中。 我们将在主要的“ BoardDisplay”代码中使用此类。 这是一个示例,说明如何使用该类初始化块的参数。

代码略

如果运行上述代码,则应打印出所有已创建的节点和面。如果您完全使用了我上面写的内容,那么您应该得到以下输出:

-- Nodes --
0: (-1.50, -1.00, -0.10) Color: (255, 255, 255)
1: (-1.50, -1.00, 0.10) Color: (255, 255, 255)
2: (-1.50, 1.00, -0.10) Color: (255, 255, 255)
3: (-1.50, 1.00, 0.10) Color: (255, 255, 255)
4: (1.50, -1.00, -0.10) Color: (255, 255, 255)
5: (1.50, -1.00, 0.10) Color: (255, 255, 255)
6: (1.50, 1.00, -0.10) Color: (255, 255, 255)
7: (1.50, 1.00, 0.10) Color: (255, 255, 255)

-- Faces --
Face 0:
Color: (255, 0, 255)
Node 0
Node 2
Node 6
Node 4
Face 1:
...
...
...

我只复制了面0的打印输出,但是由于我们总共插入了6张面的信息,因此应该可以打印到面 5为止的打印输出。 让我们首先从节点开始。 我们已经插入了8个节点的信息,并且您可以在打印输出中看到,它们的索引从0到7。对于该项目,颜色信息是多余的,因为我们将显示每个面的颜色而不是每个节点的颜色。但是,节点的索引非常重要,因为面对象引用此信息。 例如,我将面0指定为节点0、2、6和4所包围的面。下图显示了我使用的索引的顺序。 程序段的中心位于轴的原点。

这样,我们现在有了一个完全定义的块。下一步是创建在Pygame顶部看到的视图。

创建透视图

您的计算机屏幕上将显示一个二维图像。 应该没有深度,因为它只是一块平坦的屏幕。 那么,为什么上面的图在我们眼中看起来像是3D图? 这实际上是由于构成对象(以及轴)的线条给人以深度的错觉。 这是一篇有关深度感知的文章,尽管我真的很有趣,但是如果您有兴趣的话,可以随时阅读。 在计算机上创建“深度”并不难,但是如果您不使用透视图(例如正交视图)绘制对象,即使它实际上是正确的,它也会在我们眼中变形。

在本节中,我们仅讨论一个消失点透视图的简单实现。下面是我要为查看器创建的透视图。

首先,我要使原点成为消失点,因此我将不得不将对象移出原点。 为此,我将在z方向上将对象的中心偏移“ P”,以便如图所示,对象的新中心现在位于(0,0,P)。 接下来,我要将“屏幕”放在z轴上的距离“ S”处。 该屏幕是二维的Pygame屏幕。 我们现在需要做的是将立方体上的所有8个点投影到屏幕上。 如果仔细观察投影,您会发现这只是x和y坐标的线性缩放,基于与屏幕的距离。

让我们以坐标为(-1.50,-1.00,-0.10)的节点0为例。 当我们将对象移出原点时,此节点的新坐标将为(-1.50,-1.00,-0.10 P)。 为了将此点投影到屏幕上,我们可以基于相似的三角形对其进行缩放。 当z = 0时,我们知道该点消失了,因此x和y都变为零。 这是我们计算的参考点。 如果屏幕位于z = S = 5,那么我们新的投影x坐标将为:

而我们新的投影y坐标将是:

投影的深度要复杂一些,因此在此不再赘述,因为这不是本文的主题。

上面的方程式是在我的Python代码中实现的。以下是代码摘录:

代码略

现在我们准备将点绘制到我们的Pygame屏幕上,让我们进入下一部分。

Pygame中绘图

为了显示对象,我使用了Pygame的绘制多边形方法。 如果您想检阅此文档,请参阅此处的文档。 基本上,我们可以使用pygame.draw.polygon方法为多边形提供点列表,以绘制多边形。 由于我们的块是一个简单的六边形矩形,因此我们必须用一个包含4个点的列表来调用此函数,总共需要6次,每个面总共一次。 但是,不可能显示块的所有6面,因为在任何时候,我们只能看到3个面。 那么我们如何确定哪些面可见? 我们可以使用简单的画家算法来实现。

绘制图景时,我们通常从最远的图景开始绘画,然后逐渐在这些图景上绘制更近的对象。 这也是画家算法的作用。 我们要做的就是根据其深度(在面的中心)对6个面进行排序,然后从最远的面开始绘制多边形。 这在代码中实现如下:

代码略

首先,我们确定面中心的深度(面节点的平均深度),然后按递增顺序对其进行排序并按顺序绘制它们。

现在,您的块是固定的,除了绿色矩形之外,您什么都看不到:

图像略

轮换

我将介绍一些四元数的基础知识,并提供使用python的简单实现以可视化轮换。 但是,我们不会从第一原理中得出任何推论,因为它是完全数学的。 相反,我们将使用现有公式来构建代码。

四元数

四元数为我们提供了一种绕指定轴轮换指定角度的方法。 如果您只是刚开始3D轮换这一主题,那么您会经常听到人们说“使用四元数,因为它会产生万向节锁定问题”。 的确如此,但是轮换矩阵也是如此。 轮换矩阵不会遇到万向架锁定问题。 实际上,完全没有意义。 当使用欧拉角时,会发生万向架锁定问题,欧拉角只是一组3个基本轮换,以允许您描述3D空间中的任何方向。 在姿态确定中,我们通常将3D轮换可视化为偏航,俯仰和滚动的组合。 这些是欧拉角,因此无论您是否使用四元数,它们都容易受到云台锁定问题的影响。

四元数之所以这样命名是因为总共有4个分量。如果q是四元数,则

您可以将四元数视为复数的扩展,其中现在有1个实数和3个虚数,而不是1个实数和1个虚数。表示四元数的另一种方法是这样的:

但是,请注意,有些作者在虚部之前先写虚部。例如,

通常,您可以通过检查哪些变量为粗体(或斜体)来判断它们使用的顺序。 标记的变量通常是虚部,未标记的部分(通常带有数字下标)是实部。 在本文中,我们将使用第一个定义,其中实部在前。

四元数的共轭

定义如下。

不用担心它有什么用,因为您很快就会在下面找到。

四元数的大小以类似于矢量的方式定义。

因此,可以按以下方式定义单元四元数。

其中

下面是四元数加法和减法的定义(只需将“ +”替换为“-”)

详情参阅 - 亚图跨际

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值