Exemplo n.º 1
0
class TiciFanController(BaseFanController):
    def __init__(self) -> None:
        super().__init__()
        cloudlog.info("Setting up TICI fan handler")

        self.last_ignition = False
        self.controller = PIDController(k_p=0,
                                        k_i=4e-3,
                                        k_f=1,
                                        neg_limit=-80,
                                        pos_limit=0,
                                        rate=(1 / DT_TRML))

    def update(self, max_cpu_temp: float, ignition: bool) -> int:
        self.controller.neg_limit = -(80 if ignition else 30)
        self.controller.pos_limit = -(30 if ignition else 0)

        if ignition != self.last_ignition:
            self.controller.reset()

        error = 70 - max_cpu_temp
        fan_pwr_out = -int(
            self.controller.update(error=error,
                                   feedforward=interp(
                                       max_cpu_temp, [60.0, 100.0], [0, -80])))

        self.last_ignition = ignition
        return fan_pwr_out
Exemplo n.º 2
0
class LatControlPID(LatControl):
  def __init__(self, CP, CI):
    super().__init__(CP, CI)
    self.pid = PIDController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
                             (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
                             k_f=CP.lateralTuning.pid.kf,
                            k_d=(CP.lateralTuning.pid.kdBP, CP.lateralTuning.pid.kdV),
                            pos_limit=self.steer_max, neg_limit=-self.steer_max)
    self.get_steer_feedforward = CI.get_steer_feedforward_function()

    self.errors = []

  def reset(self):
    super().reset()
    self.pid.reset()
    self.errors = []

  def update(self, active, CS, VM, params, last_actuators, desired_curvature, desired_curvature_rate, llk):
    pid_log = log.ControlsState.LateralPIDState.new_message()
    pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
    pid_log.steeringRateDeg = float(CS.steeringRateDeg)

    angle_steers_des_no_offset = math.degrees(VM.get_steer_from_curvature(-desired_curvature, CS.vEgo, params.roll))
    angle_steers_des = angle_steers_des_no_offset + params.angleOffsetDeg
    error = angle_steers_des - CS.steeringAngleDeg

    pid_log.steeringAngleDesiredDeg = angle_steers_des
    pid_log.angleError = error
    if CS.vEgo < MIN_STEER_SPEED or not active:
      output_steer = 0.0
      pid_log.active = False
      self.pid.reset()
    else:
      # offset does not contribute to resistive torque
      steer_feedforward = self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)

      error_rate = 0
      if len(self.errors) >= ERROR_RATE_FRAME:
        error_rate = (error - self.errors[-ERROR_RATE_FRAME]) / ERROR_RATE_FRAME

      self.errors.append(float(error))
      while len(self.errors) > ERROR_RATE_FRAME:
        self.errors.pop(0)

      output_steer = self.pid.update(error, error_rate, override=CS.steeringPressed,
                                     feedforward=steer_feedforward, speed=CS.vEgo)
      pid_log.active = True
      pid_log.p = self.pid.p
      pid_log.i = self.pid.i
      pid_log.f = self.pid.f
      pid_log.output = output_steer
      pid_log.saturated = self._check_saturation(self.steer_max - abs(output_steer) < 1e-3, CS)

    return output_steer, angle_steers_des, pid_log
