Skip to content

Commit cf4ab5a

Browse files
committed
add animation
1 parent 6509bdb commit cf4ab5a

File tree

3 files changed

+103
-30
lines changed

3 files changed

+103
-30
lines changed

ArmNavigation/n_joint_to_point_control/NLinkArm.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,61 @@
77
import numpy as np
88
import matplotlib.pyplot as plt
99

10+
1011
class NLinkArm(object):
11-
def __init__(self, link_lengths, joint_angles, goal):
12+
def __init__(self, link_lengths, joint_angles, goal, show_animation):
13+
self.show_animation = show_animation
1214
self.n_links = len(link_lengths)
1315
if self.n_links is not len(joint_angles):
1416
raise ValueError()
1517

1618
self.link_lengths = np.array(link_lengths)
1719
self.joint_angles = np.array(joint_angles)
18-
self.points = [[0, 0] for _ in range(self.n_links+1)]
20+
self.points = [[0, 0] for _ in range(self.n_links + 1)]
1921

2022
self.lim = sum(link_lengths)
2123
self.goal = np.array(goal).T
2224

23-
self.fig = plt.figure()
24-
self.fig.canvas.mpl_connect('button_press_event', self.click)
25+
if show_animation:
26+
self.fig = plt.figure()
27+
self.fig.canvas.mpl_connect('button_press_event', self.click)
2528

26-
plt.ion()
27-
plt.show()
29+
plt.ion()
30+
plt.show()
2831

2932
self.update_points()
3033

3134
def update_joints(self, joint_angles):
3235
self.joint_angles = joint_angles
36+
3337
self.update_points()
3438

3539
def update_points(self):
36-
for i in range(1, self.n_links+1):
37-
self.points[i][0] = self.points[i-1][0] + self.link_lengths[i-1]*np.cos(np.sum(self.joint_angles[:i]))
38-
self.points[i][1] = self.points[i-1][1] + self.link_lengths[i-1]*np.sin(np.sum(self.joint_angles[:i]))
40+
for i in range(1, self.n_links + 1):
41+
self.points[i][0] = self.points[i - 1][0] + \
42+
self.link_lengths[i - 1] * \
43+
np.cos(np.sum(self.joint_angles[:i]))
44+
self.points[i][1] = self.points[i - 1][1] + \
45+
self.link_lengths[i - 1] * \
46+
np.sin(np.sum(self.joint_angles[:i]))
3947

4048
self.end_effector = np.array(self.points[self.n_links]).T
41-
self.plot()
49+
if self.show_animation:
50+
self.plot()
4251

4352
def plot(self):
4453
plt.cla()
4554

46-
for i in range(self.n_links+1):
55+
for i in range(self.n_links + 1):
4756
if i is not self.n_links:
48-
plt.plot([self.points[i][0], self.points[i+1][0]], [self.points[i][1], self.points[i+1][1]], 'r-')
57+
plt.plot([self.points[i][0], self.points[i + 1][0]],
58+
[self.points[i][1], self.points[i + 1][1]], 'r-')
4959
plt.plot(self.points[i][0], self.points[i][1], 'ko')
5060

5161
plt.plot(self.goal[0], self.goal[1], 'gx')
5262

53-
plt.plot([self.end_effector[0], self.goal[0]], [self.end_effector[1], self.goal[1]], 'g--')
63+
plt.plot([self.end_effector[0], self.goal[0]], [
64+
self.end_effector[1], self.goal[1]], 'g--')
5465

5566
plt.xlim([-self.lim, self.lim])
5667
plt.ylim([-self.lim, self.lim])
1.49 MB
Loading

ArmNavigation/n_joint_to_point_control/n_joint_to_point_control.py

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,35 @@
22
Inverse kinematics for an n-link arm using the Jacobian inverse method
33
44
Author: Daniel Ingram (daniel-s-ingram)
5+
Atsushi Sakai (@Atsushi_twi)
56
"""
67
import matplotlib.pyplot as plt
78
import numpy as np
89

910
from NLinkArm import NLinkArm
1011

11-
#Simulation parameters
12+
# Simulation parameters
1213
Kp = 2
1314
dt = 0.1
1415
N_LINKS = 10
1516
N_ITERATIONS = 10000
1617

17-
#States
18+
# States
1819
WAIT_FOR_NEW_GOAL = 1
1920
MOVING_TO_GOAL = 2
2021

21-
def n_link_arm_ik():
22+
show_animation = True
23+
24+
25+
def main():
2226
"""
2327
Creates an arm using the NLinkArm class and uses its inverse kinematics
2428
to move it to the desired position.
2529
"""
26-
link_lengths = [1]*N_LINKS
27-
joint_angles = np.array([0]*N_LINKS)
30+
link_lengths = [1] * N_LINKS
31+
joint_angles = np.array([0] * N_LINKS)
2832
goal_pos = [N_LINKS, 0]
29-
arm = NLinkArm(link_lengths, joint_angles, goal_pos)
33+
arm = NLinkArm(link_lengths, joint_angles, goal_pos, show_animation)
3034
state = WAIT_FOR_NEW_GOAL
3135
solution_found = False
3236
while True:
@@ -35,10 +39,11 @@ def n_link_arm_ik():
3539
end_effector = arm.end_effector
3640
errors, distance = distance_to_goal(end_effector, goal_pos)
3741

38-
#State machine to allow changing of goal before current goal has been reached
42+
# State machine to allow changing of goal before current goal has been reached
3943
if state is WAIT_FOR_NEW_GOAL:
4044
if distance > 0.1 and not solution_found:
41-
joint_goal_angles, solution_found = inverse_kinematics(link_lengths, joint_angles, goal_pos)
45+
joint_goal_angles, solution_found = inverse_kinematics(
46+
link_lengths, joint_angles, goal_pos)
4247
if not solution_found:
4348
print("Solution could not be found.")
4449
state = WAIT_FOR_NEW_GOAL
@@ -47,13 +52,14 @@ def n_link_arm_ik():
4752
state = MOVING_TO_GOAL
4853
elif state is MOVING_TO_GOAL:
4954
if distance > 0.1 and (old_goal is goal_pos):
50-
joint_angles = joint_angles + Kp*ang_diff(joint_goal_angles, joint_angles)*dt
55+
joint_angles = joint_angles + Kp * \
56+
ang_diff(joint_goal_angles, joint_angles) * dt
5157
else:
5258
state = WAIT_FOR_NEW_GOAL
5359
solution_found = False
5460

5561
arm.update_joints(joint_angles)
56-
62+
5763

5864
def inverse_kinematics(link_lengths, joint_angles, goal_pos):
5965
"""
@@ -69,34 +75,90 @@ def inverse_kinematics(link_lengths, joint_angles, goal_pos):
6975
joint_angles = joint_angles + np.matmul(J, errors)
7076
return joint_angles, False
7177

