当前位置: 首页 > news >正文

[pilot智驾系统] 驾驶员监控守护进程(dmonitoringd)

第7章:驾驶员监控守护进程(dmonitoringd)

在上一章中,我们研究了纵向规划器(LongitudinalPlanner),它精妙地规划车辆的加速和制动

但当sunnypilot忙于驾驶时,谁来确保我们——人类驾驶员——保持注意力集中并在需要时随时准备接管?

这就是**驾驶员监控守护进程(dmonitoringd)**的职责所在

dmonitoringd视为sunnypilot警觉副驾驶安全监督员。它通过车内面向驾驶员的摄像头持续观察我们,评估注意力水平,检测是否分心甚至困倦。如果发现注意力不足,会触发警报以恢复专注,确保当sunnypilot需要协助时我们随时准备接管

为什么需要驾驶员监控守护进程?

尽管sunnypilot是先进的驾驶辅助系统,但并非完全自动驾驶。

驾驶员始终负有最终责任,必须随时准备介入。没有dmonitoringdsunnypilot无法知晓驾驶员是否在看手机、闭眼或面朝别处,这将带来巨大安全隐患。

dmonitoringd通过主动监控驾驶员状态解决这个问题。它确保sunnypilot始终在"驾驶员完全专注"的前提下运行,如果这个前提不成立,则会提醒驾驶员恢复注意力,甚至为安全考虑解除系统。

用例:检测驾驶员分心

假设我们开启sunnypilot驾驶时低头看手机几秒钟。

dmonitoringd如何检测并响应?

  1. 摄像头输入:驾驶员摄像头持续拍摄视频流
  2. AI分析:将图像输入强大的AI模型,分析头部姿态、眼球运动和面部特征
  3. 分心检测:AI检测到头部转向或视线偏离道路
  4. 意识水平:开始降低"注意力"评分
  5. 警报:如果注意力评分过低,触发声音警报(如"请注意!")和屏幕视觉警告。若仍无响应,最终可能解除sunnypilot

驾驶员监控守护进程工作原理

dmonitoringd以后台持续运行的两个主要阶段工作:

  1. 驾驶员监控模型(dmonitoringmodeld):直接处理原始摄像头图像的"大脑",使用AI模型分析面部、眼睛和头部姿态,输出详细的"驾驶员状态"(如头部俯仰/偏航/旋转角度、眨眼概率等)
  2. 驾驶员监控逻辑(dmonitoringd):“决策者”,获取模型的原始驾驶员状态,结合其他信息(如车速、sunnypilot激活状态),通过规则集确定整体awareness(注意力水平)并决定是否触发警报

流程可视化:

驾驶员摄像头驾驶员监控模型(dmonitoringmodeld)驾驶员监控守护进程(dmonitoringd)自动驾驶守护进程UI状态发送实时视频帧1. AI模型分析面部、眼睛、头部姿态2. 发布DriverStateV2消息(原始数据)3. 解析原始数据,计算注意力水平4. 发布DriverMonitoringState消息4. 发布DriverMonitoringState消息根据注意力水平调整系统状态/警报更新界面显示驾驶员警告驾驶员摄像头驾驶员监控模型(dmonitoringmodeld)驾驶员监控守护进程(dmonitoringd)自动驾驶守护进程UI状态

如何与驾驶员监控守护进程交互(其输出)

作为初学者,我们不会直接"调用"dmonitoringd函数。其他sunnypilot组件会监听其发布的driverMonitoringState消息,该消息包含驾驶员是否分心、当前注意力水平及活动警报等关键信息。

以下是其他组件(如UI状态(UIState)或自动驾驶守护进程(selfdrived))读取该信息的示例:

import cereal.messaging as messaging
from cereal import log # 访问DriverMonitoringState和EventName# 创建SubMaster监听消息
sm = messaging.SubMaster(["driverMonitoringState"])# 在UI的高频循环中
while True:sm.update(0) # 检查新消息if sm.updated["driverMonitoringState"]:dm_state = sm["driverMonitoringState"]# 检查驾驶员是否被检测为分心if dm_state.isDistracted:print("警告:驾驶员分心!")# 查看当前注意力水平(1.0为完全专注,0.0为临界)print(f"驾驶员注意力:{dm_state.awarenessStatus:.2f}")# 检查活动警报for event in dm_state.events:if event.enable: # 仅显示启用的事件if event.name == log.OnroadEvent.EventName.promptDriverDistracted:print("  警报:提示-请注意!")elif event.name == log.OnroadEvent.EventName.driverDistracted:print("  警报:红色-立即接管控制!")# ...其他逻辑...