Exemplo n.º 3
0
class LongControl():
  def __init__(self, CP, compute_gb):
    self.long_control_state = LongCtrlState.off  # initialized to off
    kdBP = [0., 33, 55., 78]
    kdBP = [i * CV.MPH_TO_MS for i in kdBP]
    kdV = [0.05, 0.4, 0.8, 1.2]
    self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
                             (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
                             (kdBP, kdV),
                             rate=RATE,
                             sat_limit=0.8,
                             convert=compute_gb)
    self.v_pid = 0.0
    self.lastdecelForTurn = False
    #self.had_lead = False
    self.last_output_gb = 0.0

  def reset(self, v_pid):
    """Reset PID controller and change setpoint"""
    self.pid.reset()
    self.v_pid = v_pid

  def dynamic_gas(self, v_ego, gas_interceptor, gas_button_status):
    dynamic = False
    if gas_interceptor:
      if gas_button_status == 0:
        dynamic = True
        x = [0.0, 1.4082, 2.8031, 4.2266, 5.3827, 6.1656, 7.2478, 8.2831, 10.2447, 12.964, 15.423, 18.119, 20.117, 24.4661, 29.0581, 32.7101, 35.7633]
        y = [0.218, 0.222, 0.233, 0.25, 0.273, 0.294, 0.337, 0.362, 0.38, 0.389, 0.398, 0.41, 0.421, 0.459, 0.512, 0.564, 0.621]
      elif gas_button_status == 1:
        y = [0.3, 0.9, 0.9]
      elif gas_button_status == 2:
        y = [0.2, 0.5, 0.7]
    else:
      if gas_button_status == 0:
        dynamic = True
        x = [0.0, 1.4082, 2.80311, 4.22661, 5.38271, 6.16561, 7.24781, 8.28308, 10.24465, 12.96402, 15.42303, 18.11903, 20.11703, 24.46614, 29.05805, 32.71015, 35.76326]
        y = [0.35, 0.47, 0.43, 0.35, 0.3, 0.3, 0.3229, 0.34784, 0.36765, 0.38, 0.396, 0.409, 0.425, 0.478, 0.55, 0.621, 0.7]
      elif gas_button_status == 1:
        y = [0.5, 0.95, 0.99]
      elif gas_button_status == 2:
        y = [0.25, 0.2, 0.2]

    if not dynamic:
      x = [0., 9., 55.]  # default BP values

    accel = interp(v_ego, x, y)

    #if dynamic and hasLead:  # dynamic gas profile specific operations, and if lead
    #  if v_ego < 6.7056:  # if under 15 mph
    #    x = [1.61479, 1.99067, 2.28537, 2.49888, 2.6312, 2.68224]
    #    y = [-accel, -(accel / 1.06), -(accel / 1.2), -(accel / 1.8), -(accel / 4.4), 0]  # array that matches current chosen accel value
    #    accel += interp(vRel, x, y)
    #  else:
    #    x = [-0.89408, 0, 0.89408, 4.4704]
    #    y = [-.15, -.05, .005, .05]
    #    accel += interp(vRel, x, y)

    min_return = 0.0
    max_return = 1.0
    return round(max(min(accel, max_return), min_return), 5)  # ensure we return a value between range

  def update(self, active, CS, v_target, v_target_future, a_target, CP, hasLead, radarState, decelForTurn, longitudinalPlanSource, gas_button_status):
    """Update longitudinal control. This updates the state machine and runs a PID loop"""
    try:
      gas_interceptor = CP.enableGasInterceptor
    except AttributeError:
      gas_interceptor = False
    # Actuation limits
    #gas_max = interp(CS.vEgo, CP.gasMaxBP, CP.gasMaxV)
    gas_max = self.dynamic_gas(CS.vEgo, gas_interceptor, gas_button_status)
    brake_max = interp(CS.vEgo, CP.brakeMaxBP, CP.brakeMaxV)

    # Update state machine
    output_gb = self.last_output_gb
    if radarState is None:
      dRel = 200
    else:
      dRel = radarState.leadOne.dRel
    if hasLead:
      stop = True if (dRel < 4.0 and radarState.leadOne.status) else False
    else:
      stop = False
    self.long_control_state = long_control_state_trans(active, self.long_control_state, CS.vEgo,
                                                       v_target_future, self.v_pid, output_gb,
                                                       CS.brakePressed, CS.cruiseState.standstill, stop)


    v_ego_pid = max(CS.vEgo, MIN_CAN_SPEED)  # Without this we get jumps, CAN bus reports 0 when speed < 0.3

    if self.long_control_state == LongCtrlState.off or (CS.brakePressed or CS.gasPressed and not travis):
      self.v_pid = v_ego_pid
      self.pid.reset()
      output_gb = 0.

    # tracking objects and driving
    elif self.long_control_state == LongCtrlState.pid:
      self.v_pid = v_target
      self.pid.pos_limit = gas_max
      self.pid.neg_limit = - brake_max

      # Toyota starts braking more when it thinks you want to stop
      # Freeze the integrator so we don't accelerate to compensate, and don't allow positive acceleration
      prevent_overshoot = not CP.stoppingControl and CS.vEgo < 1.5 and v_target_future < 0.7
      deadzone = interp(v_ego_pid, CP.longitudinalTuning.deadzoneBP, CP.longitudinalTuning.deadzoneV)
      #if not self.had_lead and has_lead:
      #  if enableGasInterceptor:
      #    self.pid._k_p = ([0., 5., 35.], [1.2, 0.8, 0.5])
      #    self.pid._k_i = ([0., 35.], [0.18, 0.12])
      #  else:
      #    self.pid._k_p = ([0., 5., 35.], [3.6, 2.4, 1.5])
      #    self.pid._k_i = ([0., 35.], [0.54, 0.36])
      #elif self.had_lead and not has_lead:
      #  self.pid._k_p = (CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV)
      #  self.pid._k_i = (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV)
      #self.had_lead = has_lead
      if longitudinalPlanSource == 'cruise':
        if decelForTurn and not self.lastdecelForTurn:
          self.lastdecelForTurn = True
          self.pid._k_p = (CP.longitudinalTuning.kpBP, [x * 0 for x in CP.longitudinalTuning.kpV])
          self.pid._k_i = (CP.longitudinalTuning.kiBP, [x * 0 for x in CP.longitudinalTuning.kiV])
          self.pid.i = 0.0
          self.pid.k_f=1.0
          self.v_pid = CS.vEgo
          self.pid.reset()
        if self.lastdecelForTurn and not decelForTurn:
          self.lastdecelForTurn = False
          self.pid._k_p = (CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV)
          self.pid._k_i = (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV)
          self.pid.k_f=1.0
          self.v_pid = CS.vEgo
          self.pid.reset()
      else:
        if self.lastdecelForTurn:
          self.v_pid = CS.vEgo
          self.pid.reset()
        self.lastdecelForTurn = False
        self.pid._k_p = (CP.longitudinalTuning.kpBP, [x * 1 for x in CP.longitudinalTuning.kpV])
        self.pid._k_i = (CP.longitudinalTuning.kiBP, [x * 1 for x in CP.longitudinalTuning.kiV])
        self.pid.k_f=1.0


      output_gb = self.pid.update(self.v_pid, v_ego_pid, speed=v_ego_pid, deadzone=deadzone, feedforward=a_target, freeze_integrator=prevent_overshoot)

      if prevent_overshoot:
        output_gb = min(output_gb, 0.0)

    # Intention is to stop, switch to a different brake control until we stop
    elif self.long_control_state == LongCtrlState.stopping:
      # Keep applying brakes until the car is stopped
      factor = 1
      if hasLead:
        factor = interp(dRel,[2.0,3.0,4.0,5.0,6.0,7.0,8.0], [3.0,2.1,1.5,1.0,0.6,0.29,0.0])
      if not CS.standstill or output_gb > -BRAKE_STOPPING_TARGET:
        output_gb -= STOPPING_BRAKE_RATE / RATE * factor
      output_gb = clip(output_gb, -brake_max, gas_max)

      self.v_pid = CS.vEgo
      self.pid.reset()

    # Intention is to move again, release brake fast before handing control to PID
    elif self.long_control_state == LongCtrlState.starting:
      factor = 1
      if hasLead:
        factor = interp(dRel,[0.0,2.0,4.0,6.0], [0.0,0.5,1.0,2.0])
      if output_gb < -0.2:
        output_gb += STARTING_BRAKE_RATE / RATE * factor
      self.v_pid = CS.vEgo
      self.pid.reset()

    self.last_output_gb = output_gb
    final_gas = clip(output_gb, 0., gas_max)
    final_brake = -clip(output_gb, -brake_max, 0.)

    return final_gas, final_brake
