Files
Motor_v2/Robot_V2/Algorithm/FOC.cpp
T

801 lines
25 KiB
C++
Raw Normal View History

#include "FOC.h"
2025-11-06 02:07:15 +08:00
#include "Can.h"
#include "Filter.h"
2025-10-16 21:43:34 +08:00
#include "Timer.h"
2025-10-30 20:20:14 +08:00
#include "adc.h"
#include "ang_sensor.h"
#include "config.h"
#include "motor.h"
2025-10-30 20:20:14 +08:00
#include "pid.h"
2026-05-19 01:26:42 +08:00
#include "systick.h"
#include <arm_math.h>
2025-10-16 21:43:34 +08:00
#include <cmath>
2026-05-19 01:26:42 +08:00
#include <cstdio>
#include <cstring>
#include <gd32c10x.h>
2025-10-16 21:43:34 +08:00
FOC_Controller FOC; // FOC控制初始化
2025-10-30 20:20:14 +08:00
extern sampler sampler;
extern angle_sensor KTH7823;
2025-11-06 02:07:15 +08:00
extern CAN_transmiter CAN0_transmiter;
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern CurrentKalman Current_kalman;
extern u16 adc_value[3]; // regular DMA缓冲区:MCU温度 / DRV温度 / VBUS
2025-10-30 20:20:14 +08:00
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿:查表 + 线性插值
// angle_el: 电角度(度)
// 返回: 补偿电压值 (V),叠加到 Uq 上
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;
// 线性插值查表
float index_f = angle / 360.0f * (float)COGGING_TABLE_SIZE;
u16 idx0 = (u16)index_f;
u16 idx1 = (idx0 + 1) % COGGING_TABLE_SIZE;
float frac = index_f - (float)idx0;
// 根据转向选择补偿表(带滞回,避免零速附近跳变)
static float *last_table = cogging_table;
if (rt_velocity < -0.5f) last_table = cogging_table_rev;
else if (rt_velocity > 0.5f) last_table = cogging_table;
float *table = last_table;
float comp = table[idx0] * (1.0f - frac) + table[idx1] * frac;
return -comp * cogging_comp_scale; // mA→V: 补偿电流(mA) × 换算系数(V/mA)
}
// === 齿槽转矩校准(DEBUG,平时不启用)===
// 启用方法:config.h 中 FOC_DEBUG 改为 1,通过 CAN 命令触发(RESET_ID bit4)
// 校准完成后把 C Array 硬编码到 init() 中,再改回 FOC_DEBUG 0
#if FOC_DEBUG
// 齿槽转矩校准静态数据
float FOC_Controller::cog_calib_run_data[6][COGGING_TABLE_SIZE] = {};
float FOC_Controller::cog_calib_accum[COGGING_TABLE_SIZE] = {};
u32 FOC_Controller::cog_calib_count[COGGING_TABLE_SIZE] = {};
/**
* @brief 齿槽转矩校准 - 非阻塞状态机
* 正转3次 + 反转3次,分开存储补偿表。
* 只打印最终平均数据和 C Array。
*/
void FOC_Controller::calibrate_cogging_tick(void) {
constexpr u32 SETTLE_TICKS = 16000; // 800ms / 50us
constexpr u32 STOP_TICKS = 10000; // 500ms / 50us
constexpr u32 TARGET_SAMPLES = 3 * COGGING_TABLE_SIZE * 8;
constexpr float SLOW_VEL = 1.0f; // 开环速度 rad/s
constexpr u32 SAMPLE_DIV = 20; // 1ms / 50us
constexpr u8 TOTAL_RUNS = 6; // 3正+3反
switch (cog_calib_state) {
case CogCalibState::IDLE:
if (!cogging_calib_request) return;
cogging_calib_request = false;
cog_calib_run = 0;
cog_calib_saved_mode = control_mode;
cog_calib_saved_vel = target_velocity;
cogging_comp_enabled = false;
memset(cog_calib_run_data, 0, sizeof(cog_calib_run_data));
printf("\r\n[COG] === Cogging Calibration: 3 fwd + 3 rev ===\r\n");
control_mode = 6;
target_velocity = SLOW_VEL;
cog_calib_settle_tick = 0;
cog_calib_state = CogCalibState::SETTLING;
return;
case CogCalibState::SETTLING:
cog_calib_settle_tick++;
if (cog_calib_settle_tick >= SETTLE_TICKS) {
cog_calib_state = CogCalibState::SAMPLING;
cog_calib_sample_count = 0;
memset(cog_calib_accum, 0, sizeof(cog_calib_accum));
memset(cog_calib_count, 0, sizeof(cog_calib_count));
}
return;
case CogCalibState::SAMPLING:
// 采样分频
static u32 sample_div = 0;
sample_div++;
if (sample_div < SAMPLE_DIV) return;
sample_div = 0;
{
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 iq = rt_current;
if (fabsf(iq) < 5000.0f) {
u16 idx = (u16)(angle_el / 360.0f * (float)COGGING_TABLE_SIZE);
if (idx >= COGGING_TABLE_SIZE) idx = COGGING_TABLE_SIZE - 1;
cog_calib_accum[idx] += iq;
cog_calib_count[idx]++;
}
cog_calib_sample_count++;
}
if (cog_calib_sample_count >= TARGET_SAMPLES) {
target_velocity = 0;
cog_calib_state = CogCalibState::STOPPING;
cog_calib_stop_tick = 0;
}
return;
case CogCalibState::STOPPING:
cog_calib_stop_tick++;
if (cog_calib_stop_tick >= STOP_TICKS) {
// 处理本轮数据:去直流
float dc = 0;
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
cog_calib_run_data[cog_calib_run][i] =
(cog_calib_count[i] > 0) ? cog_calib_accum[i] / (float)cog_calib_count[i] : 0.0f;
dc += cog_calib_run_data[cog_calib_run][i];
}
dc /= (float)COGGING_TABLE_SIZE;
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
cog_calib_run_data[cog_calib_run][i] -= dc;
}
printf("[COG] Run %d/%d done. DC=%.2f mA\r\n",
cog_calib_run + 1, TOTAL_RUNS, dc);
cog_calib_run++;
if (cog_calib_run < TOTAL_RUNS) {
// run 0~2 正转,run 3~5 反转
control_mode = 6;
target_velocity = (cog_calib_run < 3) ? SLOW_VEL : -SLOW_VEL;
cog_calib_state = CogCalibState::SETTLING;
cog_calib_settle_tick = 0;
} else {
cog_calib_state = CogCalibState::DONE;
}
}
return;
case CogCalibState::DONE:
// 正转平均 (run 0~2)
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
cogging_table[i] = (cog_calib_run_data[0][i] +
cog_calib_run_data[1][i] +
cog_calib_run_data[2][i]) / 3.0f;
}
// 反转平均 (run 3~5)
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
cogging_table_rev[i] = (cog_calib_run_data[3][i] +
cog_calib_run_data[4][i] +
cog_calib_run_data[5][i]) / 3.0f;
}
cogging_comp_enabled = true;
control_mode = cog_calib_saved_mode;
target_velocity = cog_calib_saved_vel;
// 打印正转平均
printf("\r\n[COG] === FWD Average ===\r\n");
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
float angle_deg = (float)i / (float)COGGING_TABLE_SIZE * 360.0f;
printf("[COG] %.2f, %.2f\r\n", angle_deg, cogging_table[i]);
fwdgt_counter_reload();
}
// 打印反转平均
printf("\r\n[COG] === REV Average ===\r\n");
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
float angle_deg = (float)i / (float)COGGING_TABLE_SIZE * 360.0f;
printf("[COG] %.2f, %.2f\r\n", angle_deg, cogging_table_rev[i]);
fwdgt_counter_reload();
}
// 打印正转 C Array
printf("\r\n[COG] --- FWD C Array ---\r\n");
printf("static const float COGGING_TABLE_FWD[COGGING_TABLE_SIZE] = {\r\n");
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
if (i % 8 == 0) printf(" ");
printf("%.2ff", cogging_table[i]);
if (i < COGGING_TABLE_SIZE - 1) printf(", ");
if (i % 8 == 7 || i == COGGING_TABLE_SIZE - 1) printf("\r\n");
fwdgt_counter_reload();
}
printf("};\r\n");
// 打印反转 C Array
printf("\r\n[COG] --- REV C Array ---\r\n");
printf("static const float COGGING_TABLE_REV[COGGING_TABLE_SIZE] = {\r\n");
for (int i = 0; i < COGGING_TABLE_SIZE; i++) {
if (i % 8 == 0) printf(" ");
printf("%.2ff", cogging_table_rev[i]);
if (i < COGGING_TABLE_SIZE - 1) printf(", ");
if (i % 8 == 7 || i == COGGING_TABLE_SIZE - 1) printf("\r\n");
fwdgt_counter_reload();
}
printf("};\r\n");
printf("\r\n[COG] === Done. ===\r\n");
cog_calib_state = CogCalibState::IDLE;
return;
}
}
#endif // FOC_DEBUG
2025-10-16 21:43:34 +08:00
// 初始变量及函数定义
#define _constrain(amt, low, high) \
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
#define constrain(value, min, max, target_min, target_max) \
((value - min) / (max - min) * (target_max - target_min))
// 校准步骤(代码模板)
void calibrate_zero_position(void) {
// Set_3Pwm(.25, 0, 0); // 起劲
// delay_1ms(1000);
// KTH7823.update();
// // 改进校准算法:获取当前传感器角度并计算补偿值
// float current_sensor_angle = KTH7823.getcurrent_sensorangle();
// float electrical_angle = fmodf(current_sensor_angle * PP, 360.0f); //
// 计算当前电角度
// // 计算需要的补偿值,使得当前位置对应0°电角度
// KTH7823.calibration_angle = -electrical_angle;
// // 对补偿角进行归一化处理,确保在[-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;
// Set_3Pwm(0, 0, 0); // 停止
}
// 通过Ia,Ib,Ic计算Iq,Id(目前仅输出Iq)
inline float FOC_Controller::cal_Iq_Id(float current_a, float current_b,
float current_c) {
if (current_a == ERROR_ADC_VAL || current_b == ERROR_ADC_VAL ||
current_c == ERROR_ADC_VAL) {
return Current_kalman.getCurrent();
}
// 去除三相公共模偏置,使 Ia + Ib + Ic 更接近 0
const float current_avg = (current_a + current_b + current_c) / 3.0f;
current_a -= current_avg;
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 -
(1.0f / 3.0f) * current_c;
I_beta = _1_SQRT3 * current_b - _1_SQRT3 * current_c;
// Park变换
float sin_el, cos_el;
arm_sin_cos_f32(angle_el, &sin_el, &cos_el);
float I_q, I_d;
I_q = I_beta * cos_el - I_alpha * sin_el;
I_d = I_beta * sin_el + I_alpha * cos_el;
// 返回Iq值,乘以1000以转换为mA
return Current_kalman.update(I_q * 1000 - KE_FACTOR * rt_velocity);
// return I_q * 1000 - KE_FACTOR * rt_velocity;
}
/**
* @brief 电机控制类初始化函数
*
* @return u8 0表示初始化成功,1表示初始化失败
*/
u8 FOC_Controller::init() {
motor_init(); // 电机驱动初始化
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿表(硬编码,3正+3反平均,用真实角度算Iq)
static const float COGGING_TABLE_FWD[COGGING_TABLE_SIZE] = {
29.28f, 28.84f, 28.26f, 28.83f, 29.79f, 30.26f, 29.52f, 28.77f,
28.23f, 27.68f, 26.65f, 25.19f, 23.92f, 22.59f, 19.61f, 16.77f,
13.32f, 10.40f, 7.64f, 3.51f, -0.83f, -4.96f, -8.19f, -11.11f,
-13.40f, -14.39f, -15.69f, -15.99f, -16.39f, -15.50f, -14.76f, -14.21f,
-13.76f, -13.88f, -13.22f, -11.18f, -10.65f, -10.54f, -10.62f, -10.23f,
-9.52f, -8.19f, -6.31f, -4.14f, -1.94f, -0.25f, 2.06f, 4.08f,
6.05f, 8.30f, 9.74f, 11.38f, 13.32f, 15.65f, 17.55f, 20.22f,
21.72f, 22.28f, 23.30f, 24.78f, 23.53f, 23.35f, 23.00f, 21.42f,
20.35f, 20.57f, 20.07f, 18.18f, 17.04f, 16.03f, 14.81f, 13.71f,
12.47f, 10.93f, 9.38f, 6.53f, 4.63f, 3.37f, 1.29f, -1.28f,
-5.08f, -11.11f, -16.35f, -21.00f, -24.61f, -28.30f, -31.11f, -33.48f,
-35.25f, -36.54f, -38.01f, -38.69f, -39.27f, -39.52f, -38.18f, -36.55f,
-34.96f, -33.14f, -31.92f, -31.45f, -31.32f, -30.25f, -29.60f, -28.72f,
-27.51f, -25.30f, -22.66f, -20.87f, -18.19f, -16.10f, -13.25f, -10.81f,
-8.00f, -4.67f, -2.28f, 0.87f, 3.83f, 7.25f, 10.56f, 13.70f,
17.70f, 19.90f, 22.14f, 23.62f, 24.53f, 26.03f, 26.96f, 27.95f,
};
static const float COGGING_TABLE_REV[COGGING_TABLE_SIZE] = {
22.45f, 24.95f, 26.05f, 26.01f, 26.11f, 25.87f, 26.20f, 26.23f,
26.19f, 25.87f, 25.97f, 26.09f, 24.77f, 24.22f, 23.71f, 22.10f,
19.84f, 17.60f, 15.36f, 12.99f, 9.54f, 5.35f, 1.71f, -1.94f,
-4.15f, -6.16f, -7.93f, -9.10f, -10.01f, -10.25f, -10.85f, -11.74f,
-11.98f, -10.78f, -9.65f, -8.89f, -8.14f, -6.85f, -5.94f, -5.37f,
-4.28f, -3.38f, -3.36f, -3.40f, -2.81f, -2.36f, -1.04f, -0.18f,
1.08f, 2.15f, 4.19f, 5.51f, 7.33f, 8.64f, 10.46f, 11.89f,
13.42f, 14.83f, 17.11f, 19.12f, 20.76f, 21.88f, 22.35f, 22.86f,
22.73f, 22.13f, 21.10f, 20.53f, 18.65f, 17.09f, 15.47f, 14.76f,
14.02f, 12.94f, 11.98f, 10.29f, 8.11f, 5.83f, 4.23f, 2.42f,
1.03f, -1.80f, -4.01f, -7.93f, -11.79f, -15.90f, -20.22f, -23.04f,
-25.66f, -28.80f, -30.45f, -32.11f, -33.17f, -33.97f, -34.68f, -34.26f,
-34.18f, -33.78f, -32.47f, -31.11f, -29.40f, -27.89f, -27.05f, -26.72f,
-25.59f, -24.86f, -23.61f, -22.97f, -22.89f, -21.81f, -20.78f, -19.23f,
-17.74f, -15.09f, -13.18f, -10.51f, -8.18f, -5.89f, -3.35f, -0.02f,
2.02f, 3.87f, 6.37f, 9.11f, 12.33f, 14.63f, 17.12f, 19.12f,
};
memcpy(cogging_table, COGGING_TABLE_FWD, sizeof(COGGING_TABLE_FWD));
memcpy(cogging_table_rev, COGGING_TABLE_REV, sizeof(COGGING_TABLE_REV));
cogging_comp_enabled = true;
FOC.cur_loop_p = DEFAULT_current_loop_p * 100 / limit_voltage;
FOC.cur_MIT_p = DEFAULT_current_MIT_p * 100 / limit_voltage;
FOC.vel_loop_p = DEFAULT_vel_loop_p * 100 / limit_voltage;
FOC.vel_angloop_p = DEFAULT_vel_angloop_p * 100;
FOC.vel_MIT_p = DEFAULT_vel_MIT_p * 100;
FOC.ang_loop_p = DEFAULT_angle_loop_p * 100 / limit_voltage;
FOC.ang_angloop_p = DEFAULT_angle_angloop_p * 100 / limit_voltage;
FOC.ang_MIT_p = DEFAULT_angle_MIT_p * 100 / limit_voltage;
return 0;
}
2025-10-16 21:43:34 +08:00
/**
* @brief 电机控制类构造函数
*
*/
FOC_Controller::FOC_Controller() { ; }
2025-10-16 21:43:34 +08:00
/**
* @brief 使用SVPWM算法设置电机输出
*
* @param Uq: q轴电压
* @param Ud: d轴电压
*/
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);
// 帕克逆变换
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;
// 计算角度并归一化到 [0, 2π)
float angle = atan2f(Ubeta, Ualpha);
if (angle < 0.0f)
angle += 2.0f * PI;
// 扇区与局部角度
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;
// 模长计算
float magnitude = sqrtf(Ualpha * Ualpha + Ubeta * Ubeta);
// 计算电压调制比,同时限制最大输出电压
float modulation_index =
(magnitude / voltage_power_supply); // 90%作为安全裕量
// 电压限制
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;
float T0 = 1.0f - T1 - T2;
// 计算占空比(按规范化时间映射)
switch (sector) {
case 1:
duty_a = 0.5f * T0 + T1 + T2;
duty_b = 0.5f * T0 + T2;
duty_c = 0.5f * T0;
break;
case 2:
duty_a = 0.5f * T0 + T1;
duty_b = 0.5f * T0 + T1 + T2;
duty_c = 0.5f * T0;
break;
case 3:
duty_a = 0.5f * T0;
duty_b = 0.5f * T0 + T1 + T2;
duty_c = 0.5f * T0 + T2;
break;
case 4:
duty_a = 0.5f * T0;
duty_b = 0.5f * T0 + T1;
duty_c = 0.5f * T0 + T1 + T2;
break;
case 5:
duty_a = 0.5f * T0 + T2;
duty_b = 0.5f * T0;
duty_c = 0.5f * T0 + T1 + T2;
break;
case 6:
duty_a = 0.5f * T0 + T1 + T2;
duty_b = 0.5f * T0;
duty_c = 0.5f * T0 + T1;
break;
default:
duty_a = 0.5f;
duty_b = 0.5f;
duty_c = 0.5f;
break;
}
// 设置PWM输出
Set_3Pwm(duty_a, duty_b, duty_c);
2025-10-16 21:43:34 +08:00
}
2025-11-06 02:07:15 +08:00
/**
* @brief 电机关机(通用关机,不带原因标记)
2025-11-06 02:07:15 +08:00
*
*/
void FOC_Controller::shut_down() {
drv_stop();
2025-12-08 02:48:59 +08:00
motor_sleep();
is_shut_down = true;
}
/**
* @brief 过热关机
*
*/
void FOC_Controller::shut_down_thermal() {
drv_stop();
motor_sleep();
is_shut_down = true;
thermal_shutdown = true;
}
/**
* @brief 过热恢复
*
*/
void FOC_Controller::resume_from_thermal() {
thermal_shutdown = false;
if (!voltage_error && !over_current) {
is_shut_down = false;
motor_resume();
}
2025-11-06 02:07:15 +08:00
}
/**
* @brief 占空比置0
*
*/
void FOC_Controller::drv_stop() { Set_3Pwm(0.0f, 0.0f, 0.0f); }
/**
* @brief 电机锁止
*/
float FOC_Controller::drv_hold() {
float hold_pwm_duty = HOLD_PWM_DUTY;
if (HOLD_PWM_DUTY > 0.95f) {
hold_pwm_duty = 0.95f;
} else if (HOLD_PWM_DUTY < 0.0f) {
hold_pwm_duty = 0.0f;
}
Set_3Pwm(hold_pwm_duty, 0, 0);
return hold_pwm_duty;
}
/**
* @brief PWM模式(调试)
*/
float FOC_Controller::PWM_out() {
float hold_pwm_duty = target_velocity/100;
Set_3Pwm(hold_pwm_duty, hold_pwm_duty, hold_pwm_duty);
return hold_pwm_duty;
}
2025-11-06 02:07:15 +08:00
/**
* @brief 电机恢复
*
*/
void FOC_Controller::resume() {
over_current = false;
voltage_error = false;
is_shut_down = false;
2025-12-08 02:48:59 +08:00
motor_resume();
2025-11-06 02:07:15 +08:00
}
/**
* @brief 更新电源电压
*
*/
void FOC_Controller::update_power(float voltage) {
if (voltage < 36.0f and voltage > 8.0f) {
voltage_error = false;
voltage_power_supply = voltage;
v_half = voltage * 0.5f;
v_safe = voltage * 1.1f;
} else {
voltage_error = true;
}
2025-11-06 02:07:15 +08:00
}
2025-10-16 21:43:34 +08:00
/**
* @brief 快速电压检测(在电机控制循环中每100us调用一次)
*
* 直接从DMA缓冲区读取最新ADC值,检测电压跌幅
* 响应时间 < 200us
*
* 算法:
* 1. 使用峰值检测算法跟踪当前额定电压(vbus_reference)
* - 电压上升时,基准电压跟随
* - 电压下跌时,基准电压保持(不跟随下跌)
* 2. 计算电压跌幅 = 基准电压 - 当前电压
* 3. 关机条件(满足任一即可):
* - 电压跌幅超过 VBUS_DROP_THRESHOLD
* - 电压低于绝对下限 VBUS_ABSOLUTE_MIN
*
* 参数定义在 config.h 中:
* - VBUS_DROP_THRESHOLD: 电压跌幅阈值 (默认5V)
* - VBUS_ABSOLUTE_MIN: 绝对最低电压 (默认8V)
* - VBUS_DEBOUNCE_COUNT: 防抖计数 (默认5次)
*/
void FOC_Controller::fast_voltage_check(void) {
// 直接从DMA缓冲区读取最新ADC值(regular rank2 是 VBUS)
float current_vbus = adc_value[2] * (3.3f / 4096.0f) * 11.0f;
// 更新基准电压(峰值检测)
// 电压上升时,基准电压跟随;电压下跌时,基准电压保持
if (current_vbus > vbus_reference) {
vbus_reference = current_vbus;
}
// 电压下跌时不更新基准电压,保持之前的峰值
// 更新上次电压值
last_vbus_fast = current_vbus;
// 计算电压跌幅(相对于基准电压)
float voltage_drop = vbus_reference - current_vbus;
// 关机条件(满足任一即可):
// 1. 电压跌幅超过阈值
// 2. 电压低于绝对下限
bool drop_exceeded = (voltage_drop > VBUS_DROP_THRESHOLD);
bool below_absolute = (current_vbus < VBUS_ABSOLUTE_MIN);
if ((drop_exceeded || below_absolute) && (!is_shut_down)) {
// 电压跌落计数(防抖)
vbus_drop_count++;
if (vbus_drop_count >= VBUS_DEBOUNCE_COUNT) {
// 确认需要关机,立即停机
drv_stop();
motor_sleep();
is_shut_down = true;
emergency_shutdown = true; // 标记紧急关机,低频任务会执行保存
vbus_drop_count = 0; // 重置计数器
}
} else {
// 电压正常,重置计数器
vbus_drop_count = 0;
}
}
2025-10-16 21:43:34 +08:00
/**
* @brief 速度开环控制
*
* @param target_velocity: 目标速度
* @return float: q轴电压
*/
float FOC_Controller::velocity_open_loop() {
// 通过时间间隔和目标速度计算需要转动的机械角度,存储在 shaft_angle 中
shaft_angle =
fmod(shaft_angle + target_velocity * REDUCTION_RATIO / MOTOR_FREQUENCY,
360.0f);
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
// 因为在开环控制中,Ud 始终为 0,只控制 Uq
const float Uq = _constrain(target_velocity * REDUCTION_RATIO * 0.005f,
2.0f, voltage_power_supply * 0.5f);
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
return limit_voltage;
2025-10-16 21:43:34 +08:00
}
2025-11-06 02:07:15 +08:00
/**
* @brief 角度闭环控制
*
* @param target_angle: 目标角度
* @return float: 当前角度
2025-11-06 02:07:15 +08:00
*/
float FOC_Controller::angle_control() {
// PID 控制计算
float Uq = angle_loop(target_angle - rt_angle);
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
2025-11-06 02:07:15 +08:00
// 设置相电压
2026-05-19 01:26:42 +08:00
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
return shaft_angle;
}
/**
* @brief 速度闭环控制
*
* @param target_velocity: 目标速度
* @return float: 当前速度
*/
float FOC_Controller::velocity_control() {
// 速度误差计算
float velocity_error = (target_velocity - rt_velocity) * DIR * REDUCTION_RATIO;
// 目标速度突变检测:target 大幅变化时清积分
static float last_target_vel = 0.0f;
const float target_delta = target_velocity - last_target_vel;
if (fabsf(target_delta) > 5.0f) {
vel_loop.reset_integral();
}
last_target_vel = target_velocity;
// PID 控制计算
float Uq = vel_loop(velocity_error);
CAN0_transmiter.testfloat_union.f = Uq;
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
// 设置相电压
2026-05-19 01:26:42 +08:00
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
return rt_velocity;
}
float FOC_Controller::current_control() {
// PID 控制计算
float Iq = rt_current =
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
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;
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
// 设置相电压
2026-05-19 01:26:42 +08:00
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
return 1;
}
/**
* @brief 带速度限制的角度闭环控制
*
* @param target_angle: 目标角度
* @param max_velocity: 最大速度限制 (单位: rad/s)
* @return float: 当前角度
*/
float FOC_Controller::angle_control_with_velocity_limit() {
// 计算角度误差
float angle_error = target_angle - rt_angle;
ang_inVelAngloop.set_P(ang_angloop_p);
// 使用角度PID控制器计算目标速度
float target_velocity = ang_inVelAngloop(angle_error);
// 使用速度PID控制器计算最终输出电压
// 根据目标速度大小,选择不同的PID参数
if (target_velocity < -120.0f) {
vel_inVelAngloop.set_P(vel_angloop_p * 2.0f);
} else if (target_velocity < -30.0f) {
vel_inVelAngloop.set_P(vel_angloop_p * 1.5f);
} else {
vel_inVelAngloop.set_P(vel_angloop_p);
}
float velocity_error = target_velocity - rt_velocity;
// 目标速度突变检测:target 大幅变化时清积分
static float last_vang_target_vel = 0.0f;
if (fabsf(target_velocity - last_vang_target_vel) > 5.0f) {
vel_inVelAngloop.reset_integral();
}
last_vang_target_vel = target_velocity;
static float last_velocity_error = 0.0f;
last_velocity_error = velocity_error;
float Uq = vel_inVelAngloop(velocity_error)* DIR;
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
2026-05-19 01:26:42 +08:00
CAN0_transmiter.testfloat_union.f = shaft_angle;
// 获取当前实际电流值
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
// 设置相电压
2026-05-19 01:26:42 +08:00
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
return shaft_angle;
}
/**
* @brief MIT控制
*
* @param target_angle: 目标角度
* @param max_velocity: 最大速度限制 (单位: rad/s)
* @return float: 当前角度
*/
float FOC_Controller::MIT_Mode() {
// 第一层:角度环(外环)
float angle_error = target_angle - rt_angle;
ang_inMITloop.set_P(ang_MIT_p);
float target_velocity =
2026-05-19 01:26:42 +08:00
ang_inMITloop(angle_error);
// 第二层:速度环(中环)
float velocity_error = (target_velocity - rt_velocity)* DIR;
// 目标速度变化检测:target 大幅变化时清积分
static float last_mit_target_vel = 0.0f;
if (fabsf(target_velocity - last_mit_target_vel) > 5.0f) {
vel_inMITloop.reset_integral();
}
last_mit_target_vel = target_velocity;
vel_inMITloop.set_P(vel_MIT_p);
float target_current = vel_inMITloop(velocity_error);
// 第三层:电流环(内环)
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
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();
2026-05-19 01:26:42 +08:00
// 齿槽转矩补偿
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
// 设置相电压
2026-05-19 01:26:42 +08:00
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
2025-11-06 02:07:15 +08:00
return shaft_angle;
2025-10-30 20:20:14 +08:00
}