这段代码展示了获取当前驾驶员监控状态的简易方式。基于dm_state.isDistracteddm_state.awarenessStatusevents列表,UI可以显示警告,自动驾驶守护进程(selfdrived)可以决定是否需要调整sunnypilot行为或解除控制。

底层原理:驾驶员监控的双子系统

dmonitoringd实际上由两个协同工作的Python程序组成:

1. dmonitoringmodeld.py:AI视觉

该程序(selfdrive/modeld/dmonitoringmodeld.py)专用于运行"观察"驾驶员的神经网络(AI模型):

# 摘自selfdrive/modeld/dmonitoringmodeld.py(简化版)
import cereal.messaging as messaging
from msgq.visionipc import VisionIpcClient, VisionStreamType
# ...其他模型加载和处理导入...# 代表驾驶员监控AI模型
class ModelState:def __init__(self, cl_ctx):# 加载实际AI模型(.pkl文件)self.model_run = pickle.load(f)# ...输入缓冲区设置...def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple[np.ndarray, float]:# 1. 为AI模型准备摄像头图像(buf)input_img_cl = self.frame.prepare(buf, transform.flatten())# 2. 使用图像和校准数据运行AI模型output = self.model_run(**self.tensor_inputs).contiguous().realize().uop.base.buffer.numpy()return output, # ...执行时间...def main():# ...(初始设置)...model = ModelState(cl_context) # 初始化AI模型vipc_client = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_DRIVER, True, cl_context) # 连接摄像头pm = messaging.PubMaster(["driverStateV2"]) # 模型输出发布者while True:buf = vipc_client.recv() # 从驾驶员摄像头获取新帧if buf is None:continue# 从liveCalibration消息获取校准# calib = ...# 运行AI模型获取原始预测model_output, gpu_execution_time = model.run(buf, calib, model_transform)# 将原始模型输出转换为Cereal消息并发布pm.send("driverStateV2", get_driverstate_packet(model_output, ...))# ...

dmonitoringmodeld.py持续从驾驶员摄像头接收帧(vipc_client.recv()),将这些帧与车辆校准数据一起输入ModelState.run()方法。该方法执行专用AI模型,输出代表驾驶员面部、视线、眨眼概率等原始预测的数字数组(model_output),最后打包成driverStateV2消息发布。

2. dmonitoringd.py:逻辑引擎

该程序(selfdrive/monitoring/dmonitoringd.py)是核心逻辑,订阅dmonitoringmodelddriverStateV2消息及其他关键消息,使用DriverMonitoring类处理所有信息并确定最终的驾驶员注意力状态和警报。

# 摘自selfdrive/monitoring/dmonitoringd.py(简化版)
import cereal.messaging as messaging
from openpilot.common.params import Params
from openpilot.selfdrive.monitoring.helpers import DriverMonitoringdef dmonitoringd_thread():params = Params()pm = messaging.PubMaster(['driverMonitoringState']) # 最终DM状态发布者sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'selfdriveState', 'modelV2','carControl'], poll='driverStateV2') # 订阅者# 初始化包含所有逻辑的DriverMonitoring类DM = DriverMonitoring(rhd_saved=params.get_bool("IsRhdDetected"))while True:sm.update() # 等待新消息,特别是driverStateV2if not sm.updated['driverStateV2']:continue # 仅当有新驾驶员监控模型输出时继续# 使用所有订阅消息运行主逻辑步骤DM.run_step(sm)# 发布最终driverMonitoringState消息dat = DM.get_state_packet(valid=sm.all_checks())pm.send('driverMonitoringState', dat)# ...定期保存RHD偏好...

dmonitoringd_threadwhile True循环是主心跳,通过sm.updated['driverStateV2']持续接收处理后的驾驶员数据

将所有相关信息(来自sm)传递给DriverMonitoring类的DM.run_step()方法,这里是所有决策发生的地方。

DriverMonitoring辅助类(helpers.py)

