feat(FOC): 实现电角度零位自动校准并修复ADC采样干扰问题

- 新增FlashEEPROM用于保存零位校准角,掉电不丢失
- 实现安全的零位校准算法:运行中禁止校准、对齐后重新采样、保存到Flash
- 重构ADC架构:分离ADC0(PWM同步电流采样)和ADC1(VBUS/DRV温度轮询)
- 解决ADC采样冲突:移除ADC0的regular连续扫描,避免与注入组抢占资源
- 修复VBUS电压读取错误:从DMA缓冲区改为直接ADC1单次转换
- 修正开环控制Uq幅值限幅逻辑,保留符号避免反转时抖动
- 更新CAN协议:电流数据改为有符号16位打包,支持负电流传输
- 调整版本号至v26.8.16.7
This commit is contained in:
cbb
2026-08-16 02:13:37 +08:00
parent 42c9f2f669
commit 76f7987238
10 changed files with 214 additions and 95 deletions
+42 -21
View File
@@ -11,6 +11,7 @@
#include "adc.h"
#include "ang_sensor.h"
#include "config.h"
#include "flash.h"
#include "motor.h"
#include "pid.h"
#include "systick.h"
@@ -29,7 +30,7 @@ extern angle_sensor KTH7823;
extern CAN_transmiter CAN0_transmiter;
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern CurrentKalman Current_kalman;
extern u16 adc_value[3]; // regular DMA缓冲区:MCU温度 / DRV温度 / VBUS
extern FlashEEPROM flashEEP;
// 齿槽转矩补偿:查表 + 线性插值
// angle_el: 电角度(度)
@@ -271,26 +272,30 @@ void FOC_Controller::print_cogging_c_array(const char *title,
* @return void
*/
void calibrate_zero_position(void) {
// Set_3Pwm(.25, 0, 0); // 起劲
// delay_1ms(1000);
// KTH7823.update();
// 运行中禁止校准:要求控制模式为停止(0)且基本静止,
// 否则转子无法对齐到电气 0°,标定结果错误,甚至因电角度突变导致失控。
if (FOC.control_mode != 0 || fabsf(FOC.rt_velocity) > CALIB_MAX_SPEED) {
return;
}
// // 改进校准算法:获取当前传感器角度并计算补偿值
// float current_sensor_angle = KTH7823.getcurrent_sensorangle();
// float electrical_angle = fmodf(current_sensor_angle * PP, 360.0f); //
// 计算当前电角度
// 使能电机驱动器,准备对齐
motor_resume();
// // 计算需要的补偿值,使得当前位置对应0°电角度
// KTH7823.calibration_angle = -electrical_angle;
// 施加固定电压矢量(A 相高电平),让转子对齐到电气 0° 位置
Set_3Pwm(ALIGN_PWM_DUTY, 0.0f, 0.0f);
delay_1ms(ALIGN_SETTLE_MS);
// // 对补偿角进行归一化处理,确保在[-180, 180]范围内
// KTH7823.calibration_angle = fmodf(KTH7823.calibration_angle + 180.0f,
// 360.0f); if (KTH7823.calibration_angle < 0) { KTH7823.calibration_angle
// += 360.0f;
// }
// KTH7823.calibration_angle -= 180.0f;
// 对齐稳定后重新采样传感器角度,再计算零位补偿角,使当前位置对应电气 0°
KTH7823.update();
float current_sensor_angle = KTH7823.getcurrent_sensorangle();
float electrical_angle = fmodf(current_sensor_angle * PP, 360.0f);
KTH7823.set_calibration(-electrical_angle);
// Set_3Pwm(0, 0, 0); // 停止
// 停止施加电压
Set_3Pwm(0.0f, 0.0f, 0.0f);
// 保存校准角到 Flash,掉电不丢
flashEEP.save_calibration_angle(KTH7823.calibration_angle);
}
// 通过Ia,Ib,Ic计算Iq,Id(目前仅输出Iq)
@@ -722,8 +727,11 @@ void FOC_Controller::update_power(float voltage) {
* @return void
*/
void FOC_Controller::fast_voltage_check(void) {
// 直接从DMA缓冲区读取最新ADC值(regular rank2 是 VBUS)
float current_vbus = adc_value[2] * (3.3f / 4096.0f) * 11.0f;
// ADC1 单次转换读取 VBUS(ch6,11:1 分压)。
// 旧实现读 regular DMA 的 adc_value[2],通道顺序调整后该下标已是 DRV温度,
// 属漏改:NTC 分压值(~1.06V)按 11 倍分压换算仅 ~11.5V,逼近跌落阈值。
float current_vbus =
adc1_read_raw(ADC_CHANNEL_6) * (3.3f / 4096.0f) * 11.0f;
// 更新基准电压(峰值检测)
// 电压上升时,基准电压跟随;电压下跌时,基准电压保持
@@ -778,8 +786,21 @@ float FOC_Controller::velocity_open_loop() {
sampler.get_current('W'), angle_el_cog);
// 因为在开环控制中,Ud 始终为 0,只控制 Uq
const float Uq = _constrain(target_velocity * REDUCTION_RATIO * 0.005f,
2.0f, voltage_power_supply * 0.5f);
// 幅度限幅必须保留符号:原 _constrain 下限为 +2V,负速度会被钳到 +2V,
// 磁场角度反向而 Uq 仍为正,导致反转时电机原地抖动。
float Uq = target_velocity * REDUCTION_RATIO * 0.005f;
const float UQ_MIN_MAG = 2.0f;
const float UQ_MAX_MAG = voltage_power_supply * 0.5f;
// 零速不输出,避免 2V 最小幅值导致静止时缓慢爬行
if (Uq != 0.0f) {
float Uq_mag = fabsf(Uq);
if (Uq_mag < UQ_MIN_MAG) {
Uq_mag = UQ_MIN_MAG;
} else if (Uq_mag > UQ_MAX_MAG) {
Uq_mag = UQ_MAX_MAG;
}
Uq = (Uq < 0.0f) ? -Uq_mag : Uq_mag;
}
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
return limit_voltage;
}