Exemplo n.º 4
0
class LongControl():
  def __init__(self, CP, compute_gb):
    self.long_control_state = LongCtrlState.off  # initialized to off

    kdBP = [0., 16., 35.]
    kdV = [0.08, 0.215, 0.51]

    self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
                             (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
                             (CP.longitudinalTuning.kfBP, CP.longitudinalTuning.kfV),
                             (kdBP, kdV),
                             rate=RATE,
                             sat_limit=0.8,
                             convert=compute_gb)
    self.v_pid = 0.0
    self.last_output_gb = 0.0

  def reset(self, v_pid):
    """Reset PID controller and change setpoint"""
    self.pid.reset()
    self.v_pid = v_pid
    self.stop = False
    self.stop_timer = 0

  def update(self, active, CS, v_target, v_target_future, a_target, CP, hasLead, radarState):
    """Update longitudinal control. This updates the state machine and runs a PID loop"""
    # Actuation limits
    gas_max = interp(CS.vEgo, CP.gasMaxBP, CP.gasMaxV)
    brake_max = interp(CS.vEgo, CP.brakeMaxBP, CP.brakeMaxV)

    # Update state machine
    output_gb = self.last_output_gb
    if radarState is None:
      dRel = 200
      vLead = 0
    else:
      dRel = radarState.leadOne.dRel
      vLead = radarState.leadOne.vLead
    if hasLead and dRel < 5. and radarState.leadOne.status:
      self.stop = True
      if self.stop:
        self.stop_timer = 100
    elif self.stop_timer > 0:
      self.stop_timer -= 1
    else:
      self.stop = False
    self.long_control_state = long_control_state_trans(active, self.long_control_state, CS.vEgo, v_target,
                                                       output_gb, CS.standstill, self.stop, vLead)

    v_ego_pid = max(CS.vEgo, MIN_CAN_SPEED)  # Without this we get jumps, CAN bus reports 0 when speed < 0.3

    if self.long_control_state == LongCtrlState.off or CS.gasPressed:
      self.v_pid = v_ego_pid
      self.pid.reset()
      output_gb = 0.

    # tracking objects and driving
    elif self.long_control_state == LongCtrlState.pid:
      self.v_pid = v_target
      self.pid.pos_limit = gas_max
      self.pid.neg_limit = - brake_max

      # Toyota starts braking more when it thinks you want to stop
      # Freeze the integrator so we don't accelerate to compensate, and don't allow positive acceleration
      prevent_overshoot = not CP.stoppingControl and CS.vEgo < 1.5 and v_target_future < 0.7
      deadzone = interp(v_ego_pid, CP.longitudinalTuning.deadzoneBP, CP.longitudinalTuning.deadzoneV)

      output_gb = self.pid.update(self.v_pid, v_ego_pid, speed=v_ego_pid, deadzone=deadzone, feedforward=a_target,
                                  freeze_integrator=prevent_overshoot, leadvisible=hasLead, leaddistance=dRel, leadvel=vLead)
      if prevent_overshoot:
        output_gb = min(output_gb, 0.0)

    # Intention is to stop, switch to a different brake control until we stop
    elif self.long_control_state == LongCtrlState.stopping:
      # Keep applying brakes until the car is stopped
      factor = 1.
      if hasLead:
        factor = interp(dRel, [2., 3., 4., 5., 6., 7., 8.], [5., 2.5, 1., .5, .25, .05, .005])
      if output_gb > -BRAKE_STOPPING_TARGET:
        output_gb -= (STOPPING_BRAKE_RATE * factor) / RATE
      if output_gb < -.5 and CS.standstill:
        output_gb += .033
      output_gb = clip(output_gb, -brake_max, gas_max)
      self.v_pid = CS.vEgo
      self.pid.reset()

    # Intention is to move again, release brake fast before handing control to PID
    elif self.long_control_state == LongCtrlState.starting:
      factor = 1.
      if hasLead:
        factor = interp(dRel, [0., 2., 4., 6.], [2., 2., 2., 3.])
      if output_gb < 2.:
        output_gb += (STARTING_BRAKE_RATE * factor) / RATE
      self.v_pid = CS.vEgo
      self.pid.reset()

    self.last_output_gb = output_gb
    final_gas = clip(output_gb, 0., gas_max)
    final_brake = -clip(output_gb, -brake_max, 0.)

    return final_gas, final_brake
