我试图在2D手臂(由三个带关节的棍子组成)上实现反向运动学.我能够将最低的手臂旋转到所需的位置.现在,我有一些问题:
如何使上臂与第三臂一起移动,使臂的终点到达所需的点.我是否需要为两者使用旋转矩阵?如果有,可以有人给我一些示例或帮助,还有其他任何可能吗?没有旋转矩阵的方法吗?
最低的臂只朝一个方向移动.我试过谷歌它们,他们说两个向量的交叉产品给出了手臂的方向,但这是为3D.我正在使用2D和两个2D矢量的交叉积给出一个标量.那么,我该如何确定它的方向?
Plz家伙任何帮助将不胜感激....
在此先感谢维克拉姆
我会试一试,但是因为我的机器人技术已经过去了二十年,所以带上一粒盐.
我学习它的方式,每个关节都由它自己的旋转矩阵描述,相对于它的当前位置和方向定义.然后通过将旋转矩阵组合在一起来计算整个臂的终点的坐标.
这实现了您正在寻找的效果:您只能移动一个关节(更改其方向),并自动跟随所有其他关节.
你不会有太多的机会绕过矩阵 - 事实上,如果使用齐次坐标,所有联合计算(旋转和平移)都可以用矩阵乘法建模.优点是可以用单个矩阵(加上手臂的原点)来描述全臂位置.
使用此变换矩阵,您可以解决逆运动学问题:由于变换矩阵的元素将取决于关节的角度,您可以将整个计算'endpoint = startpoint x transformation'视为一个方程组,并使用起始点和端点已知,你可以解决这个系统来确定未知角度.这里的困难在于方程可能无法解决,或者存在多种解决方案.
我不太明白你的第二个问题 - 你在寻找什么?
旋转可以用它的角度或单位圆的复数表示,而不是旋转矩阵,但实际上它是相同的.更重要的是,你需要一个代表性T
的刚体变换,让你可以写这样的东西t1 * t2 * t3
来计算第三连杆的位置和方向.
使用atan2
来计算向量之间的角度.
如下面的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
请注意,fk()
并ccd_sweep()
在同为3D; 你只需重写fk_joint()
和ccd_step()
.
构建具有n
相同链接的臂并运行cnt
CCD扫描的迭代,从随机臂配置开始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