5
5
Author: Daniel Ingram (daniel-s-ingram)
6
6
Atsushi Sakai (@Atsushi_twi)
7
7
Seied Muhammad Yazdian (@Muhammad-Yazdian)
8
+ Wang Zheng (@Aglargil)
8
9
9
10
P. I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7
10
11
11
12
"""
12
13
13
14
import matplotlib .pyplot as plt
14
15
import 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 ))
16
20
from utils .angle import angle_mod
21
+ from random import random
22
+
17
23
18
24
class PathFinderController :
19
25
"""
@@ -70,21 +76,28 @@ def calc_control_command(self, x_diff, y_diff, theta, theta_goal):
70
76
# [-pi, pi] to prevent unstable behavior e.g. difference going
71
77
# from 0 rad to 2*pi rad with slight turn
72
78
79
+ # Ref: The velocity v always has a constant sign which depends on the initial value of α.
73
80
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 )
76
81
v = self .Kp_rho * rho
77
- w = self .Kp_alpha * alpha - self .Kp_beta * beta
78
82
83
+ alpha = angle_mod (np .arctan2 (y_diff , x_diff ) - theta )
84
+ beta = angle_mod (theta_goal - theta - alpha )
79
85
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
80
90
v = - v
91
+ else :
92
+ w = self .Kp_alpha * alpha - self .Kp_beta * beta
81
93
82
94
return rho , v , w
83
95
84
96
85
97
# simulation parameters
86
98
controller = PathFinderController (9 , 15 , 3 )
87
99
dt = 0.01
100
+ MAX_SIM_TIME = 5 # seconds, robot will stop moving when time exceeds this value
88
101
89
102
# Robot specifications
90
103
MAX_LINEAR_SPEED = 15
@@ -101,37 +114,55 @@ def move_to_pose(x_start, y_start, theta_start, x_goal, y_goal, theta_goal):
101
114
x_diff = x_goal - x
102
115
y_diff = y_goal - y
103
116
104
- x_traj , y_traj = [], []
117
+ x_traj , y_traj , v_traj , w_traj = [x ], [y ], [ 0 ], [ 0 ]
105
118
106
119
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
108
123
x_traj .append (x )
109
124
y_traj .append (y )
110
125
111
126
x_diff = x_goal - x
112
127
y_diff = y_goal - y
113
128
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 )
116
130
117
131
if abs (v ) > MAX_LINEAR_SPEED :
118
132
v = np .sign (v ) * MAX_LINEAR_SPEED
119
133
120
134
if abs (w ) > MAX_ANGULAR_SPEED :
121
135
w = np .sign (w ) * MAX_ANGULAR_SPEED
122
136
137
+ v_traj .append (v )
138
+ w_traj .append (w )
139
+
123
140
theta = theta + w * dt
124
141
x = x + v * np .cos (theta ) * dt
125
142
y = y + v * np .sin (theta ) * dt
126
143
127
144
if show_animation : # pragma: no cover
128
145
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
+ )
133
162
plot_vehicle (x , y , theta , x_traj , y_traj )
134
163
164
+ return x_traj , y_traj , v_traj , w_traj
165
+
135
166
136
167
def plot_vehicle (x , y , theta , x_traj , y_traj ): # pragma: no cover
137
168
# 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
144
175
p2 = np .matmul (T , p2_i )
145
176
p3 = np .matmul (T , p3_i )
146
177
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-" )
150
181
151
- plt .plot (x_traj , y_traj , ' b--' )
182
+ plt .plot (x_traj , y_traj , " b--" )
152
183
153
184
# for stopping simulation with the esc key.
154
185
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
+ )
157
188
158
189
plt .xlim (0 , 20 )
159
190
plt .ylim (0 , 20 )
@@ -162,26 +193,31 @@ def plot_vehicle(x, y, theta, x_traj, y_traj): # pragma: no cover
162
193
163
194
164
195
def 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
+ )
170
203
171
204
172
205
def main ():
173
-
174
206
for i in range (5 ):
175
207
x_start = 20.0 * random ()
176
208
y_start = 20.0 * random ()
177
209
theta_start : float = 2 * np .pi * random () - np .pi
178
210
x_goal = 20 * random ()
179
211
y_goal = 20 * random ()
180
212
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
+ )
183
219
move_to_pose (x_start , y_start , theta_start , x_goal , y_goal , theta_goal )
184
220
185
221
186
- if __name__ == ' __main__' :
222
+ if __name__ == " __main__" :
187
223
main ()
0 commit comments