feat(FOC): 添加齿槽转矩补偿功能
- 实现齿槽转矩补偿算法,通过查表+线性插值方式计算补偿电压值 - 添加齿槽转矩校准功能,支持正转3次+反转3次的非阻塞校准状态机 - 在所有控制模式中集成齿槽转矩补偿,包括开环、角度、速度、电流和MIT模式 - 硬编码预校准的正反转补偿表数据 - 通过CAN命令支持运行时触发校准功能 - 添加相关配置参数和调试开关
This commit is contained in:
+265
-66
@@ -7,8 +7,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "motor.h"
|
#include "motor.h"
|
||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
|
#include "systick.h"
|
||||||
#include <arm_math.h>
|
#include <arm_math.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
#include <gd32c10x.h>
|
#include <gd32c10x.h>
|
||||||
|
|
||||||
FOC_Controller FOC; // FOC控制初始化
|
FOC_Controller FOC; // FOC控制初始化
|
||||||
@@ -19,6 +22,207 @@ extern EncoderVelocityKalman Vel_kalman; // 速度滤波
|
|||||||
extern CurrentKalman Current_kalman;
|
extern CurrentKalman Current_kalman;
|
||||||
extern u16 adc_value[3]; // regular DMA缓冲区:MCU温度 / DRV温度 / VBUS
|
extern u16 adc_value[3]; // regular DMA缓冲区:MCU温度 / DRV温度 / VBUS
|
||||||
|
|
||||||
|
// 齿槽转矩补偿:查表 + 线性插值
|
||||||
|
// 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
|
||||||
|
|
||||||
// 初始变量及函数定义
|
// 初始变量及函数定义
|
||||||
#define _constrain(amt, low, high) \
|
#define _constrain(amt, low, high) \
|
||||||
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||||
@@ -92,6 +296,47 @@ inline float FOC_Controller::cal_Iq_Id(float current_a, float current_b,
|
|||||||
u8 FOC_Controller::init() {
|
u8 FOC_Controller::init() {
|
||||||
motor_init(); // 电机驱动初始化
|
motor_init(); // 电机驱动初始化
|
||||||
|
|
||||||
|
// 齿槽转矩补偿表(硬编码,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_loop_p = DEFAULT_current_loop_p * 100 / limit_voltage;
|
||||||
FOC.cur_MIT_p = DEFAULT_current_MIT_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_loop_p = DEFAULT_vel_loop_p * 100 / limit_voltage;
|
||||||
@@ -109,50 +354,6 @@ u8 FOC_Controller::init() {
|
|||||||
*/
|
*/
|
||||||
FOC_Controller::FOC_Controller() { ; }
|
FOC_Controller::FOC_Controller() { ; }
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @brief 设置电机输出
|
|
||||||
// *
|
|
||||||
// * @param Uq: q轴电压
|
|
||||||
// * @param Ud: d轴电压
|
|
||||||
// * @param angle_el: 电机轴角度
|
|
||||||
// */
|
|
||||||
// inline void FOC_Controller::setPhaseVoltage(float Uq, float Ud) {
|
|
||||||
// // 计算电气角度
|
|
||||||
// float angle_el = fmod(shaft_angle * PP, 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;
|
|
||||||
|
|
||||||
// // 克拉克逆变换 (使用预计算常量优化)
|
|
||||||
// Ua = Ualpha + v_half;
|
|
||||||
// Ub = SQRT3DV2 * Ubeta - 0.5f * Ualpha + v_half;
|
|
||||||
// Uc = -0.5f * Ualpha - SQRT3DV2 * Ubeta + v_half;
|
|
||||||
|
|
||||||
// if (Ua > v_safe)
|
|
||||||
// Ua = v_safe;
|
|
||||||
// else if (Ua < -v_safe)
|
|
||||||
// Ua = -v_safe;
|
|
||||||
// if (Ub > v_safe)
|
|
||||||
// Ub = v_safe;
|
|
||||||
// else if (Ub < -v_safe)
|
|
||||||
// Ub = -v_safe;
|
|
||||||
// if (Uc > v_safe)
|
|
||||||
// Uc = v_safe;
|
|
||||||
// else if (Uc < -v_safe)
|
|
||||||
// Uc = -v_safe;
|
|
||||||
|
|
||||||
// // 设置PWM输出
|
|
||||||
// float voltage_exchange = limit_voltage / v_safe;
|
|
||||||
// duty_a = Ua / voltage_power_supply * voltage_exchange;
|
|
||||||
// duty_b = Ub / voltage_power_supply * voltage_exchange;
|
|
||||||
// duty_c = Uc / voltage_power_supply * voltage_exchange;
|
|
||||||
|
|
||||||
// Set_3Pwm(duty_a, duty_b, duty_c);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 使用SVPWM算法设置电机输出
|
* @brief 使用SVPWM算法设置电机输出
|
||||||
*
|
*
|
||||||
@@ -418,7 +619,9 @@ float FOC_Controller::velocity_open_loop() {
|
|||||||
// 因为在开环控制中,Ud 始终为 0,只控制 Uq
|
// 因为在开环控制中,Ud 始终为 0,只控制 Uq
|
||||||
const float Uq = _constrain(target_velocity * REDUCTION_RATIO * 0.005f,
|
const float Uq = _constrain(target_velocity * REDUCTION_RATIO * 0.005f,
|
||||||
2.0f, voltage_power_supply * 0.5f);
|
2.0f, voltage_power_supply * 0.5f);
|
||||||
setSVPWM_PhaseVoltage(Uq, 0.0f);
|
// 齿槽转矩补偿
|
||||||
|
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;
|
return limit_voltage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,8 +639,10 @@ float FOC_Controller::angle_control() {
|
|||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||||
sampler.get_current('W'));
|
sampler.get_current('W'));
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||||
// 设置相电压
|
// 设置相电压
|
||||||
setSVPWM_PhaseVoltage(Uq, 0.0f);
|
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||||
return shaft_angle;
|
return shaft_angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,8 +670,10 @@ float FOC_Controller::velocity_control() {
|
|||||||
|
|
||||||
// 获取电机轴角度
|
// 获取电机轴角度
|
||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||||
// 设置相电压
|
// 设置相电压
|
||||||
setSVPWM_PhaseVoltage(Uq, 0.0f);
|
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||||
sampler.get_current('W'));
|
sampler.get_current('W'));
|
||||||
|
|
||||||
@@ -487,8 +694,10 @@ float FOC_Controller::current_control() {
|
|||||||
// 获取电机轴角度
|
// 获取电机轴角度
|
||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||||
// 设置相电压
|
// 设置相电压
|
||||||
setSVPWM_PhaseVoltage(Uq, 0.0f);
|
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,25 +738,17 @@ float FOC_Controller::angle_control_with_velocity_limit() {
|
|||||||
last_velocity_error = velocity_error;
|
last_velocity_error = velocity_error;
|
||||||
|
|
||||||
float Uq = vel_inVelAngloop(velocity_error)* DIR;
|
float Uq = vel_inVelAngloop(velocity_error)* DIR;
|
||||||
CAN0_transmiter.testfloat_union.f = Uq;
|
|
||||||
|
|
||||||
// // 实现力度控制:如果电流超过目标电流,则限制输出
|
|
||||||
// if (abs(rt_current) > abs(target_current)) {
|
|
||||||
// // 当实际电流超过目标电流时,减小输出以限制电流
|
|
||||||
// // 可以采用比例限制或直接限制输出电压的方式
|
|
||||||
// float current_ratio = abs(target_current) / abs(rt_current);
|
|
||||||
// if (current_ratio < 1.0f) {
|
|
||||||
// Uq *= current_ratio; // 按比例缩小输出电压
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取电机轴角度
|
// 获取电机轴角度
|
||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
|
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
||||||
// 获取当前实际电流值
|
// 获取当前实际电流值
|
||||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||||
sampler.get_current('W'));
|
sampler.get_current('W'));
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||||
// 设置相电压
|
// 设置相电压
|
||||||
setSVPWM_PhaseVoltage(Uq, 0.0f);
|
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||||
|
|
||||||
return shaft_angle;
|
return shaft_angle;
|
||||||
}
|
}
|
||||||
@@ -561,14 +762,12 @@ float FOC_Controller::angle_control_with_velocity_limit() {
|
|||||||
*/
|
*/
|
||||||
float FOC_Controller::MIT_Mode() {
|
float FOC_Controller::MIT_Mode() {
|
||||||
// 第一层:角度环(外环)
|
// 第一层:角度环(外环)
|
||||||
// 根据目标角度和实际角度的差值,通过角度环PID控制器计算目标速度
|
|
||||||
float angle_error = target_angle - rt_angle;
|
float angle_error = target_angle - rt_angle;
|
||||||
ang_inMITloop.set_P(ang_MIT_p);
|
ang_inMITloop.set_P(ang_MIT_p);
|
||||||
float target_velocity =
|
float target_velocity =
|
||||||
ang_inMITloop(angle_error); // 使用angle_loop作为角度到速度的映射
|
ang_inMITloop(angle_error);
|
||||||
|
|
||||||
// 第二层:速度环(中环)
|
// 第二层:速度环(中环)
|
||||||
// 根据目标速度和实际速度的差值,通过速度环PID控制器计算目标电流
|
|
||||||
float velocity_error = (target_velocity - rt_velocity)* DIR;
|
float velocity_error = (target_velocity - rt_velocity)* DIR;
|
||||||
|
|
||||||
// 目标速度变化检测:target 大幅变化时清积分
|
// 目标速度变化检测:target 大幅变化时清积分
|
||||||
@@ -582,11 +781,9 @@ float FOC_Controller::MIT_Mode() {
|
|||||||
float target_current = vel_inMITloop(velocity_error);
|
float target_current = vel_inMITloop(velocity_error);
|
||||||
|
|
||||||
// 第三层:电流环(内环)
|
// 第三层:电流环(内环)
|
||||||
// 计算当前实际电流
|
|
||||||
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
rt_current = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||||
sampler.get_current('W'));
|
sampler.get_current('W'));
|
||||||
|
|
||||||
// 通过电流环PID控制器计算输出电压
|
|
||||||
float current_error = target_current - rt_current;
|
float current_error = target_current - rt_current;
|
||||||
current_inMITloop.set_P(cur_MIT_p);
|
current_inMITloop.set_P(cur_MIT_p);
|
||||||
float Uq = current_inMITloop(current_error);
|
float Uq = current_inMITloop(current_error);
|
||||||
@@ -594,8 +791,10 @@ float FOC_Controller::MIT_Mode() {
|
|||||||
// 获取电机轴角度
|
// 获取电机轴角度
|
||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
|
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
float angle_el_cog = fmodf(shaft_angle * PP + KTH7823.calibration_angle, 360.0f);
|
||||||
// 设置相电压
|
// 设置相电压
|
||||||
setSVPWM_PhaseVoltage(Uq, 0.0f);
|
setSVPWM_PhaseVoltage(Uq + get_cogging_compensation(angle_el_cog), 0.0f);
|
||||||
|
|
||||||
return shaft_angle;
|
return shaft_angle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,37 @@ class FOC_Controller {
|
|||||||
void resume_from_thermal(void); // 过热恢复
|
void resume_from_thermal(void); // 过热恢复
|
||||||
void fast_voltage_check(void); // 快速电压检测(100us周期调用)
|
void fast_voltage_check(void); // 快速电压检测(100us周期调用)
|
||||||
|
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
bool cogging_comp_enabled = false;
|
||||||
|
float cogging_comp_scale = COGGING_COMP_SCALE;
|
||||||
|
float cogging_table[COGGING_TABLE_SIZE] = {0}; // 齿槽补偿表-正转 (mA)
|
||||||
|
float cogging_table_rev[COGGING_TABLE_SIZE] = {0}; // 齿槽补偿表-反转 (mA)
|
||||||
|
inline float get_cogging_compensation(float angle_el);
|
||||||
|
|
||||||
|
// === 校准相关(DEBUG,平时不启用)===
|
||||||
|
// 启用方法:config.h 中 FOC_DEBUG 改为 1
|
||||||
|
#if FOC_DEBUG
|
||||||
|
volatile bool cogging_calib_request = false;
|
||||||
|
void calibrate_cogging_tick(void);
|
||||||
|
enum class CogCalibState : u8 {
|
||||||
|
IDLE = 0,
|
||||||
|
SETTLING,
|
||||||
|
SAMPLING,
|
||||||
|
STOPPING,
|
||||||
|
DONE
|
||||||
|
};
|
||||||
|
CogCalibState cog_calib_state = CogCalibState::IDLE;
|
||||||
|
u8 cog_calib_run = 0;
|
||||||
|
u32 cog_calib_sample_count = 0;
|
||||||
|
u32 cog_calib_settle_tick = 0;
|
||||||
|
u32 cog_calib_stop_tick = 0;
|
||||||
|
u8 cog_calib_saved_mode = 0;
|
||||||
|
float cog_calib_saved_vel = 0;
|
||||||
|
static float cog_calib_run_data[6][COGGING_TABLE_SIZE]; // 3正+3反
|
||||||
|
static float cog_calib_accum[COGGING_TABLE_SIZE];
|
||||||
|
static u32 cog_calib_count[COGGING_TABLE_SIZE];
|
||||||
|
#endif // FOC_DEBUG
|
||||||
|
|
||||||
// 此处默认值不作数
|
// 此处默认值不作数
|
||||||
PIDController vel_loop =
|
PIDController vel_loop =
|
||||||
PIDController{DEFAULT_vel_loop_p * 100 / limit_voltage, vel_loop_Ki,
|
PIDController{DEFAULT_vel_loop_p * 100 / limit_voltage, vel_loop_Ki,
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ project:
|
|||||||
- file: device/adc.h
|
- file: device/adc.h
|
||||||
- file: device/Timer.cpp
|
- file: device/Timer.cpp
|
||||||
- file: device/Timer.h
|
- file: device/Timer.h
|
||||||
- file: device/test.cpp
|
|
||||||
- file: device/motor.cpp
|
- file: device/motor.cpp
|
||||||
- file: device/motor.h
|
- file: device/motor.h
|
||||||
- group: Algorithm
|
- group: Algorithm
|
||||||
|
|||||||
@@ -1153,6 +1153,12 @@ void CAN_transmiter::communication_check() {
|
|||||||
Angle_kalman.init(0); // 角度滤波
|
Angle_kalman.init(0); // 角度滤波
|
||||||
Vel_kalman.init(0); // 角度滤波
|
Vel_kalman.init(0); // 角度滤波
|
||||||
}
|
}
|
||||||
|
// 齿槽转矩校准 (first_byte bit4) — DEBUG,平时不启用
|
||||||
|
#if FOC_DEBUG
|
||||||
|
if (first_byte >> 4 & 0x01) {
|
||||||
|
FOC.cogging_calib_request = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// 休眠
|
// 休眠
|
||||||
if (eigth_byte & 0x80 >> 7) {
|
if (eigth_byte & 0x80 >> 7) {
|
||||||
app_prepare_deep_sleep(true);
|
app_prepare_deep_sleep(true);
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
#include "adc.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
// TEST 调试宏定义
|
|
||||||
#if TEST_DEBUG
|
|
||||||
#define TEST_DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define TEST_DEBUG_PRINT(fmt, ...) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
constexpr int status_print = 0;
|
|
||||||
extern sampler sampler;
|
|
||||||
void test_1111() {
|
|
||||||
// 初始化 CAN 回环测试
|
|
||||||
// can_loopback_init();
|
|
||||||
// can_config();
|
|
||||||
if (status_print) {
|
|
||||||
/* value print */
|
|
||||||
TEST_DEBUG_PRINT(" the temperature data is %2.2f degrees Celsius\r\n",
|
|
||||||
sampler.get_mcu_temp());
|
|
||||||
TEST_DEBUG_PRINT(" the drv_temperature data is %2.2f degrees Celsius\r\n",
|
|
||||||
sampler.get_drv_temp());
|
|
||||||
TEST_DEBUG_PRINT(" the U current data is %2.2f mA\r\n", sampler.get_current('U'));
|
|
||||||
TEST_DEBUG_PRINT(" the V current data is %2.2f mA\r\n", sampler.get_current('V'));
|
|
||||||
TEST_DEBUG_PRINT(" the W current data is %2.2f mA\r\n", sampler.get_current('W'));
|
|
||||||
TEST_DEBUG_PRINT(" the VBUS is %2.2f V\r\n", sampler.get_vbus_voltage());
|
|
||||||
// TEST_DEBUG_PRINT(" the angle is %2.2f\r\n", tle5012b_read());
|
|
||||||
|
|
||||||
TEST_DEBUG_PRINT("\n----------------------------------------------------\n");
|
|
||||||
}
|
|
||||||
// can_loopback_test();
|
|
||||||
}
|
|
||||||
@@ -99,6 +99,7 @@ u8 hardware_init(void) {
|
|||||||
void do_task(u32 currentTasks) {
|
void do_task(u32 currentTasks) {
|
||||||
busy_task_enter(); // DWT: 记录忙碌起始周期
|
busy_task_enter(); // DWT: 记录忙碌起始周期
|
||||||
cnt_test++;
|
cnt_test++;
|
||||||
|
|
||||||
// 按照优先级和重要性处理任务
|
// 按照优先级和重要性处理任务
|
||||||
if (currentTasks & (1 << TASK_CURRENT_UPDATE)) { // 更新电流采样值
|
if (currentTasks & (1 << TASK_CURRENT_UPDATE)) { // 更新电流采样值
|
||||||
sampler.update_current();
|
sampler.update_current();
|
||||||
@@ -147,6 +148,12 @@ void do_task(u32 currentTasks) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 齿槽转矩校准 tick(DEBUG,平时不启用)
|
||||||
|
#if FOC_DEBUG
|
||||||
|
FOC.calibrate_cogging_tick();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (currentTasks & (1 << TASK_MCU_TEMP_UPDATE)) { // 更新 mcu 温度传感器值
|
if (currentTasks & (1 << TASK_MCU_TEMP_UPDATE)) { // 更新 mcu 温度传感器值
|
||||||
sampler.update_mcu_temp();
|
sampler.update_mcu_temp();
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-8
@@ -6,18 +6,18 @@
|
|||||||
// 如果使用 CMSIS DSP 库,需要定义 ARM_MATH_CM4
|
// 如果使用 CMSIS DSP 库,需要定义 ARM_MATH_CM4
|
||||||
#define ARM_MATH_CM4
|
#define ARM_MATH_CM4
|
||||||
|
|
||||||
#define EEP_DEBUG 1
|
#define EEP_DEBUG 0
|
||||||
#define OTA_DEBUG 1
|
#define OTA_DEBUG 0
|
||||||
#define SLEEP_DEBUG 1
|
#define SLEEP_DEBUG 0
|
||||||
#define ANG_SENS_DEBUG 1
|
#define ANG_SENS_DEBUG 0
|
||||||
#define CAN_DEBUG 1
|
#define CAN_DEBUG 0
|
||||||
#define MAIN_DEBUG 1
|
#define MAIN_DEBUG 0
|
||||||
#define TEST_DEBUG 1
|
#define FOC_DEBUG 0
|
||||||
|
|
||||||
// 版本号定义 - 可根据实际项目进行调整
|
// 版本号定义 - 可根据实际项目进行调整
|
||||||
constexpr u16 SOFTWARE_VERSION_MAJOR = 26;
|
constexpr u16 SOFTWARE_VERSION_MAJOR = 26;
|
||||||
constexpr u16 SOFTWARE_VERSION_MINOR = 5;
|
constexpr u16 SOFTWARE_VERSION_MINOR = 5;
|
||||||
constexpr u16 SOFTWARE_VERSION_PATCH = 17;
|
constexpr u16 SOFTWARE_VERSION_PATCH = 19;
|
||||||
constexpr u16 SOFTWARE_VERSION_BUILD = 2;
|
constexpr u16 SOFTWARE_VERSION_BUILD = 2;
|
||||||
|
|
||||||
constexpr u16 HARDWARE_VERSION_MAJOR = 25;
|
constexpr u16 HARDWARE_VERSION_MAJOR = 25;
|
||||||
@@ -232,6 +232,10 @@ constexpr int TIMER1_DEFAULT_PULSE = 0;
|
|||||||
constexpr int TIMER1_CH3_COMPARE_VALUE =
|
constexpr int TIMER1_CH3_COMPARE_VALUE =
|
||||||
(TIMER1_PERIOD + 1) * 0.41 - 1; // PWM 周期 41% 位置触发ADC采样
|
(TIMER1_PERIOD + 1) * 0.41 - 1; // PWM 周期 41% 位置触发ADC采样
|
||||||
|
|
||||||
|
// 齿槽转矩补偿
|
||||||
|
constexpr u16 COGGING_TABLE_SIZE = 128; // 每电周期采样点数
|
||||||
|
constexpr float COGGING_COMP_SCALE = 0.005f; // 补偿换算系数 V/mA,40mA × 0.005 = 0.2V
|
||||||
|
|
||||||
// 电压检测参数(基于跌幅检测,不依赖固定额定电压)
|
// 电压检测参数(基于跌幅检测,不依赖固定额定电压)
|
||||||
// 快速检测层(fast_voltage_check,100us周期):
|
// 快速检测层(fast_voltage_check,100us周期):
|
||||||
// - 使用峰值检测算法跟踪当前额定电压(vbus_reference)
|
// - 使用峰值检测算法跟踪当前额定电压(vbus_reference)
|
||||||
|
|||||||
Reference in New Issue
Block a user