想要实现vector CanApe 离线标定功能,使用A2L文件开发来实现。
一、什么是标定
1、标定
汽车行业经常听到“标定”这个名词,此外,“虚拟标定”也常出现。
车辆标定英文名称为 Vehicle Calibration 或 Automotive Calibration。
2、汽车标定(Automotive Calibration)的含义是什么?
标定是指对各种车辆系统进行微调,以确保其性能符合设计规范的过程。这可能涉及调整软件设置、标定传感器或修改机械部件,以达到预期效果。
标定意味着教授(teach),目标是让标定的对象学到些东西。例如在标定传感器时,你要告诉它相对于车辆的位置,以及它应该看哪里。
3、汽车上哪些系统通常需要标定?
- 高级驾驶员辅助系统(ADAS): 包括车道偏离警告、自动制动和自适应巡航控制等功能。
- 发动机控制模块(ECM):管理发动机功能、燃料燃烧和排放。
- 变速箱系统: 确保平稳换挡和最佳性能。
- 各种传感器: 从胎压传感器到泊车辅助系统。
二、标定使用工具 CANape
CANape 是一种测量和标定工具。用于实时分析和优化控制单元参数。它为工程师提供了测量、记录和分析来自各种传感器和 ECU 的数据的能力。
- 为 ECU 提供测量和标定功能
- 允许实时数据记录和分析
- 支持 CAN、LIN、FlexRay 等总线
- 实现 ECU 的快速原型设计、测试和标定
- 具有用户友好的图形界面
三、基础知识回想
1、存储空间布局
2、map文件
在编译链接阶段,编译器会为变量、常量、函数等分配地址,分配的地址是固定唯一的,可以通过编译器生成的map文件查看。
3、ld文件
在编译链接阶段,gcc编译器会加载ld(link description)文件,将程序中定义的数据按照ld文件描述分配地址。
四、标定实现
1、生成srec文件
- 在标定功能实现的过程中,我们期望标定的参数存储在一个固定的区域,该区域仅存储需要标定的变量或者常量。这个时候就需要调整GCC的LD文件,在LD文件中添加一个标定区域。
- 在定义需要标定的参数的时候通过GCC的attribute扩展将参数量定义到标定参数区。
编译完成后,查看对应的map文件,可以看到编译器给这几个变量分配的地址。
生产的对应的bin文件中,按照地址空间定义对应
对应的bin文件地址为add=0x410000 -(0x300000+0x30000)=0xe0020
arc-elf32-objcopy 将elf文件转换为srec文件。
arc-elf32-objcopy -O srec sensor_gnu_arcem6.elf firmware.srec
- arc-elf32-objcopy在ARC_GUN eclipse安装软件bin文件夹中有包含。
生成的 firmware.srec 0x410020地址下包含要标定的数据。
2、生成a2l文件
import re
from copy import deepcopy
class Map_to_A2L(object):
def __init__(self):
self.__mapfile_buf = []
self.__a2lfile_buf = []
self.a2lfile_adrr = r"C:\Users\Desktop\example.a2l"
self.mapfile_adrr = r"C:\Users\Desktop\test.map"
self.__measurement_vars_list = []
self.__a2file_buflen_previous = 0
self.__map_characteristic_buf = r".calipara"
self.__insert_pos = 0
self.measurement_sec_template = " /begin MEASUREMENT"+"\n" \
+ " name\n" \
+ " \"this is for test\n" \
+ " FLOAT32_IEEE\n" \
+ " none\n" \
+ " 0\n" \
+ " 0\n" \
+ " 0\n" \
+ " 0\n" \
+ " ECU Address" \
+ " "+"0X32\n" \
+ " /end MEASUREMENT"+"\r\n"
self.characteristic_template = ' /begin CHARACTERISTIC Name \n'\
+ ' \"DESCRIPTION FOR THIS QUANTITATIVE\" \n'\
+ ' VALUE \n'\
+ ' ECUADDRESS \n'\
+ ' __ULONG_S \n'\
+ ' 0 \n'\
+ ' NO_COMPU_METHOD \n'\
+ ' 0 \n'\
+ ' 4294967295 \n'\
+ ' FORMAT \"%10.3\" \n'\
+ ' /end CHARACTERISTIC \n'\
+ ' \n'
def __open_and_get_mapfile(self):
with open(self.mapfile_adrr, mode = "rb") as f:
while True:
line = f.readline().decode('ascii', 'ignore')
if not line:
break
else:
self.__mapfile_buf.append(line)
def __get_info_from_map_file(self):
row = 0
buf_measurement_index = []
while row != len(self.__mapfile_buf):
if re.findall(self.__map_characteristic_buf, self.__mapfile_buf[row], re.I):
buf_measurement_index.append(row)
row = row + 1
buf_measurement_index = buf_measurement_index[1:]
measurement_dict = {"Name": None, "ECU Address": None}
for i in range(len(buf_measurement_index)):
if i == len(buf_measurement_index) - 1:
break
index1 = buf_measurement_index[i]
index2 = buf_measurement_index[i + 1]
my_characteristic_buf = (' ' + self.__map_characteristic_buf + '\r\n')
if my_characteristic_buf == self.__mapfile_buf[index1]:
start_index = index1 + 2 #Skip the next invalid line
else:
start_index = index1 + 1 #Skip current invalid line
endof_index = index2
for j in range(start_index, endof_index):
if str(self.__mapfile_buf[j]).strip() == "" :
break
dict_ = deepcopy(measurement_dict)
data = self.__mapfile_buf[j].replace("\r\n", "").strip().split()
dict_["Name"] = data[1]
dict_["ECU Address"] = data[0]
self.__measurement_vars_list.append(dict_)
for index in self.__measurement_vars_list:
print(index)
def __open_and_get_a2l_file(self): #store origin a2l file in buf and then rewrite it(I consider to use the default template and create a new a2l file in the same folder as mapfile)
with open(self.a2lfile_adrr, mode="r") as f:
while True:
line = f.readline()
if not line:
self.__a2file_buflen_previous = len(self.__a2lfile_buf)
break
else:
self.__a2lfile_buf.append(line)
def __del_old_characteristic_sec_in_a2l_file(self): #find measurement sectors in origin or default a2l file and delete them (just in buf not in file)
a2l_buf_index = []
index = 0
for line in self.__a2lfile_buf:
if re.findall(r'/begin CHARACTERISTIC',line,re.I) or re.findall(r'/end CHARACTERISTIC',line,re.I):
a2l_buf_index.append(index)
index = index + 1
if len(a2l_buf_index) >= 2 and len(a2l_buf_index) % 2 == 0:
del self.__a2lfile_buf[a2l_buf_index[0] : (a2l_buf_index[-1] + 1)]
self.__a2lfile_buf.pop(a2l_buf_index[0])
# a2file_buflen_change = self.__a2file_buflen_previous - len(self.__a2lfile_buf) - 2
# self.__insert_pos = a2l_buf_index[-1] - a2file_buflen_change
self.__insert_pos = a2l_buf_index[0]
print("self.__insert_pos = %d" % (self.__insert_pos))
else:
print("A2L Contains no keywords CHARACTERISTIC...\r\n")
def __update_a2l_characteristic_paragraph(self):
for i in range(len(self.__measurement_vars_list)):
NAME = self.__measurement_vars_list[i]["Name"]
ADRR = self.__measurement_vars_list[i]["ECU Address"]
my_characteristic_template = self.characteristic_template.replace("Name",NAME).replace("ECUADDRESS",ADRR)
self.__a2lfile_buf.insert(self.__insert_pos + i, my_characteristic_template)
print(my_characteristic_template)
print('----------------------------------------------------------------------------------------------------')
def __update_a2l_measurement_paragraph(self):
for i in range(len(self.__measurement_vars_list)):
name = self.__measurement_vars_list[i]["Name"]
ECU_ADRR = self.__measurement_vars_list[i]["ECU Address"]
self.__a2lfile_buf.insert(self.__insert_pos+i, self.measurement_sec_template.replace("name",name).replace("0X32",ECU_ADRR))
def __update_a2l_buf(self):
self.__update_a2l_characteristic_paragraph()
# self.__update_a2l_measurement_paragraph()
def __update_a2lfile(self):
with open(self.a2lfile_adrr, mode = "w") as f:
for line in self.__a2lfile_buf:
f.write(line)
def exchange(self):
self.__open_and_get_mapfile()
if len(self.__mapfile_buf) >=1:
self.__get_info_from_map_file()
else:
print("map为空")
self.__open_and_get_a2l_file()
if len(self.__a2lfile_buf) >=1:
self.__del_old_characteristic_sec_in_a2l_file()
else:
print("a2l文件为空")
self.__update_a2l_buf()
if len(self.__a2lfile_buf) >=10:
self.__update_a2lfile()
else:
print("A2L_File_Error")
ob=Map_to_A2L()
ob.exchange()
其中 example.a2l模板,可从下面的CDM Studio安装路径获取。
或者将下面拷贝到新建example.a2l文件中。
ASAP2_VERSION 1 60
/begin PROJECT CCPSIM ""
/begin MODULE CPP ""
/begin MOD_COMMON ""
BYTE_ORDER MSB_FIRST
/end MOD_COMMON
/*
/begin IF_DATA ASAP1B_CCP
/end IF_DATA
*/
/begin COMPU_METHOD Method_AAAA "AAAA"
RAT_FUNC "" ""
COEFFS 0 1 0 0 0 1
/end COMPU_METHOD
/begin CHARACTERISTIC PARAME_DATE_VER
"DESCRIPTION FOR THIS QUANTITATIVE"
VALUE
0x004e0000
__ULONG_S
0
NO_COMPU_METHOD
0
4294967295
FORMAT "%10.3"
/end CHARACTERISTIC
/begin CHARACTERISTIC PARAME_DATE_DAY
"DESCRIPTION FOR THIS QUANTITATIVE"
VALUE
0x004e0004
__ULONG_S
0
NO_COMPU_METHOD
0
4294967295
FORMAT "%10.3"
/end CHARACTERISTIC
/begin CHARACTERISTIC PARAME_DATE_MONTH
"DESCRIPTION FOR THIS QUANTITATIVE"
VALUE
0x004e0008
__ULONG_S
0
NO_COMPU_METHOD
0
4294967295
FORMAT "%10.3"
/end CHARACTERISTIC
/begin CHARACTERISTIC PARAME_DATE_YEAR
"DESCRIPTION FOR THIS QUANTITATIVE"
VALUE
0x004e000c
__ULONG_S
0
NO_COMPU_METHOD
0
4294967295
FORMAT "%10.3"
/end CHARACTERISTIC
/begin CHARACTERISTIC PARAME_VERSION
"DESCRIPTION FOR THIS QUANTITATIVE"
VALUE
0x004e0010
__ULONG_S
0
NO_COMPU_METHOD
0
4294967295
FORMAT "%10.3"
/end CHARACTERISTIC
/begin CHARACTERISTIC DEVICE_VERSION
"DESCRIPTION FOR THIS QUANTITATIVE"
VALUE
0x004e0014
__ULONG_S
0
NO_COMPU_METHOD
0
4294967295
FORMAT "%10.3"
/end CHARACTERISTIC
/begin RECORD_LAYOUT CurveNxVub
FNC_VALUES 2 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT CurveNxXVub
FNC_VALUES 3 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 2 UBYTE INDEX_INCR DIRECT
NO_AXIS_PTS_X 1 UBYTE
/end RECORD_LAYOUT
/begin RECORD_LAYOUT CurveV8ub
FNC_VALUES 1 UBYTE ROW_DIR DIRECT
FIX_NO_AXIS_PTS_X 8
/end RECORD_LAYOUT
/begin RECORD_LAYOUT CurveVub
FNC_VALUES 1 UBYTE ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT CurveX8V8ub
FNC_VALUES 2 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
FIX_NO_AXIS_PTS_X 8
/end RECORD_LAYOUT
/begin RECORD_LAYOUT CurveX8V8ubAlternate
FNC_VALUES 2 UWORD ALTERNATE_WITH_X DIRECT
AXIS_PTS_X 1 UWORD INDEX_INCR DIRECT
FIX_NO_AXIS_PTS_X 8
/end RECORD_LAYOUT
/begin RECORD_LAYOUT CurveX8ub
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
FIX_NO_AXIS_PTS_X 8
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapColRowuw
FNC_VALUES 1 UWORD COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapNxNyVub
FNC_VALUES 3 UBYTE ROW_DIR DIRECT
NO_AXIS_PTS_X 1 UBYTE
NO_AXIS_PTS_Y 2 UBYTE
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapNxNyXYVub
FNC_VALUES 5 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 3 UBYTE INDEX_INCR DIRECT
AXIS_PTS_Y 4 UBYTE INDEX_INCR DIRECT
NO_AXIS_PTS_X 1 UBYTE
NO_AXIS_PTS_Y 2 UBYTE
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapNxXNyYVuc
FNC_VALUES 5 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 2 UBYTE INDEX_INCR DIRECT
AXIS_PTS_Y 4 UBYTE INDEX_INCR DIRECT
NO_AXIS_PTS_X 1 UBYTE
NO_AXIS_PTS_Y 3 UBYTE
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapRowColub
FNC_VALUES 1 UBYTE ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapV86ub
FNC_VALUES 1 UBYTE ROW_DIR DIRECT
FIX_NO_AXIS_PTS_X 8
FIX_NO_AXIS_PTS_Y 6
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapX8Y6V86ub
FNC_VALUES 3 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
AXIS_PTS_Y 2 UBYTE INDEX_INCR DIRECT
FIX_NO_AXIS_PTS_X 8
FIX_NO_AXIS_PTS_Y 6
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapX8Y8V88ub
FNC_VALUES 3 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
AXIS_PTS_Y 2 UBYTE INDEX_INCR DIRECT
FIX_NO_AXIS_PTS_X 8
FIX_NO_AXIS_PTS_Y 8
/end RECORD_LAYOUT
/begin RECORD_LAYOUT MapXYVub
FNC_VALUES 3 UBYTE ROW_DIR DIRECT
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
AXIS_PTS_Y 2 UBYTE INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __UBYTE_Z
FNC_VALUES 1 UBYTE ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __UWORD_Z
FNC_VALUES 1 UWORD ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __ULONG_Z
FNC_VALUES 1 ULONG ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __SBYTE_Z
FNC_VALUES 1 SBYTE ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __SWORD_Z
FNC_VALUES 1 SWORD ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __SLONG_Z
FNC_VALUES 1 SLONG ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __FLOAT32_IEEE_Z
FNC_VALUES 1 FLOAT32_IEEE ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __FLOAT64_IEEE_Z
FNC_VALUES 1 FLOAT64_IEEE ROW_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __UBYTE_S
FNC_VALUES 1 UBYTE COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __UWORD_S
FNC_VALUES 1 UWORD COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __ULONG_S
FNC_VALUES 1 ULONG COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __SBYTE_S
FNC_VALUES 1 SBYTE COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __SWORD_S
FNC_VALUES 1 SWORD COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __SLONG_S
FNC_VALUES 1 SLONG COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __FLOAT32_IEEE_S
FNC_VALUES 1 FLOAT32_IEEE COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT __FLOAT64_IEEE_S
FNC_VALUES 1 FLOAT64_IEEE COLUMN_DIR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__UBYTE_S
AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__UWORD_S
AXIS_PTS_X 1 UWORD INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__ULONG_S
AXIS_PTS_X 1 ULONG INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__SBYTE_S
AXIS_PTS_X 1 SBYTE INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__SWORD_S
AXIS_PTS_X 1 SWORD INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__SLONG_S
AXIS_PTS_X 1 SLONG INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__FLOAT32_IEEE_S
AXIS_PTS_X 1 FLOAT32_IEEE INDEX_INCR DIRECT
/end RECORD_LAYOUT
/begin RECORD_LAYOUT SSV__FLOAT64_IEEE_S
AXIS_PTS_X 1 FLOAT64_IEEE INDEX_INCR DIRECT
/end RECORD_LAYOUT
/end MODULE
/end PROJECT
执行上面的python脚本,生成新的example.a2l, 将map文件中标定量的地址信息和标定量名称更新到该A2L文件中。
其中:
- Type
- A2L文件预定义类型:
- ConversionType:
BYTE_ORDER:字节序,
MSB_LAST=Intel,默认为Intel
MSB_FIRST = Motorola
3、安装和使用CDM Studio
通过CDM读取A2L的标定量以及更新S19文件中对应的标定值
- File → Open 打开雷达APP文件,然后打开对应A2L文件。将srec和A2L文件文件导入CDM Studio中。
将013A0009h改为024A0009h,点击save as,保存为新的srec文件。
srec_cat 将srec文件转换为bin文件
srec_cat firmware.srec -offset - -minimum-addr firmware.srec -Output out_firmware.bin -Binary
- srec_cat 即 srecord官网下载:http://srecord.sourceforge.net/
查看对应的bin文件地址为add=0x410000 -(0x300000+0x30000)=0xe0020
已经标定成功。