In [1]:
    
%matplotlib inline
from pylab import *
from numpy import sin, cos, pi, matrix, random
from __future__ import division
from math import atan2
rcParams['figure.figsize'] = 12, 10  # that's default image size for this interactive session
from IPython import display
from IPython.html.widgets import interact, fixed
    
    
In [ ]:
    
def trans(x, y, a):
    '''create a 2D transformation'''
    s = sin(a)
    c = cos(a)
    return matrix([[c, -s, x],
                   [s,  c, y],
                   [0,  0, 1]])
def from_trans(m):
    '''get x, y, theta from transform matrix'''
    return [m[0, -1], m[1, -1], atan2(m[1, 0], m[0, 0])]
    
In [ ]:
    
trans(0, 0, 0)
    
In [ ]:
    
N = 3  # number of links
l = [0] + range(N, 0, -1)  # length of link, l[0] is ingored
max_len = sum(l)
a = random.random_sample(N)  # angles of joints
T0 = trans(0, 0, 0)  # base
    
In [ ]:
    
def forward_kinematics(T0, l, a):
    T = [T0]
    for i in range(len(a)):
        Ti = T[-1] * trans(l[i], 0, a[i])
        T.append(Ti)
    Te = T[-1] * trans(l[-1], 0, 0)  # end effector
    T.append(Te)
    return T
    
In [ ]:
    
def show_robot_arm(T):
    cla()
    x = [Ti[0,-1] for Ti in T]
    y = [Ti[1,-1] for Ti in T]
    plot(x, y, '-or', linewidth=5, markersize=10)
    xlim([-max_len, max_len])
    ylim([-max_len, max_len]) 
    ax = axes()
    ax.set_aspect('equal')
    t = atan2(T[-1][1, 0], T[-1][0,0])
    ax.annotate('[%f,%f,%f]' % (x[-1], y[-1], t), xy=(x[-1], y[-1]), xytext=(x[-1], y[-1] + 0.5))
    display.clear_output(wait=True)
    
In [ ]:
    
for i in range(N):
    @interact(value=(-pi/2, pi/2, 0.1), n=fixed(i))
    def set_joint_angle(n, value=0):
        global a
        a[n] = value
        T = forward_kinematics(T0, l, a)
        show_robot_arm(T)
    
SymPy is a Python library for symbolic mathematics.
In [ ]:
    
from sympy import init_printing, sin, cos, pi, asin, acos, atan2, atan, sqrt, simplify, solve, latex, symbols
from sympy import Matrix as matrix
init_printing()
    
In [ ]:
    
from sympy.abc import x, y, theta
trans(x, y, theta)
    
In [ ]:
    
N = 4
l = [symbols('l_%d' % i) for i in range(N + 1)]
l[0] = 0
a = [symbols('theta_%d' % i) for i in range(N)]
T0 = trans(0, 0, 0)
    
In [ ]:
    
l, a
    
In [ ]:
    
T0
    
In [ ]:
    
T = forward_kinematics(T0, l, a)
Te = T[-1]
Te
    
In [ ]:
    
Te = simplify(Te)
Te
    
In [2]:
    
eq = Te * trans(x, y, theta).inv() - T0
eq
    
    
In [3]:
    
eq = [a[0] + a[1] + a[2] - theta, eq[0, 2], eq[1, 2]]
eq
    
    
In [4]:
    
solve(eq, a)  # sympy is too stupid to solve it
    
    
In [5]:
    
b = [symbols('theta_%d' % i) for i in range(N)]
T3 = trans(x, y, theta) * trans(l[3], 0, 0).inv()
l_1_2 = T3[0,-1] ** 2 + T3[1,-1] ** 2
b_1_2 = acos((l[1] ** 2 + l[2] ** 2 - l_1_2) / (2 * l[1] * l[2]))  # cosine rule
b[1] = pi - b_1_2
b_1 = acos((l[1] ** 2 - l[2] ** 2 + l_1_2) / (2 * l[1] * sqrt(l_1_2)))  # cosine rule
b_0 = atan(T3[1,-1] / T3[0,-1])
b[0] = b_0 - b_1
b[2] = atan(T3[1,0] / T3[0,0]) - b[0] - b[1]
B = matrix([b]).T
B = simplify(B)
B
    
    
In [ ]:
    
print latex(B)
    
In [6]:
    
T_new = forward_kinematics(T0, l, b)
Te_new = T_new[-1]
Te_new
    
    
In [7]:
    
simplify(Te_new[0, 0])
    
    
In [8]:
    
simplify(Te_new[1, 0])
    
    
In [9]:
    
simplify(Te_new[0, -1])
    
    
In [10]:
    
from numpy import sin, cos, pi, matrix
from math import atan2, acos
T0 = trans(0, 0, 0)
lv = [0] + range(N, 0, -1)  # length of link, l[0] is ingored
bf = B
for i in range(N):
    bf = bf.subs(l[i + 1], lv[i + 1])
def inverse_kinematics(x_e, y_e, theta_e):
    b = bf.subs(x, x_e).subs(y, y_e).subs(theta, theta_e)
    b = (b.subs('I', 1).subs('pi', pi).tolist())
    b = [float(i[0]) for i in b]
    return b
    
@interact(x_e=(0, max_len, 0.1), y_e=(-max_len, max_len, 0.1), theta_e=(-pi, pi, 0.1))
def set_end_effector(x_e=6, y_e=0, theta_e=0):
    b = inverse_kinematics(x_e, y_e, theta_e)
    T = forward_kinematics(T0, lv, b)
    show_robot_arm(T)
    
    
In [11]:
    
from numpy import asarray
theta = asarray([0.1] * N)
def inverse_kinematics(x_e, y_e, theta_e, theta):
    target = matrix([[x_e, y_e, theta_e]])
    while True:
        T = forward_kinematics(T0, lv, theta)
        Te = matrix([from_trans(T[-1])])
        e = target - Te
        T = matrix([from_trans(i) for i in T[1:-1]])
        J = Te - T
        J = J.T
        J[-1, :] = 1
        JJT = J * J.T
        d_theta = 0.001 * J.T * JJT.I * e.T
        #print (d_theta.T * d_theta)[0, 0]
        theta += asarray(d_theta.T)[0]
        if (d_theta.T * d_theta)[0, 0] < 1e-6:
            break
    return theta
T = forward_kinematics(T0, lv, theta)
Te = matrix([from_trans(T[-1])])
@interact(x_e=(0, max_len, 0.01), y_e=(-max_len, max_len, 0.01), theta_e=(-pi, pi, 0.01), theta=fixed(theta))
def set_end_effector(x_e=Te[0,0], y_e=Te[0,1], theta_e=Te[0,2], theta=theta):
    theta = inverse_kinematics(x_e, y_e, theta_e, theta)
    T = forward_kinematics(T0, lv, theta)
    show_robot_arm(T)
    
    
In [ ]: