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