Exemplo n.º 5
0
class LongControl():
  def __init__(self, CP, compute_gb):
    self.long_control_state = LongCtrlState.off  # initialized to off

    kdBP = [0., 16., 35.]
    kdV = [0.08, 0.215, 0.51]

    self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
                             (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
                             (CP.longitudinalTuning.kfBP, CP.longitudinalTuning.kfV),
                             (kdBP, kdV),
                             rate=RATE,
                             sat_limit=0.8,
                             convert=compute_gb)
    self.v_pid = 0.0
    self.last_output_gb = 0.0

  def reset(self, v_pid):
    """Reset PID controller and change setpoint"""
    self.pid.reset()
    self.v_pid = v_pid

  def update(self, active, CS, v_target, v_target_future, a_target, CP):
    """Update longitudinal control. This updates the state machine and runs a PID loop"""
    # Actuation limits
    gas_max = interp(CS.vEgo, CP.gasMaxBP, CP.gasMaxV)
    brake_max = interp(CS.vEgo, CP.brakeMaxBP, CP.brakeMaxV)

    # Update state machine
    output_gb = self.last_output_gb
    self.long_control_state = long_control_state_trans(active, self.long_control_state, CS.vEgo,
                                                       v_target_future, self.v_pid, output_gb,
                                                       CS.brakePressed, CS.cruiseState.standstill)

    v_ego_pid = max(CS.vEgo, MIN_CAN_SPEED)  # Without this we get jumps, CAN bus reports 0 when speed < 0.3

    if self.long_control_state == LongCtrlState.off or CS.gasPressed:
      self.reset(v_ego_pid)
      output_gb = 0.

    # tracking objects and driving
    elif self.long_control_state == LongCtrlState.pid:
      self.v_pid = v_target
      self.pid.pos_limit = gas_max
      self.pid.neg_limit = - brake_max

      # Toyota starts braking more when it thinks you want to stop
      # Freeze the integrator so we don't accelerate to compensate, and don't allow positive acceleration
      prevent_overshoot = not CP.stoppingControl and CS.vEgo < 1.5 and v_target_future < 0.7
      deadzone = interp(v_ego_pid, CP.longitudinalTuning.deadzoneBP, CP.longitudinalTuning.deadzoneV)

      output_gb = self.pid.update(self.v_pid, v_ego_pid, speed=v_ego_pid, deadzone=deadzone, feedforward=a_target, freeze_integrator=prevent_overshoot)

      if prevent_overshoot:
        output_gb = min(output_gb, 0.0)

    # Intention is to stop, switch to a different brake control until we stop
    elif self.long_control_state == LongCtrlState.stopping:
      # Keep applying brakes until the car is stopped
      if not CS.standstill or output_gb > -BRAKE_STOPPING_TARGET:
        output_gb -= STOPPING_BRAKE_RATE / RATE
      output_gb = clip(output_gb, -brake_max, gas_max)

      self.reset(CS.vEgo)

    # Intention is to move again, release brake fast before handing control to PID
    elif self.long_control_state == LongCtrlState.starting:
      if output_gb < -0.2:
        output_gb += STARTING_BRAKE_RATE / RATE
      self.reset(CS.vEgo)

    self.last_output_gb = output_gb
    final_gas = clip(output_gb, 0., gas_max)
    final_brake = -clip(output_gb, -brake_max, 0.)

    return final_gas, final_brake
