空飛ぶロボットのつくりかた

ロボットをつくるために必要な技術をまとめます。ロボットの未来についても考えたりします。

シミュレーターを作ってみる

やりたいこと

簡単な機構のロボットシミュレータをつくってみる

モデル

f:id:robonchu:20180121084802p:plain ls

順運動学を解いてみる

# -*- coding: utf-8 -*-
import numpy as np
from numpy import sin,cos
import matplotlib.pyplot as plt

def fk(l1, l2, l3, th1, th2):
    x2 = l2 * cos(th2) - (l1 + l3) * cos(th1)
    y2 = l2 * sin(th2) + (l1 + l3) * sin(th1)
    
    x1 = -l1 * cos(th1)
    y1 = l1 * sin(th1)

    return x1, y1, x2, y2

def fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2):
    x3 = - l4 * cos(th2) - l1 * cos(th1)
    y3 = - l4 * sin(th2) + l1 * sin(th1)

    x4 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) - l7 * sin(th2)
    y4 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) + l7 * cos(th2)

    x5 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) + l7 * sin(th2)
    y5 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) - l7 * cos(th2)

    x_f1 = [0, -l4 * cos(th2), x3, x1]
    y_f1 = [0, -l4 * sin(th2), y3, y1]

    x_f2 = [x3, x1 - l5 * sin(th2), x2]
    y_f2 = [y3, y1 + l5 * cos(th2), y2]

    x_l = [x2, x4, x5, x2]
    y_l = [y2, y4, y5, y2]

    return x_f1, y_f1, x_f2, y_f2, x_l, y_l

# グラフの描画
def plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # リンクの描画
    plt.plot(x, y,"-g",lw=5,label="link")
    plt.plot(x_f1, y_f1,"-g",lw=5,label="link")
    plt.plot(x_f2, y_f2,"-g",lw=5,label="link")
    plt.plot(x_l, y_l,"-g",lw=5,label="link")
    # 関節の描画
    plt.plot(x, y,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f1, y_f1,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f2, y_f2,"or",lw=5, ms=10,label="joint")
    plt.plot(x_l, y_l,"or",lw=5, ms=10,label="joint")
    plt.xlim(-0.4, 0.4)
    plt.ylim(-0.1,0.4)
    plt.grid()
    plt.show()

def main():
    # リンクの長さ
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    # 第1, 2の関節角度
    [th1, th2] = np.radians([90, 0])

    # 順運動学の計算
    x1, y1, x2, y2 = fk(l1, l2, l3, th1, th2)

    # ロボットアームのx座標, y座標をリストに格納
    x = [0, x1, x2]
    y = [0, y1, y2]

    x_f1, y_f1, x_f2, y_f2, x_l, y_l = fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2)

    # ロボットアームの姿勢をグラフにプロット
    plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l)

if __name__ == '__main__':
    main()

f:id:robonchu:20180121102438p:plain

参考:【Python】2リンクマニピュレータの順運動学シミュレーション | アルゴリズム雑記

解析的に逆運動学を解いてみる

sympyのシンボリック計算を用いて解いてみる

from sympy import *

theta1, theta2 = symbols('theta1 theta2')
l1, l2 ,l3, x, y = symbols('l1 l2 l3 x y')
eq1 = l2 * sin(theta2) + (l1 + l3) * sin(theta1) - y
eq2 = l2 * cos(theta2) - (l1 + l3) * cos(theta1) - x

init_printing()
ans = solve([eq1, eq2], [theta1, theta2])
print ans

計算結果

[(asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi, 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) ,
(asin((l2*sin(2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi, 2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) ,
(-asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)), 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) ,
(-asin((l2*sin(2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)), 2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2)))]

4つ解出てきた。えげつない。。。

解が正しく出ているかチェック

上記スクリプトをちょっと修正。一番上の解を使用。

# -*- coding: utf-8 -*-
import numpy as np
from numpy import sin,cos,pi,sqrt
from numpy import arcsin as asin
from numpy import arccos as acos
from numpy import arctan as atan
import matplotlib.pyplot as plt

def fk(l1, l2, l3, th1, th2):
    x2 = l2 * cos(th2) - (l1 + l3) * cos(th1)
    y2 = l2 * sin(th2) + (l1 + l3) * sin(th1)
    
    x1 = -l1 * cos(th1)
    y1 = l1 * sin(th1)

    return x1, y1, x2, y2

def fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2):
    x3 = - l4 * cos(th2) - l1 * cos(th1)
    y3 = - l4 * sin(th2) + l1 * sin(th1)

    x4 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) - l7 * sin(th2)
    y4 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) + l7 * cos(th2)

    x5 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) + l7 * sin(th2)
    y5 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) - l7 * cos(th2)

    x_f1 = [0, -l4 * cos(th2), x3, x1]
    y_f1 = [0, -l4 * sin(th2), y3, y1]

    x_f2 = [x3, x1 - l5 * sin(th2), x2]
    y_f2 = [y3, y1 + l5 * cos(th2), y2]

    x_l = [x2, x4, x5, x2]
    y_l = [y2, y4, y5, y2]

    return x_f1, y_f1, x_f2, y_f2, x_l, y_l

# グラフの描画
def plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # リンクの描画
    plt.plot(x, y,"-g",lw=5,label="link")
    plt.plot(x_f1, y_f1,"-g",lw=5,label="link")
    plt.plot(x_f2, y_f2,"-g",lw=5,label="link")
    plt.plot(x_l, y_l,"-g",lw=5,label="link")
    # 関節の描画
    plt.plot(x, y,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f1, y_f1,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f2, y_f2,"or",lw=5, ms=10,label="joint")
    plt.plot(x_l, y_l,"or",lw=5, ms=10,label="joint")
    plt.xlim(-0.4, 0.4)
    plt.ylim(-0.1,0.4)
    plt.grid()
    plt.show()

