@@ -32,233 +32,6 @@ extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern CurrentKalman Current_kalman ;
extern FlashEEPROM flashEEP ;
// 齿槽转矩补偿:查表 + 线性插值
// 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 ;
// angle_el 已由调用方归一化到 [0, 360),无需重复
float angle = angle_el ;
// 线性插值查表
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
// 齿槽转矩校准参数
constexpr u32 COG_CALIB_SETTLE_TICKS = 16000 ; // 800ms / 50us
constexpr u32 COG_CALIB_STOP_TICKS = 10000 ; // 500ms / 50us
constexpr u32 COG_CALIB_TARGET_SAMPLES = 3 * COGGING_TABLE_SIZE * 8 ;
constexpr float COG_CALIB_SLOW_VEL = 1.0f ; // 开环速度 rad/s
constexpr u32 COG_CALIB_SAMPLE_DIV = 20 ; // 1ms / 50us
constexpr u8 COG_CALIB_TOTAL_RUNS = 6 ; // 3正+3反
// 齿槽转矩校准静态数据
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次,分开存储补偿表。
*/
void FOC_Controller : : calibrate_cogging_tick ( void ) {
// 入口只做状态派发,避免单函数堆叠所有校准分支。
switch ( cog_calib_state ) {
case CogCalibState : : IDLE :
start_cogging_calibration ( ) ;
return ;
case CogCalibState : : SETTLING :
cogging_settling_tick ( ) ;
return ;
case CogCalibState : : SAMPLING :
cogging_sampling_tick ( ) ;
return ;
case CogCalibState : : STOPPING :
cogging_stopping_tick ( ) ;
return ;
case CogCalibState : : DONE :
cogging_done_tick ( ) ;
return ;
default :
// 防御性处理:枚举值异常时回到空闲态,避免状态机卡死。
cog_calib_state = CogCalibState : : IDLE ;
return ;
}
}
void FOC_Controller : : start_cogging_calibration ( void ) {
// 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 = COG_CALIB_SLOW_VEL ;
cog_calib_settle_tick = 0 ;
cog_calib_state = CogCalibState : : SETTLING ;
}
void FOC_Controller : : cogging_settling_tick ( void ) {
// 给低速开环运行留出稳定时间,再开始采样。
cog_calib_settle_tick + + ;
if ( cog_calib_settle_tick < COG_CALIB_SETTLE_TICKS ) return ;
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 ) ) ;
}
void FOC_Controller : : cogging_sampling_tick ( void ) {
static u32 sample_div = 0 ;
// 每 1ms 采一次,降低校准数据相关处理对实时控制的影响。
sample_div + + ;
if ( sample_div < COG_CALIB_SAMPLE_DIV ) return ;
sample_div = 0 ;
float real_angle = KTH7823 . getcurrent_sensorangle ( ) ;
float angle_el = normalizeAngle360 ( real_angle * PP + KTH7823 . calibration_angle ) ;
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 > = COG_CALIB_TARGET_SAMPLES ) {
target_velocity = 0 ;
cog_calib_state = CogCalibState : : STOPPING ;
cog_calib_stop_tick = 0 ;
}
}
void FOC_Controller : : cogging_stopping_tick ( void ) {
// 每轮采样结束后先停稳,再计算本轮去直流数据。
cog_calib_stop_tick + + ;
if ( cog_calib_stop_tick < COG_CALIB_STOP_TICKS ) return ;
float dc = process_cogging_run_data ( ) ;
printf ( " [COG] Run %d/%d done. DC=%.2f mA \r \n " ,
cog_calib_run + 1 , COG_CALIB_TOTAL_RUNS , dc ) ;
cog_calib_run + + ;
if ( cog_calib_run < COG_CALIB_TOTAL_RUNS ) {
start_next_cogging_run ( ) ;
} else {
cog_calib_state = CogCalibState : : DONE ;
}
}
float FOC_Controller : : process_cogging_run_data ( void ) {
// 先求每个角度桶的平均电流,再统一去除直流偏置。
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 ;
}
return dc ;
}
void FOC_Controller : : start_next_cogging_run ( void ) {
control_mode = 6 ;
target_velocity = ( cog_calib_run < 3 ) ? COG_CALIB_SLOW_VEL : - COG_CALIB_SLOW_VEL ;
cog_calib_state = CogCalibState : : SETTLING ;
cog_calib_settle_tick = 0 ;
}
void FOC_Controller : : cogging_done_tick ( void ) {
// 生成最终表后恢复用户进入校准前的控制模式和目标速度。
build_cogging_tables ( ) ;
cogging_comp_enabled = true ;
control_mode = cog_calib_saved_mode ;
target_velocity = cog_calib_saved_vel ;
print_cogging_table ( " \r \n [COG] === FWD Average === \r \n " , cogging_table ) ;
print_cogging_table ( " \r \n [COG] === REV Average === \r \n " , cogging_table_rev ) ;
print_cogging_c_array ( " \r \n [COG] --- FWD C Array --- \r \n " ,
" COGGING_TABLE_FWD " , cogging_table ) ;
print_cogging_c_array ( " \r \n [COG] --- REV C Array --- \r \n " ,
" COGGING_TABLE_REV " , cogging_table_rev ) ;
printf ( " \r \n [COG] === Done. === \r \n " ) ;
cog_calib_state = CogCalibState : : IDLE ;
}
void FOC_Controller : : build_cogging_tables ( void ) {
// 前 3 轮为正转,后 3 轮为反转,分别求平均表。
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 ;
cogging_table_rev [ i ] = ( cog_calib_run_data [ 3 ] [ i ] +
cog_calib_run_data [ 4 ] [ i ] +
cog_calib_run_data [ 5 ] [ i ] ) / 3.0f ;
}
}
void FOC_Controller : : print_cogging_table ( const char * title , float * table ) {
printf ( " %s " , title ) ;
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 , table [ i ] ) ;
fwdgt_counter_reload ( ) ;
}
}
void FOC_Controller : : print_cogging_c_array ( const char * title ,
const char * arrayName ,
float * table ) {
printf ( " %s " , title ) ;
printf ( " static const float %s[COGGING_TABLE_SIZE] = { \r \n " , arrayName ) ;
for ( int i = 0 ; i < COGGING_TABLE_SIZE ; i + + ) {
if ( i % 8 = = 0 ) printf ( " " ) ;
printf ( " %.2ff " , 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 " ) ;
}
# endif // FOC_DEBUG
// 初始变量及函数定义
# define _constrain(amt, low, high) \
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
@@ -455,7 +228,7 @@ float FOC_Controller::get_mode3_velocity_scale(float target_vel,
* 后改为连续线性过渡):连续化后反转仍剧烈震荡,说明问题不在
* 台阶突跳,而在增益本身——×2 只对反转生效,把反转环路增益整体
* 翻倍而正转不变,正是"正转正常、反转震荡"的直接来源之一。
* 已移除。反转阻力差异由 REV 齿槽补偿表与 Uq 前馈学习承担;
* 已移除。反转阻力差异由 Uq 前馈学习承担;
* 若实测反转欠速/偏慢,优先增大前馈学习限幅,不要恢复非对称 P。
*/
float FOC_Controller : : get_mode3_velocity_p ( float target_vel , float actual_vel ) {
@@ -471,47 +244,6 @@ float FOC_Controller::get_mode3_velocity_p(float target_vel, float actual_vel) {
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 ;
// limit_voltage 从 Flash/CAN 恢复,可能为 0:分母下限保护,防止 P=inf
const float denom = ( limit_voltage > MIN_LIMIT_VOLTAGE )
? limit_voltage
@@ -820,9 +552,9 @@ float FOC_Controller::velocity_open_loop() {
// 通过时间间隔和目标速度计算需要转动的机械角度,存储在 shaft_angle 中
shaft_angle =
normalizeAngle360 ( shaft_angle + target_velocity * REDUCTION_RATIO / MOTOR_FREQUENCY ) ;
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
float angle_el_cog = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el_cog ) ;
// 电气角度(算一次,供 cal_Iq_Id / setSVPWM 共用)
float angle_el = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el ) ;
rt_current = cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
sampler . get_current ( ' W ' ) ) ;
@@ -842,7 +574,7 @@ float FOC_Controller::velocity_open_loop() {
}
Uq = ( Uq < 0.0f ) ? - Uq_mag : Uq_mag ;
}
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
return limit_voltage ;
}
@@ -859,13 +591,13 @@ 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 ) ;
update_el_sincos ( angle_el_cog ) ;
// 电气角度(算一次,供 cal_Iq_Id / setSVPWM 共用)
float angle_el = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el ) ;
rt_current = cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
sampler . get_current ( ' W ' ) ) ;
// 设置相电压
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
return shaft_angle ;
}
@@ -917,11 +649,11 @@ float FOC_Controller::velocity_control() {
}
CAN0_transmiter . testfloat_union . f = Uq ;
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
float angle_el_cog = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el_cog ) ;
// 电气角度(算一次,供 cal_Iq_Id / setSVPWM 共用)
float angle_el = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el ) ;
// 设置相电压
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
rt_current = cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
sampler . get_current ( ' W ' ) ) ;
@@ -936,9 +668,9 @@ 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 ) ;
update_el_sincos ( angle_el_cog ) ;
// 电气角度(算一次,供 cal_Iq_Id / setSVPWM 共用)
float angle_el = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el ) ;
// PID 控制计算
float Iq = rt_current =
cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
@@ -951,7 +683,7 @@ float FOC_Controller::current_control() {
Uq = - limit_voltage ;
}
// 设置相电压
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
return 1 ;
}
@@ -1008,14 +740,14 @@ float FOC_Controller::angle_control_with_velocity_limit() {
}
CAN0_transmiter . testfloat_union . f = shaft_angle ;
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
float angle_el_cog = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el_cog ) ;
// 电气角度(算一次,供 cal_Iq_Id / setSVPWM 共用)
float angle_el = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el ) ;
// 获取当前实际电流值
rt_current = cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
sampler . get_current ( ' W ' ) ) ;
// 设置相电压
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
return shaft_angle ;
}
@@ -1050,9 +782,9 @@ float FOC_Controller::MIT_Mode() {
// 获取电机轴角度
shaft_angle = KTH7823 . getcurrent_sensorangle ( ) ;
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
float angle_el_cog = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el_cog ) ;
// 电气角度(算一次,供 cal_Iq_Id / setSVPWM 共用)
float angle_el = normalizeAngle360 ( shaft_angle * PP + KTH7823 . calibration_angle ) ;
update_el_sincos ( angle_el ) ;
// 第三层:电流环(内环)
rt_current = cal_Iq_Id ( sampler . get_current ( ' U ' ) , sampler . get_current ( ' V ' ) ,
@@ -1063,7 +795,7 @@ float FOC_Controller::MIT_Mode() {
float Uq = current_inMITloop ( current_error , rt_current ) ;
// 设置相电压
setSVPWM_PhaseVoltage ( Uq + get_cogging_compensation ( angle_el_cog ) , 0.0f ) ;
setSVPWM_PhaseVoltage ( Uq , 0.0f ) ;
return shaft_angle ;
}