以前、逆運動学のFABRIKとCCDを実装しましたが、各アームの可動域が無制限だったので今回は角度制限を追加してみました。
環境:Python3.8.5、Jupyter Notebook
小型サーボの場合、通常0〜180度程度の可動域しかないので、同じような条件にしてみました。設定変数によって可動域は変えられるようにしてます。
上図(3リンクの場合):
- Link1は地面に対して鉛直方向を90度、Joint1を回転軸として0〜180度に設定(絶対角度)
- Link2の可動域はLink1に対してJoint2を回転軸として-90〜90度に設定(相対角度)
- Link3の可動域はLink2に対してJoint3を回転軸として-90〜90度に設定(相対角度)
CCDの角度制限の場合:
- まずLinkの角度を-180〜180度に変換するconvTheta()を用意し角度表現を統一しておく
- Armクラス内コンストラクタにminAngleとmaxAngleのパラメータを追加(デフォルト値を設定)
- Armクラス内にangleLimit()メソッドを追加して角度制限する
def convTheta(theta):
theta = theta % tau
if theta > pi:
theta = theta - tau
return theta
class Arm:
def __init__(self, ax, ay, length, angle, minAngle=-pi/2, maxAngle=pi/2):
self.ax = ax
self.ay = ay
self.length = length
self.angle = convTheta(angle)
self.bx = self.ax + self.length * cos(self.angle)
self.by = self.ay + self.length * sin(self.angle)
self.minAngle = convTheta(minAngle)
self.maxAngle = convTheta(maxAngle)
def angleLimit(self, prevTheta, newTheta):
theta = convTheta(newTheta - prevTheta)
if theta < self.minAngle:
theta = self.minAngle
elif theta > self.maxAngle:
theta = self.maxAngle
self.angle = theta + prevTheta
self.bx = self.ax + self.length * cos(self.angle)
self.by = self.ay + self.length * sin(self.angle)
FABRIKの角度制限の場合:
FABRIKの場合は、backward()とforward()の2つのメソッドがあり、それぞれに角度制限の手続きを追加しておきます。先程のCCDと同様にconvTheta()で角度を-180〜180度に変換しておきます。以下が角度制限なしのbackward()メソッド。
def backward(self, tx, ty):
theta = np.arctan2(ty - self.ay, tx - self.ax)
self.bx = tx
self.by = ty
self.ax = tx - self.length * cos(theta)
self.ay = ty - self.length * sin(theta)
self.angle = convTheta(theta)
def backward2(self, tx, ty, prevTheta):
theta = convTheta(np.arctan2(ty - self.ay, tx - self.ax) - prevTheta)
if theta < self.minAngle:
theta = self.minAngle
elif theta > self.maxAngle:
theta = self.maxAngle
self.angle = convTheta(theta + prevTheta)
self.bx = tx
self.by = ty
self.ax = self.bx - self.length * cos(self.angle)
self.ay = self.by - self.length * sin(self.angle)


















