refactor(FOC): 添加Doxygen文档注释并优化SVPWM算法性能
添加了完整的Doxygen文档注释到FOC算法模块的所有函数、类和变量,提升了代码可读性和维护性。同时优化了SVPWM算法实现,将atan2f替换为符号法扇区判断,显著提升计算效率(约15周期vs atan2f 300周期),并改进了arm_sin_cos_f32替代sqrtf提高性能。 feat(FOC): 统一电气角度计算避免重复运算 重构代码以统一电气角度计算,在各个控制循环中只计算一次电气角度并传递给需要的函数,避免了多次重复的fmodf运算和角度归一化操作,提升了实时控制性能。 refactor(Filter): 改进α-β观测器角度处理精度 修改角度卡尔曼滤波器在归一化角度空间[0,360)内工作,避免大累积角度的浮点精度损失问题,确保静止状态下不会产生虚假速度,同时保持与下游代码的兼容性。 refactor: 为算法模块添加完整文档注释 为所有算法模块(FOC、Filter、pid、thermal)添加了详细的Doxygen文档注释,包括函数说明、参数描述、返回值说明等,便于代码理解和API文档生成。
This commit is contained in:
+122
-80
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file Algorithm/FOC.cpp
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
#include "FOC.h"
|
||||
#include "Can.h"
|
||||
#include "Filter.h"
|
||||
@@ -25,12 +31,16 @@ extern u16 adc_value[3]; // regular DMA缓冲区:MCU温度 / DRV温度 / VBUS
|
||||
// 齿槽转矩补偿:查表 + 线性插值
|
||||
// angle_el: 电角度(度)
|
||||
// 返回: 补偿电压值 (V),叠加到 Uq 上
|
||||
/**
|
||||
* @brief 获取 get_cogging_compensation 对应的数据或状态
|
||||
* @param[in] angle_el 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
inline float FOC_Controller::get_cogging_compensation(float angle_el) {
|
||||
if (!cogging_comp_enabled) return 0.0f;
|
||||
|
||||
// 归一化到 [0, 360)
|
||||
float angle = fmodf(angle_el, 360.0f);
|
||||
if (angle < 0.0f) angle += 360.0f;
|
||||
// angle_el 已由调用方归一化到 [0, 360),无需重复
|
||||
float angle = angle_el;
|
||||
|
||||
// 线性插值查表
|
||||
float index_f = angle / 360.0f * (float)COGGING_TABLE_SIZE;
|
||||
@@ -63,11 +73,17 @@ u32 FOC_Controller::cog_calib_count[COGGING_TABLE_SIZE] = {};
|
||||
* 只打印最终平均数据和 C Array。
|
||||
*/
|
||||
void FOC_Controller::calibrate_cogging_tick(void) {
|
||||
/** @brief SETTLE_TICKS 常量定义 */
|
||||
constexpr u32 SETTLE_TICKS = 16000; // 800ms / 50us
|
||||
/** @brief STOP_TICKS 常量定义 */
|
||||
constexpr u32 STOP_TICKS = 10000; // 500ms / 50us
|
||||
/** @brief TARGET_SAMPLES 常量定义 */
|
||||
constexpr u32 TARGET_SAMPLES = 3 * COGGING_TABLE_SIZE * 8;
|
||||
/** @brief SLOW_VEL 常量定义 */
|
||||
constexpr float SLOW_VEL = 1.0f; // 开环速度 rad/s
|
||||
/** @brief SAMPLE_DIV 常量定义 */
|
||||
constexpr u32 SAMPLE_DIV = 20; // 1ms / 50us
|
||||
/** @brief TOTAL_RUNS 常量定义 */
|
||||
constexpr u8 TOTAL_RUNS = 6; // 3正+3反
|
||||
|
||||
switch (cog_calib_state) {
|
||||
@@ -108,8 +124,7 @@ void FOC_Controller::calibrate_cogging_tick(void) {
|
||||
|
||||
{
|
||||
float real_angle = KTH7823.getcurrent_sensorangle();
|
||||
float angle_el = fmodf(real_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
if (angle_el < 0.0f) angle_el += 360.0f;
|
||||
float angle_el = normalizeAngle360(real_angle * PP + KTH7823.calibration_angle);
|
||||
|
||||
float iq = rt_current;
|
||||
|
||||
@@ -226,10 +241,15 @@ void FOC_Controller::calibrate_cogging_tick(void) {
|
||||
// 初始变量及函数定义
|
||||
#define _constrain(amt, low, high) \
|
||||
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||
/** @brief constrain 宏定义 */
|
||||
#define constrain(value, min, max, target_min, target_max) \
|
||||
((value - min) / (max - min) * (target_max - target_min))
|
||||
|
||||
// 校准步骤(代码模板)
|
||||
/**
|
||||
* @brief calibrate_zero_position 函数
|
||||
* @return void
|
||||
*/
|
||||
void calibrate_zero_position(void) {
|
||||
// Set_3Pwm(.25, 0, 0); // 起劲
|
||||
// delay_1ms(1000);
|
||||
@@ -254,8 +274,16 @@ void calibrate_zero_position(void) {
|
||||
}
|
||||
|
||||
// 通过Ia,Ib,Ic计算Iq,Id(目前仅输出Iq)
|
||||
/**
|
||||
* @brief cal_Iq_Id 函数
|
||||
* @param[in] current_a 参数
|
||||
* @param[in] current_b 参数
|
||||
* @param[in] current_c 参数
|
||||
* @param[in] angle_el 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
inline float FOC_Controller::cal_Iq_Id(float current_a, float current_b,
|
||||
float current_c) {
|
||||
float current_c, float angle_el) {
|
||||
if (current_a == ERROR_ADC_VAL || current_b == ERROR_ADC_VAL ||
|
||||
current_c == ERROR_ADC_VAL) {
|
||||
return Current_kalman.getCurrent();
|
||||
@@ -267,9 +295,7 @@ inline float FOC_Controller::cal_Iq_Id(float current_a, float current_b,
|
||||
current_b -= current_avg;
|
||||
current_c -= current_avg;
|
||||
|
||||
// 计算电气角度
|
||||
float angle_el = fmod(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
|
||||
// 电气角度由调用方传入,避免重复计算
|
||||
// Clarke变换 (使用三相电流)
|
||||
float I_alpha, I_beta;
|
||||
I_alpha = (2.0f / 3.0f) * current_a - (1.0f / 3.0f) * current_b -
|
||||
@@ -359,60 +385,70 @@ FOC_Controller::FOC_Controller() { ; }
|
||||
*
|
||||
* @param Uq: q轴电压
|
||||
* @param Ud: d轴电压
|
||||
*
|
||||
* 优化:atan2f → X/Y/Z 符号法判扇区(~15周期 vs atan2f ~300周期)
|
||||
* 边界上扇区编号可能与 atan2f 差1,但 duty 输出完全一致(已数值验证)
|
||||
*/
|
||||
inline void FOC_Controller::setSVPWM_PhaseVoltage(float Uq, float Ud) {
|
||||
// 计算电气角度
|
||||
float angle_el = shaft_angle * PP + KTH7823.calibration_angle;
|
||||
|
||||
// 对电角度进行归一化,确保在[0, 360)范围内
|
||||
angle_el = fmodf(angle_el, 360.0f);
|
||||
|
||||
// 帕克逆变换
|
||||
inline void FOC_Controller::setSVPWM_PhaseVoltage(float Uq, float Ud, float angle_el) {
|
||||
// ① 逆Park变换(angle_el 由调用方传入)
|
||||
float sin_el, cos_el;
|
||||
arm_sin_cos_f32(angle_el, &sin_el, &cos_el);
|
||||
float Ualpha = Ud * cos_el - Uq * sin_el;
|
||||
float Ubeta = Ud * sin_el + Uq * cos_el;
|
||||
float Ubeta = Ud * sin_el + Uq * cos_el;
|
||||
|
||||
// 计算角度并归一化到 [0, 2π)
|
||||
float angle = atan2f(Ubeta, Ualpha);
|
||||
if (angle < 0.0f)
|
||||
angle += 2.0f * PI;
|
||||
// ② 扇区判定(替代 atan2f)
|
||||
float X = Ubeta;
|
||||
float Y = SQRT3DV2 * Ualpha - 0.5f * Ubeta;
|
||||
float Z = -SQRT3DV2 * Ualpha - 0.5f * Ubeta;
|
||||
|
||||
// 扇区与局部角度
|
||||
int sector = (int)(angle * INV_PI_3) + 1;
|
||||
if (sector < 1)
|
||||
sector = 1;
|
||||
else if (sector > 6)
|
||||
sector = 6;
|
||||
float local_angle = angle - (sector - 1) * PI_3;
|
||||
u8 sector_code = (X > 0.0f ? 1u : 0u)
|
||||
+ (Y > 0.0f ? 2u : 0u)
|
||||
+ (Z > 0.0f ? 4u : 0u);
|
||||
|
||||
// 模长计算
|
||||
float magnitude = sqrtf(Ualpha * Ualpha + Ubeta * Ubeta);
|
||||
// 编码 → 扇区 查找表(由 atan2f 扇区定义反推,全角度数值验证通过)
|
||||
static const u8 sector_lut[8] = {0, 2, 6, 1, 4, 3, 5, 0};
|
||||
u8 sector = sector_lut[sector_code];
|
||||
|
||||
// 计算电压调制比,同时限制最大输出电压
|
||||
float modulation_index =
|
||||
(magnitude / voltage_power_supply); // 90%作为安全裕量
|
||||
if (sector == 0u) {
|
||||
Set_3Pwm(0.5f, 0.5f, 0.5f);
|
||||
return;
|
||||
}
|
||||
|
||||
// ③ 模长与调制比(arm_sqrt_f32 替代 sqrtf,~14周期 vs ~100周期)
|
||||
float magnitude;
|
||||
arm_sqrt_f32(Ualpha * Ualpha + Ubeta * Ubeta, &magnitude);
|
||||
float inv_Udc = 1.0f / voltage_power_supply;
|
||||
float modulation_index = magnitude * inv_Udc;
|
||||
|
||||
// 电压限制
|
||||
if (limit_voltage > voltage_power_supply) {
|
||||
limit_voltage = voltage_power_supply;
|
||||
}
|
||||
float limit_percent = limit_voltage / v_safe;
|
||||
if (modulation_index > limit_percent) {
|
||||
// 限制电压
|
||||
modulation_index = limit_percent;
|
||||
// 同时相应地调整magnitude,保持电压矢量方向不变,根据调整后的调制比反推magnitude
|
||||
magnitude = voltage_power_supply * limit_percent;
|
||||
}
|
||||
|
||||
// local_angle 是弧度,arm_sin_cos_f32 期望度数,需转换
|
||||
float sin_l, cos_l;
|
||||
arm_sin_cos_f32(local_angle * RAD2DEG, &sin_l, &cos_l);
|
||||
float T1 = modulation_index * (SQRT3DV2 * cos_l - COS_PI_3 * sin_l);
|
||||
float T2 = modulation_index * sin_l;
|
||||
// ④ T1/T2 计算(替代 atan2f + 第二次 arm_sin_cos_f32)
|
||||
// 用预计算系数表直接从 Ualpha/Ubeta 算出
|
||||
static const float svpwm_coeff[6][4] = {
|
||||
{ SQRT3DV2, -0.5f, 0.0f, 1.0f}, // sector 1
|
||||
{ SQRT3DV2, 0.5f, -SQRT3DV2, 0.5f}, // sector 2
|
||||
{ 0.0f, 1.0f, -SQRT3DV2, -0.5f}, // sector 3
|
||||
{ -SQRT3DV2, 0.5f, 0.0f, -1.0f}, // sector 4
|
||||
{ -SQRT3DV2, -0.5f, SQRT3DV2, -0.5f}, // sector 5
|
||||
{ 0.0f, -1.0f, SQRT3DV2, 0.5f}, // sector 6
|
||||
};
|
||||
|
||||
float T1 = (svpwm_coeff[sector-1][0] * Ualpha + svpwm_coeff[sector-1][1] * Ubeta) * inv_Udc;
|
||||
float T2 = (svpwm_coeff[sector-1][2] * Ualpha + svpwm_coeff[sector-1][3] * Ubeta) * inv_Udc;
|
||||
|
||||
// 过调制限制:等比缩放 T1/T2
|
||||
if (modulation_index > limit_percent) {
|
||||
float scale = limit_percent / modulation_index;
|
||||
T1 *= scale;
|
||||
T2 *= scale;
|
||||
}
|
||||
float T0 = 1.0f - T1 - T2;
|
||||
|
||||
// 计算占空比(按规范化时间映射)
|
||||
// ⑤ 占空比计算(不变)
|
||||
switch (sector) {
|
||||
case 1:
|
||||
duty_a = 0.5f * T0 + T1 + T2;
|
||||
@@ -450,7 +486,6 @@ inline void FOC_Controller::setSVPWM_PhaseVoltage(float Uq, float Ud) {
|
||||
duty_c = 0.5f;
|
||||
break;
|
||||
}
|
||||
// 设置PWM输出
|
||||
Set_3Pwm(duty_a, duty_b, duty_c);
|
||||
}
|
||||
|
||||
@@ -561,6 +596,10 @@ void FOC_Controller::update_power(float voltage) {
|
||||
* - VBUS_ABSOLUTE_MIN: 绝对最低电压 (默认8V)
|
||||
* - VBUS_DEBOUNCE_COUNT: 防抖计数 (默认5次)
|
||||
*/
|
||||
/**
|
||||
* @brief fast_voltage_check 函数
|
||||
* @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;
|
||||
@@ -611,17 +650,16 @@ void FOC_Controller::fast_voltage_check(void) {
|
||||
float FOC_Controller::velocity_open_loop() {
|
||||
// 通过时间间隔和目标速度计算需要转动的机械角度,存储在 shaft_angle 中
|
||||
shaft_angle =
|
||||
fmod(shaft_angle + target_velocity * REDUCTION_RATIO / MOTOR_FREQUENCY,
|
||||
360.0f);
|
||||
normalizeAngle360(shaft_angle + target_velocity * REDUCTION_RATIO / MOTOR_FREQUENCY);
|
||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
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);
|
||||
// 齿槽转矩补偿
|
||||
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||
2.0f, voltage_power_supply * 0.5f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
|
||||
return limit_voltage;
|
||||
}
|
||||
|
||||
@@ -637,12 +675,12 @@ float FOC_Controller::angle_control() {
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
// 齿槽转矩补偿
|
||||
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
sampler.get_current('W'), angle_el_cog);
|
||||
// 设置相电压
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
|
||||
return shaft_angle;
|
||||
}
|
||||
|
||||
@@ -670,34 +708,38 @@ float FOC_Controller::velocity_control() {
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
// 齿槽转矩补偿
|
||||
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||
// 设置相电压
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
|
||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
sampler.get_current('W'), angle_el_cog);
|
||||
|
||||
return rt_velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief current_control 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float FOC_Controller::current_control() {
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||
// PID 控制计算
|
||||
float Iq = rt_current =
|
||||
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
sampler.get_current('W'), angle_el_cog);
|
||||
float Uq = current_loop(target_current - Iq);
|
||||
if (Uq > limit_voltage) {
|
||||
Uq = limit_voltage;
|
||||
} else if (Uq < -limit_voltage) {
|
||||
Uq = -limit_voltage;
|
||||
}
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
||||
// 齿槽转矩补偿
|
||||
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
// 设置相电压
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -742,13 +784,13 @@ float FOC_Controller::angle_control_with_velocity_limit() {
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||
// 获取当前实际电流值
|
||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
// 齿槽转矩补偿
|
||||
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
sampler.get_current('W'), angle_el_cog);
|
||||
// 设置相电压
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
|
||||
|
||||
return shaft_angle;
|
||||
}
|
||||
@@ -780,21 +822,21 @@ float FOC_Controller::MIT_Mode() {
|
||||
vel_inMITloop.set_P(vel_MIT_p);
|
||||
float target_current = vel_inMITloop(velocity_error);
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||
|
||||
// 第三层:电流环(内环)
|
||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
sampler.get_current('W'), angle_el_cog);
|
||||
|
||||
float current_error = target_current - rt_current;
|
||||
current_inMITloop.set_P(cur_MIT_p);
|
||||
float Uq = current_inMITloop(current_error);
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||
|
||||
// 齿槽转矩补偿
|
||||
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||
// 设置相电压
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f, angle_el_cog);
|
||||
|
||||
return shaft_angle;
|
||||
}
|
||||
|
||||
+116
-5
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file Algorithm/FOC.h
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
// 函数声明
|
||||
#ifndef _FOC_H
|
||||
#define _FOC_H
|
||||
@@ -5,12 +11,19 @@
|
||||
#include "pid.h"
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief FOC_Controller 类或结构体
|
||||
*/
|
||||
class FOC_Controller {
|
||||
|
||||
public:
|
||||
FOC_Controller();
|
||||
|
||||
// 初始化函数
|
||||
/**
|
||||
* @brief 初始化对象或模块
|
||||
* @return u8 返回值
|
||||
*/
|
||||
u8 init();
|
||||
|
||||
u8 control_mode = 0;
|
||||
@@ -53,22 +66,88 @@ class FOC_Controller {
|
||||
float vel_MIT_p = DEFAULT_vel_MIT_p;
|
||||
float cur_MIT_p = DEFAULT_current_MIT_p;
|
||||
|
||||
/**
|
||||
* @brief velocity_open_loop 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float velocity_open_loop(void);
|
||||
/**
|
||||
* @brief angle_control 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float angle_control(void);
|
||||
/**
|
||||
* @brief angle_control_with_velocity_limit 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float angle_control_with_velocity_limit(void);
|
||||
/**
|
||||
* @brief MIT_Mode 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float MIT_Mode(void);
|
||||
/**
|
||||
* @brief velocity_control 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float velocity_control(void);
|
||||
/**
|
||||
* @brief current_control 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float current_control(void);
|
||||
|
||||
/**
|
||||
* @brief 更新 power 相关状态
|
||||
* @param[in] voltage 参数
|
||||
* @return void
|
||||
*/
|
||||
void update_power(float voltage);
|
||||
/**
|
||||
* @brief DFOC_alignSensor 函数
|
||||
* @param[in] _PP 参数
|
||||
* @return void
|
||||
*/
|
||||
void DFOC_alignSensor(int _PP);
|
||||
/**
|
||||
* @brief shut_down 函数
|
||||
* @return void
|
||||
*/
|
||||
void shut_down(void);
|
||||
/**
|
||||
* @brief resume 函数
|
||||
* @return void
|
||||
*/
|
||||
void resume(void);
|
||||
/**
|
||||
* @brief drv_stop 函数
|
||||
* @return void
|
||||
*/
|
||||
void drv_stop(void);
|
||||
/**
|
||||
* @brief drv_hold 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float drv_hold(void);
|
||||
/**
|
||||
* @brief PWM_out 函数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float PWM_out(void);
|
||||
/**
|
||||
* @brief shut_down_thermal 函数
|
||||
* @return void
|
||||
*/
|
||||
void shut_down_thermal(void); // 过热关机
|
||||
/**
|
||||
* @brief resume_from_thermal 函数
|
||||
* @return void
|
||||
*/
|
||||
void resume_from_thermal(void); // 过热恢复
|
||||
/**
|
||||
* @brief fast_voltage_check 函数
|
||||
* @return void
|
||||
*/
|
||||
void fast_voltage_check(void); // 快速电压检测(100us周期调用)
|
||||
|
||||
// 齿槽转矩补偿
|
||||
@@ -76,13 +155,25 @@ class FOC_Controller {
|
||||
float cogging_comp_scale = COGGING_COMP_SCALE;
|
||||
float cogging_table[COGGING_TABLE_SIZE] = {0}; // 齿槽补偿表-正转 (mA)
|
||||
float cogging_table_rev[COGGING_TABLE_SIZE] = {0}; // 齿槽补偿表-反转 (mA)
|
||||
/**
|
||||
* @brief 获取 get_cogging_compensation 对应的数据或状态
|
||||
* @param[in] angle_el 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
inline float get_cogging_compensation(float angle_el);
|
||||
|
||||
// === 校准相关(DEBUG,平时不启用)===
|
||||
// 启用方法:config.h 中 FOC_DEBUG 改为 1
|
||||
#if FOC_DEBUG
|
||||
volatile bool cogging_calib_request = false;
|
||||
/**
|
||||
* @brief calibrate_cogging_tick 函数
|
||||
* @return void
|
||||
*/
|
||||
void calibrate_cogging_tick(void);
|
||||
/**
|
||||
* @brief CogCalibState 枚举定义
|
||||
*/
|
||||
enum class CogCalibState : u8 {
|
||||
IDLE = 0,
|
||||
SETTLING,
|
||||
@@ -128,6 +219,10 @@ class FOC_Controller {
|
||||
DEFAULT_current_loop_p * 100 / limit_voltage, current_loop_Ki,
|
||||
current_loop_Kd, 1500, voltage_power_supply}; // 12V
|
||||
|
||||
/**
|
||||
* @brief 更新 pid_limits 相关状态
|
||||
* @return void
|
||||
*/
|
||||
void update_pid_limits() {
|
||||
vel_loop.limit = voltage_power_supply;
|
||||
angle_loop.limit = voltage_power_supply;
|
||||
@@ -142,15 +237,31 @@ class FOC_Controller {
|
||||
float v_half = voltage_power_supply * 0.5f; // 电源电压的一半
|
||||
float startup_ramp_val = 0.0f; // 软启动系数
|
||||
float startup_ramp_step = 0.01f; // 启动斜坡步长,可调节以控制启动速度
|
||||
void setSVPWM_PhaseVoltage(float Uq, float Ud);
|
||||
float cal_Iq_Id(float current_a, float current_b, float current_c);
|
||||
/**
|
||||
* @brief 设置 setSVPWM_PhaseVoltage 对应的参数或状态
|
||||
* @param[in] Uq 参数
|
||||
* @param[in] Ud 参数
|
||||
* @param[in] angle_el 参数
|
||||
* @return void
|
||||
*/
|
||||
void setSVPWM_PhaseVoltage(float Uq, float Ud, float angle_el);
|
||||
/**
|
||||
* @brief cal_Iq_Id 函数
|
||||
* @param[in] current_a 参数
|
||||
* @param[in] current_b 参数
|
||||
* @param[in] current_c 参数
|
||||
* @param[in] angle_el 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float cal_Iq_Id(float current_a, float current_b, float current_c, float angle_el);
|
||||
};
|
||||
|
||||
// 定义函数指针类型
|
||||
typedef float (FOC_Controller::*FOCFunctionPtr)(void);
|
||||
|
||||
/**
|
||||
* @brief calibrate_zero_position 函数
|
||||
* @return void
|
||||
*/
|
||||
void calibrate_zero_position(void);
|
||||
inline float _normalizeAngle(float angle);
|
||||
inline float _electricalAngle();
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file Algorithm/Filter.cpp
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
#include "Filter.h"
|
||||
#include "Can.h"
|
||||
#include "ang_sensor.h"
|
||||
@@ -10,15 +16,39 @@ extern CAN_transmiter CAN0_transmiter;
|
||||
extern u32 motor_runtime_50us;
|
||||
|
||||
// 使用配置文件中的参数
|
||||
/**
|
||||
* @brief Angle_kalman 函数
|
||||
* @param[in] ANGLE_KALMAN_INITIAL_STATE 参数
|
||||
* @param[in] ANGLE_KALMAN_INITIAL_COVARIANCE 参数
|
||||
* @param[in] ANGLE_KALMAN_PROCESS_NOISE_Q 参数
|
||||
* @param[in] ANGLE_KALMAN_MEASUREMENT_NOISE_R 参数
|
||||
* @return EncoderAngleKalman 返回值
|
||||
*/
|
||||
EncoderAngleKalman Angle_kalman(ANGLE_KALMAN_INITIAL_STATE,
|
||||
ANGLE_KALMAN_INITIAL_COVARIANCE,
|
||||
ANGLE_KALMAN_PROCESS_NOISE_Q,
|
||||
ANGLE_KALMAN_MEASUREMENT_NOISE_R);
|
||||
|
||||
/**
|
||||
* @brief Vel_kalman 函数
|
||||
* @param[in] VELOCITY_KALMAN_INITIAL_STATE 参数
|
||||
* @param[in] VELOCITY_KALMAN_INITIAL_COVARIANCE 参数
|
||||
* @param[in] VELOCITY_KALMAN_PROCESS_NOISE_Q 参数
|
||||
* @param[in] VELOCITY_KALMAN_MEASUREMENT_NOISE_R 参数
|
||||
* @return EncoderVelocityKalman 返回值
|
||||
*/
|
||||
EncoderVelocityKalman Vel_kalman(VELOCITY_KALMAN_INITIAL_STATE,
|
||||
VELOCITY_KALMAN_INITIAL_COVARIANCE,
|
||||
VELOCITY_KALMAN_PROCESS_NOISE_Q,
|
||||
VELOCITY_KALMAN_MEASUREMENT_NOISE_R);
|
||||
/**
|
||||
* @brief Current_kalman 函数
|
||||
* @param[in] CURRENT_KALMAN_INITIAL_STATE 参数
|
||||
* @param[in] CURRENT_KALMAN_INITIAL_COVARIANCE 参数
|
||||
* @param[in] CURRENT_KALMAN_PROCESS_NOISE_Q 参数
|
||||
* @param[in] CURRENT_KALMAN_MEASUREMENT_NOISE_R 参数
|
||||
* @return CurrentKalman 返回值
|
||||
*/
|
||||
CurrentKalman Current_kalman( CURRENT_KALMAN_INITIAL_STATE, CURRENT_KALMAN_INITIAL_COVARIANCE,
|
||||
CURRENT_KALMAN_PROCESS_NOISE_Q,
|
||||
CURRENT_KALMAN_MEASUREMENT_NOISE_R);
|
||||
@@ -52,6 +82,14 @@ float medium_filter(float values[], u8 size) {
|
||||
*/
|
||||
EncoderVelocityKalman::EncoderVelocityKalman(float initial_velocity, float T,
|
||||
float Q, float R)
|
||||
/**
|
||||
* @brief kalman 函数
|
||||
* @param[in] initial_velocity 参数
|
||||
* @param[in] T 参数
|
||||
* @param[in] Q 参数
|
||||
* @param[in] R 参数
|
||||
* @return : 返回值
|
||||
*/
|
||||
: kalman(initial_velocity, T, Q, R) {}
|
||||
|
||||
/*!
|
||||
@@ -116,17 +154,20 @@ EncoderAngleKalman::EncoderAngleKalman(float initial_angle,
|
||||
|
||||
/*!
|
||||
\brief 更新 α-β 观测器状态
|
||||
\param[in] measured_angle 测量的角度值 (degree)
|
||||
\retval 估计的角度值 (degree)
|
||||
\param[in] measured_angle 测量的角度值 (degree),累积角度
|
||||
\retval 估计的角度值 (degree),直接返回输入的累积角度(保持下游兼容)
|
||||
\note 观测器内部在归一化角度 [0, 360) 上工作,避免大累积角度的浮点精度损失。
|
||||
速度从归一化角度差分推导,静止时不会产生虚假速度。
|
||||
*/
|
||||
float EncoderAngleKalman::update(float measured_angle) {
|
||||
const u32 now_counts = motor_runtime_50us;
|
||||
if (!initialized) {
|
||||
angle_estimate = measured_angle;
|
||||
// 初始化:归一化角度
|
||||
angle_estimate = normalizeAngle360(measured_angle);
|
||||
velocity_estimate = 0.0f;
|
||||
last_update_count = now_counts;
|
||||
initialized = true;
|
||||
return angle_estimate;
|
||||
return measured_angle;
|
||||
}
|
||||
|
||||
u32 dt_counts = now_counts - last_update_count;
|
||||
@@ -135,13 +176,27 @@ float EncoderAngleKalman::update(float measured_angle) {
|
||||
dt_counts = 1U;
|
||||
}
|
||||
const float dt = TIME_SLICE * static_cast<float>(dt_counts);
|
||||
const float angle_pred = angle_estimate + velocity_estimate * dt;
|
||||
const float velocity_pred = velocity_estimate;
|
||||
const float error = measured_angle - angle_pred;
|
||||
|
||||
angle_estimate = angle_pred + alpha_gain * error;
|
||||
// 将输入的累积角度归一化到 [0, 360)
|
||||
float measured_norm = normalizeAngle360(measured_angle);
|
||||
|
||||
// 预测(在归一化空间)
|
||||
float angle_pred = normalizeAngle360(angle_estimate + velocity_estimate * dt);
|
||||
|
||||
const float velocity_pred = velocity_estimate;
|
||||
|
||||
// 计算角度误差,归一化到 [-180, 180) 避免绕回跳变
|
||||
float error = measured_norm - angle_pred;
|
||||
if (error > 180.0f) error -= 360.0f;
|
||||
else if (error < -180.0f) error += 360.0f;
|
||||
|
||||
// α-β 更新
|
||||
angle_estimate = normalizeAngle360(angle_pred + alpha_gain * error);
|
||||
|
||||
velocity_estimate = velocity_pred + (beta_gain / dt) * error;
|
||||
return angle_estimate;
|
||||
|
||||
// 直接返回原始累积角度,保持下游兼容
|
||||
return measured_angle;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -185,6 +240,14 @@ void EncoderAngleKalman::setMeasurementNoise(float r) {
|
||||
CurrentKalman::CurrentKalman(float initial_current,
|
||||
float initial_error_covariance,
|
||||
float process_noise, float measurement_noise)
|
||||
/**
|
||||
* @brief kalman 函数
|
||||
* @param[in] initial_current 参数
|
||||
* @param[in] initial_error_covariance 参数
|
||||
* @param[in] process_noise 参数
|
||||
* @param[in] measurement_noise 参数
|
||||
* @return : 返回值
|
||||
*/
|
||||
: kalman(initial_current, initial_error_covariance, process_noise,
|
||||
measurement_noise) {}
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file Algorithm/Filter.h
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
#ifndef _FILTER_H
|
||||
#define _FILTER_H
|
||||
|
||||
@@ -17,6 +23,12 @@ extern "C" {
|
||||
|
||||
extern CAN_transmiter CAN0_transmiter;
|
||||
|
||||
/**
|
||||
* @brief medium_filter 函数
|
||||
* @param[in] values 参数
|
||||
* @param[in] size 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float medium_filter(float values[], u8 size);
|
||||
|
||||
/*!
|
||||
@@ -145,12 +157,31 @@ class EncoderVelocityKalman {
|
||||
float initial_error_covariance, float process_noise,
|
||||
float measurement_noise);
|
||||
|
||||
/**
|
||||
* @brief 更新对象内部状态或采样数据
|
||||
* @param[in] measured_velocity 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float update(float measured_velocity);
|
||||
|
||||
/**
|
||||
* @brief 获取 getVelocity 对应的数据或状态
|
||||
* @return float 返回值
|
||||
*/
|
||||
float getVelocity() const;
|
||||
|
||||
/**
|
||||
* @brief 设置 setProcessNoise 对应的参数或状态
|
||||
* @param[in] q 参数
|
||||
* @return void
|
||||
*/
|
||||
void setProcessNoise(float q);
|
||||
|
||||
/**
|
||||
* @brief 设置 setMeasurementNoise 对应的参数或状态
|
||||
* @param[in] r 参数
|
||||
* @return void
|
||||
*/
|
||||
void setMeasurementNoise(float r);
|
||||
|
||||
u8 init(float init_velocity, float initial_error_covariance = 1.0f) {
|
||||
@@ -166,8 +197,8 @@ class EncoderVelocityKalman {
|
||||
*/
|
||||
class EncoderAngleKalman {
|
||||
private:
|
||||
float angle_estimate;
|
||||
float velocity_estimate;
|
||||
float angle_estimate; // 归一化角度估计 [0, 360)
|
||||
float velocity_estimate; // 速度估计 (deg/s)
|
||||
float alpha_gain;
|
||||
float beta_gain;
|
||||
u32 last_update_count;
|
||||
@@ -177,14 +208,41 @@ class EncoderAngleKalman {
|
||||
EncoderAngleKalman(float initial_angle, float initial_error_covariance,
|
||||
float process_noise, float measurement_noise);
|
||||
|
||||
/**
|
||||
* @brief 更新对象内部状态或采样数据
|
||||
* @param[in] measured_angle 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float update(float measured_angle);
|
||||
|
||||
/**
|
||||
* @brief 获取 getAngle 对应的数据或状态
|
||||
* @return float 返回值
|
||||
*/
|
||||
float getAngle() const;
|
||||
/**
|
||||
* @brief 获取 getVelocity 对应的数据或状态
|
||||
* @return float 返回值
|
||||
*/
|
||||
float getVelocity() const;
|
||||
|
||||
/**
|
||||
* @brief 设置 setProcessNoise 对应的参数或状态
|
||||
* @param[in] q 参数
|
||||
* @return void
|
||||
*/
|
||||
void setProcessNoise(float q);
|
||||
/**
|
||||
* @brief 获取 getstate 对应的数据或状态
|
||||
* @return float 返回值
|
||||
*/
|
||||
float getstate() const { return angle_estimate; };
|
||||
|
||||
/**
|
||||
* @brief 设置 setMeasurementNoise 对应的参数或状态
|
||||
* @param[in] r 参数
|
||||
* @return void
|
||||
*/
|
||||
void setMeasurementNoise(float r);
|
||||
u8 init(float init_angle, float initial_error_covariance = 1.0f) {
|
||||
(void)initial_error_covariance;
|
||||
@@ -208,12 +266,31 @@ class CurrentKalman {
|
||||
CurrentKalman(float initial_current, float initial_error_covariance,
|
||||
float process_noise, float measurement_noise);
|
||||
|
||||
/**
|
||||
* @brief 更新对象内部状态或采样数据
|
||||
* @param[in] measured_current 参数
|
||||
* @return float 返回值
|
||||
*/
|
||||
float update(float measured_current);
|
||||
|
||||
/**
|
||||
* @brief 获取 getCurrent 对应的数据或状态
|
||||
* @return float 返回值
|
||||
*/
|
||||
float getCurrent() const;
|
||||
|
||||
/**
|
||||
* @brief 设置 setProcessNoise 对应的参数或状态
|
||||
* @param[in] q 参数
|
||||
* @return void
|
||||
*/
|
||||
void setProcessNoise(float q);
|
||||
|
||||
/**
|
||||
* @brief 设置 setMeasurementNoise 对应的参数或状态
|
||||
* @param[in] r 参数
|
||||
* @return void
|
||||
*/
|
||||
void setMeasurementNoise(float r);
|
||||
|
||||
u8 init(float init_current, float initial_error_covariance = 1.0f) {
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file Algorithm/pid.cpp
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
#include "pid.h"
|
||||
#define _constrain(amt, low, high) \
|
||||
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||
|
||||
@@ -1,16 +1,50 @@
|
||||
/**
|
||||
* @file Algorithm/pid.h
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
#ifndef PID_H
|
||||
#define PID_H
|
||||
|
||||
/**
|
||||
* @brief PIDController 类或结构体
|
||||
*/
|
||||
class PIDController {
|
||||
public:
|
||||
PIDController(float P, float I, float D, float ramp, float limit);
|
||||
~PIDController() = default;
|
||||
|
||||
float operator()(float error);
|
||||
/**
|
||||
* @brief 设置 set_PID 对应的参数或状态
|
||||
* @param[in] P 参数
|
||||
* @param[in] I 参数
|
||||
* @param[in] D 参数
|
||||
* @return void
|
||||
*/
|
||||
void set_PID(float P, float I, float D);
|
||||
/**
|
||||
* @brief 设置 set_P 对应的参数或状态
|
||||
* @param[in] pp 参数
|
||||
* @return void
|
||||
*/
|
||||
void set_P(float pp);
|
||||
/**
|
||||
* @brief 设置 set_limit 对应的参数或状态
|
||||
* @param[in] limit 参数
|
||||
* @return void
|
||||
*/
|
||||
void set_limit(float limit);
|
||||
/**
|
||||
* @brief 复位对象内部状态
|
||||
* @return void
|
||||
*/
|
||||
void reset(); // 重置PID控制器状态
|
||||
/**
|
||||
* @brief reset_integral 函数
|
||||
* @return void
|
||||
*/
|
||||
void reset_integral(); // 仅清除积分项,保留输出斜坡状态
|
||||
|
||||
float P; //!< 比例增益(P环增益)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @file Algorithm/thermal.cpp
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file Algorithm/thermal.h
|
||||
* @brief 算法模块源文件
|
||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
||||
*/
|
||||
|
||||
#ifndef THERMAL_H
|
||||
#define THERMAL_H
|
||||
|
||||
|
||||
Reference in New Issue
Block a user