mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-07 04:53:47 +08:00
80fbb4f6db
Register vehicle controls, planner modes, UI actions and Galaxy services after their providers exist. Wire the shared runtime entrypoints and cover their combined behavior. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Kacper Rączy <gfw.kra@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: haraschax <6804392+haraschax@users.noreply.github.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
122 lines
6.0 KiB
Python
122 lines
6.0 KiB
Python
import numpy as np
|
|
from opendbc.car.structs import car
|
|
from openpilot.common.realtime import DT_CTRL
|
|
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N
|
|
from openpilot.common.pid import PIDController
|
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
|
from openpilot.starpilot.longitudinal.extension import LongitudinalContext, create_extension
|
|
from openpilot.starpilot.longitudinal.takeoffs import TakeoffStart, eligible as takeoff_eligible
|
|
|
|
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
|
|
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
|
|
|
|
|
def long_control_state_trans(active, long_control_state, should_stop, brake_pressed, cruise_standstill):
|
|
starting_condition = (not should_stop and
|
|
not cruise_standstill and
|
|
not brake_pressed)
|
|
|
|
if not active:
|
|
long_control_state = LongCtrlState.off
|
|
|
|
else:
|
|
if long_control_state == LongCtrlState.off:
|
|
if not starting_condition:
|
|
long_control_state = LongCtrlState.stopping
|
|
else:
|
|
long_control_state = LongCtrlState.pid
|
|
|
|
elif long_control_state == LongCtrlState.stopping:
|
|
if starting_condition:
|
|
long_control_state = LongCtrlState.pid
|
|
|
|
elif long_control_state == LongCtrlState.pid:
|
|
if should_stop:
|
|
long_control_state = LongCtrlState.stopping
|
|
|
|
return long_control_state
|
|
|
|
class LongControl:
|
|
def __init__(self, CP, startup_preferences=None):
|
|
self.CP = CP
|
|
self.long_control_state = LongCtrlState.off
|
|
self.extension = create_extension(CP, startup_preferences)
|
|
self.stopping_decel_rate = self.extension.stopping_decel_rate if self.extension is not None else 1.0
|
|
self.pid = PIDController(self.extension.kp if self.extension is not None else 0.0,
|
|
(self.extension.ki if self.extension is not None and self.extension.ki is not None
|
|
else (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV)),
|
|
rate=1 / DT_CTRL)
|
|
self.last_output_accel = 0.0
|
|
self.takeoff_start = TakeoffStart() if takeoff_eligible(CP) else None
|
|
self.takeoff_starting = False
|
|
|
|
def reset(self, *, reset_start: bool = True):
|
|
self.pid.reset()
|
|
if self.extension is not None:
|
|
self.extension.reset(reset_start=reset_start)
|
|
|
|
def update(self, active, CS, a_target, should_stop, accel_limits, *, context=None):
|
|
"""Update longitudinal control. This updates the state machine and runs a PID loop"""
|
|
context = context if context is not None else LongitudinalContext()
|
|
self.pid.neg_limit = accel_limits[0]
|
|
self.pid.pos_limit = accel_limits[1]
|
|
|
|
planner_target = a_target
|
|
previous_state = self.long_control_state
|
|
enabled_takeoff = bool(context.faster_takeoffs and self.takeoff_start is not None)
|
|
ioniq_start = self.extension is not None and self.extension.ioniq6_start is not None
|
|
native_previous = (LongCtrlState.pid if previous_state == LongCtrlState.starting and
|
|
(self.takeoff_starting or enabled_takeoff and ioniq_start) else previous_state)
|
|
native_state = long_control_state_trans(active, native_previous, should_stop,
|
|
CS.brakePressed, CS.cruiseState.standstill and
|
|
not (self.extension is not None and self.extension.ignore_cruise_standstill))
|
|
owned_start = self.extension is not None and any((self.extension.gm_start, self.extension.vehicle_stop,
|
|
self.extension.stopping_policy))
|
|
selected = bool(enabled_takeoff and not owned_start and self.takeoff_start.select(
|
|
active=active, CS=CS, target=a_target, should_stop=should_stop, limits=accel_limits,
|
|
evidence=context.start_evidence, stock_hold_allowed=ioniq_start))
|
|
if selected:
|
|
native_state = LongCtrlState.starting
|
|
self.long_control_state = native_state
|
|
if self.extension is not None:
|
|
self.long_control_state = self.extension.transition(
|
|
native_state, previous_state, active, CS, a_target, should_stop, accel_limits,
|
|
context=context)
|
|
self.takeoff_starting = selected and self.long_control_state == LongCtrlState.starting
|
|
if self.long_control_state == LongCtrlState.off:
|
|
self.reset()
|
|
output_accel = 0.
|
|
|
|
elif self.long_control_state == LongCtrlState.stopping:
|
|
output_accel = self.last_output_accel
|
|
if output_accel > self.CP.stopAccel:
|
|
output_accel = min(output_accel, 0.0)
|
|
# TODO: can we just go straight to stopAccel?
|
|
output_accel -= self.stopping_decel_rate * DT_CTRL # m/s^2/s while trying to stop
|
|
if self.extension is not None:
|
|
output_accel = self.extension.stopping_output(output_accel, a_target, should_stop, CS)
|
|
self.reset(reset_start=False)
|
|
|
|
elif self.long_control_state == LongCtrlState.starting and self.extension is not None and self.extension.starting:
|
|
output_accel = self.extension.starting_output(self.pid, a_target, accel_limits, context)
|
|
|
|
else: # LongCtrlState.pid
|
|
if self.extension is not None:
|
|
a_target = self.extension.target(a_target, CS, should_stop, self.last_output_accel, context)
|
|
error = a_target - CS.aEgo
|
|
feedforward, freeze_integrator = a_target, False
|
|
if self.extension is not None:
|
|
feedforward, freeze_integrator = self.extension.prepare_pid(
|
|
self.pid, a_target, error, CS, self.last_output_accel, accel_limits, should_stop, context)
|
|
output_accel = self.pid.update(error, speed=CS.vEgo, feedforward=feedforward,
|
|
freeze_integrator=freeze_integrator)
|
|
if self.extension is not None:
|
|
output_accel = self.extension.shape_output(output_accel, a_target, error, CS, self.last_output_accel,
|
|
previous_state, should_stop, context)
|
|
|
|
if self.takeoff_starting:
|
|
output_accel = min(output_accel, planner_target)
|
|
self.last_output_accel = np.clip(output_accel, accel_limits[0], accel_limits[1])
|
|
return self.last_output_accel
|