[pilot智驾系统] 自动驾驶守护进程(selfdrived)

第3章:自动驾驶守护进程(selfdrived)

在前几章中,我们探讨了sunnypilot如何使用用户界面状态(UIState)更新屏幕显示,以及通过参数系统记住重要设置。

sunnypilot实际上是如何思考并决定该做什么的?它如何知道何时驾驶、何时警告我们或何时退出控制?

这就是**自动驾驶守护进程(selfdrived)**发挥作用的地方

selfdrived视为sunnypilot中央大脑指挥官

它是核心组件,接收所有传入信息------如车辆速度、转向、传感器数据、驾驶模型的预测,甚至我们作为驾驶员的操作------并利用这些信息做出关于sunnypilot整体行为的关键决策。

基于所有这些输入,selfdrived不断确定sunnypilot的当前"状态"(如已激活、未激活、警告中),并为系统的其他部分(包括屏幕)发布必要的命令和信息。

它在管理安全警报和整体系统行为以确保行车安全方面也起着关键作用。

为什么需要自动驾驶守护进程?

没有selfdrivedsunnypilot将是一堆互不关联的部件。一个部件可能知道车速,另一个可能知道车道线,但没有一个组件负责将所有信息整合成对驾驶情况的连贯理解,并决定系统的整体行动。

selfdrived通过成为决策者来解决这个问题。

它聚合数据,根据安全规则和操作条件评估当前情况,然后指导sunnypilot的行为,确保统一且安全的驾驶体验。

用例:决定sunnypilot的驾驶状态

想象我们正在驾驶,按下"启用"按钮激活sunnypilotselfdrived如何决定是否应该真正激活 并开始辅助驾驶?或者,如果sunnypilot已激活,但突然车门打开,selfdrived会如何反应?

这是通过selfdrived持续评估其"状态"来处理的,这些状态可以是:

  • 禁用sunnypilot关闭,不控制车辆。
  • 预启用:等待条件(如松开刹车)以完全激活。
  • 已启用sunnypilot正在主动控制车辆。
  • 覆盖中 :我们在sunnypilot技术上仍启用时轻微转向或踩踏板。
  • 软禁用sunnypilot由于非关键问题优雅地关闭控制,给我们时间接管。
  • 立即禁用sunnypilot由于关键安全问题快速关闭控制。

selfdrived始终监视可能触发这些状态变化的情况。

自动驾驶守护进程的工作原理

selfdrived想象成飞机驾驶舱中训练有素的飞行员。

这位飞行员不断接收来自所有仪器和传感器的信息,听取空中交通管制,并监控副驾驶。基于所有这些输入,飞行员做出关于飞行的决策(起飞、巡航、着陆、应急程序),并将这些决策传达给飞机其他系统。

以下是selfdrived主要任务的简化视图:

  1. 收集信息 :它读取来自许多其他sunnypilot组件的消息,如:
    • 车辆状态:当前速度、转向角度、踏板输入、档位等。
    • 模型守护进程:关于道路、车道线和其他车辆的预测。
    • 驾驶员监控:驾驶员是否在注意路况。
    • 传感器:设备温度、剩余存储、摄像头状态。
  2. 生成事件 :基于收集的信息,selfdrived生成"事件"。事件就是值得注意的情况,如"驾驶员踩踏板"、"车门打开"、"低于激活速度"或"系统过热"。
  3. 确定状态 :它使用"状态机"来确定sunnypilot的整体驾驶状态(如已启用禁用)。这个决策很大程度上受刚刚生成的事件影响。
  4. 管理警报 :然后,它根据当前状态和事件确定应向驾驶员显示哪些视觉或听觉警报(如"接管控制"、"驾驶员分心")。
  5. 发布输出 :最后,selfdrived发布其计算的selfdriveStateonroadEvents消息。其他守护进程,如UI(使用用户界面状态(UIState)),读取这些消息以更新屏幕并执行其他操作。

让我们可视化这个流程:

如何使用自动驾驶守护进程(与其输出交互)

作为初学者,我们不会像使用Params那样直接"使用"selfdrived调用其函数。

