2010-04-12 61 views
9

我想在二维手臂(由三个关节组成)上实现逆运动学。我能够将最低臂旋转到所需的位置。现在,我有一些问题:二维逆运动学实现

  1. 我该如何让上臂随第三个一起移动,以便臂的终点达到所需点。我是否需要为两者使用旋转矩阵,如果是的话,是否有人可以给我一些例子或帮助,并有任何其他可能;没有旋转矩阵的方式做这个?

  2. 最下臂只能朝一个方向移动。我试过谷歌它,他们说,两个向量的交叉产品给手臂的方向,但这是3D。我正在使用2D和两个2D向量的叉积给出一个标量。那么,我怎样才能确定它的方向?

PLZ人任何帮助,将不胜感激....

在此先感谢 维克拉姆

回答

7

我给它一个镜头,但因为我的机器人是二十年过去,带上一粒盐。

我学到的方式,每一个关节由自己的旋转矩阵描述,相对于当前位置和方向确定。然后通过将旋转矩阵组合在一起来计算整个手臂端点的坐标。

这正是实现你正在寻找的效果:你可以只移动一个关节(改变其方向),和所有其他关节会自动跟随。

你不会有让周围多少机会矩阵这里 - 事实上,如果你使用齐次坐标,所有关节计算(旋转和平移)可以用矩阵乘法模型。优点是可以用单个矩阵(加上手臂的原点)来描述完整的手臂位置。

使用这种变换矩阵,可以解决逆运动学问题:由于变换矩阵的元素将取决于关节的角度,因此可以将整个计算的“终点=起点x变换”视为一个方程组,并且已知起点和终点,则可以解决该系统以确定未知角度。这里的困难在于方程可能不可解,或者有多种解决方案。

虽然我不太明白你的第二个问题 - 你在找什么?

3

在机器人技术中,我们经常使用DH参数来计算正向和反向运动。 Wikipedia有一个很好的介绍。

3

DH(Denavit-Hartenberg)符号是解决方案的一部分。它可以帮助您收集一组简洁的值,描述机器人的机械装置,例如连接长度和连接类型。

从那里计算正向运动学变得更加容易。首先,您必须了解的是如何将坐标系从一个地方翻译成另一个坐标系。例如,给定你的机器人(或它的DH表),你必须将一组旋转和平移应用于一个坐标系(例如世界)以知道点(或矢量)在机器人的手腕坐标系。

正如您可能已经知道的,齐次变换矩阵对于这种变换非常有用。它们是封装旋转和平移的4x4矩阵。这些矩阵的另一个非常有用的特性是,如果有两个坐标框架通过一些旋转和平移进行链接和定义,那么如果将两个矩阵相乘,那么只需将乘积乘以转换目标即可。

所以DH表将帮助你建立矩阵。

逆运动学虽然有点复杂,但取决于您的应用。复杂性来自针对相同问题的多种解决方案。自由度越多,解决方案的数量就越多。

想想你的手臂。捏住你周围的东西。您可以将手臂移动到空间中的多个位置,并仍然保持捏合矢量不变。解决逆运动学问题涉及决定选择哪种解决方案。

6
  1. 除了旋转矩阵,旋转可以用角度表示,也可以用complex number of the unit circle表示,但它确实是一回事。更重要的是,你需要一个代表Trigid body transformations,这样你就可以编写像t1 * t2 * t3这样的东西来计算第三个链接的位置和方向。

  2. 使用atan2来计算angle between the vectors

正如以下Python示例所示,这两件事足以构建一个小型IK解算器。

from gameobjects.vector2 import Vector2 as V 
from matrix33 import Matrix33 as T 
from math import sin, cos, atan2, pi 
import random 

gameobjects库没有2D转换,所以你要自己写matrix33。它的接口就像gameobjects.matrix44

定义从一个关节到下一个关节转换的正向运动学函数。我们通过angle担任联合旋转,接着是一个固定的转型joint

def fk_joint(joint, angle): return T.rotation(angle) * joint 

工具的转型是tool == fk(joints, q)其中joints是固定的转换和q是关节角度:

def fk(joints, q): 
    prev = T.identity() 
    for i, joint in enumerate(joints): 
     prev = prev * fk_joint(joint, q[i]) 
    return prev 

如果手臂的底部有偏移量,则替换T.identity()变换。

OP正在通过循环坐标下降来解决位置IK问题。这个想法是通过一次调整一个关节变量来将工具靠近目标位置。设q为联合的角度,并且prev为联合的基础的变换。接头应通过向工具和目标位置的矢量之间的角度进行旋转:

def ccd_step(q, prev, tool, goal): 
    a = tool.get_position() - prev.get_position() 
    b = goal - prev.get_position() 
    return q + atan2(b.get_y(), b.get_x()) - atan2(a.get_y(), a.get_x()) 

遍历关节和更新关节值的每一个变化的工具结构:

def ccd_sweep(joints, tool, q, goal): 
    prev = T.identity() 
    for i, joint in enumerate(joints): 
     next = prev * fk_joint(joint, q[i]) 
     q[i] = ccd_step(q[i], prev, tool, goal) 
     prev = prev * fk_joint(joint, q[i]) 
     tool = prev * next.get_inverse() * tool 
    return prev 

注意对于3D,fk()ccd_sweep()是相同的;你只需要重写fk_joint()ccd_step()

构造一个臂n相同的链接和运行CCD扫描的cnt迭代,从随机臂形态q开始:

def ccd_demo(n, cnt): 
    q = [random.uniform(-pi, pi) for i in range(n)] 
    joints = [T.translation(0, 1)] * n 
    tool = fk(joints, q) 
    goal = V(0.9, 0.75) # Some arbitrary goal. 
    print "i  Error" 
    for i in range(cnt): 
     tool = ccd_sweep(joints, tool, q, goal) 
     error = (tool.get_position() - goal).get_length() 
     print "%d %e" % (i, error) 

我们可以尝试求解器和比较收敛的不同数量的速度链接:

>>> ccd_demo(3, 7) 
i  Error 
0 1.671521e-03 
1 8.849190e-05 
2 4.704854e-06 
3 2.500868e-07 
4 1.329354e-08 
5 7.066271e-10 
6 3.756145e-11 
>>> ccd_demo(20, 7) 
i  Error 
0 1.504538e-01 
1 1.189107e-04 
2 8.508951e-08 
3 6.089372e-11 
4 4.485040e-14 
5 2.601336e-15 
6 2.504777e-15