Skip to content

Commit fe8b329

Browse files
authored
Merge pull request AtsushiSakai#94 from daniel-s-ingram/master
Algorithm for moving to specified pose
2 parents 3ec87cd + 98441a2 commit fe8b329

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"""
2+
Move to specified pose
3+
Author: Daniel Ingram (daniel-s-ingram)
4+
5+
P. I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7
6+
"""
7+
8+
from __future__ import print_function, division
9+
10+
import matplotlib.pyplot as plt
11+
import numpy as np
12+
13+
from math import cos, sin, sqrt, atan2, pi
14+
from random import random
15+
16+
Kp_rho = 9
17+
Kp_alpha = 15
18+
Kp_beta = -3
19+
dt = 0.01
20+
21+
#Corners of triangular vehicle when pointing to the right (0 radians)
22+
p1_i = np.array([0.5, 0, 1]).T
23+
p2_i = np.array([-0.5, 0.25, 1]).T
24+
p3_i = np.array([-0.5, -0.25, 1]).T
25+
26+
x_traj = []
27+
y_traj = []
28+
29+
plt.ion()
30+
31+
def move_to_pose(x_start, y_start, theta_start, x_goal, y_goal, theta_goal):
32+
"""
33+
rho is the distance between the robot and the goal position
34+
alpha is the angle to the goal relative to the heading of the robot
35+
beta is the angle between the robot's position and the goal position plus the goal angle
36+
37+
Kp_rho*rho and Kp_alpha*alpha drive the robot along a line towards the goal
38+
Kp*beta*beta rotates the line so that it is parallel to the goal angle
39+
"""
40+
x = x_start
41+
y = y_start
42+
theta = theta_start
43+
44+
x_diff = x_goal - x
45+
y_diff = y_goal - y
46+
47+
rho = sqrt(x_diff**2 + y_diff**2)
48+
while rho > 0.001:
49+
x_traj.append(x)
50+
y_traj.append(y)
51+
52+
x_diff = x_goal - x
53+
y_diff = y_goal - y
54+
55+
"""
56+
Restrict alpha and beta (angle differences) to the range
57+
[-pi, pi] to prevent unstable behavior e.g. difference going
58+
from 0 rad to 2*pi rad with slight turn
59+
"""
60+
61+
rho = sqrt(x_diff**2 + y_diff**2)
62+
alpha = (atan2(y_diff, x_diff) - theta + pi)%(2*pi) - pi
63+
beta = (theta_goal - theta - alpha + pi)%(2*pi) - pi
64+
65+
v = Kp_rho*rho
66+
w = Kp_alpha*alpha + Kp_beta*beta
67+
68+
if alpha > pi/2 or alpha < -pi/2:
69+
v = -v
70+
71+
theta = theta + w*dt
72+
x = x + v*cos(theta)*dt
73+
y = y + v*sin(theta)*dt
74+
75+
plot_vehicle(x, y, theta, x_traj, y_traj)
76+
77+
78+
def plot_vehicle(x, y, theta, x_traj, y_traj):
79+
T = transformation_matrix(x, y, theta)
80+
p1 = np.matmul(T, p1_i)
81+
p2 = np.matmul(T, p2_i)
82+
p3 = np.matmul(T, p3_i)
83+
84+
plt.cla()
85+
86+
plt.plot([p1[0], p2[0]], [p1[1], p2[1]], 'k-')
87+
plt.plot([p2[0], p3[0]], [p2[1], p3[1]], 'k-')
88+
plt.plot([p3[0], p1[0]], [p3[1], p1[1]], 'k-')
89+
90+
plt.arrow(x_start, y_start, cos(theta_start), sin(theta_start), color='r', width=0.1)
91+
plt.arrow(x_goal, y_goal, cos(theta_goal), sin(theta_goal), color='g', width=0.1)
92+
plt.plot(x_traj, y_traj, 'b--')
93+
94+
plt.xlim(0, 20)
95+
plt.ylim(0, 20)
96+
97+
plt.show()
98+
plt.pause(dt)
99+
100+
def transformation_matrix(x, y, theta):
101+
return np.array([
102+
[cos(theta), -sin(theta), x],
103+
[sin(theta), cos(theta), y],
104+
[0, 0, 1]
105+
])
106+
107+
if __name__ == '__main__':
108+
x_start = 20*random()
109+
y_start = 20*random()
110+
theta_start = 2*pi*random() - pi
111+
x_goal = 20*random()
112+
y_goal = 20*random()
113+
theta_goal = 2*pi*random() - pi
114+
print("Initial x: %.2f m\nInitial y: %.2f m\nInitial theta: %.2f rad\n" % (x_start, y_start, theta_start))
115+
print("Goal x: %.2f m\nGoal y: %.2f m\nGoal theta: %.2f rad\n" % (x_goal, y_goal, theta_goal))
116+
move_to_pose(x_start, y_start, theta_start, x_goal, y_goal, theta_goal)

