55Author: Daniel Ingram (daniel-s-ingram)
66 Atsushi Sakai (@Atsushi_twi)
77 Seied Muhammad Yazdian (@Muhammad-Yazdian)
8+ Wang Zheng (@Aglargil)
89
910P. I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7
1011
1112"""
1213
1314import matplotlib .pyplot as plt
1415import numpy as np
15- from random import random
16+ import sys
17+ import pathlib
18+
19+ sys .path .append (str (pathlib .Path (__file__ ).parent .parent .parent ))
1620from utils .angle import angle_mod
21+ from random import random
22+
1723
1824class PathFinderController :
1925 """
@@ -70,21 +76,28 @@ def calc_control_command(self, x_diff, y_diff, theta, theta_goal):
7076 # [-pi, pi] to prevent unstable behavior e.g. difference going
7177 # from 0 rad to 2*pi rad with slight turn
7278
79+ # Ref: The velocity v always has a constant sign which depends on the initial value of α.
7380 rho = np .hypot (x_diff , y_diff )
74- alpha = angle_mod (np .arctan2 (y_diff , x_diff ) - theta )
75- beta = angle_mod (theta_goal - theta - alpha )
7681 v = self .Kp_rho * rho
77- w = self .Kp_alpha * alpha - self .Kp_beta * beta
7882
83+ alpha = angle_mod (np .arctan2 (y_diff , x_diff ) - theta )
84+ beta = angle_mod (theta_goal - theta - alpha )
7985 if alpha > np .pi / 2 or alpha < - np .pi / 2 :
86+ # recalculate alpha to make alpha in the range of [-pi/2, pi/2]
87+ alpha = angle_mod (np .arctan2 (- y_diff , - x_diff ) - theta )
88+ beta = angle_mod (theta_goal - theta - alpha )
89+ w = self .Kp_alpha * alpha - self .Kp_beta * beta
8090 v = - v
91+ else :
92+ w = self .Kp_alpha * alpha - self .Kp_beta * beta
8193
8294 return rho , v , w
8395
8496
8597# simulation parameters
8698controller = PathFinderController (9 , 15 , 3 )
8799dt = 0.01
100+ MAX_SIM_TIME = 5 # seconds, robot will stop moving when time exceeds this value
88101
89102# Robot specifications
90103MAX_LINEAR_SPEED = 15
@@ -101,37 +114,55 @@ def move_to_pose(x_start, y_start, theta_start, x_goal, y_goal, theta_goal):
101114 x_diff = x_goal - x
102115 y_diff = y_goal - y
103116
104- x_traj , y_traj = [], []
117+ x_traj , y_traj , v_traj , w_traj = [x ], [y ], [ 0 ], [ 0 ]
105118
106119 rho = np .hypot (x_diff , y_diff )
107- while rho > 0.001 :
120+ t = 0
121+ while rho > 0.001 and t < MAX_SIM_TIME :
122+ t += dt
108123 x_traj .append (x )
109124 y_traj .append (y )
110125
111126 x_diff = x_goal - x
112127 y_diff = y_goal - y
113128
114- rho , v , w = controller .calc_control_command (
115- x_diff , y_diff , theta , theta_goal )
129+ rho , v , w = controller .calc_control_command (x_diff , y_diff , theta , theta_goal )
116130
117131 if abs (v ) > MAX_LINEAR_SPEED :
118132 v = np .sign (v ) * MAX_LINEAR_SPEED
119133
120134 if abs (w ) > MAX_ANGULAR_SPEED :
121135 w = np .sign (w ) * MAX_ANGULAR_SPEED
122136
137+ v_traj .append (v )
138+ w_traj .append (w )
139+
123140 theta = theta + w * dt
124141 x = x + v * np .cos (theta ) * dt
125142 y = y + v * np .sin (theta ) * dt
126143
127144 if show_animation : # pragma: no cover
128145 plt .cla ()
129- plt .arrow (x_start , y_start , np .cos (theta_start ),
130- np .sin (theta_start ), color = 'r' , width = 0.1 )
131- plt .arrow (x_goal , y_goal , np .cos (theta_goal ),
132- np .sin (theta_goal ), color = 'g' , width = 0.1 )
146+ plt .arrow (
147+ x_start ,
148+ y_start ,
149+ np .cos (theta_start ),
150+ np .sin (theta_start ),
151+ color = "r" ,
152+ width = 0.1 ,
153+ )
154+ plt .arrow (
155+ x_goal ,
156+ y_goal ,
157+ np .cos (theta_goal ),
158+ np .sin (theta_goal ),
159+ color = "g" ,
160+ width = 0.1 ,
161+ )
133162 plot_vehicle (x , y , theta , x_traj , y_traj )
134163
164+ return x_traj , y_traj , v_traj , w_traj
165+
135166
136167def plot_vehicle (x , y , theta , x_traj , y_traj ): # pragma: no cover
137168 # Corners of triangular vehicle when pointing to the right (0 radians)
@@ -144,16 +175,16 @@ def plot_vehicle(x, y, theta, x_traj, y_traj): # pragma: no cover
144175 p2 = np .matmul (T , p2_i )
145176 p3 = np .matmul (T , p3_i )
146177
147- plt .plot ([p1 [0 ], p2 [0 ]], [p1 [1 ], p2 [1 ]], 'k-' )
148- plt .plot ([p2 [0 ], p3 [0 ]], [p2 [1 ], p3 [1 ]], 'k-' )
149- plt .plot ([p3 [0 ], p1 [0 ]], [p3 [1 ], p1 [1 ]], 'k-' )
178+ plt .plot ([p1 [0 ], p2 [0 ]], [p1 [1 ], p2 [1 ]], "k-" )
179+ plt .plot ([p2 [0 ], p3 [0 ]], [p2 [1 ], p3 [1 ]], "k-" )
180+ plt .plot ([p3 [0 ], p1 [0 ]], [p3 [1 ], p1 [1 ]], "k-" )
150181
151- plt .plot (x_traj , y_traj , ' b--' )
182+ plt .plot (x_traj , y_traj , " b--" )
152183
153184 # for stopping simulation with the esc key.
154185 plt .gcf ().canvas .mpl_connect (
155- ' key_release_event' ,
156- lambda event : [ exit ( 0 ) if event . key == 'escape' else None ] )
186+ " key_release_event" , lambda event : [ exit ( 0 ) if event . key == "escape" else None ]
187+ )
157188
158189 plt .xlim (0 , 20 )
159190 plt .ylim (0 , 20 )
@@ -162,26 +193,31 @@ def plot_vehicle(x, y, theta, x_traj, y_traj): # pragma: no cover
162193
163194
164195def transformation_matrix (x , y , theta ):
165- return np .array ([
166- [np .cos (theta ), - np .sin (theta ), x ],
167- [np .sin (theta ), np .cos (theta ), y ],
168- [0 , 0 , 1 ]
169- ])
196+ return np .array (
197+ [
198+ [np .cos (theta ), - np .sin (theta ), x ],
199+ [np .sin (theta ), np .cos (theta ), y ],
200+ [0 , 0 , 1 ],
201+ ]
202+ )
170203
171204
172205def main ():
173-
174206 for i in range (5 ):
175207 x_start = 20.0 * random ()
176208 y_start = 20.0 * random ()
177209 theta_start : float = 2 * np .pi * random () - np .pi
178210 x_goal = 20 * random ()
179211 y_goal = 20 * random ()
180212 theta_goal = 2 * np .pi * random () - np .pi
181- print (f"Initial x: { round (x_start , 2 )} m\n Initial y: { round (y_start , 2 )} m\n Initial theta: { round (theta_start , 2 )} rad\n " )
182- print (f"Goal x: { round (x_goal , 2 )} m\n Goal y: { round (y_goal , 2 )} m\n Goal theta: { round (theta_goal , 2 )} rad\n " )
213+ print (
214+ f"Initial x: { round (x_start , 2 )} m\n Initial y: { round (y_start , 2 )} m\n Initial theta: { round (theta_start , 2 )} rad\n "
215+ )
216+ print (
217+ f"Goal x: { round (x_goal , 2 )} m\n Goal y: { round (y_goal , 2 )} m\n Goal theta: { round (theta_goal , 2 )} rad\n "
218+ )
183219 move_to_pose (x_start , y_start , theta_start , x_goal , y_goal , theta_goal )
184220
185221
186- if __name__ == ' __main__' :
222+ if __name__ == " __main__" :
187223 main ()
0 commit comments