15
15
import time
16
16
import os
17
17
18
- #
19
18
# 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
- #
33
19
def vehicle_update (t , x , u , params ):
34
20
# Get the parameters for the model
35
21
l = params .get ('wheelbase' , 3. ) # vehicle wheelbase
@@ -45,14 +31,14 @@ def vehicle_update(t, x, u, params):
45
31
(u [0 ] / l ) * math .tan (phi ) # thdot = v/l tan(phi)
46
32
])
47
33
48
-
49
34
def vehicle_output (t , x , u , params ):
50
35
return x # return x, y, theta (full state)
51
36
52
37
vehicle = ct .NonlinearIOSystem (
53
38
vehicle_update , vehicle_output , states = 3 , name = 'vehicle' ,
54
39
inputs = ('v' , 'phi' ), outputs = ('x' , 'y' , 'theta' ))
55
40
41
+ # Initial and final conditions
56
42
x0 = [0. , - 2. , 0. ]; u0 = [10. , 0. ]
57
43
xf = [100. , 2. , 0. ]; uf = [10. , 0. ]
58
44
Tf = 10
@@ -63,7 +49,7 @@ def vehicle_output(t, x, u, params):
63
49
# Provide an intial guess (will be extended to entire horizon)
64
50
bend_left = [10 , 0.01 ] # slight left veer
65
51
66
- def time_integrated_cost ():
52
+ def time_steering_integrated_cost ():
67
53
# Set up the cost functions
68
54
Q = np .diag ([.1 , 10 , .1 ]) # keep lateral error low
69
55
R = np .diag ([.1 , 1 ]) # minimize applied inputs
@@ -81,7 +67,7 @@ def time_integrated_cost():
81
67
# Only count this as a benchmark if we converged
82
68
assert res .success
83
69
84
- def time_terminal_cost ():
70
+ def time_steering_terminal_cost ():
85
71
# Define cost and constraints
86
72
traj_cost = opt .quadratic_cost (
87
73
vehicle , None , np .diag ([0.1 , 1 ]), u0 = uf )
@@ -93,14 +79,35 @@ def time_terminal_cost():
93
79
res = opt .solve_ocp (
94
80
vehicle , horizon , x0 , traj_cost , constraints ,
95
81
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 },
98
86
)
99
-
100
87
# Only count this as a benchmark if we converged
101
88
assert res .success
102
89
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
+
104
111
# Input cost and terminal constraints
105
112
R = np .diag ([1 , 1 ]) # minimize applied inputs
106
113
cost = opt .quadratic_cost (vehicle , np .zeros ((3 ,3 )), R , u0 = uf )
@@ -111,58 +118,59 @@ def time_terminal_constraint():
111
118
res = opt .solve_ocp (
112
119
vehicle , horizon , x0 , cost , constraints ,
113
120
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 ],
118
123
)
119
-
120
124
# Only count this as a benchmark if we converged
121
125
assert res .success
122
126
123
127
# 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
+ )
125
136
126
- def time_optimal_basis_vehicle ( ):
137
+ def time_steering_bezier_basis ( nbasis , ntimes ):
127
138
# Set up costs and constriants
128
139
Q = np .diag ([.1 , 10 , .1 ]) # keep lateral error low
129
140
R = np .diag ([1 , 1 ]) # minimize applied inputs
130
141
cost = opt .quadratic_cost (vehicle , Q , R , x0 = xf , u0 = uf )
131
142
constraints = [ opt .input_range_constraint (vehicle , [0 , - 0.1 ], [20 , 0.1 ]) ]
132
143
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 ] ]
143
144
144
145
# Set up horizon
145
- horizon = np .linspace (0 , Tf , 10 , endpoint = True )
146
+ horizon = np .linspace (0 , Tf , ntimes , endpoint = True )
146
147
147
148
# Set up the optimal control problem
148
149
res = opt .solve_ocp (
149
150
vehicle , horizon , x0 , cost ,
150
151
constraints ,
151
152
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},
154
156
minimize_method = 'trust-constr' ,
157
+ minimize_options = {'finite_diff_rel_step' : 0.01 },
155
158
# minimize_method='SLSQP', minimize_options={'eps': 0.01},
156
- solve_ivp_kwargs = {'atol' : 1e-4 , 'rtol' : 1e-2 },
157
159
return_states = True , print_summary = False
158
160
)
159
161
t , u , x = res .time , res .inputs , res .states
160
162
161
163
# Make sure we found a valid solution
162
164
assert res .success
163
- np .testing .assert_almost_equal (x [:, - 1 ], xf , decimal = 4 )
164
165
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 ():
166
174
# model of an aircraft discretized with 0.2s sampling time
167
175
# Source: https://www.mpt3.org/UI/RegulationProblem
168
176
A = [[0.99 , 0.01 , 0.18 , - 0.09 , 0 ],
0 commit comments