RoboticArm/two_joint_arm.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""
2+
Inverse kinematics of a two-joint arm
3+
Left-click the plot to set the goal position of the end effector
4+
5+
Author: Daniel Ingram (daniel-s-ingram)
6+
"""
7+
from __future__ import print_function, division
8+
9+
import matplotlib.pyplot as plt
10+
import numpy as np
11+
12+
from math import sin, cos, atan2, acos, pi
13+
14+
Kp = 15
15+
dt = 0.01
16+
17+
#Link lengths
18+
l1 = l2 = 1
19+
20+
shoulder = np.array([0, 0])
21+
22+
#Set initial goal position to the initial end-effector position
23+
x = 2
24+
y = 0
25+
26+
plt.ion()
27+
28+
def two_joint_arm():
29+
"""
30+
Computes the inverse kinematics for a planar 2DOF arm
31+
"""
32+
theta1 = theta2 = 0
33+
while True:
34+
try:
35+
theta2_goal = acos((x**2 + y**2 - l1**2 -l2**2)/(2*l1*l2))
36+
theta1_goal = atan2(y, x) - atan2(l2*sin(theta2_goal), (l1 + l2*cos(theta2_goal)))
37+
38+
if theta1_goal < 0:
39+
theta2_goal = -theta2_goal
40+
theta1_goal = atan2(y, x) - atan2(l2*sin(theta2_goal), (l1 + l2*cos(theta2_goal)))
41+
42+
theta1 = theta1 + Kp*ang_diff(theta1_goal, theta1)*dt
43+
theta2 = theta2 + Kp*ang_diff(theta2_goal, theta2)*dt
44+
except ValueError as e:
45+
print("Unreachable goal")
46+
47+
plot_arm(theta1, theta2, x, y)
48+
49+
def plot_arm(theta1, theta2, x, y):
50+
elbow = shoulder + np.array([l1*cos(theta1), l1*sin(theta1)])
51+
wrist = elbow + np.array([l2*cos(theta1+theta2), l2*sin(theta1+theta2)])
52+
53+
plt.cla()
54+
55+
plt.plot([shoulder[0], elbow[0]], [shoulder[1], elbow[1]], 'k-')
56+
plt.plot([elbow[0], wrist[0]], [elbow[1], wrist[1]], 'k-')
57+
58+
plt.plot(shoulder[0], shoulder[1], 'ro')
59+
plt.plot(elbow[0], elbow[1], 'ro')
60+
plt.plot(wrist[0], wrist[1], 'ro')
61+
62+
plt.plot([wrist[0], x], [wrist[1], y], 'g--')
63+
plt.plot(x, y, 'g*')
64+
65+
plt.xlim(-2, 2)
66+
plt.ylim(-2, 2)
67+
68+
plt.show()
69+
plt.pause(dt)
70+
71+
def ang_diff(theta1, theta2):
72+
#Returns the difference between two angles in the range -pi to +pi
73+
return (theta1-theta2+pi)%(2*pi)-pi
74+
75+
def click(event):
76+
global x, y
77+
x = event.xdata
78+
y = event.ydata
79+
80+
if __name__ == "__main__":
81+
fig = plt.figure()
82+
fig.canvas.mpl_connect("button_press_event", click)
83+
two_joint_arm()

0 commit comments

Comments
 (0)