DriverMonitoring类(selfdrive/monitoring/helpers.py)包含管理驾驶员注意力和警报的所有复杂逻辑,围绕几个关键概念构建:

  • awareness:0.0到1.0的值,代表驾驶员专注程度。检测到分心时降低,专注时升高(或触摸方向盘表示参与时)
  • _set_timers(active_monitoring):决定awareness衰减速度。检测到面部且模型置信度高(active_monitoring=True)时衰减较慢;未检测到面部或模型不确定时awareness快速衰减,更快触发警报
  • _update_states(driver_state, ...):处理原始driverStateV2数据:
    • face_orientation_from_net:将原始神经网络输出转换为易懂的驾驶员头部相对于车辆的横滚、俯仰和偏航角度
    • DriverPose:跟踪驾驶员头部姿态,使用RunningStatFilter学习"自然"头部姿态偏移以校准
    • DistractedType:识别特定分心类型,如DISTRACTED_POSE(头部转向)、DISTRACTED_BLINK(闭眼或眨眼过多)或DISTRACTED_E2E(模型直接"未准备"预测)
    • 更新self.face_detectedself.pose.low_std(模型对姿态检测的置信度)和self.driver_distracted
  • _update_events(driver_engaged, op_engaged, ...):核心注意力逻辑和警报生成:
    • 驾驶员分心或模型不确定时递减self.awareness
    • 驾驶员专注时递增self.awareness(恢复)
    • 根据awareness水平和预定义阈值(threshold_prethreshold_prompt),添加特定OnroadEvent(如橙色警报promptDriverDistracted或红色警报driverDistracted)到self.current_events
    • 管理"终止警报"以防止驾驶员严重分心多次后重新激活
  • DRIVE_MONITOR_SETTINGS:定义驾驶员监控的所有关键阈值和时间,如警报触发时间(_AWARENESS_TIMEDISTRACTED_TIME)、面部/眼睛检测概率(_FACE_THRESHOLD_EYE_THRESHOLD)和头部姿态限制(_POSE_PITCH_THRESHOLD_POSE_YAW_THRESHOLD)。这些设置经过精心调校以确保安全
# 摘自selfdrive/monitoring/helpers.py(简化版)
from cereal import log
from openpilot.selfdrive.selfdrived.events import Events
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.stat_live import RunningStatFilterclass DriverMonitoring:def __init__(self, rhd_saved=False, settings=None, always_on=False):self.settings = DRIVER_MONITOR_SETTINGS() if settings is None else settingsself.awareness = 1.0 # 初始完全专注self.driver_distracted = Falseself.driver_distraction_filter = FirstOrderFilter(0., self.settings._DISTRACTED_FILTER_TS, self.settings._DT_DMON)self.pose = DriverPose(self.settings._POSE_OFFSET_MAX_COUNT) # 跟踪头部姿态self.current_events = Events() # 存储活动警报# ...其他初始化...def _update_states(self, driver_state, cal_rpy, car_speed, op_engaged):# 确定是否检测到面部,从原始模型输出计算横滚、俯仰、偏航self.face_detected = driver_state.leftDriverData.faceProb > self.settings._FACE_THRESHOLDself.pose.roll, self.pose.pitch, self.pose.yaw = face_orientation_from_net(driver_state.leftDriverData.faceOrientation, driver_state.leftDriverData.facePosition, cal_rpy)# 基于姿态、眨眼或端到端模型输出检测驾驶员是否分心self.distracted_types = self._get_distracted_types()self.driver_distracted = (DistractedType.DISTRACTED_POSE in self.distracted_types) and self.face_detected and self.pose.low_std# 更新注意力过滤器并校准自然头部姿态if self.face_detected and car_speed > self.settings._POSE_CALIB_MIN_SPEED:self.pose.pitch_offseter.push_and_update(self.pose.pitch)self.pose.yaw_offseter.push_and_update(self.pose.yaw)self.pose.calibrated = self.pose.pitch_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT# ...(更多模型不确定性和计时器设置逻辑)...def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car_speed):self._reset_events() # 清除前一周期的事件# 如果驾驶员专注且注意力未达最大值,恢复注意力driver_attentive = self.driver_distraction_filter.x < 0.37if (driver_attentive and self.face_detected and self.pose.low_std and self.awareness > 0):self.awareness = min(self.awareness + self.settings._RECOVERY_FACTOR_MIN * self.step_change, 1.)# 如果驾驶员分心,降低注意力certainly_distracted = self.driver_distraction_filter.x > 0.63 and self.driver_distracted and self.face_detectedif certainly_distracted:self.awareness = max(self.awareness - self.step_change, -0.1)# 根据注意力水平添加警报alert = Noneif self.awareness <= 0.:alert = EventName.driverDistracted # 红色警报,解除控制elif self.awareness <= self.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME:alert = EventName.promptDriverDistracted # 橙色警报elif self.awareness <= self.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME:alert = EventName.preDriverDistracted # 绿色警报if alert is not None:self.current_events.add(alert)def get_state_packet(self, valid=True):# 构建并返回driverMonitoringState消息dat = messaging.new_message('driverMonitoringState', valid=valid)# ...填充当前注意力、事件、faceDetected等...return datdef run_step(self, sm):# 由dmonitoringd.py调用以运行主逻辑self._update_states(driver_state=sm['driverStateV2'],cal_rpy=sm['liveCalibration'].rpyCalib,car_speed=sm['carState'].vEgo,op_engaged=sm['selfdriveState'].enabled)self._update_events(driver_engaged=sm['carState'].steeringPressed or sm['carState'].gasPressed,op_engaged=sm['selfdriveState'].enabled,standstill=sm['carState'].standstill,wrong_gear=sm['carState'].gearShifter in [car.CarState.GearShifter.reverse, car.CarState.GearShifter.park],car_speed=sm['carState'].vEgo)