def main(th1, th2):
    # リンクの長さ
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    # 第1, 2の関節角度
    # [th1, th2] = np.radians([110, 15])

    # 順運動学の計算
    x1, y1, x2, y2 = fk(l1, l2, l3, th1, th2)

    # ロボットアームのx座標, y座標をリストに格納
    x = [0, x1, x2]
    y = [0, y1, y2]

    x_f1, y_f1, x_f2, y_f2, x_l, y_l = fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2)

    # ロボットアームの姿勢をグラフにプロット
    plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l)

if __name__ == '__main__':
    # リンクの長さ
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    x = 0.15
    y = 0.15

    th = (asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi, 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2)))

    th1, th2 = th[0], th[1]

    main(th1, th2)

f:id:robonchu:20180121111446p:plain

あってる。sympy使いやすい。

アニメーションを作ってみる

import numpy as np
from numpy import sin,cos,pi,sqrt
from numpy import arcsin as asin
from numpy import arccos as acos
from numpy import arctan as atan

import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation

def fk(l1, l2, l3, th1, th2):
    x2 = l2 * cos(th2) - (l1 + l3) * cos(th1)
    y2 = l2 * sin(th2) + (l1 + l3) * sin(th1)
    
    x1 = -l1 * cos(th1)
    y1 = l1 * sin(th1)

    return x1, y1, x2, y2

def fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2):
    x3 = - l4 * cos(th2) - l1 * cos(th1)
    y3 = - l4 * sin(th2) + l1 * sin(th1)

    x4 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) - l7 * sin(th2)
    y4 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) + l7 * cos(th2)

    x5 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) + l7 * sin(th2)
    y5 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) - l7 * cos(th2)

    x_f1 = [0, -l4 * cos(th2), x3, x1]
    y_f1 = [0, -l4 * sin(th2), y3, y1]

    x_f2 = [x3, x1 - l5 * sin(th2), x2]
    y_f2 = [y3, y1 + l5 * cos(th2), y2]

    x_l = [x2, x4, x5, x2]
    y_l = [y2, y4, y5, y2]

    return x_f1, y_f1, x_f2, y_f2, x_l, y_l


fig = plt.figure(1)
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, xlim=(-0.4, 0.4), ylim=(-0.1, 0.4))
ax.grid()

#th1 = [pi / 4] * 100
#th2 = np.linspace(- pi / 6, pi / 6, 100)

l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

x0 = np.linspace(0.15, 0.2, 100) 
x1 = np.linspace(0.2, 0.2, 100)
y0 = np.linspace(0.15, 0.2, 100)
y1 = np.linspace(0.2, 0.25, 100)

x = np.append(x0, x1)
y = np.append(y0, y1)

ite_len = len(x)

# 90 < th1
th1 = asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi
print th1
th2 = 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))
print th2

# 0 < 90 < th1
# th1 = -asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3))
# th2 = 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))

def two_link(th1, th2):
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    # [th1, th2] = np.radians([110, 15])

    x1, y1, x2, y2 = fk(l1, l2, l3, th1, th2)

    x = [0, x1, x2]
    y = [0, y1, y2]

    x_f1, y_f1, x_f2, y_f2, x_l, y_l = fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2)

    return x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l

xl, yl, x_f1l, y_f1l, x_f2l, y_f2l, x_ll, y_ll = [], [], [], [], [], [], [], []

for t1, t2 in zip(th1, th2):
    x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l = two_link(t1, t2)
    
    xl.append(x)
    yl.append(y)
    x_f1l.append(x_f1)
    y_f1l.append(y_f1)
    x_f2l.append(x_f2)
    y_f2l.append(y_f2)
    x_ll.append(x_l)
    y_ll.append(y_l)
    
line1, = plt.plot([], [],"-g",lw=5,label="link")
line2, = plt.plot([], [],"-g",lw=5,label="link")
line3, = plt.plot([], [],"-g",lw=5,label="link")
line4, = plt.plot([], [],"-g",lw=5,label="link")
circle1, = plt.plot([], [],"or",lw=5, ms=10,label="joint")
circle2, = plt.plot([], [],"or",lw=5, ms=10,label="joint")
circle3, = plt.plot([], [],"or",lw=5, ms=10,label="joint")
circle4, = plt.plot([], [],"or",lw=5, ms=10,label="joint")

def update(i):
    line1.set_data(xl[i], yl[i])
    line2.set_data(x_f1l[i], y_f1l[i])
    line3.set_data(x_f2l[i], y_f2l[i])
    line4.set_data(x_ll[i], y_ll[i])

    circle1.set_data(xl[i], yl[i])
    circle2.set_data(x_f1l[i], y_f1l[i])
    circle3.set_data(x_f2l[i], y_f2l[i])
    circle4.set_data(x_ll[i], y_ll[i])
    
ani = animation.FuncAnimation(fig, update, ite_len, blit=False, interval=10, repeat=False)

plt.show()

matplotlibのanimation.FuncAnimationを用いて柔軟にアニメーション作成 - Qiita

Animation

pythonで二重振り子のアニメーションを作る – into the lambda

参考まとめ

物理計算エンジン

倒立振子のシミュレーション(スクラッチ)

simpy

アームリンク

↓是非時間を見つけて一度流したい

パラレルリンク

逆運動学

MoveIt!