Skip to content

Commit 41fc77f

Browse files
committed
Support adjustable following distance with ACADOS
distance cost doesn't work, try removing it (may not brake enough for leads!!) test it out add opEdit no static analysis fix toyota pedal gas fix pedal make desired distance a live parameter (is it this easy??) probs okay using whole arr fixes Try this clean up Revert "no static analysis" This reverts commit a05af01. clean up Revert "fix pedal" This reverts commit 54cd7c2. Revert "fix toyota pedal gas" This reverts commit d14bdd5. Revert "add opEdit" This reverts commit ade5cce. clean up add x_ego cost tuning revert uncomment clean up consistent name clean up better to differentiate update CamryH tune theoretically 0.9 seconds is safe up to -3 m/s/s lead braking live tuning update tune, rate limits not permanent Revert "update tune, rate limits not permanent" This reverts commit 806ffdf. more sane costs, and set on each TR update revert clean up clean up clean up fill xva revert debugging code revert debugging code revert perms change clean up
1 parent e8598f7 commit 41fc77f

File tree

2 files changed

+39
-17
lines changed

2 files changed

+39
-17
lines changed

selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@
5151
MAX_BRAKE = 9.81
5252

5353

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)
5656

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
5959

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)
6262

6363

6464
def gen_long_model():
@@ -83,9 +83,10 @@ def gen_long_model():
8383

8484
# live parameters
8585
x_obstacle = SX.sym('x_obstacle')
86+
desired_TR = SX.sym('desired_TR')
8687
a_min = SX.sym('a_min')
8788
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)
8990

9091
# dynamics model
9192
f_expl = vertcat(v_ego, a_ego, j_ego)
@@ -118,11 +119,12 @@ def gen_long_mpc_solver():
118119

119120
a_min, a_max = ocp.model.p[0], ocp.model.p[1]
120121
x_obstacle = ocp.model.p[2]
122+
desired_TR = ocp.model.p[3]
121123

122124
ocp.cost.yref = np.zeros((COST_DIM, ))
123125
ocp.cost.yref_e = np.zeros((COST_E_DIM, ))
124126

125-
desired_dist_comfort = get_safe_obstacle_distance(v_ego)
127+
desired_dist_comfort = get_safe_obstacle_distance(v_ego, desired_TR)
126128

127129
# The main cost in normal operation is how close you are to the "desired" distance
128130
# from an obstacle at every timestep. This obstacle can be a lead car
@@ -148,7 +150,7 @@ def gen_long_mpc_solver():
148150

149151
x0 = np.zeros(X_DIM)
150152
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
152154

153155
# We put all constraint cost weights to 0 and only set them at runtime
154156
cost_weights = np.zeros(CONSTR_DIM)
@@ -186,8 +188,10 @@ def gen_long_mpc_solver():
186188

187189

188190
class LongitudinalMpc():
189-
def __init__(self, e2e=False):
191+
def __init__(self, e2e=False, desired_TR=T_REACT):
190192
self.e2e = e2e
193+
self.desired_TR = desired_TR
194+
self.v_ego = 0.
191195
self.reset()
192196
self.accel_limit_arr = np.zeros((N+1, 2))
193197
self.accel_limit_arr[:,0] = -1.2
@@ -205,7 +209,7 @@ def reset(self):
205209
self.solver.cost_set(N, "yref", self.yref[N][:COST_E_DIM])
206210
self.x_sol = np.zeros((N+1, X_DIM))
207211
self.u_sol = np.zeros((N,1))
208-
self.params = np.zeros((N+1,3))
212+
self.params = np.zeros((N+1,4))
209213
for i in range(N+1):
210214
self.solver.set(i, 'x', np.zeros(X_DIM))
211215
self.last_cloudlog_t = 0
@@ -222,15 +226,25 @@ def set_weights(self):
222226
self.set_weights_for_lead_policy()
223227

224228
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]))
226240
for i in range(N):
227241
self.solver.cost_set(i, 'W', W)
228242
# Setting the slice without the copy make the array not contiguous,
229243
# causing issues with the C interface.
230244
self.solver.cost_set(N, 'W', np.copy(W[:COST_E_DIM, :COST_E_DIM]))
231245

232246
# 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])
234248
for i in range(N):
235249
self.solver.cost_set(i, 'Zl', Zl)
236250

@@ -291,7 +305,12 @@ def set_accel_limits(self, min_a, max_a):
291305
self.cruise_min_a = min_a
292306
self.cruise_max_a = max_a
293307

308+
def set_desired_TR(self, desired_TR):
309+
self.desired_TR = clip(desired_TR, 1.2, 2.7)
310+
self.set_weights()
311+
294312
def update(self, carstate, radarstate, v_cruise):
313+
self.v_ego = carstate.vEgo
295314
v_ego = self.x0[1]
296315
self.status = radarstate.leadOne.status or radarstate.leadTwo.status
297316

@@ -305,8 +324,8 @@ def update(self, carstate, radarstate, v_cruise):
305324
# To estimate a safe distance from a moving lead, we calculate how much stopping
306325
# distance that lead needs as a minimum. We can add that to the current distance
307326
# 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)
310329

311330
# Fake an obstacle for cruise, this ensures smooth acceleration to set speed
312331
# when the leads are no factor.
@@ -315,11 +334,12 @@ def update(self, carstate, radarstate, v_cruise):
315334
v_cruise_clipped = np.clip(v_cruise * np.ones(N+1),
316335
cruise_lower_bound,
317336
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)
319338

320339
x_obstacles = np.column_stack([lead_0_obstacle, lead_1_obstacle, cruise_obstacle])
321340
self.source = SOURCES[np.argmin(x_obstacles[0])]
322341
self.params[:,2] = np.min(x_obstacles, axis=1)
342+
self.params[:,3] = self.desired_TR
323343

324344
self.run()
325345
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):
338358
self.accel_limit_arr[:,0] = -10.
339359
self.accel_limit_arr[:,1] = 10.
340360
x_obstacle = 1e5*np.ones((N+1))
361+
desired_TR = T_REACT*np.ones((N+1))
341362
self.params = np.concatenate([self.accel_limit_arr,
342-
x_obstacle[:,None]], axis=1)
363+
x_obstacle[:,None], desired_TR[:,None]], axis=1)
343364
self.run()
344365

345366

selfdrive/controls/lib/longitudinal_planner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def update(self, sm, CP):
8888
accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05)
8989
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1])
9090
self.mpc.set_cur_state(self.v_desired, self.a_desired)
91+
# self.mpc.set_desired_TR(1.8)
9192
self.mpc.update(sm['carState'], sm['radarState'], v_cruise)
9293
self.v_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.v_solution)
9394
self.a_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.a_solution)

0 commit comments

Comments
 (0)