[pilot智驾系统] 自动驾驶守护进程(selfdrived)
第3章:自动驾驶守护进程(selfdrived)
在前几章中,我们探讨了sunnypilot
如何使用用户界面状态(UIState)更新屏幕显示,以及通过参数系统记住重要设置。
但sunnypilot
实际上是如何思考并决定该做什么的?它如何知道何时驾驶、何时警告我们或何时退出控制?
这就是**自动驾驶守护进程(selfdrived)**发挥作用的地方
将
selfdrived
视为sunnypilot
的中央大脑或指挥官。
它是核心组件,接收所有传入信息——如车辆速度、转向、传感器数据、驾驶模型的预测,甚至我们作为驾驶员的操作——并利用这些信息做出关于sunnypilot
整体行为的关键决策。
基于所有这些输入,selfdrived
不断确定sunnypilot
的当前"状态"(如已激活、未激活、警告中),并为系统的其他部分(包括屏幕)发布必要的命令和信息。
它在管理安全警报和整体系统行为以确保行车安全方面也起着关键作用。
为什么需要自动驾驶守护进程?
没有selfdrived
,sunnypilot
将是一堆互不关联的部件。一个部件可能知道车速,另一个可能知道车道线,但没有一个组件负责将所有信息整合成对驾驶情况的连贯理解,并决定系统的整体行动。
selfdrived
通过成为决策者来解决这个问题。
它聚合数据,根据安全规则和操作条件评估当前情况,然后指导sunnypilot
的行为,确保统一且安全的驾驶体验。
用例:决定sunnypilot
的驾驶状态
想象我们正在驾驶,按下"启用"按钮激活sunnypilot
。selfdrived
如何决定是否应该真正激活并开始辅助驾驶?或者,如果sunnypilot
已激活,但突然车门打开,selfdrived
会如何反应?
这是通过selfdrived
持续评估其"状态"来处理的,这些状态可以是:
- 禁用:
sunnypilot
关闭,不控制车辆。 - 预启用:等待条件(如松开刹车)以完全激活。
- 已启用:
sunnypilot
正在主动控制车辆。 - 覆盖中:我们在
sunnypilot
技术上仍启用时轻微转向或踩踏板。 - 软禁用:
sunnypilot
由于非关键问题优雅地关闭控制,给我们时间接管。 - 立即禁用:
sunnypilot
由于关键安全问题快速关闭控制。
selfdrived
始终监视可能触发这些状态变化的情况。
自动驾驶守护进程的工作原理
将selfdrived
想象成飞机驾驶舱中训练有素的飞行员。
这位飞行员不断接收来自所有仪器和传感器的信息,听取空中交通管制,并监控副驾驶。基于所有这些输入,飞行员做出关于飞行的决策(起飞、巡航、着陆、应急程序),并将这些决策传达给飞机其他系统。
以下是selfdrived
主要任务的简化视图:
- 收集信息:它读取来自许多其他
sunnypilot
组件的消息,如:- 车辆状态:当前速度、转向角度、踏板输入、档位等。
- 模型守护进程:关于道路、车道线和其他车辆的预测。
- 驾驶员监控:驾驶员是否在注意路况。
- 传感器:设备温度、剩余存储、摄像头状态。
- 生成事件:基于收集的信息,
selfdrived
生成"事件"。事件就是值得注意的情况,如"驾驶员踩踏板"、“车门打开”、“低于激活速度"或"系统过热”。 - 确定状态:它使用"状态机"来确定
sunnypilot
的整体驾驶状态(如已启用
、禁用
)。这个决策很大程度上受刚刚生成的事件
影响。 - 管理警报:然后,它根据当前状态和
事件
确定应向驾驶员显示哪些视觉或听觉警报(如"接管控制"、“驾驶员分心”)。 - 发布输出:最后,
selfdrived
发布其计算的selfdriveState
和onroadEvents
消息。其他守护进程,如UI(使用用户界面状态(UIState)),读取这些消息以更新屏幕并执行其他操作。
让我们可视化这个流程:
如何使用自动驾驶守护进程(与其输出交互)
作为初学者,我们不会像使用Params
那样直接"使用"selfdrived
调用其函数。
相反,我们会读取它发布的消息以了解sunnypilot
的当前驾驶状态和警报。selfdrived
发布的最重要消息是selfdriveState
。
以下是sunnypilot
的其他部分(如用户界面状态(UIState))读取此信息的方式:
import cereal.messaging as messaging
from cereal import log # 访问SelfdriveState枚举# 创建SubMaster以监听消息
sm = messaging.SubMaster(["selfdriveState"])# 在运行非常频繁的循环中(如UI的更新循环)
while True:sm.update(0) # 检查新消息if sm.updated["selfdriveState"]:current_selfdrive_state = sm["selfdriveState"]# 检查sunnypilot的驾驶状态if current_selfdrive_state.enabled:print("sunnypilot当前已激活并正在驾驶!")elif current_selfdrive_state.state == log.SelfdriveState.OpenpilotState.softDisabling:print(f"sunnypilot正在软禁用。原因:{current_selfdrive_state.alertText2}")else:print("sunnypilot未激活。")# 检查活动警报if current_selfdrive_state.alertText1:print(f"活动警报:{current_selfdrive_state.alertText1} - {current_selfdrive_state.alertText2}")print(f" 状态:{current_selfdrive_state.alertStatus}, 声音:{current_selfdrive_state.alertSound}")# ... 其他逻辑 ...
这段代码展示了从selfdrived
获取当前selfdriveState
是多么简单。
它允许任何组件(如仪表盘显示)立即知道sunnypilot
是否已激活、为何可能正在软禁用或需要显示哪些警报。
这个selfdriveState
消息正是用户界面状态(UIState)监听其许多显示属性的内容
底层原理:selfdrived
核心循环
selfdrived
是一个Python程序(selfdrive/selfdrived/selfdrived.py
),在后台持续运行。
其核心是一个run
方法,该方法重复调用step
方法。这个step
方法协调我们讨论的所有任务。
让我们看看step
方法的简化版本:
# 摘自selfdrive/selfdrived/selfdrived.py(简化版)
class SelfdriveD:# ... (初始化方法) ...def step(self):# 1. 收集所有必要的输入数据CS = self.data_sample()# 2. 更新当前驾驶事件列表self.update_events(CS)# 3. 使用事件更新sunnypilot的整体状态self.enabled, self.active = self.state_machine.update(self.events)# 4. 确定应显示哪些警报self.update_alerts(CS)# 5. 发布结果供其他守护进程读取self.publish_selfdriveState(CS)# 记住下一次循环迭代的车辆状态self.CS_prev = CS
这个step
方法每秒运行多次(100 Hz),确保selfdrived
始终快速响应新信息。让我们分解最重要的部分。
1. 生成事件:update_events
update_events
方法是selfdrived
将原始传感器数据、车辆状态和其他系统信息转换为有意义"事件"的地方。
# 摘自selfdrive/selfdrived/selfdrived.py(简化版)
from cereal import car, log
from openpilot.selfdrive.selfdrived.events import Events # 我们的事件管理器class SelfdriveD:# ... (初始化和其他方法) ...def update_events(self, CS):self.events.clear() # 为这个周期开始一个全新的事件列表# 示例:如果驾驶员踩下油门踏板if CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator:self.events.add(log.OnroadEvent.EventName.pedalPressed) # 添加'pedalPressed'事件# 示例:如果车门打开if CS.doorOpen:self.events.add(log.OnroadEvent.EventName.doorOpen)# 示例:如果系统过热if self.sm['deviceState'].thermalStatus >= log.DeviceState.ThermalStatus.red:self.events.add(log.OnroadEvent.EventName.overheat)# ... 更多对各种条件的检查 ...
在update_events
中,selfdrived
检查各种条件(如CS.gasPressed
、CS.doorOpen
、设备温度),并向其self.events
对象添加相应的EventName
。
Events
类(来自selfdrive/selfdrived/events.py
)本质上是当前正在发生或检测到的所有事情的列表。这些事件对下一步至关重要。
2. 确定系统状态:StateMachine
一旦selfdrived
有了所有当前Events
的列表,它就将它们传递给其StateMachine
(selfdrive/selfdrived/state.py
)。StateMachine
就像一本规则手册,规定了sunnypilot
应如何在其不同驾驶状态之间转换。
# 摘自selfdrive/selfdrived/state.py(简化版)
from cereal import log
from openpilot.selfdrive.selfdrived.events import Events, ET # ET表示事件类型State = log.SelfdriveState.OpenpilotState # 例如enabled, disabled, softDisablingclass StateMachine:def __init__(self):self.state = State.disabled # 从禁用状态开始self.soft_disable_timer = 0def update(self, events: Events):# 如果当前状态不是禁用,检查退出触发条件if self.state != State.disabled: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)elif self.state == State.enabled:if events.contains(ET.SOFT_DISABLE): # 例如系统过热self.state = State.softDisabling # 转换为软禁用self.soft_disable_timer = 300 # 大约3秒(300步@100Hz)# self.current_alert_types.append(ET.SOFT_DISABLE)elif self.state == State.softDisabling:if not events.contains(ET.SOFT_DISABLE):self.state = State.enabled # 如果软禁用条件清除,返回启用elif self.soft_disable_timer <= 0:self.state = State.disabled # 如果软禁用时间用完,完全禁用# 如果当前状态是禁用,检查激活触发条件elif self.state == State.disabled:if events.contains(ET.ENABLE): # 例如驾驶员按下恢复按钮if not events.contains(ET.NO_ENTRY): # 检查是否存在"禁止进入"条件self.state = State.enabled # 转换为启用# self.current_alert_types.append(ET.ENABLE)# 最后,确定openpilot是否实际"启用"和"活跃"enabled = self.state in (State.preEnabled, State.enabled, State.softDisabling, State.overriding)active = self.state in (State.enabled, State.softDisabling, State.overriding)return enabled, active
StateMachine
的update
方法是核心逻辑。它查看events
列表和self.state
来决定sunnypilot
是否应改变其模式。例如:
- 如果
self.state
是enabled
且events.contains(ET.SOFT_DISABLE)
(如overheat
),它转换为softDisabling
。 - 如果
self.state
是disabled
且events.contains(ET.ENABLE)
(如按下恢复)且不events.contains(ET.NO_ENTRY)
(如"车门打开"),它转换为enabled
。
3. 管理警报:update_alerts
确定状态后,selfdrived
使用AlertManager
处理Events
并决定应向驾驶员显示哪些特定警报(如"注意"或"转向暂时不可用")。这是实际警报文本、声音和视觉提示确定的地方。
4. 发布输出:publish_selfdriveState
最后,selfdrived
创建并发送selfdriveState
消息,其中包含:
enabled
:指示sunnypilot
是否已激活的布尔值。state
:来自StateMachine
的当前状态(如enabled
、disabled
)。alertText1
、alertText2
、alertStatus
等:关于要显示的最高优先级警报的详细信息。personality
:我们选择的驾驶个性(如激进、标准)。
这个消息对用户界面状态(UIState)和其他守护进程做出适当反应至关重要。
总结
**自动驾驶守护进程(selfdrived)**确实是sunnypilot
的大脑。
它持续监控大量信息,将其处理为可理解的Events
,使用StateMachine
确定sunnypilot
的整体驾驶状态,管理关键安全警报,并发布其决策供系统其余部分执行。通过集中这种复杂的决策,selfdrived
确保sunnypilot
在道路上安全、响应迅速且智能地运行。
在下一章中,我们将通过深入研究**控制守护进程(controlsd)**,了解selfdrived
的这些决策如何转化为车辆的实际动作。
下一章:控制守护进程(controlsd)