51
51
MAX_BRAKE = 9.81
52
52
53
53
54
- def get_stopped_equivalence_factor (v_lead ):
55
- return T_REACT * v_lead + (v_lead * v_lead ) / (2 * MAX_BRAKE )
54
+ def get_stopped_equivalence_factor (v_lead , t_react = T_REACT ):
55
+ return t_react * v_lead + (v_lead * v_lead ) / (2 * MAX_BRAKE )
56
56
57
- def get_safe_obstacle_distance (v_ego ):
58
- return 2 * T_REACT * v_ego + (v_ego * v_ego ) / (2 * MAX_BRAKE ) + 4.0
57
+ def get_safe_obstacle_distance (v_ego , t_react = T_REACT ):
58
+ return 2 * t_react * v_ego + (v_ego * v_ego ) / (2 * MAX_BRAKE ) + 4.0
59
59
60
- def desired_follow_distance (v_ego , v_lead ):
61
- return get_safe_obstacle_distance (v_ego ) - get_stopped_equivalence_factor (v_lead )
60
+ def desired_follow_distance (v_ego , v_lead , t_react = T_REACT ):
61
+ return get_safe_obstacle_distance (v_ego , t_react ) - get_stopped_equivalence_factor (v_lead , t_react )
62
62
63
63
64
64
def gen_long_model ():
@@ -83,9 +83,10 @@ def gen_long_model():
83
83
84
84
# live parameters
85
85
x_obstacle = SX .sym ('x_obstacle' )
86
+ desired_TR = SX .sym ('desired_TR' )
86
87
a_min = SX .sym ('a_min' )
87
88
a_max = SX .sym ('a_max' )
88
- model .p = vertcat (a_min , a_max , x_obstacle )
89
+ model .p = vertcat (a_min , a_max , x_obstacle , desired_TR )
89
90
90
91
# dynamics model
91
92
f_expl = vertcat (v_ego , a_ego , j_ego )
@@ -118,11 +119,12 @@ def gen_long_mpc_solver():
118
119
119
120
a_min , a_max = ocp .model .p [0 ], ocp .model .p [1 ]
120
121
x_obstacle = ocp .model .p [2 ]
122
+ desired_TR = ocp .model .p [3 ]
121
123
122
124
ocp .cost .yref = np .zeros ((COST_DIM , ))
123
125
ocp .cost .yref_e = np .zeros ((COST_E_DIM , ))
124
126
125
- desired_dist_comfort = get_safe_obstacle_distance (v_ego )
127
+ desired_dist_comfort = get_safe_obstacle_distance (v_ego , desired_TR )
126
128
127
129
# The main cost in normal operation is how close you are to the "desired" distance
128
130
# from an obstacle at every timestep. This obstacle can be a lead car
@@ -148,7 +150,7 @@ def gen_long_mpc_solver():
148
150
149
151
x0 = np .zeros (X_DIM )
150
152
ocp .constraints .x0 = x0
151
- ocp .parameter_values = np .array ([- 1.2 , 1.2 , 0.0 ])
153
+ ocp .parameter_values = np .array ([- 1.2 , 1.2 , 0.0 , T_REACT ]) # defaults
152
154
153
155
# We put all constraint cost weights to 0 and only set them at runtime
154
156
cost_weights = np .zeros (CONSTR_DIM )
@@ -186,8 +188,10 @@ def gen_long_mpc_solver():
186
188
187
189
188
190
class LongitudinalMpc ():
189
- def __init__ (self , e2e = False ):
191
+ def __init__ (self , e2e = False , desired_TR = T_REACT ):
190
192
self .e2e = e2e
193
+ self .desired_TR = desired_TR
194
+ self .v_ego = 0.
191
195
self .reset ()
192
196
self .accel_limit_arr = np .zeros ((N + 1 , 2 ))
193
197
self .accel_limit_arr [:,0 ] = - 1.2
@@ -205,7 +209,7 @@ def reset(self):
205
209
self .solver .cost_set (N , "yref" , self .yref [N ][:COST_E_DIM ])
206
210
self .x_sol = np .zeros ((N + 1 , X_DIM ))
207
211
self .u_sol = np .zeros ((N ,1 ))
208
- self .params = np .zeros ((N + 1 ,3 ))
212
+ self .params = np .zeros ((N + 1 ,4 ))
209
213
for i in range (N + 1 ):
210
214
self .solver .set (i , 'x' , np .zeros (X_DIM ))
211
215
self .last_cloudlog_t = 0
@@ -222,15 +226,25 @@ def set_weights(self):
222
226
self .set_weights_for_lead_policy ()
223
227
224
228
def set_weights_for_lead_policy (self ):
225
- W = np .asfortranarray (np .diag ([X_EGO_OBSTACLE_COST , X_EGO_COST , V_EGO_COST , A_EGO_COST , J_EGO_COST ]))
229
+ # WARNING: deceleration tests with these costs:
230
+ # 1.0 TR fails at 3 m/s/s test
231
+ # 1.1 TR fails at 3+ m/s/s test
232
+ # 1.2-1.8 TR succeeds at all tests with no FCW
233
+
234
+ TRs = [1.2 , 1.8 , 2.7 ]
235
+ x_ego_obstacle_cost_multiplier = interp (self .desired_TR , TRs , [3. , 1.0 , 0.1 ])
236
+ j_ego_cost_multiplier = interp (self .desired_TR , TRs , [0.5 , 1.0 , 1.0 ])
237
+ d_zone_cost_multiplier = interp (self .desired_TR , TRs , [4. , 1.0 , 1.0 ])
238
+
239
+ W = np .asfortranarray (np .diag ([X_EGO_OBSTACLE_COST * x_ego_obstacle_cost_multiplier , X_EGO_COST , V_EGO_COST , A_EGO_COST , J_EGO_COST * j_ego_cost_multiplier ]))
226
240
for i in range (N ):
227
241
self .solver .cost_set (i , 'W' , W )
228
242
# Setting the slice without the copy make the array not contiguous,
229
243
# causing issues with the C interface.
230
244
self .solver .cost_set (N , 'W' , np .copy (W [:COST_E_DIM , :COST_E_DIM ]))
231
245
232
246
# Set L2 slack cost on lower bound constraints
233
- Zl = np .array ([LIMIT_COST , LIMIT_COST , LIMIT_COST , DANGER_ZONE_COST ])
247
+ Zl = np .array ([LIMIT_COST , LIMIT_COST , LIMIT_COST , DANGER_ZONE_COST * d_zone_cost_multiplier ])
234
248
for i in range (N ):
235
249
self .solver .cost_set (i , 'Zl' , Zl )
236
250
@@ -291,7 +305,12 @@ def set_accel_limits(self, min_a, max_a):
291
305
self .cruise_min_a = min_a
292
306
self .cruise_max_a = max_a
293
307
308
+ def set_desired_TR (self , desired_TR ):
309
+ self .desired_TR = clip (desired_TR , 1.2 , 2.7 )
310
+ self .set_weights ()
311
+
294
312
def update (self , carstate , radarstate , v_cruise ):
313
+ self .v_ego = carstate .vEgo
295
314
v_ego = self .x0 [1 ]
296
315
self .status = radarstate .leadOne .status or radarstate .leadTwo .status
297
316
@@ -305,8 +324,8 @@ def update(self, carstate, radarstate, v_cruise):
305
324
# To estimate a safe distance from a moving lead, we calculate how much stopping
306
325
# distance that lead needs as a minimum. We can add that to the current distance
307
326
# and then treat that as a stopped car/obstacle at this new distance.
308
- lead_0_obstacle = lead_xv_0 [:,0 ] + get_stopped_equivalence_factor (lead_xv_0 [:,1 ])
309
- lead_1_obstacle = lead_xv_1 [:,0 ] + get_stopped_equivalence_factor (lead_xv_1 [:,1 ])
327
+ lead_0_obstacle = lead_xv_0 [:,0 ] + get_stopped_equivalence_factor (lead_xv_0 [:,1 ], self . desired_TR )
328
+ lead_1_obstacle = lead_xv_1 [:,0 ] + get_stopped_equivalence_factor (lead_xv_1 [:,1 ], self . desired_TR )
310
329
311
330
# Fake an obstacle for cruise, this ensures smooth acceleration to set speed
312
331
# when the leads are no factor.
@@ -315,11 +334,12 @@ def update(self, carstate, radarstate, v_cruise):
315
334
v_cruise_clipped = np .clip (v_cruise * np .ones (N + 1 ),
316
335
cruise_lower_bound ,
317
336
cruise_upper_bound )
318
- cruise_obstacle = T_IDXS * v_cruise_clipped + get_safe_obstacle_distance (v_cruise_clipped )
337
+ cruise_obstacle = T_IDXS * v_cruise_clipped + get_safe_obstacle_distance (v_cruise_clipped , self . desired_TR )
319
338
320
339
x_obstacles = np .column_stack ([lead_0_obstacle , lead_1_obstacle , cruise_obstacle ])
321
340
self .source = SOURCES [np .argmin (x_obstacles [0 ])]
322
341
self .params [:,2 ] = np .min (x_obstacles , axis = 1 )
342
+ self .params [:,3 ] = self .desired_TR
323
343
324
344
self .run ()
325
345
if (np .any (lead_xv_0 [:,0 ] - self .x_sol [:,0 ] < CRASH_DISTANCE ) and
@@ -338,8 +358,9 @@ def update_with_xva(self, x, v, a):
338
358
self .accel_limit_arr [:,0 ] = - 10.
339
359
self .accel_limit_arr [:,1 ] = 10.
340
360
x_obstacle = 1e5 * np .ones ((N + 1 ))
361
+ desired_TR = T_REACT * np .ones ((N + 1 ))
341
362
self .params = np .concatenate ([self .accel_limit_arr ,
342
- x_obstacle [:,None ]], axis = 1 )
363
+ x_obstacle [:,None ], desired_TR [:, None ] ], axis = 1 )
343
364
self .run ()
344
365
345
366
0 commit comments