ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OBDⅡ、OBDonUDS与ZEV OBD:车载诊断协议演进与选型避坑指南

OBDⅡ、OBDonUDS与ZEV OBD:车载诊断协议演进与选型避坑指南 干这行的人应该都有这种经历新车进店诊断仪往方向盘下方的OBD口一怼第一个问题往往不是“有没有故障码”而是“这台车到底走的是哪套诊断协议”。OBDⅡ、OBDonUDS、ZEV OBD这三个词摆在一起别说刚入行的售后技师就是不少做嵌入式开发的兄弟也容易绕晕。我自己从CAN总线抓包测OBD开始又跟着整车厂项目从SAE J1979切到J1979-2再到现在越来越多车型要过ZEV OBD相关的标定才慢慢把这三层关系理顺。这篇就把我实际踩过的路梳理一遍重点讲清三套标准的定位差异、报文层面的核心机制以及做诊断设备和车联网终端时最容易翻车的细节适合做车载诊断开发、售后检测仪器和车联网数据采集的朋友参考。1. 一切从物理层说起OBD口的CAN定义是绕不开的第一课1.1 16针DLC里到底哪几根线在干活OBD接口的学名叫DLCData Link Connector标准规定了16针梯形接口这个大家都不陌生。但真正动手测量过的人都知道绝大多数现代汽车真正干活的只有6号针和14号针6号是CAN_H14号是CAN_L剩下的大部分引脚要么悬空要么只接了电源和地。这就是现在大家在搜“obd can口定义”时最关心的答案。引脚功能说明2J1850 Bus美系老车协议现在基本淘汰4底盘地车身与底盘地5信号地诊断设备参考地和数据地分开6CAN_H诊断CAN高OBD诊断速率通常500 kbit/s7K线ISO 9141-2 / ISO 14230 K线老欧洲车用14CAN_L诊断CAN低15L线历史遗留很少使用16电源蓄电池正极给诊断设备供电实际操作中判断一辆车是不是走CAN OBD最快的方法不是看协议栈而是万用表量6号针和14号针之间的电阻。正常情况下应该是60欧左右因为总线上有两个120欧终端电阻并联。如果量出来是120欧说明只挂了一个终端通信可能“能通但余量不足”如果量出来无穷大那基本可以断定这条CAN总线是断的后面报文解析做得再漂亮也白搭。这个细节我见过不少刚入行的同事栽过跟头一上来就怪工具结果拿万用表一量线束都脱了。1.2 为什么CAN能成为OBD的绝对主流现在的OBD口看起来全是CAN但历史上不是这样的。90年代到2000年代初期车载诊断物理层五花八门美系车用SAE J1850 VPW/PWM欧洲车用ISO 9141-2的K线后来又有ISO 14230也就是KWP2000。当时做诊断仪真是噩梦一台机器要兼容好几种物理层而且速率低、抗干扰差、通信距离短基本就是一根线一根线地试。CAN之所以胜出核心原因是三条抗干扰能力强差分信号天然抗共模噪声速率高500 kbit/s的位速率足以支撑当时所有诊断需求多节点能力强总线仲裁机制让多个ECU可以挂在同一条线上。所以从2008年前后开始全球主流车企几乎全部切到了“OBD on CAN”这条路上来ISO 15765-4和SAE J1979也就成了实际上的物理层和协议层基准。需要说明的是现在有些新平台开始用CAN FD做诊断总线单帧能塞64字节但CAN接口定义和物理层仍然是同一个逻辑工具上只有支持不支持的区别不存在“换了一套物理层”的问题。2. OBDⅡSAE J1979排放监管逼出来的“最小公倍数”2.1 十个诊断模式到底在干什么SAE J1979这套标准一开始就不是为了“全车诊断”设计的它的核心服务对象是排放监管。整车厂、环保机构、第三方修理厂需要一套统一的口径能够读排放相关数据、读故障码、清故障码、验证车辆是否做好了I/M测试准备。于是J1979把诊断内容拆成了若干个Mode也就是模式每个模式干一类事情。模式功能说明01读取当前动力系统数据请求PID比如转速、车速、水温02读取冻结帧数据记录故障发生瞬间的数据快照03读取已确认的排放相关故障码存储在非易失性存储里04清除排放相关信息清码并复位监视器状态05氧传感器测试结果CAN网络上已废弃06读取在线监测测试结果三元催化、失火等监视器结果07读取待定故障码一次驾驶循环内发现但未确认的故障08控制系统部件用于测试特定执行器09读取车辆信息VIN、标定ID、软件版本等0A读取永久故障码清码后仍然存在的永久性故障这里面有一个很实用的小知识点03读的是“已经确认”的故障码故障至少出现了一个驾驶循环07读的是“待定”故障码就是电脑已经发现了异常但还没到“确认”的程度。07有个场景特别常见——车主说发动机灯没亮但读出来一堆P0开头的待定码这种通常就是偶发性失火或者油品问题。而0A永久故障码是清不掉的它和OBD监管要求绑定一旦某个故障确认并置为永久码连UDS的0x14清除诊断信息也消不掉这是法规为了防止作弊故意设计的。2.2 报文怎么走功能寻址与物理寻址J1979 on CAN的报文结构其实非常简单。请求帧的CAN ID通常用0x7DF这个叫功能寻址发给总线上所有ECU每个ECU各自回复回复的CAN ID一般是0x7E8到0x7EF对应不同ECU地址。另一种是物理寻址请求CAN ID是0x7E0到0x7E7指定某一个ECU响应就是对应用0x7E8到0x7EF。功能寻址适合“谁有问题谁回我”物理寻址适合点对点。举个例子读取发动机转速请求数据是CAN ID: 0x7DF Data: 01 0C 00 00 00 00 00 00第一个字节01表示模式第二个字节0C是PID也就是发动机转速。响应CAN ID: 0x7E8 Data: 41 0C 1A F8 00 00 00 00第一个字节41是模式01加0x40表示“对模式01的肯定响应”第二个字节0C回显PID后面两个字节1A F8就是原始值。转速的计算公式是(256*AB)/4这里A0x1A26B0xF8248算出来是1726转。熟悉这套换算之后看到数据就能口算大概转速做台架标定和售后排查都方便很多。2.3 PID、DTC与冻结帧看得懂数据才叫会诊断PID就是参数ID0x00这个PID很特殊它告诉外部设备“我支持01到20这32个PID里的哪些”返回的32位bitmap每一位对应一个PID。同理PID 0x20表示支持21到40PID 0x40表示支持41到60以此类推。所以规范做法是先发一次01 00拿到支持列表再根据列表去发具体的PID请求而不是一上来就瞎猜。常见基础PID的计算公式我列一下基本是所有诊断软件的地基PID参数计算公式0x04计算负荷A×100/255 %0x05冷却液温度A-40 ℃0x0C发动机转速(A×256B)/40x0D车速A km/h0x0F进气温度A-40 ℃0x10空气流量(A×256B)/100 g/s0x11节气门位置A×100/255 %0x2F燃油液位A×100/255 %DTC的编码规则更要熟记P开头是动力系统C是底盘B是车身U是网络通信。后面第一位1表示厂家自定义0和2表示SAE通用定义3是厂家自定义的扩展。比如P0301含义就是1缸失火P0171是系统过稀。这里有个容易被忽略的点OBD里的DTC存储和清码虽然很标准但是冻结帧只保留“最先发生”的故障现场如果多个故障几乎同时发生你只能看到第一个触发冻结帧的故障而不是故障码列表里的第一个。这个问题我在实车上碰到过好几次排查时必须结合多个数据源不能只信一个冻结帧。3. OBDonUDSSAE J1979-2把诊断从“排放仪表”升级成“全车总线”3.1 UDS服务怎么对应OBD模式J1979-2即OBDonUDS是把ISO 14229统一诊断服务UDS装进OBD框架里的产物。这里的“UDS”不是某一个具体报文而是一整套基于请求/响应的服务机制最常用的是0x10会话控制、0x22按ID读数据、0x2E按ID写数据、0x19读故障码、0x14清故障码、0x27安全访问、0x31例程控制、0x3E在线保持。它们和OBD模式的对应关系大概是这样J1979 OBD模式UDS服务说明01 读当前数据0x22 读数据标识符DID可以拿到比PID丰富得多的数据03 读已确认故障码0x19 子功能02按状态掩码读取故障码04 清码0x14 清除诊断信息只清指定组别的故障07 读待定故障码0x19 子功能02 状态掩码状态掩码里的待定状态位09 读车辆信息0x22 读VIN等DID不再需要Mode 09的固定PID这里要特别强调OBDonUDS不是把OBD的Mode翻译成UDS服务那么简单它的报文格式变了。OBD Mode请求的头两个字节是“模式PID”而UDS请求的格式是“服务ID子功能/数据标识”比如0x22后面要跟两个字节的DID如22 F1 90读VIN。我见过不少从OBD转过来的开发人员习惯性把一个DID当成PID直接塞进0x22请求里结果收到0x7F 22 31也就是请求超出范围排查半天发现是DID没对齐字节序。3.2 会话与安全两个必须跨过的门槛J1979-2和传统OBD最大差异是引入了会话状态和安全访问。OBD模式几乎不关心“你是谁”任何设备都能读排放数据这是法规要求。但OBDonUDS承载的是全车诊断比如ECU刷写、标定、学习值重置这些操作必须区分权限。0x10服务可以切到默认会话、扩展会话、编程会话只有特定会话下才能执行特定的读写服务。0x27安全访问则是“种子-密钥”机制外部诊断仪发送27 01请求种子ECU返回4字节种子外部设备用算法算出密钥后回27 02密钥错误会触发锁定计数连续错几次安全访问会锁一段时间有的ECU甚至会要求你断开电源等待。这部分实际做工具时会很痛苦。不同厂家种子算法完全不同有的用DES有的用CRC逆推甚至有些ECU的算法是保密的只授权给指定工具。所以做第三方诊断仪的公司通常只能通过车厂授权或者逆向分析来兼容。我的建议是项目初期就把“需要进安全访问的功能”和“只读功能”分开设计只读功能完全走标准服务能不进安全就不进这样既能保证诊断覆盖又能降低被车厂投诉的风险。3.3 长数据怎么传ISO-TP分包机制简单讲OBD on CAN的单帧最多8字节数据去掉服务ID和长度信息一次能传的纯应用数据非常有限。VIN有17个ASCII字符如果只靠单帧根本装不下。于是ISO 15765-2定义了传输层ISO-TP也叫分包协议。它把CAN帧分成四种类型。单帧SFPCI首字节0到7最多带7字节数据。首帧FFPCI首字节0x10到0x1F用来声明总长度最多声明4095字节。连续帧CFPCI首字节0x20到0x2F按顺序号0到F循环编号。流控帧FCPCI首字节0x30到0x3F带两个参数块大小BS和最小间隔时间STmin。举个例子读VIN返回17字节常见流程是ECU先发一个首帧PCI声明“我要发17字节”收端回一个流控帧“放行”然后ECU再发3个连续帧每个7字节两个7字节加一个3字节正好17字节。这个机制本身不复杂但工具如果没按STmin等待就着急发下一帧或者BS计数不对就会出现“丢帧”“错帧”的问题。我建议做协议栈时把ISO-TP状态机单独封装别和上层服务混在一起不然以后排查问题你会疯。3.4 为什么主机厂愿意统一到OBDonUDS从成本角度讲同时维护两套诊断协议栈是非常不划算的。早年ECU里既要有OBD模式又要有UDS服务相当于两套代码、两套测试用例、两套文档。J1979-2出现之后车厂可以只实现一套UDS服务再通过映射关系覆盖OBD监管要求减少了大量重复工作。对售后设备来说协议统一是好事一套协议栈既能读排放数据也能做深度诊断不需要再跳来跳去。这也是为什么现在很多新车型虽然还挂着OBD口但实际通信已经全面转向OBDonUDS传统的Mode 01到0A只是作为兼容层存在。4. 详细对比OBDⅡ、OBDonUDS、ZEV OBD一张表看清4.1 三层技术参数对比这三套东西经常被人拿来比较实际上它们根本不是同一个维度的概念。OBDⅡ是一个具体协议OBDonUDS也是具体协议而ZEV OBD更多是面向电动车的一套完整监管架构它依托UDS但又加入了新的数据定义和监控要求。下面这张表是我整理参数对比时常用的基本能覆盖90%以上选型问题。对比项OBDⅡ (SAE J1979)OBDonUDS (SAE J1979-2)ZEV OBD标准定位排放诊断模式统一诊断服务框架零排放车辆的诊断监管架构物理层CAN / CAN FD为主CAN / CAN FDCAN / CAN FD传输层内置简单分包ISO-TPISO-TP寻址方式7DF功能寻址为主物理寻址为主基于物理寻址整车多ECU业务范围排放相关数据与故障全车诊断、刷写、配置高压电池、电驱、热管理、充电数据结构PIDDIDDID ZEV特有PID簇安全访问一般不涉及0x27必须实现同样依赖0x27典型应用尾气检测、I/M检测售后诊断、下线检测电池健康、车辆合规、年检4.2 使用场景与工具链差异选哪套协议取决于你面对的是什么场景。如果你的设备只用于年检站、尾气检测那J1979的Mode 01到0A足够了工具成本能压得非常低。如果你做的是OBD盒子、车联网终端需要从新车大量采集数据那必须支持OBDonUDS否则很多DID读不到尤其是新能源车型。如果你做的是电池健康评估、二手车检测、电池回收评估那ZEV OBD相关的数据和监控项比传统OBD重要得多。工具链方面传统OBD的调试很简单一个USB转CAN适配器加一个串口助手就能看报文。OBDonUDS就至少要配支持ISO-TP的软件比如PCAN、CANalyzer、或者Linux下socketcan的isotp模块。ZEV OBD调试更复杂一个报文请求经常要通过中央网关转发到电池管理系统BMS、电机控制器、充电控制器等好几个ECU抓包时不能只盯着OBD口看最好在整车CAN骨干网络上做镜像抓包才能看到真实的跨ECU请求链路。4.3 从OBDⅡ换到OBDonUDS最容易踩的坑先明确一个观点OBDⅡ的PID和UDS的DID不是一回事。PID是全局编号有统一公式DID是厂家定义随意的同一个DID在不同车上含义可能完全不一样。开发新工具时最容易踩的坑就是把两者混在一起拿到一台新车的诊断请求表就去套用老协议栈结果要么返回NRC要么读到错误数据。第二个坑是超时机制。OBD Mode 01请求ECU一般要在50毫秒内响应否则就是超时但UDS请求有P2和P2两档定时P2通常是50毫秒P2可到5000毫秒。某些ECU在做电写、擦除、或者例程控制时响应时间会长得离谱中间还会回0x78“请求已收到但处理中”。如果按照OBD的超时习惯去判定UDS超时你会误杀一片正常通讯。第三个坑是CAN FD。部分新平台的诊断总线已经切到CAN FD帧数据场最大64字节。虽然ISO-TP在CAN FD上还在用但首帧格式、流控参数都有调整。工具只支持经典CAN遇到CAN FD节点会直接丢帧或者报错。建议现在选型时不管眼下用不用得上优先选支持CAN FD的收发器和协议栈省得两年后又要换硬件。5. ZEV OBD技术架构电动车把诊断标准重新定义了一遍5.1 ZEV OBD在监管什么ZEV就是零排放车辆也就是纯电、燃料电池这一类车。它没有内燃机没有三元催化没有氧传感器传统的排放相关监视器几乎全部失效。但监管机构并没有因此放松要求加州空气资源委员会CARB和美国环保署EPA这些年已经逐步把零排放车辆纳入OBD监管范围SAE也制定了面向零排放车辆的诊断测试模式标准业内一般叫ZEV OBD。ZEV OBD不再盯尾气而是盯三类核心问题一是高压电池的安全和健康状态包括电池总压、总电流、单体电压离散度、温度离散度、绝缘电阻二是电驱动系统的完整性和性能包括电机控制器状态、旋变传感器故障、扭矩异常、功率降级记录三是充电系统的合规性包括充电连接状态、通信握手、充电过程中发现的电池异常。这些系统有一个共同特点它们直接影响车辆安全但又不像发动机故障那样有“尾气超标”这种明确的判罚标尺所以监管逻辑从“排放阈值”变成了“安全与性能监视”。5.2 新增的监控项与数据格式ZEV OBD的数据结构和传统OBD差异很大。传统OBD的PID大多在动力域比如转速、负荷、空燃比而ZEV OBD需要读到的数据是电池包层面的。一套典型的ZEV诊断数据列表至少要包含下面这些项动力电池总电压、总电流单位精确到0.1V和0.1A电池荷电状态SOC和健康状态SOH一般用百分比表示电池包最高单体电压、最低单体电压以及对应的单体编号电池包最高温度、最低温度以及对应的温度采样点编号高压回路绝缘电阻单位kΩ这个值低于阈值会直接亮故障灯电驱动系统扭矩指令值和实际值用于判断是否存在扭矩中断充电过程中的电压、电流、充电枪锁止状态和充电桩通信状态。可以看出来这些数据不是简单的“故障码冻结帧”能覆盖的它需要ECU持续计算并存储大量运行数据。所以在ZEV OBD的架构里DID变得异常重要很多数据不再以PID形式暴露而是封装成一个一个DID按需读取。这也就解释了为什么前面说OBDonUDS是ZEV OBD落地的必要基础——没有UDS的DID机制和分包传输这些动辄几十字节的数据根本传不出来。5.3 整车架构怎么落地网关转发与多ECU协同传统燃油车的诊断请求基本都是发动机ECU一个人在应付但电动车不一样电池管理系统是独立的ECU电机控制器是独立的ECU充电控制器是独立的ECU热管理控制器也在忙自己的事。OBD口不可能让每个控制器都直接挂一条线所以实际架构通常是这样的OBD诊断请求先到达中央网关或者车机网关网关根据DID的服务范围把请求转发给对应的ECU再把ECU的响应原路返回。对诊断仪来说看到的只是一个OBD口但实际上背后是一张诊断路由表。这个架构带来一个新的调试问题诊断仪发一个0x22请求到网关如果网关转发超时或者目标ECU当前在休眠返回的就不是正常的肯定响应而是0x78等待甚至干脆没有响应。我在实际项目里遇到过一次读电池组温度请求网关把它转给BMS结果BMS正在做均衡CPU被占用响应时间拖到了2秒多。诊断仪这边如果没有做好P2*处理和0x78的等待逻辑就会把正常情况误判成总线故障。处理办法其实也简单就是抓全网的报文不要只看OBD口段的流量把网关前后的请求和响应对应起来看问题就清楚了。6. 实操记录与问题排查的九条经验6.1 用CAN工具抓报文的规范流程不管做协议解析还是调试诊断仪我都建议把抓包当成第一步。Linux环境下用socketcan是最省钱的方案can0配好之后先用candump把OBD口的原始流量全量抓下来。ip link set can0 type can bitrate 500000 ip link set can0 up candump can0如果只关注诊断相关的帧可以加过滤条件candump can0,7DF:7FF,7E0:7E8抓到报文后看几帧你就能判断当前走的是J1979还是UDS。如果收到大量以01到0A开头的请求且响应是41到4A开头这是在跑传统OBD模式如果收到以10、22、27、19这类开头的帧基本就是UDS。再接着看DLC普通OBD请求基本是8字节固定长度UDS如果出现大量连续帧说明在读长数据。这个流程足够解决90%以上的“为什么我的工具读不到数据”问题。6.2 常见否定响应码速查表UDS里最让新人头疼的就是0x7F开头的否定响应。格式很简单7F 服务ID 错误码。比如收到7F 22 31就是“0x22这个服务返回了请求超出范围”。下表是我整理的最常用错误码NRC含义处理建议0x11服务不支持检查服务ID是否拼错是否在正确会话0x12子功能不支持检查子功能参数比如0x10的01/02/030x13报文长度或格式错误检查DID长度和字节序0x22条件不满足车辆状态不对比如没上电0x24请求顺序错误常见于安全访问、编程会话顺序不对0x31请求超出范围DID地址不存在或参数无效0x33安全访问被拒绝还没进安全访问就尝试写操作0x35密钥无效种子算法算错了0x36尝试次数超限锁定等待时间到了才能继续0x78已在处理请稍候必须等待并正确处理不是错误0x7E当前会话不支持子功能切到正确的诊断会话再试0x7F当前会话不支持该服务可能是默认会话下禁止了刷写服务6.3 我踩过的坑和现在会提前规避的问题第一波特率不匹配。很多新平台诊断CAN已经不是500 kbit/s了像某些车型用250 kbit/s有个别新平台用2 Mbit/s的CAN FD。拿到车先做波特率扫描别默认就是500 k。第二功能寻址冲突。发7DF请求后多个ECU可能同时回复如果工具滤波做得不好收到的响应现场会乱。排查特定ECU问题用物理寻址别图省事一直用功能寻址。第三PID分页机制。0x00只表示支持01到20要读0x40以上的PID必须先发0x20、0x40来确认支持列表跳过这一步直接发请求很容易收到NRC。第四永久故障码清不掉是正常的。0x04和0x14能清常规故障码清不掉的是永久故障码它是法规要求保留的别在清码逻辑里反复重试。第五安全访问锁定计数。协议栈里一定要记录重试次数连续错误后主动暂停一段时间否则ECU会锁到“断电重启才恢复”现场查问题时你哭都来不及。第六TesterPresent不能省。很多诊断仪会在3E 00上偷懒结果长时间不发ECU自动退出扩展会话后面的写操作全部失败。建议每2秒发一次0x3E稳得很。第七0x78响应要单独处理。收到78之后要等流控和后续响应不能当成错误也不能立即超时断开。第八终端电阻不能忽视。现场遇到偶发通信失败第一件事量6脚和14脚之间的电阻不是60欧就先配电再谈协议问题。第九CAN FD的DLC判断。如果抓包软件显示帧长度是64而你还在用经典CAN的DLC8去解析结果一定全是错的。选工具和协议栈时CAN FD支持已经是我现在选型的硬性门槛。说实话这三套协议讲穿了并不难难的是你真正面对一台实车时能快速判断它当前用哪套机制、该用哪条CAN ID去谈、超时等了多久算正常、否定响应码背后的真正意图是什么。我自己做VCI和诊断协议栈这几年最大的体会是协议标准是死的但整车实现是活的OBD口定义、CAN ID表、DID清单这些东西永远要以实车抓包结果为准不能拿着标准文档想当然。下一次遇到新车型读不出数据别急着怪ECU先抓包看一眼总线上发生了什么答案往往就在那几帧报文里。
返回列表