@@ -7,8 +7,11 @@
# include "config.h"
# include "motor.h"
# include "pid.h"
# include "systick.h"
# include <arm_math.h>
# include <cmath>
# include <cstdio>
# include <cstring>
# include <gd32c10x.h>
FOC_Controller FOC ; // FOC控制初始化
@@ -19,6 +22,207 @@ extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern CurrentKalman Current_kalman ;
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) \
((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 ( ) {
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_MIT_p = DEFAULT_current_MIT_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 ( ) { ; }
// /**
// * @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算法设置电机输出
*
@@ -418,7 +619,9 @@ float FOC_Controller::velocity_open_loop() {
// 因为在开环控制中,Ud 始终为 0,只控制 Uq
const float Uq = _constrain ( target_velocity * REDUCTION_RATIO * 0.005f ,
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 ;
}
@@ -436,8 +639,10 @@ float FOC_Controller::angle_control() {
shaft_angle = KTH7823 . getcurrent_sensorangle ( ) ;
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 ) ;
// 设置相电压
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
return shaft_angle ;
}
@@ -465,8 +670,10 @@ float FOC_Controller::velocity_control() {
// 获取电机轴角度
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 ' ) ,
sampler . get_current ( ' W ' ) ) ;
@@ -487,8 +694,10 @@ float FOC_Controller::current_control() {
// 获取电机轴角度
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 , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
return 1 ;
}
@@ -529,25 +738,17 @@ float FOC_Controller::angle_control_with_velocity_limit() {
last_velocity_error = velocity_error ;
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 ( ) ;
CAN0_transmiter . testfloat_union . f = shaft_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 ) ;
// 设置相电压
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
return shaft_angle ;
}
@@ -561,14 +762,12 @@ float FOC_Controller::angle_control_with_velocity_limit() {
*/
float FOC_Controller : : MIT_Mode ( ) {
// 第一层:角度环(外环)
// 根据目标角度和实际角度的差值,通过角度环PID控制器计算目标速度
float angle_error = target_angle - rt_angle ;
ang_inMITloop . set_P ( ang_MIT_p ) ;
float target_velocity =
ang_inMITloop ( angle_error ) ; // 使用angle_loop作为角度到速度的映射
ang_inMITloop ( angle_error ) ;
// 第二层:速度环(中环)
// 根据目标速度和实际速度的差值,通过速度环PID控制器计算目标电流
float velocity_error = ( target_velocity - rt_velocity ) * DIR ;
// 目标速度变化检测:target 大幅变化时清积分
@@ -582,11 +781,9 @@ float FOC_Controller::MIT_Mode() {
float target_current = vel_inMITloop ( velocity_error ) ;
// 第三层:电流环(内环)
// 计算当前实际电流
rt_current = cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
sampler . get_current ( ' W ' ) ) ;
// 通过电流环PID控制器计算输出电压
float current_error = target_current - rt_current ;
current_inMITloop . set_P ( cur_MIT_p ) ;
float Uq = current_inMITloop ( current_error ) ;
@@ -594,8 +791,10 @@ float FOC_Controller::MIT_Mode() {
// 获取电机轴角度
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 ;
}