78+
79+
def get_random_goal():
80+
from random import random
81+
SAREA = 15.0
82+
return [SAREA * random() - SAREA / 2.0,
83+
SAREA * random() - SAREA / 2.0]
84+
85+
86+
def animation():
87+
link_lengths = [1] * N_LINKS
88+
joint_angles = np.array([0] * N_LINKS)
89+
goal_pos = get_random_goal()
90+
arm = NLinkArm(link_lengths, joint_angles, goal_pos, show_animation)
91+
state = WAIT_FOR_NEW_GOAL
92+
solution_found = False
93+
94+
i_goal = 0
95+
while True:
96+
old_goal = goal_pos
97+
goal_pos = arm.goal
98+
end_effector = arm.end_effector
99+
errors, distance = distance_to_goal(end_effector, goal_pos)
100+
101+
# State machine to allow changing of goal before current goal has been reached
102+
if state is WAIT_FOR_NEW_GOAL:
103+
104+
if distance > 0.1 and not solution_found:
105+
joint_goal_angles, solution_found = inverse_kinematics(
106+
link_lengths, joint_angles, goal_pos)
107+
if not solution_found:
108+
print("Solution could not be found.")
109+
state = WAIT_FOR_NEW_GOAL
110+
arm.goal = get_random_goal()
111+
elif solution_found:
112+
state = MOVING_TO_GOAL
113+
elif state is MOVING_TO_GOAL:
114+
if distance > 0.1 and (old_goal is goal_pos):
115+
joint_angles = joint_angles + Kp * \
116+
ang_diff(joint_goal_angles, joint_angles) * dt
117+
else:
118+
state = WAIT_FOR_NEW_GOAL
119+
solution_found = False
120+
arm.goal = get_random_goal()
121+
i_goal += 1
122+
123+
if i_goal >= 5:
124+
break
125+
126+
arm.update_joints(joint_angles)
127+
128+
72129
def forward_kinematics(link_lengths, joint_angles):
73130
x = y = 0
74-
for i in range(1, N_LINKS+1):
75-
x += link_lengths[i-1]*np.cos(np.sum(joint_angles[:i]))
76-
y += link_lengths[i-1]*np.sin(np.sum(joint_angles[:i]))
131+
for i in range(1, N_LINKS + 1):
132+
x += link_lengths[i - 1] * np.cos(np.sum(joint_angles[:i]))
133+
y += link_lengths[i - 1] * np.sin(np.sum(joint_angles[:i]))
77134
return np.array([x, y]).T
78135

136+
79137
def jacobian_inverse(link_lengths, joint_angles):
80138
J = np.zeros((2, N_LINKS))
81139
for i in range(N_LINKS):
82140
J[0, i] = 0
83141
J[1, i] = 0
84142
for j in range(i, N_LINKS):
85-
J[0, i] -= link_lengths[j]*np.sin(np.sum(joint_angles[:j]))
86-
J[1, i] += link_lengths[j]*np.cos(np.sum(joint_angles[:j]))
143+
J[0, i] -= link_lengths[j] * np.sin(np.sum(joint_angles[:j]))
144+
J[1, i] += link_lengths[j] * np.cos(np.sum(joint_angles[:j]))
87145

88146
return np.linalg.pinv(J)
89147

148+
90149
def distance_to_goal(current_pos, goal_pos):
91150
x_diff = goal_pos[0] - current_pos[0]
92151
y_diff = goal_pos[1] - current_pos[1]
93152
return np.array([x_diff, y_diff]).T, np.math.sqrt(x_diff**2 + y_diff**2)
94153

154+
95155
def ang_diff(theta1, theta2):
96156
"""
97157
Returns the difference between two angles in the range -pi to +pi
98158
"""
99-
return (theta1 - theta2 + np.pi)%(2*np.pi) - np.pi
159+
return (theta1 - theta2 + np.pi) % (2 * np.pi) - np.pi
160+
100161

101162
if __name__ == '__main__':
102-
n_link_arm_ik()
163+
main()
164+
# animation()

0 commit comments

Comments
 (0)