DriverMonitoring类是dmonitoringd的核心,使用_update_states方法从driverStateV2消息初步理解驾驶员物理状态,然后_update_events结合车辆数据持续调整awareness水平并生成适当警报,确保驾驶员始终参与并准备接管。

总结

**驾驶员监控守护进程(dmonitoringd)**是sunnypilot至关重要的安全组件。

通过专用摄像头持续观察驾驶员并运用先进AI,它确保方向盘后的人保持专注并准备介入。它智能评估分心和困倦,提供及时警报,使sunnypilot成为更安全、更负责的驾驶辅助系统。

接下来,我们将焦点从驾驶员转回车辆,探索车辆接口(CarInterface)——sunnypilot实际与车辆通信并理解其状态的方式

下一章:车辆接口(CarInterface)

http://www.dtcms.com/a/351733.html

相关文章:

  • 从代码学习深度强化学习 - 多智能体强化学习 IPPO PyTorch版
  • pytorch_grad_cam 库学习笔记——基类ActivationsAndGradient
  • vue2 和 vue3 生命周期的区别
  • 【Android】不同系统API版本_如何进行兼容性配置
  • 2014-2024高教社杯全国大学生数学建模竞赛赛题汇总预览分析
  • VMDK 文件
  • 软考-系统架构设计师 计算机系统基础知识详细讲解二
  • springcloud篇5-微服务保护(Sentinel)
  • Spring Boot mybatis-plus 多数据源配置
  • 【CVE-2025-5419】(内附EXP) Google Chrome 越界读写漏洞【内附EXP】
  • Kafka面试精讲 Day 1:Kafka核心概念与分布式架构
  • Elasticsearch中的协调节点
  • 详解kafka基础(一)
  • JavaScript常用的算法详解
  • Cherry-pick冲突与Git回滚
  • Oracle跟踪及分析方法
  • 力扣100+补充大完结
  • MySql 事务 锁
  • 推荐系统学习笔记(十四)-粗排三塔模型
  • 庖丁解牛:深入解析Oracle SQL语言的四大分类——DML、DDL、DCL、TCL
  • KubeBlocks for Oracle 容器化之路
  • 高校党建系统设计与实现(代码+数据库+LW)
  • 从零开始的 Docker 之旅
  • HIVE的高频面试UDTF函数
  • 【软考论文】论面向对象建模方法(动态、静态)
  • 无人机倾斜摄影农田航线规划
  • HTML应用指南:利用GET请求获取中国银行人民币存款利率数据
  • SciPy科学计算与应用:SciPy线性代数模块入门-矩阵运算与应用
  • 精确位置定位,AR交互助力高效作业流程​
  • 余承东:鸿蒙智行累计交付突破90万辆