标签: Ford

  • Ford 构帧:CAN FD 校验不是 CRC,名义频率不是负载预算

    结论:Ford 的 fordcan.py 只负责生成候选帧:横向、纵向、界面与按钮四类构帧函数把 CarControl 变成带计算器/校验的 CAN 载荷,是否真正上总线由独立固件白名单与继电器门裁决。CAN FD 校验 calculate_lat_ctl2_checksum() 是「原始位求和取反」的专用算法,不是通用 CRC;而函数注释里的 33/20/50/5/1 Hz 只是名义频率,不能当作总线最大负载预算。

    本文基于固定源码快照,从 fordcan.py 的公开构帧函数出发,追踪 CarController.update() 与 panda 安全钩子,属于静态结构分析,未连接车辆或发送 CAN。完整固件侧规则见 Ford panda safety 专题,本文只解释主机侧「构帧了什么、依赖了什么」。

    构帧函数与报文契约

    四类输出分工明确:横向有 create_lka_msg()(空 Lane Assist)、create_lat_ctl_msg()(经典 CAN 曲率与路径)、create_lat_ctl2_msg()(CAN FD 曲率、计数、校验);纵向是 create_acc_msg();界面与按钮是 create_acc_ui_msg()、create_lkas_ui_msg()、create_button_msg()。它们只产出候选帧,不提供安全许可。

    函数 控制器调用 输出与关键限制
    create_lka_msg() 33 Hz 名义节拍 对 Lane_Assist_Data1 传空信号字典;panda 要求其动作字段必须为零,不能当额外转向通道
    create_lat_ctl_msg() 经典 CAN 分支 构造 LateralMotionControl,LatCtl_D_Rq 随横向活动位切换;曲率取限幅后符号反转值
    create_lat_ctl2_msg() CAN FD 分支 先以校验字段零值打包同名帧,算完校验再以实际 CAN.main 构帧;计数器按节拍 modulo 16,当前只用 mode=0/1
    create_acc_msg() 纵向控制分支 ACCDATA 带加速度、油门、预充/减速、停车与目标速度;仅自控纵向配置下按名义 50 Hz 发送
    create_acc_ui_msg() 5 Hz 或 UI 变化 从相机 ACCDATA_3 复制多项字段,再覆盖 TJA 状态、自控纵向显示与 FCW 告警
    create_lkas_ui_msg() 1 Hz 或 UI 变化 从相机 IPMA_Data 复制配置/告警字段,再改写车道线状态与握盘提示
    create_button_msg() 按钮分支 从主总线 Steering_Data_FD1 复制开关状态,只覆盖 cancel/resume/TJA 三个位;取消和恢复同时送 camera/main,TJA toggle 只送 camera

    CanBus 定下总线映射:main=offset、radar=offset+1、camera=offset+2,基类以 len(CP.safetyConfigs) 推导 4 路一组的偏移。不能硬编码所有车辆为 bus 0,偏移取决于安全配置数量。

    CAN FD 校验:专用算法,不是通用 CRC

    calculate_lat_ctl2_checksum() 从已编码的 8 字节中抽取曲率、曲率率、路径角、路径偏移的原始位值,加模式和计数器,再取 0xFF - (sum & 0xFF)。它与固件侧从相同位置提取字段的做法对应,所以构帧器依赖所选 DBC 的位布局与物理总线映射——把该函数当成跨平台字节数组插件会失效。

    两步打包的原因也在这里:先打包零校验占位帧是为了让校验字段取值稳定,计算后再用实际 CAN.main 构帧。计数器和校验只保证字节自洽,不保证 ECU 接受,也不替代安全门。

    环节 做法 边界
    校验算法 原始位求和后取 0xFF - (sum & 0xFF) 专用算法,非通用 CRC;依赖 DBC 位布局
    计数器 按发送节拍 modulo 16 节拍来自 100 Hz 控制帧计数与状态变化时的额外发送
    模式字段 当前只用 mode=0/1 不代表其余模式在实车被验证

    横向与纵向:控制器负责限幅,构帧器不查许可

    CarController 在横向发送前计算当前曲率、按车速施加曲率误差/速率限制,然后对 CAN FD 与经典 CAN 分别构帧。两条路径的 path_offset、path_angle、curvature_rate 在当前调用中都传零——源码中对多项式完整操控的描述不是当前已启用能力。

    纵向方面,自控纵向的 gas 和 accel 分开限幅;若非 longActive 或油门低于门槛,油门设为中性原始值。制动预充/减速请求根据坡度补偿后的加速度在 >0.3 与 <0 之间迟滞,位状态由控制器记忆。构帧器不自行检查这些状态是否与 panda 许可一致:限幅是主机策略,许可在固件。

    两种 UI 构帧和按钮构帧从 CarState.update() 缓存的原车解析字典复制字段。字典存在不等于所依赖 CAN 帧足够新鲜;插件接口应保留总线、时间戳和健康信息,并在台架验证失联后的透传行为。panda 对 ACCDATA_3/IPMA_Data 有白名单但无逐字段专属限制,对按钮仅专门约束 cancel/resume 权限。

    名义频率不能当负载预算

    fordcan.py 的 docstring 所列 33/20/50/5/1 Hz 是名义频率,实际来自 100 Hz 控制帧计数和状态变化时的额外发送。create_button_msg() 自身写 10 Hz,但 cancel 可以随每次控制更新发送。不能拿函数注释当作总线最大负载预算。

    新硬件或插件化验收至少要分别验证:车型 flags、CAN FD/经典 DBC、总线偏移、帧长度、计数器/校验、原车 UI 字段的新鲜度,以及 panda TX 拒帧。Ford 构帧插件只能交付候选帧;白名单、曲率/纵向限值及原车 AEB 禁止位必须继续由独立安全层执行。

    固定快照附带两份离线探针用于核对契约:原版 DBC 构帧探针把经典 CAN 与 CAN FD 两种格式各验证一次,界内帧通过、主机速度突变候选被拒;此前的手工帧探针用正的曲率 CAN 单位测试对称安全限值,但控制器实际在调用 fordcan 前将曲率取负,原版探针按该符号链送入 CANPacker,并包含 DBC 精度位与 CAN FD 校验。需要记住边界:它未覆盖 CarController.update() 的前置测量裁剪、状态迁移或车辆 ECU 响应。

    常见问题

    calculate_lat_ctl2_checksum 是 CRC 吗?

    不是。它从已编码的 8 字节中抽取曲率、曲率率、路径角、路径偏移的原始位值,加模式和计数器,再取 0xFF - (sum & 0xFF),是与固件同位置取值对应的专用算法,不是通用 CRC,也不能当作跨平台字节数组插件。

    Ford 的 CAN 总线一定是 bus 0 吗?

    不是固定值。CanBus 用 main=offset、radar=offset+1、camera=offset+2 映射,偏移由基类按 len(CP.safetyConfigs) 以 4 路一组推导,所以不能硬编码所有车辆为 bus 0。

    控制器已经限幅,为什么还要固件安全门?

    因为构帧器不检查状态是否与 panda 许可一致。主机侧只负责曲率/纵向限幅与状态记忆,白名单、曲率与纵向限值、原车 AEB 禁止位仍由独立固件层裁决;构帧器只交付候选帧。

    函数注释里的发送频率能当负载预算吗?

    不能。33/20/50/5/1 Hz 是名义频率,实际来自 100 Hz 控制帧计数和状态变化时的额外发送;create_button_msg() 虽写 10 Hz,cancel 仍可随每次控制更新发送。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/FORD_CAN_FRAME_CONSTRUCTION_CONTRACT_DEEP_DIVE.md(取用了 fordcan.py 构帧函数契约、CAN FD 校验算法、总线映射与名义频率边界)。
    • 项目 02 —— openpilot-research/FORD_PANDA_SAFETY_MODE_DEEP_DIVE.md(仅用于确认固件侧白名单与限值边界,未取用其未公开内容)。

    说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • Ford 与 GM:曲率、ASCM 网关与双车速检查的三道安全边界

    结论:Ford 与 GM 都以「软件控制器只生成候选 CAN 帧、panda 固件独立放行」为前提,但两者路径不同:Ford 走角度/曲率式横向控制并用 ABS 车速与 PCM 第二车速交叉核验;GM 分 ASCM/OBD-II 网关与相机 ACC 两条接法,部分车型用 sigmoid 加线性拟合做横向映射。无论哪种,alpha_long、safetyParam、ALLOW_DEBUG 与 dashcamOnly 必须同时核对,不能单看软件发送代码推断硬件可执行。本文为源码静态分析,不是接线图、适配声明或实车安全验证。

    Ford:曲率控制与双车速检查

    CarInterface._get_params() 使用角度/曲率式横向控制,按 CAN FD、雷达 DBC、EPS 固件和指纹设置 ford 安全模式与总线。非 CAN FD 通过 EPS 固件配置排除缺少 TJA/LCA API 的车辆;CAN FD 的 16 字节 SecOC 控制报文未支持时标记 dashcamOnly;手动车型设最低使能车速。get_pid_accel_limits() 在临近巡航目标速度时降低 PID 正加速度上限以防积分饱和——参数层在 alpha_long 或雷达可用路径写入纵向安全参数,但这不是固件已放行的充分证据,CAN FD 纵向白名单还受编译门限制。

    输出侧,CarController.update() 以 20 Hz 曲率命令工作,部分车型先用 anti_overshoot() 平滑,随后限测量曲率误差和变化率;CAN FD 与经典 CAN 分别调用不同 lateral 构帧函数,其它未验证的曲率率、路径角和偏移信号保持 inactive。纵向由 apply_creep_compensation() 及 CarController.update() 根据低速蠕行、目标加速度下降率和坡度影响生成 ACC 的油门、减速度及制动预充请求。

    层 关键入口 已核对行为
    参数 _get_params() 角度/曲率式横向;按 CAN FD、雷达 DBC、EPS 固件设置安全模式;SecOC 未支持标 dashcamOnly
    横向输出 CarController.update() 20 Hz 曲率;可先 anti_overshoot() 平滑;限曲率误差与变化率
    纵向输出 apply_creep_compensation() 按蠕行、目标加速度下降率与坡度生成油门、减速度及制动预充
    雷达 RadarInterface.update() 按 DBC 区分 Delphi ESR 与 MRR;MRR 检查扫描序列、覆盖范围及临时不可用
    固件 RX ford_rx_hook() ABS 车速与 PCM 第二车速交叉核验;用 yaw rate 估算曲率
    固件 TX ford_tx_hook() 不允许 Lane_Assist_Data1 承载执行转向;不允许设置阻止原车 AEB 的位
    模式选择 ford_init() CAN FD 自控纵向仅在 ALLOW_DEBUG 且安全参数启用时添加 ACCDATA

    两个细节需要单独记住:Ford 固件 TX 对两种横向报文都要求额外路径信号为 inactive;RX 对部分 PCM 第二车速帧忽略计数器/校验和,但仍检查质量位。因此把多条总线合并为无来源的 VehicleSpeed 会损失安全判据。

    GM:ASCM 网关与相机 ACC

    CarInterface._get_params() 在 ASCM/OBD-II 网关路径默认自控纵向,在相机 ACC 路径默认原车纵向,实验纵向由 alpha_long 和安全参数选择;EV、无雷达、替代 ACC、SDGM 分支另有限制,无雷达或缺少测试覆盖可标记 dashcamOnly。alphaLongitudinalAvailable 只是能力提示,不能代替检查 openpilotLongitudinalControl 与固件模式。

    横向映射上,部分车型用 get_lataccel_torque_siglin() 与 torque_from_lateral_accel() 以 sigmoid 加线性拟合横向加速度与扭矩并提供逆向插值,其余走基础线性映射——此调校是车型特定控制模型,不可作为新硬件通用执行器标定。输出侧 CarController.update() 按驾驶员扭矩限幅;相机接法需对齐相机计数器,回环确认距上次发送不足 15 ms 时跳过以避免 EPS 故障,活跃/非活跃横向采用不同节拍。

    层 关键入口 已核对行为
    参数 _get_params() ASCM/OBD-II 网关默认自控纵向;相机 ACC 默认原车纵向;EV/无雷达等另有限制
    横向映射 get_lataccel_torque_siglin() / torque_from_lateral_accel() 部分车型 sigmoid + 线性拟合与逆向插值;其余基础线性映射
    横向输出 CarController.update() 相机接法对齐相机计数器;回环确认不足 15 ms 时跳过
    纵向输出 同上 自控纵向按 25 Hz 生成油门/再生制动与摩擦制动;网关接法发 ADAS keepalive
    雷达 create_radar_can_parser() / RadarInterface.update() ASCM 路径解析 Continental LRR 头与目标槽,检查故障、CAN 有效性与目标生命周期
    固件 RX gm_rx_hook() 从驾驶员扭矩、后轮速度、巡航按钮或原车 ACC 决定 controls_allowed
    固件 TX gm_tx_hook() 检查扭矩、摩擦制动、油门/再生制动及 apply 位;原车纵向仅允许取消语义按钮
    模式选择 gm_init() 相机自控纵向仅在 ALLOW_DEBUG 中添加白名单;ASCM 模式关闭固件转发

    需要指出的是,GM 的公共 RX 检查仍有校验和/计数器 TODO,不能称为完整协议完整性验证;ASCM 模式则关闭固件转发,与相机接法的行为不同。原车纵向仅发送延迟后的取消按钮,以降低用户踩刹车时的 ECM 故障风险。

    对车载硬件和插件接口的结论

    1. 车型插件应声明精确平台、DBC、总线拓扑、雷达来源、纵向模式、编译能力和 safetyParam。Ford CAN FD SecOC 不支持、GM 相机自控纵向需调试固件的限制,必须在装车前阻止执行模式。
    2. Ford 的双车速与 yaw 质量位、GM 的回环计数器/时间间隔需要在硬件接口中保留来源与时间戳;把多条总线合并为无来源字段会损失安全判据。
    3. 软件控制器只生成候选 CAN 帧。panda 的 RX/TX/转发规则仍是独立硬件边界;未知平台、无法确认固件、错误总线或诊断失败时保持被动。
    4. 后续目标车型需完成 DBC 解析/打包、丢帧/错校验/双车速失配、回环时序、AEB 干预、断电与失联的 SIL/HIL,再做封闭场地验证。这里没有实车结论。

    常见问题

    alphaLongitudinalAvailable 为真,是否就能启用纵向控制?

    不能。GM 侧源文档明确 alphaLongitudinalAvailable 只是能力提示,不能代替检查 openpilotLongitudinalControl 与固件模式;Ford 侧参数层即使写入纵向安全参数,也不是固件已放行的充分证据,CAN FD 纵向白名单还受编译门限制。

    Ford 的转向命令能否走 Lane_Assist_Data1?

    不能。ford_tx_hook() 明确不允许 Lane_Assist_Data1 承载执行转向,也不允许设置阻止原车 AEB 的位;固件还会对曲率及测量误差、ACC 油门/制动、按钮权限分别检查,并要求两种横向报文的额外路径信号为 inactive。

    GM 的横向映射能不能直接照搬到新硬件?

    不能。部分车型使用的 sigmoid 加线性拟合与逆向插值属于车型特定控制模型,源文档明确它不可作为新硬件通用执行器标定;其余车型走基础线性映射,两者不能混用。

    为什么不能把多条总线合并成一个 VehicleSpeed?

    因为会损失安全判据。Ford 用 ABS 车速与 PCM 第二车速交叉核验、GM 依赖回环计数器/时间间隔,这些来源与时间戳本身就是判据;源文档要求硬件接口保留来源与时间戳,未知平台或无法确认固件时保持被动。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/FORD_GM_DEEP_DIVE.md(取用了 Ford 曲率控制与双车速检查、GM ASCM/相机两条接法、固件 RX/TX 边界与插件结论)。
    • 项目 02 —— openpilot-research/CAR_PROTOCOL_IMPLEMENTATIONS.md(仅用于确认 Ford/GM 品牌目录与跨品牌流程的总体位置)。

    说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11