1515import time
1616import os
1717
18- #
1918# Vehicle steering dynamics
20- #
21- # The vehicle dynamics are given by a simple bicycle model. We take the state
22- # of the system as (x, y, theta) where (x, y) is the position of the vehicle
23- # in the plane and theta is the angle of the vehicle with respect to
24- # horizontal. The vehicle input is given by (v, phi) where v is the forward
25- # velocity of the vehicle and phi is the angle of the steering wheel. The
26- # model includes saturation of the vehicle steering angle.
27- #
28- # System state: x, y, theta
29- # System input: v, phi
30- # System output: x, y
31- # System parameters: wheelbase, maxsteer
32- #
3319def vehicle_update (t , x , u , params ):
3420 # Get the parameters for the model
3521 l = params .get ('wheelbase' , 3. ) # vehicle wheelbase
@@ -45,14 +31,14 @@ def vehicle_update(t, x, u, params):
4531 (u [0 ] / l ) * math .tan (phi ) # thdot = v/l tan(phi)
4632 ])
4733
48-
4934def vehicle_output (t , x , u , params ):
5035 return x # return x, y, theta (full state)
5136
5237vehicle = ct .NonlinearIOSystem (
5338 vehicle_update , vehicle_output , states = 3 , name = 'vehicle' ,
5439 inputs = ('v' , 'phi' ), outputs = ('x' , 'y' , 'theta' ))
5540
41+ # Initial and final conditions
5642x0 = [0. , - 2. , 0. ]; u0 = [10. , 0. ]
5743xf = [100. , 2. , 0. ]; uf = [10. , 0. ]
5844Tf = 10
@@ -63,7 +49,7 @@ def vehicle_output(t, x, u, params):
6349# Provide an intial guess (will be extended to entire horizon)
6450bend_left = [10 , 0.01 ] # slight left veer
6551
66- def time_integrated_cost ():
52+ def time_steering_integrated_cost ():
6753 # Set up the cost functions
6854 Q = np .diag ([.1 , 10 , .1 ]) # keep lateral error low
6955 R = np .diag ([.1 , 1 ]) # minimize applied inputs
@@ -81,7 +67,7 @@ def time_integrated_cost():
8167 # Only count this as a benchmark if we converged
8268 assert res .success
8369
84- def time_terminal_cost ():
70+ def time_steering_terminal_cost ():
8571 # Define cost and constraints
8672 traj_cost = opt .quadratic_cost (
8773 vehicle , None , np .diag ([0.1 , 1 ]), u0 = uf )
@@ -93,14 +79,35 @@ def time_terminal_cost():
9379 res = opt .solve_ocp (
9480 vehicle , horizon , x0 , traj_cost , constraints ,
9581 terminal_cost = term_cost , initial_guess = bend_left , print_summary = False ,
96- # solve_ivp_kwargs={'atol': 1e-4, 'rtol': 1e-2},
97- minimize_method = 'SLSQP' , minimize_options = {'eps' : 0.01 }
82+ solve_ivp_kwargs = {'atol' : 1e-4 , 'rtol' : 1e-2 },
83+ # minimize_method='SLSQP', minimize_options={'eps': 0.01}
84+ minimize_method = 'trust-constr' ,
85+ minimize_options = {'finite_diff_rel_step' : 0.01 },
9886 )
99-
10087 # Only count this as a benchmark if we converged
10188 assert res .success
10289
103- def time_terminal_constraint ():
90+ # Define integrator and minimizer methods and options/keywords
91+ integrator_table = {
92+ 'RK23_default' : ('RK23' , {'atol' : 1e-4 , 'rtol' : 1e-2 }),
93+ 'RK23_sloppy' : ('RK23' , {}),
94+ 'RK45_default' : ('RK45' , {}),
95+ 'RK45_sloppy' : ('RK45' , {'atol' : 1e-4 , 'rtol' : 1e-2 }),
96+ }
97+
98+ minimizer_table = {
99+ 'trust_default' : ('trust-constr' , {}),
100+ 'trust_bigstep' : ('trust-constr' , {'finite_diff_rel_step' : 0.01 }),
101+ 'SLSQP_default' : ('SLSQP' , {}),
102+ 'SLSQP_bigstep' : ('SLSQP' , {'eps' : 0.01 }),
103+ }
104+
105+
106+ def time_steering_terminal_constraint (integrator_name , minimizer_name ):
107+ # Get the integrator and minimizer parameters to use
108+ integrator = integrator_table [integrator_name ]
109+ minimizer = minimizer_table [minimizer_name ]
110+
104111 # Input cost and terminal constraints
105112 R = np .diag ([1 , 1 ]) # minimize applied inputs
106113 cost = opt .quadratic_cost (vehicle , np .zeros ((3 ,3 )), R , u0 = uf )
@@ -111,58 +118,59 @@ def time_terminal_constraint():
111118 res = opt .solve_ocp (
112119 vehicle , horizon , x0 , cost , constraints ,
113120 terminal_constraints = terminal , initial_guess = bend_left , log = False ,
114- solve_ivp_kwargs = {'atol' : 1e-3 , 'rtol' : 1e-2 },
115- # solve_ivp_kwargs={'atol': 1e-4, 'rtol': 1e-2},
116- minimize_method = 'trust-constr' ,
117- # minimize_method='SLSQP', minimize_options={'eps': 0.01}
121+ solve_ivp_method = integrator [0 ], solve_ivp_kwargs = integrator [1 ],
122+ minimize_method = minimizer [0 ], minimize_options = minimizer [1 ],
118123 )
119-
120124 # Only count this as a benchmark if we converged
121125 assert res .success
122126
123127# Reset the timeout value to allow for longer runs
124- time_terminal_constraint .timeout = 120
128+ time_steering_terminal_constraint .timeout = 120
129+
130+ # Parameterize the test against different choices of integrator and minimizer
131+ time_steering_terminal_constraint .param_names = ['integrator' , 'minimizer' ]
132+ time_steering_terminal_constraint .params = (
133+ ['RK23_default' , 'RK23_sloppy' , 'RK45_default' , 'RK45_sloppy' ],
134+ ['trust_default' , 'trust_bigstep' , 'SLSQP_default' , 'SLSQP_bigstep' ]
135+ )
125136
126- def time_optimal_basis_vehicle ( ):
137+ def time_steering_bezier_basis ( nbasis , ntimes ):
127138 # Set up costs and constriants
128139 Q = np .diag ([.1 , 10 , .1 ]) # keep lateral error low
129140 R = np .diag ([1 , 1 ]) # minimize applied inputs
130141 cost = opt .quadratic_cost (vehicle , Q , R , x0 = xf , u0 = uf )
131142 constraints = [ opt .input_range_constraint (vehicle , [0 , - 0.1 ], [20 , 0.1 ]) ]
132143 terminal = [ opt .state_range_constraint (vehicle , xf , xf ) ]
133- bend_left = [10 , 0.05 ] # slight left veer
134- near_optimal = [
135- [ 1.15073736e+01 , 1.16838616e+01 , 1.15413395e+01 ,
136- 1.11585544e+01 , 1.06142537e+01 , 9.98718468e+00 ,
137- 9.35609454e+00 , 8.79973057e+00 , 8.39684004e+00 ,
138- 8.22617023e+00 ],
139- [ - 9.99830506e-02 , 8.98139594e-03 , 5.26385615e-02 ,
140- 4.96635954e-02 , 1.87316470e-02 , - 2.14821345e-02 ,
141- - 5.23025996e-02 , - 5.50545990e-02 , - 1.10629834e-02 ,
142- 9.83473965e-02 ] ]
143144
144145 # Set up horizon
145- horizon = np .linspace (0 , Tf , 10 , endpoint = True )
146+ horizon = np .linspace (0 , Tf , ntimes , endpoint = True )
146147
147148 # Set up the optimal control problem
148149 res = opt .solve_ocp (
149150 vehicle , horizon , x0 , cost ,
150151 constraints ,
151152 terminal_constraints = terminal ,
152- initial_guess = near_optimal ,
153- basis = flat .BezierFamily (4 , T = Tf ),
153+ initial_guess = bend_left ,
154+ basis = flat .BezierFamily (nbasis , T = Tf ),
155+ # solve_ivp_kwargs={'atol': 1e-4, 'rtol': 1e-2},
154156 minimize_method = 'trust-constr' ,
157+ minimize_options = {'finite_diff_rel_step' : 0.01 },
155158 # minimize_method='SLSQP', minimize_options={'eps': 0.01},
156- solve_ivp_kwargs = {'atol' : 1e-4 , 'rtol' : 1e-2 },
157159 return_states = True , print_summary = False
158160 )
159161 t , u , x = res .time , res .inputs , res .states
160162
161163 # Make sure we found a valid solution
162164 assert res .success
163- np .testing .assert_almost_equal (x [:, - 1 ], xf , decimal = 4 )
164165
165- def time_mpc_iosystem ():
166+ # Reset the timeout value to allow for longer runs
167+ time_steering_bezier_basis .timeout = 120
168+
169+ # Set the parameter values for the number of times and basis vectors
170+ time_steering_bezier_basis .param_names = ['nbasis' , 'ntimes' ]
171+ time_steering_bezier_basis .params = ([2 , 4 , 6 ], [5 , 10 , 20 ])
172+
173+ def time_aircraft_mpc ():
166174 # model of an aircraft discretized with 0.2s sampling time
167175 # Source: https://www.mpt3.org/UI/RegulationProblem
168176 A = [[0.99 , 0.01 , 0.18 , - 0.09 , 0 ],
0 commit comments