1+ """
2+ Move to specified pose
3+ Author: Daniel Ingram (daniel-s-ingram)
4+ Atsushi Sakai (@Atsushi_twi)
5+ Seied Muhammad Yazdian (@Muhammad-Yazdian)
6+ P. I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7
7+ """
8+
9+ import matplotlib .pyplot as plt
10+ import numpy as np
11+ from random import random
12+
13+
14+ class PathFinderController :
15+ """
16+ Constructs an instantiate of the PathFinderController for navigating a
17+ 3-DOF wheeled robot on a 2D plane
18+ Parameters
19+ ----------
20+ Kp_rho : The linear velocity gain to translate the robot along a line
21+ towards the goal
22+ Kp_alpha : The angular velocity gain to rotate the robot towards the goal
23+ Kp_beta : The offset angular velocity gain accounting for smooth merging to
24+ the goal angle (i.e., it helps the robot heading to be parallel
25+ to the target angle.)
26+ """
27+
28+ def __init__ (self , Kp_rho , Kp_alpha , Kp_beta ):
29+ self .Kp_rho = Kp_rho
30+ self .Kp_alpha = Kp_alpha
31+ self .Kp_beta = Kp_beta
32+
33+ def calc_control_command (self , x_diff , y_diff , theta , theta_goal ):
34+ """
35+ Returns the control command for the linear and angular velocities as
36+ well as the distance to goal
37+ Parameters
38+ ----------
39+ x_diff : The position of target with respect to current robot position
40+ in x direction
41+ y_diff : The position of target with respect to current robot position
42+ in y direction
43+ theta : The current heading angle of robot with respect to x axis
44+ theta_goal: The target angle of robot with respect to x axis
45+ Returns
46+ -------
47+ rho : The distance between the robot and the goal position
48+ v : Command linear velocity
49+ w : Command angular velocity
50+ """
51+
52+ # Description of local variables:
53+ # - alpha is the angle to the goal relative to the heading of the robot
54+ # - beta is the angle between the robot's position and the goal
55+ # position plus the goal angle
56+ # - Kp_rho*rho and Kp_alpha*alpha drive the robot along a line towards
57+ # the goal
58+ # - Kp_beta*beta rotates the line so that it is parallel to the goal
59+ # angle
60+ #
61+ # Note:
62+ # we restrict alpha and beta (angle differences) to the range
63+ # [-pi, pi] to prevent unstable behavior e.g. difference going
64+ # from 0 rad to 2*pi rad with slight turn
65+
66+ rho = np .hypot (x_diff , y_diff )
67+ alpha = (np .arctan2 (y_diff , x_diff )
68+ - theta + np .pi ) % (2 * np .pi ) - np .pi
69+ beta = (theta_goal - theta - alpha + np .pi ) % (2 * np .pi ) - np .pi
70+ v = self .Kp_rho * rho
71+ w = self .Kp_alpha * alpha - self .Kp_beta * beta
72+
73+ if alpha > np .pi / 2 or alpha < - np .pi / 2 :
74+ v = - v
75+
76+ return rho , v , w
77+
78+
79+ def move_to_pose (controller , x_start , y_start , theta_start , x_goal , y_goal , theta_goal , trajectory_color ):
80+ x = x_start
81+ y = y_start
82+ theta = theta_start
83+
84+ x_diff = x_goal - x
85+ y_diff = y_goal - y
86+
87+ x_traj , y_traj = [], []
88+
89+ rho = np .hypot (x_diff , y_diff )
90+ while rho > 0.003 or (abs (theta - theta_goal ) > 0.01 ):
91+ x_traj .append (x )
92+ y_traj .append (y )
93+
94+ x_diff = x_goal - x
95+ y_diff = y_goal - y
96+
97+ rho , v , w = controller .calc_control_command (
98+ x_diff , y_diff , theta , theta_goal )
99+
100+ if abs (v ) > MAX_LINEAR_SPEED :
101+ v = np .sign (v ) * MAX_LINEAR_SPEED
102+
103+ if abs (w ) > MAX_ANGULAR_SPEED :
104+ w = np .sign (w ) * MAX_ANGULAR_SPEED
105+
106+ theta = theta + w * dt
107+ x = x + v * np .cos (theta ) * dt
108+ y = y + v * np .sin (theta ) * dt
109+
110+ if show_animation : # pragma: no cover
111+ plt .cla ()
112+ plot_scene (x_start , y_start , theta_start ,
113+ x_goal , y_goal , theta_goal ,
114+ x , y , theta ,
115+ x_traj , y_traj ,
116+ trajectory_color )
117+
118+ plot_scene (x_start , y_start , theta_start ,
119+ x_goal , y_goal , theta_goal ,
120+ x , y , theta ,
121+ x_traj , y_traj ,
122+ trajectory_color )
123+
124+ def plot_scene (x_start , y_start , theta_start ,
125+ x_goal , y_goal , theta_goal ,
126+ x , y , theta ,
127+ x_traj , y_traj ,
128+ trajectory_color ):
129+ plt .text (10 , 10 , "diff_x = {:>2.2f}\n diff_y = {:>2.2f}\n diff_t = {:>2.2f}" .
130+ format (abs (x_goal - x ),
131+ abs (y_goal - y ),
132+ abs (theta_goal - theta )
133+ ))
134+ plt .arrow (x_start , y_start , np .cos (theta_start ),
135+ np .sin (theta_start ), color = 'r' , width = 0.1 )
136+ plt .arrow (x_goal , y_goal , np .cos (theta_goal ),
137+ np .sin (theta_goal ), color = 'g' , width = 0.1 )
138+ plot_vehicle (x , y , theta , x_traj , y_traj , trajectory_color )
139+
140+
141+ def plot_vehicle (x , y , theta , x_traj , y_traj , trajectory_color ): # pragma: no cover
142+ # Corners of triangular vehicle when pointing to the right (0 radians)
143+ p1_i = np .array ([0.5 , 0 , 1 ]).T
144+ p2_i = np .array ([- 0.5 , 0.25 , 1 ]).T
145+ p3_i = np .array ([- 0.5 , - 0.25 , 1 ]).T
146+
147+ T = transformation_matrix (x , y , theta )
148+ p1 = np .matmul (T , p1_i )
149+ p2 = np .matmul (T , p2_i )
150+ p3 = np .matmul (T , p3_i )
151+
152+ plt .plot ([p1 [0 ], p2 [0 ]], [p1 [1 ], p2 [1 ]], 'k-' )
153+ plt .plot ([p2 [0 ], p3 [0 ]], [p2 [1 ], p3 [1 ]], 'k-' )
154+ plt .plot ([p3 [0 ], p1 [0 ]], [p3 [1 ], p1 [1 ]], 'k-' )
155+
156+ plt .plot (x_traj , y_traj , trajectory_color )
157+
158+ # for stopping simulation with the esc key.
159+ plt .gcf ().canvas .mpl_connect (
160+ 'key_release_event' ,
161+ lambda event : [exit (0 ) if event .key == 'escape' else None ])
162+
163+ plt .xlim (0 , 20 )
164+ plt .ylim (0 , 20 )
165+
166+ plt .pause (dt )
167+
168+
169+ def transformation_matrix (x , y , theta ):
170+ return np .array ([
171+ [np .cos (theta ), - np .sin (theta ), x ],
172+ [np .sin (theta ), np .cos (theta ), y ],
173+ [0 , 0 , 1 ]
174+ ])
175+
176+ # Robot specifications
177+ MAX_LINEAR_SPEED = 15
178+ MAX_ANGULAR_SPEED = 8
179+
180+ # Animated or static visualisation
181+ show_animation = False
182+ dt = 0.005
183+
184+ def main ():
185+ x_start = 3.25
186+ y_start = 16.0
187+ theta_start = 0.38
188+ x_goal = 15
189+ y_goal = 2.5
190+ theta_goal = - 1.2
191+
192+ print ("Initial x: %.2f m\n Initial y: %.2f m\n Initial theta: %.2f rad\n " %
193+ (x_start , y_start , theta_start ))
194+ print ("Goal x: %.2f m\n Goal y: %.2f m\n Goal theta: %.2f rad\n " %
195+ (x_goal , y_goal , theta_goal ))
196+
197+ print ("Press Esc to stop." )
198+
199+ controller_A = PathFinderController (5 , 15 , 3 )
200+ move_to_pose (controller_A , x_start , y_start , theta_start , x_goal , y_goal , theta_goal , '--b' )
201+
202+ controller_B = PathFinderController (5 , 3 , 3 )
203+ move_to_pose (controller_B , x_start , y_start , theta_start , x_goal , y_goal , theta_goal , '--r' )
204+
205+ #plt.savefig('move_to_pose.png')
206+ plt .show ()
207+ print ("Aus die Maus" )
208+
209+ if __name__ == '__main__' :
210+ main ()
0 commit comments