回転行列の代わりに、回転はその角度または単位円の複素数で表すことができますが、実際には同じことです。さらに重要なことに、剛体変換T
の表現が必要です。これにより、3 番目のリンクの位置と向きを計算するようなものを記述できます。t1 * t2 * t3
ベクトル間の角度atan2
を計算するために使用します。
次の Python の例が示すように、小さな IK ソルバーを構築するには、これら 2 つの要素で十分です。
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問題を解決しています。アイデアは、一度に 1 つのジョイント変数を調整することによって、ツールを目標位置に近づけることです。を関節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