2
2
Inverse kinematics for an n-link arm using the Jacobian inverse method
3
3
4
4
Author: Daniel Ingram (daniel-s-ingram)
5
+ Atsushi Sakai (@Atsushi_twi)
5
6
"""
6
7
import matplotlib .pyplot as plt
7
8
import numpy as np
8
9
9
10
from NLinkArm import NLinkArm
10
11
11
- #Simulation parameters
12
+ # Simulation parameters
12
13
Kp = 2
13
14
dt = 0.1
14
15
N_LINKS = 10
15
16
N_ITERATIONS = 10000
16
17
17
- #States
18
+ # States
18
19
WAIT_FOR_NEW_GOAL = 1
19
20
MOVING_TO_GOAL = 2
20
21
21
- def n_link_arm_ik ():
22
+ show_animation = True
23
+
24
+
25
+ def main ():
22
26
"""
23
27
Creates an arm using the NLinkArm class and uses its inverse kinematics
24
28
to move it to the desired position.
25
29
"""
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 )
28
32
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 )
30
34
state = WAIT_FOR_NEW_GOAL
31
35
solution_found = False
32
36
while True :
@@ -35,10 +39,11 @@ def n_link_arm_ik():
35
39
end_effector = arm .end_effector
36
40
errors , distance = distance_to_goal (end_effector , goal_pos )
37
41
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
39
43
if state is WAIT_FOR_NEW_GOAL :
40
44
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 )
42
47
if not solution_found :
43
48
print ("Solution could not be found." )
44
49
state = WAIT_FOR_NEW_GOAL
@@ -47,13 +52,14 @@ def n_link_arm_ik():
47
52
state = MOVING_TO_GOAL
48
53
elif state is MOVING_TO_GOAL :
49
54
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
51
57
else :
52
58
state = WAIT_FOR_NEW_GOAL
53
59
solution_found = False
54
60
55
61
arm .update_joints (joint_angles )
56
-
62
+
57
63
58
64
def inverse_kinematics (link_lengths , joint_angles , goal_pos ):
59
65
"""
@@ -69,34 +75,90 @@ def inverse_kinematics(link_lengths, joint_angles, goal_pos):
69
75
joint_angles = joint_angles + np .matmul (J , errors )
70
76
return joint_angles , False
71
77
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
+
72
129
def forward_kinematics (link_lengths , joint_angles ):
73
130
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 ]))
77
134
return np .array ([x , y ]).T
78
135
136
+
79
137
def jacobian_inverse (link_lengths , joint_angles ):
80
138
J = np .zeros ((2 , N_LINKS ))
81
139
for i in range (N_LINKS ):
82
140
J [0 , i ] = 0
83
141
J [1 , i ] = 0
84
142
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 ]))
87
145
88
146
return np .linalg .pinv (J )
89
147
148
+
90
149
def distance_to_goal (current_pos , goal_pos ):
91
150
x_diff = goal_pos [0 ] - current_pos [0 ]
92
151
y_diff = goal_pos [1 ] - current_pos [1 ]
93
152
return np .array ([x_diff , y_diff ]).T , np .math .sqrt (x_diff ** 2 + y_diff ** 2 )
94
153
154
+
95
155
def ang_diff (theta1 , theta2 ):
96
156
"""
97
157
Returns the difference between two angles in the range -pi to +pi
98
158
"""
99
- return (theta1 - theta2 + np .pi )% (2 * np .pi ) - np .pi
159
+ return (theta1 - theta2 + np .pi ) % (2 * np .pi ) - np .pi
160
+
100
161
101
162
if __name__ == '__main__' :
102
- n_link_arm_ik ()
163
+ main ()
164
+ # animation()
0 commit comments