相反,我们会读取它发布的消息以了解sunnypilot的当前驾驶状态和警报。selfdrived发布的最重要消息是selfdriveState

以下是sunnypilot的其他部分(如用户界面状态(UIState))读取此信息的方式:

python 复制代码
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方法的简化版本:

python 复制代码
# 摘自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将原始传感器数据、车辆状态和其他系统信息转换为有意义"事件"的地方。

python 复制代码
# 摘自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.gasPressedCS.doorOpen、设备温度),并向其self.events对象添加相应的EventName

Events类(来自selfdrive/selfdrived/events.py)本质上是当前正在发生或检测到的所有事情的列表。这些事件对下一步至关重要。

2. 确定系统状态:StateMachine

一旦selfdrived有了所有当前Events的列表,它就将它们传递给其StateMachineselfdrive/selfdrived/state.py)。StateMachine就像一本规则手册,规定了sunnypilot应如何在其不同驾驶状态之间转换。

python 复制代码
# 摘自selfdrive/selfdrived/state.py(简化版)
from cereal import log
from openpilot.selfdrive.selfdrived.events import Events, ET # ET表示事件类型

State = log.SelfdriveState.OpenpilotState # 例如enabled, disabled, softDisabling

class StateMachine:
  def __init__(self):
    self.state = State.disabled # 从禁用状态开始
    self.soft_disable_timer = 0

  def 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

StateMachineupdate方法是核心逻辑。它查看events列表和self.state来决定sunnypilot是否应改变其模式。例如:

  • 如果self.stateenabledevents.contains(ET.SOFT_DISABLE)(如overheat),它转换为softDisabling
  • 如果self.statedisabledevents.contains(ET.ENABLE)(如按下恢复)且 events.contains(ET.NO_ENTRY)(如"车门打开"),它转换为enabled

3. 管理警报:update_alerts

确定状态后,selfdrived使用AlertManager处理Events并决定应向驾驶员显示哪些特定警报(如"注意"或"转向暂时不可用")。这是实际警报文本、声音和视觉提示确定的地方。

4. 发布输出:publish_selfdriveState

最后,selfdrived创建并发送selfdriveState消息,其中包含:

  • enabled:指示sunnypilot是否已激活的布尔值。
  • state:来自StateMachine的当前状态(如enableddisabled)。
  • alertText1alertText2alertStatus等:关于要显示的最高优先级警报的详细信息。
  • personality:我们选择的驾驶个性(如激进、标准)。

这个消息对用户界面状态(UIState)和其他守护进程做出适当反应至关重要。

总结

**自动驾驶守护进程(selfdrived)**确实是sunnypilot的大脑。

它持续监控大量信息,将其处理为可理解的Events,使用StateMachine确定sunnypilot的整体驾驶状态,管理关键安全警报,并发布其决策供系统其余部分执行。通过集中这种复杂的决策,selfdrived确保sunnypilot在道路上安全、响应迅速且智能地运行。

在下一章中,我们将通过深入研究**控制守护进程(controlsd)**,了解selfdrived的这些决策如何转化为车辆的实际动作。

下一章:控制守护进程(controlsd)

相关推荐
来根烟了寂寞21 分钟前
瑞芯微rv1106交叉编译openssl 1.x
linux·嵌入式
一川月白7091 小时前
Linux--->网络编程(TCP并发服务器构建:[ 多进程、多线程、select ])
linux·运维·服务器·网络编程·io并发服务器
EnigmaCoder1 小时前
【Linux】用户与用户组管理
linux·运维·服务器·数据库
tan77º2 小时前
【项目】分布式Json-RPC框架 - 抽象层与具象层实现
linux·服务器·c++·分布式·tcp/ip·rpc·json
xiaok2 小时前
chown和chmod的使用
linux
zzx_blog2 小时前
c++函数工厂实现两种方式:lambda和function
c++
jokr_3 小时前
C++ STL 顶层设计与安全:迭代器、失效与线程安全
java·c++·安全
Lovyk3 小时前
完整实验命令解析:从集群搭建到负载均衡配置(2)
linux·运维·服务器
jokr_3 小时前
C++ 指针与引用面试深度解析
java·c++·面试