Exemplo n.º 6
0
class LatControlTorque(LatControl):
    def __init__(self, CP, CI):
        super().__init__(CP, CI)
        self.pid = PIDController(CP.lateralTuning.torque.kp,
                                 CP.lateralTuning.torque.ki,
                                 k_f=CP.lateralTuning.torque.kf,
                                 pos_limit=self.steer_max,
                                 neg_limit=-self.steer_max)
        self.get_steer_feedforward = CI.get_steer_feedforward_function()
        self.use_steering_angle = CP.lateralTuning.torque.useSteeringAngle
        self.friction = CP.lateralTuning.torque.friction
        self.kf = CP.lateralTuning.torque.kf

    def reset(self):
        super().reset()
        self.pid.reset()

    def update(self, active, CS, VM, params, last_actuators, desired_curvature,
               desired_curvature_rate, llk):
        pid_log = log.ControlsState.LateralTorqueState.new_message()

        if CS.vEgo < MIN_STEER_SPEED or not active:
            output_torque = 0.0
            pid_log.active = False
            if not active:
                self.pid.reset()
        else:
            if self.use_steering_angle:
                actual_curvature = -VM.calc_curvature(
                    math.radians(CS.steeringAngleDeg - params.angleOffsetDeg),
                    CS.vEgo, params.roll)
            else:
                actual_curvature = llk.angularVelocityCalibrated.value[
                    2] / CS.vEgo
            desired_lateral_accel = desired_curvature * CS.vEgo**2
            desired_lateral_jerk = desired_curvature_rate * CS.vEgo**2
            actual_lateral_accel = actual_curvature * CS.vEgo**2

            setpoint = desired_lateral_accel + LOW_SPEED_FACTOR * desired_curvature
            measurement = actual_lateral_accel + LOW_SPEED_FACTOR * actual_curvature
            error = setpoint - measurement
            pid_log.error = error

            ff = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY
            # convert friction into lateral accel units for feedforward
            friction_compensation = interp(desired_lateral_jerk,
                                           [-JERK_THRESHOLD, JERK_THRESHOLD],
                                           [-self.friction, self.friction])
            ff += friction_compensation / self.kf
            output_torque = self.pid.update(
                error,
                override=CS.steeringPressed,
                feedforward=ff,
                speed=CS.vEgo,
                freeze_integrator=CS.steeringRateLimited)

            pid_log.active = True
            pid_log.p = self.pid.p
            pid_log.i = self.pid.i
            pid_log.d = self.pid.d
            pid_log.f = self.pid.f
            pid_log.output = -output_torque
            pid_log.saturated = self._check_saturation(
                self.steer_max - abs(output_torque) < 1e-3, CS)
            pid_log.actualLateralAccel = actual_lateral_accel
            pid_log.desiredLateralAccel = desired_lateral_accel

        # TODO left is positive in this convention
        return -output_torque, 0.0, pid_log
