Python OBD编码
Python OBD encoding
我想获取一些 OBD 数据并按照 this article 所述进行了尝试
文章(使用python 2.7)说:
The elm327 device returns values in HEX.
To read the value you just requested in Python type speed_hex = ser.readline().split(' ')
Convert the HEX to decimal by using: speed = float(int('0x'+speed_hex[3], 0 ))
但是我从 OBD 得到的答案不包含任何空格,而且它们看起来根本没有任何意义。
['\xd0MA\r?\r\r>\xd0\x15\r?\r\r>\x981\xf0\n']
所以我放弃了这种方法,转而使用 Python 3。
然后我写了一个受this SO post
启发的小脚本
但是我将其更改为定期提取大量数据并添加了时间戳,所有这些都保存到一个 csv 文件中 - 因为路径暗示我正在处理 Windows(准确地说是 10), COM 已正确配置且汽车符合 OBD。
现在,当我 运行 我的脚本时,它会打印出它读取的内容:
b'h\xf4\rSTOPPED\r\r>'
然后告诉我
Traceback (most recent call last):
File "python3test.py", line 36, in <module> r.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf4 in position 1:
invalid continuation byte
我知道编码肯定是个问题,但是这个字符串根本没有多大意义。即使我仔细查看 0xf4 - 它也只是 244(dec),这离合理的 RPM 数据不远。
那为什么它在 the other script 中有效呢?不会是 Windows 问题吧?
任何人都可以帮我了解这里发生了什么吗?
这是我的代码。
import serial
import time
import string
import io
import os
import sys
import datetime as dt
ser = serial.Serial("COM1")
ser.baudrate = 38400
ser.write(bytes('ATSP0\r\n', encoding = 'utf-8'))
ser.timeout = 1
ser.write(bytes('ATE0\r\n', encoding = 'utf-8'))
ser.timeout = 1
def millis_interval(start, end):
'''start and end are datetime instances'''
diff = end - start
millis = diff.days * 24 * 60 * 60 * 1000
millis += diff.seconds * 1000
millis += diff.microseconds / 1000
return millis
Testtime = str(dt.datetime.now()).split(' ')
PIDs = ["0C","0D","43","04","11","5C","05","10","46"]
response = []
''' open file and create header row'''
with open("C:/test/test_"+Testtime[0]+"_"+Testtime[1].replace(":","-")+".csv", "a") as myfile:
myfile.write("Time,Timestep,RPM,Speed, AbsLoad, CalcLoad, ThrottlePos, CoolTemp, OilTemp, MAF, AmbAirTemp")
start = dt.datetime.now() # need initial value
while 1:
end = dt.datetime.now()
myfile.write("\n"+str(dt.datetime.now())+','+str(millis_interval(start,end))+)
count = 0
for s in PIDs:
start = dt.datetime.now()
ser.write(bytes(("01" + s) + '\r\n', encoding = 'utf-8'))
ser.timeout = 1
''' if answer not finished but new information sent OBD will stop writing and listen to UART *'''
r = ser.read(999)
while ">" not in r
r = r + ser.read(999)
print(r) # debug
r.decode('utf-8')
response[count] = r
print(response[count]) #see what it looks like in utf-8
myfile.write(str(','+response[count]))
count +=1
ser.close()
如果有任何兴趣:我正在通过 USB 使用 ELM327 兼容设备,它似乎与 Scantool 软件完美配合,我的汽车是 2000 年制造的,ECU 是大众汽车。
- 有关 STOPPED 信息的新信息:
https://www.scantool.net/forum/index.php?topic=10164.0
答案是关键字协议。因此,以防万一有人对同样的问题感到疑惑:
在你浪费生命的 10 分钟之前:不,我不提供代码解决方案。我只是弄清楚了,为什么它不起作用。所以在这里你只会找到协议的描述。有兴趣的reader参考Konrad Reif的Springer Bosch Mechatronic系列
在早期的协议(1990 年代)中,有 ISO 9141 和 ISO 14230 描述的 K 线协议。大众使用 K 线,该协议在千禧年左右以两种方式在汽车中实施。测试车辆是 2000 年制造的 VAG 模型,根据给出的数据,该车预计具有 OBD II(但没有 CAN)和 ISO9141 以及关键字协议 KWP1282 或 ISO14230 KWP2000。经过更多研究后,很明显该车实施了 ISO9140 KWP1281。 KWP1281 的一个主要问题是初始化,因为 K 线和 L 线使用 5 波特信号进行唤醒。唤醒请求如下所示:
测试仪在地址0x33以每秒5位发出初始化请求。一旦车辆的 ECU 验证了地址(在时间 W1 之后),就会在 0x55(即所谓的同步字节)处向测试仪发送确认信息。该同步字节告诉测试仪进行通信的波特率,通常为 10400 波特。然后测试仪重新配置波特率,同时车辆等待 (W2)。在时间 W2 过去后,车辆会延迟 W3 向测试仪发送两个密钥字节(08,08 或 94,94)。这些关键字节描述了碰撞预防时间 P2MIN,在此之后 ECU 检查 K 线的下降沿。 [Reif, 汽车机电, BOSCH]
如果测试仪确认 P2Min,则第二个密钥字节被反转并返回给车辆。然后,车辆将 0x33 的补码发送给测试仪作为确认,表示已准备好进行交互。
ELM327 芯片根本不支持 KWP1281,它支持 KWP2000,但在这种情况下,它只是作为一些 OBD2 参数的传输问题,其余的是供应商特定的。就大众汽车排放法规而言,ELM327 KWP2000 通过 OBD2 提供排放特定故障代码,但仅此而已。
由于手头时间有限,我没有费心去实施一个解决方案,因为已经有软件可以为大众汽车做这个,而且我的论文不允许我花时间。我可能有一天。
通过大众特定的 KKL 适配器与大众软件 VCDS 的结合,测试车辆的 OBD 最终提供了足够的结果。
VCDS (VAG-COM) 具有缓慢但足够的记录能力,包括用于结果评估的 VAG-Scope 软件,导出格式为 CSV,这种格式简单且易于处理大多数程序。测量分辨率约为 3Hz,每秒读取三个测量组,每个测量组具有四个参数。
有兴趣的 reader 请参阅 Konrad Reif 的 Springer Bosch Mechatronic 系列 了解更多信息。
抱歉,我无法提供有关如何实施它的答案。但至少有一份指南,说明为什么它可能不适用于您的(大众、斯柯达、奥迪、西雅特……)汽车。
我想获取一些 OBD 数据并按照 this article 所述进行了尝试 文章(使用python 2.7)说:
The elm327 device returns values in HEX.
To read the value you just requested in Python type speed_hex = ser.readline().split(' ')
Convert the HEX to decimal by using: speed = float(int('0x'+speed_hex[3], 0 ))
但是我从 OBD 得到的答案不包含任何空格,而且它们看起来根本没有任何意义。
['\xd0MA\r?\r\r>\xd0\x15\r?\r\r>\x981\xf0\n']
所以我放弃了这种方法,转而使用 Python 3。
然后我写了一个受this SO post
启发的小脚本但是我将其更改为定期提取大量数据并添加了时间戳,所有这些都保存到一个 csv 文件中 - 因为路径暗示我正在处理 Windows(准确地说是 10), COM 已正确配置且汽车符合 OBD。
现在,当我 运行 我的脚本时,它会打印出它读取的内容:
b'h\xf4\rSTOPPED\r\r>'
然后告诉我
Traceback (most recent call last):
File "python3test.py", line 36, in <module> r.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf4 in position 1:
invalid continuation byte
我知道编码肯定是个问题,但是这个字符串根本没有多大意义。即使我仔细查看 0xf4 - 它也只是 244(dec),这离合理的 RPM 数据不远。
那为什么它在 the other script 中有效呢?不会是 Windows 问题吧?
任何人都可以帮我了解这里发生了什么吗?
这是我的代码。
import serial
import time
import string
import io
import os
import sys
import datetime as dt
ser = serial.Serial("COM1")
ser.baudrate = 38400
ser.write(bytes('ATSP0\r\n', encoding = 'utf-8'))
ser.timeout = 1
ser.write(bytes('ATE0\r\n', encoding = 'utf-8'))
ser.timeout = 1
def millis_interval(start, end):
'''start and end are datetime instances'''
diff = end - start
millis = diff.days * 24 * 60 * 60 * 1000
millis += diff.seconds * 1000
millis += diff.microseconds / 1000
return millis
Testtime = str(dt.datetime.now()).split(' ')
PIDs = ["0C","0D","43","04","11","5C","05","10","46"]
response = []
''' open file and create header row'''
with open("C:/test/test_"+Testtime[0]+"_"+Testtime[1].replace(":","-")+".csv", "a") as myfile:
myfile.write("Time,Timestep,RPM,Speed, AbsLoad, CalcLoad, ThrottlePos, CoolTemp, OilTemp, MAF, AmbAirTemp")
start = dt.datetime.now() # need initial value
while 1:
end = dt.datetime.now()
myfile.write("\n"+str(dt.datetime.now())+','+str(millis_interval(start,end))+)
count = 0
for s in PIDs:
start = dt.datetime.now()
ser.write(bytes(("01" + s) + '\r\n', encoding = 'utf-8'))
ser.timeout = 1
''' if answer not finished but new information sent OBD will stop writing and listen to UART *'''
r = ser.read(999)
while ">" not in r
r = r + ser.read(999)
print(r) # debug
r.decode('utf-8')
response[count] = r
print(response[count]) #see what it looks like in utf-8
myfile.write(str(','+response[count]))
count +=1
ser.close()
如果有任何兴趣:我正在通过 USB 使用 ELM327 兼容设备,它似乎与 Scantool 软件完美配合,我的汽车是 2000 年制造的,ECU 是大众汽车。
- 有关 STOPPED 信息的新信息: https://www.scantool.net/forum/index.php?topic=10164.0
答案是关键字协议。因此,以防万一有人对同样的问题感到疑惑:
在你浪费生命的 10 分钟之前:不,我不提供代码解决方案。我只是弄清楚了,为什么它不起作用。所以在这里你只会找到协议的描述。有兴趣的reader参考Konrad Reif的Springer Bosch Mechatronic系列
在早期的协议(1990 年代)中,有 ISO 9141 和 ISO 14230 描述的 K 线协议。大众使用 K 线,该协议在千禧年左右以两种方式在汽车中实施。测试车辆是 2000 年制造的 VAG 模型,根据给出的数据,该车预计具有 OBD II(但没有 CAN)和 ISO9141 以及关键字协议 KWP1282 或 ISO14230 KWP2000。经过更多研究后,很明显该车实施了 ISO9140 KWP1281。 KWP1281 的一个主要问题是初始化,因为 K 线和 L 线使用 5 波特信号进行唤醒。唤醒请求如下所示:
测试仪在地址0x33以每秒5位发出初始化请求。一旦车辆的 ECU 验证了地址(在时间 W1 之后),就会在 0x55(即所谓的同步字节)处向测试仪发送确认信息。该同步字节告诉测试仪进行通信的波特率,通常为 10400 波特。然后测试仪重新配置波特率,同时车辆等待 (W2)。在时间 W2 过去后,车辆会延迟 W3 向测试仪发送两个密钥字节(08,08 或 94,94)。这些关键字节描述了碰撞预防时间 P2MIN,在此之后 ECU 检查 K 线的下降沿。 [Reif, 汽车机电, BOSCH] 如果测试仪确认 P2Min,则第二个密钥字节被反转并返回给车辆。然后,车辆将 0x33 的补码发送给测试仪作为确认,表示已准备好进行交互。
ELM327 芯片根本不支持 KWP1281,它支持 KWP2000,但在这种情况下,它只是作为一些 OBD2 参数的传输问题,其余的是供应商特定的。就大众汽车排放法规而言,ELM327 KWP2000 通过 OBD2 提供排放特定故障代码,但仅此而已。
由于手头时间有限,我没有费心去实施一个解决方案,因为已经有软件可以为大众汽车做这个,而且我的论文不允许我花时间。我可能有一天。
通过大众特定的 KKL 适配器与大众软件 VCDS 的结合,测试车辆的 OBD 最终提供了足够的结果。 VCDS (VAG-COM) 具有缓慢但足够的记录能力,包括用于结果评估的 VAG-Scope 软件,导出格式为 CSV,这种格式简单且易于处理大多数程序。测量分辨率约为 3Hz,每秒读取三个测量组,每个测量组具有四个参数。
有兴趣的 reader 请参阅 Konrad Reif 的 Springer Bosch Mechatronic 系列 了解更多信息。
抱歉,我无法提供有关如何实施它的答案。但至少有一份指南,说明为什么它可能不适用于您的(大众、斯柯达、奥迪、西雅特……)汽车。