1010
1111plt .ion ()
1212
13- #Simulation parameters
13+ # Simulation parameters
1414M = 100
1515obstacles = [[1.75 , 0.75 , 0.6 ], [0.55 , 1.5 , 0.5 ], [0 , - 1 , 0.25 ]]
1616
17+
1718def main ():
1819 arm = NLinkArm ([1 , 1 ], [0 , 0 ])
20+ start = (10 , 50 )
21+ goal = (58 , 56 )
1922 grid = get_occupancy_grid (arm , obstacles )
2023 plt .imshow (grid )
2124 plt .show ()
22- #(50,50) (58,56)
23- route = astar_torus (grid , (10 , 50 ), (58 , 56 ))
25+ route = astar_torus (grid , start , goal )
2426 for node in route :
25- theta1 = 2 * pi * node [0 ]/ M - pi
26- theta2 = 2 * pi * node [1 ]/ M - pi
27+ theta1 = 2 * pi * node [0 ] / M - pi
28+ theta2 = 2 * pi * node [1 ] / M - pi
2729 arm .update_joints ([theta1 , theta2 ])
2830 arm .plot (obstacles = obstacles )
2931
32+
3033def detect_collision (line_seg , circle ):
3134 """
3235 Determines whether a line segment (arm link) is in contact
@@ -48,18 +51,19 @@ def detect_collision(line_seg, circle):
4851 line_vec = b_vec - a_vec
4952 line_mag = np .linalg .norm (line_vec )
5053 circle_vec = c_vec - a_vec
51- proj = circle_vec .dot (line_vec / line_mag )
54+ proj = circle_vec .dot (line_vec / line_mag )
5255 if proj <= 0 :
5356 closest_point = a_vec
5457 elif proj >= line_mag :
5558 closest_point = b_vec
5659 else :
57- closest_point = a_vec + line_vec * proj / line_mag
58- if np .linalg .norm (closest_point - c_vec ) > radius :
60+ closest_point = a_vec + line_vec * proj / line_mag
61+ if np .linalg .norm (closest_point - c_vec ) > radius :
5962 return False
6063 else :
6164 return True
6265
66+
6367def get_occupancy_grid (arm , obstacles ):
6468 """
6569 Discretizes joint space into M values from -pi to +pi
@@ -76,23 +80,24 @@ def get_occupancy_grid(arm, obstacles):
7680 Occupancy grid in joint space
7781 """
7882 grid = [[0 for _ in range (M )] for _ in range (M )]
79- theta_list = [2 * i * pi / M for i in range (- M // 2 , M // 2 + 1 )]
83+ theta_list = [2 * i * pi / M for i in range (- M // 2 , M // 2 + 1 )]
8084 for i in range (M ):
8185 for j in range (M ):
8286 arm .update_joints ([theta_list [i ], theta_list [j ]])
8387 points = arm .points
8488 collision_detected = False
85- for k in range (len (points )- 1 ):
89+ for k in range (len (points ) - 1 ):
8690 for obstacle in obstacles :
87- line_seg = [points [k ], points [k + 1 ]]
91+ line_seg = [points [k ], points [k + 1 ]]
8892 collision_detected = detect_collision (line_seg , obstacle )
8993 if collision_detected :
9094 break
9195 if collision_detected :
92- break
96+ break
9397 grid [i ][j ] = int (collision_detected )
9498 return np .array (grid )
9599
100+
96101def astar_torus (grid , start_node , goal_node ):
97102 """
98103 Finds a path between an initial and goal joint configuration using
@@ -119,12 +124,12 @@ def astar_torus(grid, start_node, goal_node):
119124 heuristic_map = np .abs (X - goal_node [1 ]) + np .abs (Y - goal_node [0 ])
120125 for i in range (heuristic_map .shape [0 ]):
121126 for j in range (heuristic_map .shape [1 ]):
122- heuristic_map [i ,j ] = min (heuristic_map [i ,j ],
123- i + 1 + heuristic_map [M - 1 , j ],
124- M - i + heuristic_map [0 ,j ],
125- j + 1 + heuristic_map [i ,M - 1 ],
126- M - j + heuristic_map [i ,0 ]
127- )
127+ heuristic_map [i , j ] = min (heuristic_map [i , j ],
128+ i + 1 + heuristic_map [M - 1 , j ],
129+ M - i + heuristic_map [0 , j ],
130+ j + 1 + heuristic_map [i , M - 1 ],
131+ M - j + heuristic_map [i , 0 ]
132+ )
128133
129134 explored_heuristic_map = np .full ((M , M ), np .inf )
130135 distance_map = np .full ((M , M ), np .inf )
@@ -134,7 +139,8 @@ def astar_torus(grid, start_node, goal_node):
134139 grid [start_node ] = 4
135140 grid [goal_node ] = 5
136141
137- current_node = np .unravel_index (np .argmin (explored_heuristic_map , axis = None ), explored_heuristic_map .shape )
142+ current_node = np .unravel_index (
143+ np .argmin (explored_heuristic_map , axis = None ), explored_heuristic_map .shape )
138144 min_distance = np .min (explored_heuristic_map )
139145 if (current_node == goal_node ) or np .isinf (min_distance ):
140146 break
@@ -145,23 +151,23 @@ def astar_torus(grid, start_node, goal_node):
145151 i , j = current_node [0 ], current_node [1 ]
146152
147153 neighbors = []
148- if i - 1 >= 0 :
149- neighbors .append ((i - 1 , j ))
154+ if i - 1 >= 0 :
155+ neighbors .append ((i - 1 , j ))
150156 else :
151- neighbors .append ((M - 1 , j ))
157+ neighbors .append ((M - 1 , j ))
152158
153- if i + 1 < M :
154- neighbors .append ((i + 1 , j ))
159+ if i + 1 < M :
160+ neighbors .append ((i + 1 , j ))
155161 else :
156162 neighbors .append ((0 , j ))
157163
158- if j - 1 >= 0 :
159- neighbors .append ((i , j - 1 ))
164+ if j - 1 >= 0 :
165+ neighbors .append ((i , j - 1 ))
160166 else :
161- neighbors .append ((i , M - 1 ))
167+ neighbors .append ((i , M - 1 ))
162168
163- if j + 1 < M :
164- neighbors .append ((i , j + 1 ))
169+ if j + 1 < M :
170+ neighbors .append ((i , j + 1 ))
165171 else :
166172 neighbors .append ((i , 0 ))
167173
@@ -196,18 +202,20 @@ def astar_torus(grid, start_node, goal_node):
196202
197203 return route
198204
205+
199206class NLinkArm (object ):
200207 """
201208 Class for controlling and plotting a planar arm with an arbitrary number of links.
202209 """
210+
203211 def __init__ (self , link_lengths , joint_angles ):
204212 self .n_links = len (link_lengths )
205213 if self .n_links is not len (joint_angles ):
206214 raise ValueError ()
207215
208216 self .link_lengths = np .array (link_lengths )
209217 self .joint_angles = np .array (joint_angles )
210- self .points = [[0 , 0 ] for _ in range (self .n_links + 1 )]
218+ self .points = [[0 , 0 ] for _ in range (self .n_links + 1 )]
211219
212220 self .lim = sum (link_lengths )
213221 self .update_points ()
@@ -217,28 +225,35 @@ def update_joints(self, joint_angles):
217225 self .update_points ()
218226
219227 def update_points (self ):
220- for i in range (1 , self .n_links + 1 ):
221- self .points [i ][0 ] = self .points [i - 1 ][0 ] + self .link_lengths [i - 1 ]* np .cos (np .sum (self .joint_angles [:i ]))
222- self .points [i ][1 ] = self .points [i - 1 ][1 ] + self .link_lengths [i - 1 ]* np .sin (np .sum (self .joint_angles [:i ]))
228+ for i in range (1 , self .n_links + 1 ):
229+ self .points [i ][0 ] = self .points [i - 1 ][0 ] + \
230+ self .link_lengths [i - 1 ] * \
231+ np .cos (np .sum (self .joint_angles [:i ]))
232+ self .points [i ][1 ] = self .points [i - 1 ][1 ] + \
233+ self .link_lengths [i - 1 ] * \
234+ np .sin (np .sum (self .joint_angles [:i ]))
223235
224236 self .end_effector = np .array (self .points [self .n_links ]).T
225237
226238 def plot (self , obstacles = []):
227239 plt .cla ()
228240
229241 for obstacle in obstacles :
230- circle = plt .Circle ((obstacle [0 ], obstacle [1 ]), radius = 0.5 * obstacle [2 ], fc = 'k' )
242+ circle = plt .Circle (
243+ (obstacle [0 ], obstacle [1 ]), radius = 0.5 * obstacle [2 ], fc = 'k' )
231244 plt .gca ().add_patch (circle )
232245
233- for i in range (self .n_links + 1 ):
246+ for i in range (self .n_links + 1 ):
234247 if i is not self .n_links :
235- plt .plot ([self .points [i ][0 ], self .points [i + 1 ][0 ]], [self .points [i ][1 ], self .points [i + 1 ][1 ]], 'r-' )
248+ plt .plot ([self .points [i ][0 ], self .points [i + 1 ][0 ]],
249+ [self .points [i ][1 ], self .points [i + 1 ][1 ]], 'r-' )
236250 plt .plot (self .points [i ][0 ], self .points [i ][1 ], 'k.' )
237251
238252 plt .xlim ([- self .lim , self .lim ])
239253 plt .ylim ([- self .lim , self .lim ])
240254 plt .draw ()
241255 plt .pause (1e-5 )
242256
257+
243258if __name__ == '__main__' :
244259 main ()
0 commit comments