controlsd: pull out selfdrive state machine (#33477)
* controlsd: pull out selfdrive state machine * cleanup test * cleanuppull/33479/head
parent
54a2626e44
commit
77f4f57e73
3 changed files with 148 additions and 147 deletions
@ -0,0 +1,98 @@ |
||||
from cereal import log |
||||
from openpilot.selfdrive.controls.lib.events import Events, ET |
||||
from openpilot.common.realtime import DT_CTRL |
||||
|
||||
State = log.SelfdriveState.OpenpilotState |
||||
|
||||
SOFT_DISABLE_TIME = 3 # seconds |
||||
ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding) |
||||
ENABLED_STATES = (State.preEnabled, *ACTIVE_STATES) |
||||
|
||||
class StateMachine: |
||||
def __init__(self): |
||||
self.current_alert_types = [ET.PERMANENT] |
||||
self.state = State.disabled |
||||
self.soft_disable_timer = 0 |
||||
|
||||
def update(self, events: Events): |
||||
# decrement the soft disable timer at every step, as it's reset on |
||||
# entrance in SOFT_DISABLING state |
||||
self.soft_disable_timer = max(0, self.soft_disable_timer - 1) |
||||
|
||||
self.current_alert_types = [ET.PERMANENT] |
||||
|
||||
# ENABLED, SOFT DISABLING, PRE ENABLING, OVERRIDING |
||||
if self.state != State.disabled: |
||||
# user and immediate disable always have priority in a non-disabled state |
||||
if events.contains(ET.USER_DISABLE): |
||||
self.state = State.disabled |
||||
self.current_alert_types.append(ET.USER_DISABLE) |
||||
|
||||
elif events.contains(ET.IMMEDIATE_DISABLE): |
||||
self.state = State.disabled |
||||
self.current_alert_types.append(ET.IMMEDIATE_DISABLE) |
||||
|
||||
else: |
||||
# ENABLED |
||||
if self.state == State.enabled: |
||||
if events.contains(ET.SOFT_DISABLE): |
||||
self.state = State.softDisabling |
||||
self.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL) |
||||
self.current_alert_types.append(ET.SOFT_DISABLE) |
||||
|
||||
elif events.contains(ET.OVERRIDE_LATERAL) or events.contains(ET.OVERRIDE_LONGITUDINAL): |
||||
self.state = State.overriding |
||||
self.current_alert_types += [ET.OVERRIDE_LATERAL, ET.OVERRIDE_LONGITUDINAL] |
||||
|
||||
# SOFT DISABLING |
||||
elif self.state == State.softDisabling: |
||||
if not events.contains(ET.SOFT_DISABLE): |
||||
# no more soft disabling condition, so go back to ENABLED |
||||
self.state = State.enabled |
||||
|
||||
elif self.soft_disable_timer > 0: |
||||
self.current_alert_types.append(ET.SOFT_DISABLE) |
||||
|
||||
elif self.soft_disable_timer <= 0: |
||||
self.state = State.disabled |
||||
|
||||
# PRE ENABLING |
||||
elif self.state == State.preEnabled: |
||||
if not events.contains(ET.PRE_ENABLE): |
||||
self.state = State.enabled |
||||
else: |
||||
self.current_alert_types.append(ET.PRE_ENABLE) |
||||
|
||||
# OVERRIDING |
||||
elif self.state == State.overriding: |
||||
if events.contains(ET.SOFT_DISABLE): |
||||
self.state = State.softDisabling |
||||
self.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL) |
||||
self.current_alert_types.append(ET.SOFT_DISABLE) |
||||
elif not (events.contains(ET.OVERRIDE_LATERAL) or events.contains(ET.OVERRIDE_LONGITUDINAL)): |
||||
self.state = State.enabled |
||||
else: |
||||
self.current_alert_types += [ET.OVERRIDE_LATERAL, ET.OVERRIDE_LONGITUDINAL] |
||||
|
||||
# DISABLED |
||||
elif self.state == State.disabled: |
||||
if events.contains(ET.ENABLE): |
||||
if events.contains(ET.NO_ENTRY): |
||||
self.current_alert_types.append(ET.NO_ENTRY) |
||||
|
||||
else: |
||||
if events.contains(ET.PRE_ENABLE): |
||||
self.state = State.preEnabled |
||||
elif events.contains(ET.OVERRIDE_LATERAL) or events.contains(ET.OVERRIDE_LONGITUDINAL): |
||||
self.state = State.overriding |
||||
else: |
||||
self.state = State.enabled |
||||
self.current_alert_types.append(ET.ENABLE) |
||||
|
||||
# Check if openpilot is engaged and actuators are enabled |
||||
enabled = self.state in ENABLED_STATES |
||||
active = self.state in ACTIVE_STATES |
||||
if active: |
||||
self.current_alert_types.append(ET.WARNING) |
||||
return enabled, active |
||||
|
Loading…
Reference in new issue