Exemplo n.º 7
0
class LongControl:
    def __init__(self, CP):
        self.CP = CP
        self.long_control_state = LongCtrlState.off  # initialized to off
        self.pid = PIDController(
            (CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
            (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
            k_f=CP.longitudinalTuning.kf,
            rate=1 / DT_CTRL)
        self.v_pid = 0.0
        self.last_output_accel = 0.0

    def reset(self, v_pid):
        """Reset PID controller and change setpoint"""
        self.pid.reset()
        self.v_pid = v_pid

    def update(self, active, CS, long_plan, accel_limits, t_since_plan,
               radar_state):
        """Update longitudinal control. This updates the state machine and runs a PID loop"""
        # Interp control trajectory
        speeds = long_plan.speeds
        if len(speeds) == CONTROL_N:
            v_target = interp(t_since_plan, T_IDXS[:CONTROL_N], speeds)
            a_target = interp(t_since_plan, T_IDXS[:CONTROL_N],
                              long_plan.accels)

            v_target_lower = interp(
                self.CP.longitudinalActuatorDelayLowerBound + t_since_plan,
                T_IDXS[:CONTROL_N], speeds)
            a_target_lower = 2 * (
                v_target_lower - v_target
            ) / self.CP.longitudinalActuatorDelayLowerBound - a_target

            v_target_upper = interp(
                self.CP.longitudinalActuatorDelayUpperBound + t_since_plan,
                T_IDXS[:CONTROL_N], speeds)
            a_target_upper = 2 * (
                v_target_upper - v_target
            ) / self.CP.longitudinalActuatorDelayUpperBound - a_target
            a_target = min(a_target_lower, a_target_upper)

            v_target_future = speeds[-1]
        else:
            v_target = 0.0
            v_target_future = 0.0
            a_target = 0.0

        # TODO: This check is not complete and needs to be enforced by MPC
        a_target = clip(a_target, ACCEL_MIN_ISO, ACCEL_MAX_ISO)

        self.pid.neg_limit = accel_limits[0]
        self.pid.pos_limit = accel_limits[1]

        # Update state machine
        output_accel = self.last_output_accel
        self.long_control_state = long_control_state_trans(
            self.CP, active, self.long_control_state, CS.vEgo, v_target,
            v_target_future, CS.brakePressed, CS.cruiseState.standstill,
            radar_state)

        if self.long_control_state == LongCtrlState.off:
            self.reset(CS.vEgo)
            output_accel = 0.

        # tracking objects and driving
        elif self.long_control_state == LongCtrlState.pid:
            self.v_pid = v_target

            # Toyota starts braking more when it thinks you want to stop
            # Freeze the integrator so we don't accelerate to compensate, and don't allow positive acceleration
            prevent_overshoot = not self.CP.stoppingControl and CS.vEgo < 1.5 and v_target_future < 0.7 and v_target_future < self.v_pid
            deadzone = interp(CS.vEgo, self.CP.longitudinalTuning.deadzoneBP,
                              self.CP.longitudinalTuning.deadzoneV)
            freeze_integrator = prevent_overshoot

            error = self.v_pid - CS.vEgo
            error_deadzone = apply_deadzone(error, deadzone)
            output_accel = self.pid.update(error_deadzone,
                                           speed=CS.vEgo,
                                           feedforward=a_target,
                                           freeze_integrator=freeze_integrator)

            if prevent_overshoot:
                output_accel = min(output_accel, 0.0)

        # Intention is to stop, switch to a different brake control until we stop
        elif self.long_control_state == LongCtrlState.stopping:
            # Keep applying brakes until the car is stopped
            if not CS.standstill or output_accel > self.CP.stopAccel:
                output_accel -= self.CP.stoppingDecelRate * DT_CTRL * \
                                interp(output_accel, [self.CP.stopAccel, self.CP.stopAccel/2., self.CP.stopAccel/4., 0.], [0.3, 0.65, 1., 2.])
            output_accel = clip(output_accel, accel_limits[0], accel_limits[1])
            self.reset(CS.vEgo)

        self.last_output_accel = output_accel
        final_accel = clip(output_accel, accel_limits[0], accel_limits[1])

        return final_accel
Exemplo n.º 8
0
class LatControlPID(LatControl):
    def __init__(self, CP, CI):
        super().__init__(CP, CI)
        self.pid = PIDController(
            (CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
            (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
            (CP.lateralTuning.pid.kdBP, CP.lateralTuning.pid.kdV),
            k_f=CP.lateralTuning.pid.kf,
            pos_limit=1.0,
            neg_limit=-1.0,
            sat_limit=CP.steerLimitTimer,
            derivative_period=0.1)
        self.get_steer_feedforward = CI.get_steer_feedforward_function()

    def reset(self):
        super().reset()
        self.pid.reset()

    def update(self, active, CS, CP, VM, params, desired_curvature,
               desired_curvature_rate):
        pid_log = log.ControlsState.LateralPIDState.new_message()
        pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
        pid_log.steeringRateDeg = float(CS.steeringRateDeg)

        angle_steers_des_no_offset = math.degrees(
            VM.get_steer_from_curvature(-desired_curvature, CS.vEgo,
                                        params.roll))
        angle_steers_des = angle_steers_des_no_offset + params.angleOffsetDeg

        pid_log.steeringAngleDesiredDeg = angle_steers_des
        pid_log.angleError = angle_steers_des - CS.steeringAngleDeg
        if CS.vEgo < MIN_STEER_SPEED or not active:
            output_steer = 0.0
            pid_log.active = False
            self.pid.reset()
        else:
            steers_max = get_steer_max(CP, CS.vEgo)
            self.pid.pos_limit = steers_max
            self.pid.neg_limit = -steers_max

            # offset does not contribute to resistive torque
            steer_feedforward = self.get_steer_feedforward(
                angle_steers_des_no_offset, CS.vEgo)

            # torque for steer rate. ~0 angle, steer rate ~= steer command.
            steer_rate_actual = CS.steeringRateDeg
            steer_rate_desired = math.degrees(
                VM.get_steer_from_curvature(-desired_curvature_rate, CS.vEgo,
                                            0))
            speed_mph = CS.vEgo * CV.MS_TO_MPH
            steer_rate_max = 0.0389837 * speed_mph**2 - 5.34858 * speed_mph + 223.831

            steer_feedforward += ((steer_rate_desired - steer_rate_actual) /
                                  steer_rate_max)

            deadzone = 0.0

            check_saturation = (
                CS.vEgo >
                10) and not CS.steeringRateLimited and not CS.steeringPressed
            output_steer = self.pid.update(angle_steers_des,
                                           CS.steeringAngleDeg,
                                           check_saturation=check_saturation,
                                           override=CS.steeringPressed,
                                           feedforward=steer_feedforward,
                                           speed=CS.vEgo,
                                           deadzone=deadzone)
            pid_log.active = True
            pid_log.p = self.pid.p
            pid_log.i = self.pid.i
            pid_log.f = self.pid.f
            pid_log.output = output_steer
            pid_log.saturated = self._check_saturation(
                steers_max - abs(output_steer) < 1e-3, CS)

        return output_steer, angle_steers_des, pid_log
Exemplo n.º 9
0
class LatControlTorque(LatControl):
    def __init__(self, CP, CI):
        super().__init__(CP, CI)
        self.CP = CP
        self.pid = PIDController(CP.lateralTuning.torque.kp,
                                 CP.lateralTuning.torque.ki,
                                 k_d=CP.lateralTuning.torque.kd,
                                 k_f=CP.lateralTuning.torque.kf,
                                 pos_limit=self.steer_max,
                                 neg_limit=-self.steer_max)
        self.get_steer_feedforward = CI.get_steer_feedforward_function()
        self.use_steering_angle = CP.lateralTuning.torque.useSteeringAngle
        self.friction = CP.lateralTuning.torque.friction
        self.deadzone = CP.lateralTuning.torque.deadzone
        self.errors = []
        self.tune = nTune(CP, self)

    def reset(self):
        super().reset()
        self.pid.reset()
        self.errors = []

    def update(self, active, CS, VM, params, last_actuators, desired_curvature,
               desired_curvature_rate, llk):
        self.tune.check()
        pid_log = log.ControlsState.LateralTorqueState.new_message()

        if CS.vEgo < MIN_STEER_SPEED or not active:
            output_torque = 0.0
            pid_log.active = False
            self.pid.reset()
            angle_steers_des = 0.0
        else:
            if self.use_steering_angle:
                actual_curvature = -VM.calc_curvature(
                    math.radians(CS.steeringAngleDeg - params.angleOffsetDeg),
                    CS.vEgo, params.roll)
            else:
                actual_curvature = llk.angularVelocityCalibrated.value[
                    2] / CS.vEgo
            desired_lateral_accel = desired_curvature * CS.vEgo**2
            desired_lateral_jerk = desired_curvature_rate * CS.vEgo**2
            actual_lateral_accel = actual_curvature * CS.vEgo**2

            setpoint = desired_lateral_accel + LOW_SPEED_FACTOR * desired_curvature
            measurement = actual_lateral_accel + LOW_SPEED_FACTOR * actual_curvature
            error = setpoint - measurement

            error_rate = 0
            if len(self.errors) >= ERROR_RATE_FRAME:
                error_rate = (
                    error - self.errors[-ERROR_RATE_FRAME]) / ERROR_RATE_FRAME

            self.errors.append(float(error))
            while len(self.errors) > ERROR_RATE_FRAME:
                self.errors.pop(0)

            error_deadzone = apply_deadzone(error, self.deadzone)

            pid_log.error = error_deadzone

            ff = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY
            # convert friction into lateral accel units for feedforward
            friction_compensation = interp(desired_lateral_jerk,
                                           [-JERK_THRESHOLD, JERK_THRESHOLD],
                                           [-self.friction, self.friction])
            ff += friction_compensation / self.CP.lateralTuning.torque.kf
            output_torque = self.pid.update(
                error_deadzone,
                error_rate,
                override=CS.steeringPressed,
                feedforward=ff,
                speed=CS.vEgo,
                freeze_integrator=CS.steeringRateLimited)

            pid_log.active = True
            pid_log.p = self.pid.p
            pid_log.i = self.pid.i
            pid_log.d = self.pid.d
            pid_log.f = self.pid.f
            pid_log.output = -output_torque
            pid_log.saturated = self._check_saturation(
                self.steer_max - abs(output_torque) < 1e-3, CS)

            angle_steers_des = math.degrees(
                VM.get_steer_from_curvature(
                    -desired_curvature, CS.vEgo,
                    params.roll)) + params.angleOffsetDeg

        # TODO left is positive in this convention
        return -output_torque, angle_steers_des, pid_log