|
|
|
@ -16,7 +16,6 @@ from openpilot.selfdrive.car.cruise import V_CRUISE_MAX, V_CRUISE_UNSET |
|
|
|
|
from openpilot.common.swaglog import cloudlog |
|
|
|
|
|
|
|
|
|
LON_MPC_STEP = 0.2 # first step is 0.2s |
|
|
|
|
A_CRUISE_MIN = -1.2 |
|
|
|
|
A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6] |
|
|
|
|
A_CRUISE_MAX_BP = [0., 10.0, 25., 40.] |
|
|
|
|
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N] |
|
|
|
@ -76,7 +75,10 @@ class LongitudinalPlanner: |
|
|
|
|
|
|
|
|
|
self.a_desired = init_a |
|
|
|
|
self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt) |
|
|
|
|
self.prev_accel_clip = [ACCEL_MIN, ACCEL_MAX] |
|
|
|
|
self.v_model_error = 0.0 |
|
|
|
|
self.output_a_target = 0.0 |
|
|
|
|
self.output_should_stop = False |
|
|
|
|
|
|
|
|
|
self.v_desired_trajectory = np.zeros(CONTROL_N) |
|
|
|
|
self.a_desired_trajectory = np.zeros(CONTROL_N) |
|
|
|
@ -128,17 +130,16 @@ class LongitudinalPlanner: |
|
|
|
|
prev_accel_constraint = not (reset_state or sm['carState'].standstill) |
|
|
|
|
|
|
|
|
|
if self.mpc.mode == 'acc': |
|
|
|
|
accel_limits = [A_CRUISE_MIN, get_max_accel(v_ego)] |
|
|
|
|
accel_clip = [ACCEL_MIN, get_max_accel(v_ego)] |
|
|
|
|
steer_angle_without_offset = sm['carState'].steeringAngleDeg - sm['liveParameters'].angleOffsetDeg |
|
|
|
|
accel_limits_turns = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_limits, self.CP) |
|
|
|
|
accel_clip = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_clip, self.CP) |
|
|
|
|
else: |
|
|
|
|
accel_limits = [ACCEL_MIN, ACCEL_MAX] |
|
|
|
|
accel_limits_turns = [ACCEL_MIN, ACCEL_MAX] |
|
|
|
|
accel_clip = [ACCEL_MIN, ACCEL_MAX] |
|
|
|
|
|
|
|
|
|
if reset_state: |
|
|
|
|
self.v_desired_filter.x = v_ego |
|
|
|
|
# Clip aEgo to cruise limits to prevent large accelerations when becoming active |
|
|
|
|
self.a_desired = np.clip(sm['carState'].aEgo, accel_limits[0], accel_limits[1]) |
|
|
|
|
self.a_desired = np.clip(sm['carState'].aEgo, accel_clip[0], accel_clip[1]) |
|
|
|
|
|
|
|
|
|
# Prevent divergence, smooth in current v_ego |
|
|
|
|
self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego)) |
|
|
|
@ -149,18 +150,14 @@ class LongitudinalPlanner: |
|
|
|
|
self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED |
|
|
|
|
|
|
|
|
|
if not self.allow_throttle: |
|
|
|
|
clipped_accel_coast = max(accel_coast, accel_limits_turns[0]) |
|
|
|
|
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_limits_turns[1], clipped_accel_coast]) |
|
|
|
|
accel_limits_turns[1] = min(accel_limits_turns[1], clipped_accel_coast_interp) |
|
|
|
|
clipped_accel_coast = max(accel_coast, accel_clip[0]) |
|
|
|
|
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_clip[1], clipped_accel_coast]) |
|
|
|
|
accel_clip[1] = min(accel_clip[1], clipped_accel_coast_interp) |
|
|
|
|
|
|
|
|
|
if force_slow_decel: |
|
|
|
|
v_cruise = 0.0 |
|
|
|
|
# clip limits, cannot init MPC outside of bounds |
|
|
|
|
accel_limits_turns[0] = min(accel_limits_turns[0], self.a_desired + 0.05) |
|
|
|
|
accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05) |
|
|
|
|
|
|
|
|
|
self.mpc.set_weights(prev_accel_constraint, personality=sm['selfdriveState'].personality) |
|
|
|
|
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1]) |
|
|
|
|
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired) |
|
|
|
|
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=sm['selfdriveState'].personality) |
|
|
|
|
|
|
|
|
@ -178,6 +175,15 @@ class LongitudinalPlanner: |
|
|
|
|
self.a_desired = float(np.interp(self.dt, CONTROL_N_T_IDX, self.a_desired_trajectory)) |
|
|
|
|
self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0 |
|
|
|
|
|
|
|
|
|
action_t = self.CP.longitudinalActuatorDelay + DT_MDL |
|
|
|
|
output_a_target, self.output_should_stop = get_accel_from_plan(self.v_desired_trajectory, self.a_desired_trajectory, |
|
|
|
|
action_t=action_t, vEgoStopping=self.CP.vEgoStopping) |
|
|
|
|
|
|
|
|
|
for idx in range(2): |
|
|
|
|
accel_clip[idx] = np.clip(accel_clip[idx], self.prev_accel_clip[idx] - 0.05, self.prev_accel_clip[idx] + 0.05) |
|
|
|
|
self.output_a_target = np.clip(output_a_target, accel_clip[0], accel_clip[1]) |
|
|
|
|
self.prev_accel_clip = accel_clip |
|
|
|
|
|
|
|
|
|
def publish(self, sm, pm): |
|
|
|
|
plan_send = messaging.new_message('longitudinalPlan') |
|
|
|
|
|
|
|
|
@ -196,11 +202,8 @@ class LongitudinalPlanner: |
|
|
|
|
longitudinalPlan.longitudinalPlanSource = self.mpc.source |
|
|
|
|
longitudinalPlan.fcw = self.fcw |
|
|
|
|
|
|
|
|
|
action_t = self.CP.longitudinalActuatorDelay + DT_MDL |
|
|
|
|
a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels, |
|
|
|
|
action_t=action_t, vEgoStopping=self.CP.vEgoStopping) |
|
|
|
|
longitudinalPlan.aTarget = float(a_target) |
|
|
|
|
longitudinalPlan.shouldStop = bool(should_stop) |
|
|
|
|
longitudinalPlan.aTarget = float(self.output_a_target) |
|
|
|
|
longitudinalPlan.shouldStop = bool(self.output_should_stop) |
|
|
|
|
longitudinalPlan.allowBrake = True |
|
|
|
|
longitudinalPlan.allowThrottle = bool(self.allow_throttle) |
|
|
|
|
|
|
|
|
|