2. 转向盘转角传感器数据采集与标定
任务说明
本案例面向线控转向系统中的方向盘转角测量环节,需要完成:使用角度传感器采集方向盘转角原始数据,实现零点标定(消除安装偏差)与线性度校准(修正传感器非线性误差),最终输出可直接用于转向控制的角度值。以下实现基于AS5047P磁编码器(14位分辨率,SPI接口),以STM32F4系列MCU作为采集主控。
硬件连接与数据协议
核心代码实现
代码包含三个层次:SPI底层读取、标定算法、应用接口。标定采用两点法(零点偏移+线性增益),通过旋转方向盘至机械限位获取实际角度范围,与传感器读数进行线性回归。
// ============ angle_sensor.h ============
#ifndef ANGLE_SENSOR_H
#define ANGLE_SENSOR_H
#include <stdint.h>
#define SENSOR_RESOLUTION 16384.0f // 14位
#define MECH_MAX_DEG 540.0f // 机械最大转角 ±540°
#define CAL_POINTS 5 // 标定采样点数
typedef struct {
float zero_offset; // 零点偏移(度)
float scale_factor; // 线性增益
uint8_t calibrated; // 标定标志
} CalibParam_t;
// SPI读取原始角度(0~16383)
uint16_t AS5047P_ReadRaw(void);
// 执行标定:输入机械参考角度数组,输出标定参数
void Angle_Calibrate(const float mech_deg[], CalibParam_t *param);
// 应用标定:原始值 -> 实际角度(度)
float Angle_ApplyCalib(uint16_t raw_value, const CalibParam_t *param);
// 保存/加载标定参数(Flash模拟)
void Calib_Save(const CalibParam_t *param);
void Calib_Load(CalibParam_t *param);
#endif
// ============ angle_sensor.c ============
#include "angle_sensor.h"
#include <math.h>
// --- SPI读取(假设已配置SPI1,CS为PA4) ---
uint16_t AS5047P_ReadRaw(void) {
uint16_t rx_data;
// 发送0xFFFF读取角度寄存器(0x3FFF)
// 此处为简化,直接返回模拟值;实际需SPI通信
// 注意:真实代码需包含SPI收发与CS控制
extern uint16_t spi_read_angle(void);
return spi_read_angle() & 0x3FFF;
}
// --- 最小二乘线性拟合 ---
void Angle_Calibrate(const float mech_deg[], CalibParam_t *param) {
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
float raw_deg[CAL_POINTS];
// 采集原始角度并转换为度数(未标定)
for (int i = 0; i < CAL_POINTS; i++) {
uint16_t raw = AS5047P_ReadRaw();
raw_deg[i] = (float)raw * 360.0f / SENSOR_RESOLUTION;
sum_x += raw_deg[i];
sum_y += mech_deg[i];
sum_xy += raw_deg[i] * mech_deg[i];
sum_xx += raw_deg[i] * raw_deg[i];
}
// 最小二乘:y = k*x + b
float denom = CAL_POINTS * sum_xx - sum_x * sum_x;
if (fabs(denom) < 1e-6) {
param->scale_factor = 1.0f;
param->zero_offset = 0.0f;
param->calibrated = 0;
return;
}
float k = (CAL_POINTS * sum_xy - sum_x * sum_y) / denom;
float b = (sum_y - k * sum_x) / CAL_POINTS;
param->scale_factor = k;
param->zero_offset = b;
param->calibrated = 1;
}
// --- 应用标定 ---
float Angle_ApplyCalib(uint16_t raw_value, const CalibParam_t *param) {
float raw_deg = (float)raw_value * 360.0f / SENSOR_RESOLUTION;
return param->scale_factor * raw_deg + param->zero_offset;
}
// --- Flash存储模拟(EEPROM模拟) ---
void Calib_Save(const CalibParam_t *param) {
// 实际项目中写入内部Flash或外部EEPROM
// 此处仅示意,需包含解锁、擦除、写入流程
volatile uint32_t *addr = (uint32_t *)0x080E0000;
addr[0] = *(const uint32_t *)¶m->zero_offset;
addr[1] = *(const uint32_t *)¶m->scale_factor;
addr[2] = param->calibrated;
}
void Calib_Load(CalibParam_t *param) {
volatile uint32_t *addr = (uint32_t *)0x080E0000;
if (addr[2] == 0x01) {
*(uint32_t *)¶m->zero_offset = addr[0];
*(uint32_t *)¶m->scale_factor = addr[1];
param->calibrated = 1;
} else {
param->zero_offset = 0.0f;
param->scale_factor = 1.0f;
param->calibrated = 0;
}
}
// ============ main.c 标定与验证示例 ============
#include "angle_sensor.h"
#include <stdio.h>
// 模拟SPI读取(测试用)
uint16_t spi_read_angle(void) {
// 模拟传感器:真实角度 = 0.98 * 机械角 + 5度偏差
static float mech = -540.0f;
mech += 270.0f; // 每次递增270度
if (mech > 540.0f) mech = -540.0f;
float raw_deg = (mech - 5.0f) / 0.98f;
if (raw_deg < 0) raw_deg += 360.0f;
return (uint16_t)(raw_deg * SENSOR_RESOLUTION / 360.0f);
}
int main(void) {
CalibParam_t param;
float mech_ref[CAL_POINTS] = {-540.0f, -270.0f, 0.0f, 270.0f, 540.0f};
// 执行标定
Angle_Calibrate(mech_ref, ¶m);
// 输出标定结果
printf("scale_factor: %.4f\n", param.scale_factor);
printf("zero_offset: %.2f deg\n", param.zero_offset);
// 验证:读取一个已知位置
uint16_t raw = AS5047P_ReadRaw();
float result = Angle_ApplyCalib(raw, ¶m);
printf("raw=%u, calibrated=%.2f deg\n", raw, result);
// 保存参数
Calib_Save(¶m);
while(1);
}
标定流程与验证方法
标定步骤:
- 将方向盘机械居中,记录此时传感器原始值作为零点参考(本实现通过多点拟合自动获得零点偏移);
- 将方向盘分别旋转至 -540°、-270°、0°、270°、540° 五个机械位置(可用分度头或转向系统限位块定位),每个位置读取传感器原始值;
- 运行
Angle_Calibrate(),通过最小二乘法拟合出scale_factor(理想值为1.0)和zero_offset(理想值为0); - 将标定参数通过
Calib_Save()写入Flash,上电时由Calib_Load()恢复。
验证判定标准:
- 标定后,在任意机械角度下,传感器输出角度与机械参考角度的偏差应 ≤ ±0.5°;
- 零点位置(机械0°)输出应在 -0.5° ~ +0.5° 范围内;
- 正反行程(顺时针/逆时针旋转至同一位置)的重复性误差 ≤ ±0.2°;
- 若标定参数异常(如
scale_factor超出 0.9~1.1 范围),应判定传感器安装或硬件故障。
预期输出示例(基于模拟数据,实际值取决于传感器个体差异):
scale_factor: 0.9800
zero_offset: 5.00 deg
raw=8192, calibrated=0.00 deg
该输出表明:传感器原始增益为0.98(即实际转角 = 0.98 × 原始读数),零点偏移为+5°,当原始值对应0°时,校准后输出为0.00°,标定成功。
工程落地说明
本案例代码可直接编译运行于STM32F407最小系统板,需配置SPI1(PA5-SCK, PA6-MISO, PA7-MOSI, PA4-CS)与AS5047P连接。模拟的 spi_read_angle() 函数在实际工程中应替换为真实SPI读取代码。标定参数存储地址0x080E0000为示例,实际需根据MCU Flash扇区规划调整。验证时建议使用上位机通过UART读取标定后的角度值,与机械转台读数比对。