feat(FOC): 添加角度同步Uq前馈补偿和速度环优化
- 实现update_angle_sync_uq_feedforward函数,支持mode2和mode3的角度同步 Uq前馈补偿,按物理360°查表学习负载/阻力差异 - 实现get_mode3_velocity_p函数,mode3低速时降低速度环P参数减少抖动 - 在velocity_control和angle_control_with_velocity_limit中集成Uq前馈补偿 - 优化normalizeAngle360函数,大角度时先扣整圈数避免while循环过多 - 调整配置参数,降低DEFAULT_vel_loop_p并添加详细的Uq前馈补偿配置 - 更新电源电压参数使用本周期采样值,避免电压滞后影响
This commit is contained in:
+129
-25
@@ -334,6 +334,107 @@ inline float FOC_Controller::cal_Iq_Id(float current_a, float current_b,
|
|||||||
// return I_q * 1000 - KE_FACTOR * rt_velocity;
|
// return I_q * 1000 - KE_FACTOR * rt_velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 角度同步 Uq 前馈更新/输出。
|
||||||
|
* @note 只在稳定同向巡航时输出和学习;停止、低速、反向、明显刹车/超速时立即退出。
|
||||||
|
*/
|
||||||
|
float FOC_Controller::update_angle_sync_uq_feedforward(
|
||||||
|
u8 mode, float table[], u16 table_size, float mech_angle,
|
||||||
|
float target_vel, float actual_vel, float velocity_error) {
|
||||||
|
if (table_size == 0U) return 0.0f;
|
||||||
|
|
||||||
|
bool enable = false;
|
||||||
|
bool learn_enable = false;
|
||||||
|
float min_target = 0.0f;
|
||||||
|
float stop_speed = 0.0f;
|
||||||
|
float brake_err = 0.0f;
|
||||||
|
float learn_alpha = 0.0f;
|
||||||
|
float gain = 0.0f;
|
||||||
|
float max_ff = 0.0f;
|
||||||
|
float dir_sign = 1.0f;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 2:
|
||||||
|
enable = MODE2_UQ_FF_ENABLE;
|
||||||
|
learn_enable = MODE2_UQ_FF_LEARN_ENABLE;
|
||||||
|
min_target = MODE2_UQ_FF_MIN_TARGET;
|
||||||
|
stop_speed = MODE2_UQ_FF_STOP_SPEED;
|
||||||
|
brake_err = MODE2_UQ_FF_BRAKE_ERR;
|
||||||
|
learn_alpha = MODE2_UQ_FF_LEARN_ALPHA;
|
||||||
|
gain = MODE2_UQ_FF_GAIN;
|
||||||
|
max_ff = MODE2_UQ_FF_MAX;
|
||||||
|
dir_sign = 1.0f;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
enable = MODE3_UQ_FF_ENABLE;
|
||||||
|
learn_enable = MODE3_UQ_FF_LEARN_ENABLE;
|
||||||
|
min_target = MODE3_UQ_FF_MIN_TARGET;
|
||||||
|
stop_speed = MODE3_UQ_FF_STOP_SPEED;
|
||||||
|
brake_err = MODE3_UQ_FF_BRAKE_ERR;
|
||||||
|
learn_alpha = MODE3_UQ_FF_LEARN_ALPHA;
|
||||||
|
gain = MODE3_UQ_FF_GAIN;
|
||||||
|
max_ff = MODE3_UQ_FF_MAX;
|
||||||
|
dir_sign = DIR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool active = (fabsf(target_vel) > stop_speed) &&
|
||||||
|
(fabsf(actual_vel) > stop_speed) &&
|
||||||
|
((target_vel * actual_vel) > 0.0f) &&
|
||||||
|
((velocity_error * dir_sign) > -brake_err);
|
||||||
|
|
||||||
|
float angle = normalizeAngle360(mech_angle);
|
||||||
|
float index_f = angle / 360.0f * (float)table_size;
|
||||||
|
u16 idx0 = (u16)index_f;
|
||||||
|
if (idx0 >= table_size) idx0 = table_size - 1U;
|
||||||
|
u16 idx1 = (idx0 + 1U) % table_size;
|
||||||
|
float frac = index_f - (float)idx0;
|
||||||
|
|
||||||
|
float ff = table[idx0] * (1.0f - frac) + table[idx1] * frac;
|
||||||
|
if (ff > max_ff) ff = max_ff;
|
||||||
|
else if (ff < -max_ff) ff = -max_ff;
|
||||||
|
|
||||||
|
if (learn_enable && active && fabsf(target_vel) > min_target) {
|
||||||
|
float ff_target = velocity_error * dir_sign * gain;
|
||||||
|
if (ff_target > max_ff) ff_target = max_ff;
|
||||||
|
else if (ff_target < -max_ff) ff_target = -max_ff;
|
||||||
|
table[idx0] += learn_alpha * (ff_target - table[idx0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (enable && active && fabsf(target_vel) > min_target) ? ff : 0.0f;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief mode3 低速/静止附近降低速度内环 P,运行速度升高后平滑恢复。
|
||||||
|
*/
|
||||||
|
float FOC_Controller::get_mode3_velocity_p(float target_vel, float actual_vel) {
|
||||||
|
float vel_p = vel_angloop_p;
|
||||||
|
if (target_vel < -120.0f) {
|
||||||
|
vel_p = vel_angloop_p * 2.0f;
|
||||||
|
} else if (target_vel < -30.0f) {
|
||||||
|
vel_p = vel_angloop_p * 1.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MODE3_LOW_SPEED_P_SCALE_ENABLE) {
|
||||||
|
float abs_target = fabsf(target_vel);
|
||||||
|
float abs_speed = fabsf(actual_vel);
|
||||||
|
float speed_ref = (abs_target > abs_speed) ? abs_target : abs_speed;
|
||||||
|
float p_scale = 1.0f;
|
||||||
|
if (speed_ref <= MODE3_LOW_SPEED_P_LOW) {
|
||||||
|
p_scale = MODE3_LOW_SPEED_P_MIN_SCALE;
|
||||||
|
} else if (speed_ref < MODE3_LOW_SPEED_P_FULL) {
|
||||||
|
p_scale = MODE3_LOW_SPEED_P_MIN_SCALE +
|
||||||
|
(1.0f - MODE3_LOW_SPEED_P_MIN_SCALE) *
|
||||||
|
(speed_ref - MODE3_LOW_SPEED_P_LOW) /
|
||||||
|
(MODE3_LOW_SPEED_P_FULL - MODE3_LOW_SPEED_P_LOW);
|
||||||
|
}
|
||||||
|
vel_p *= p_scale;
|
||||||
|
}
|
||||||
|
return vel_p;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 电机控制类初始化函数
|
* @brief 电机控制类初始化函数
|
||||||
*
|
*
|
||||||
@@ -711,23 +812,27 @@ float FOC_Controller::angle_control() {
|
|||||||
* @return float: 当前速度
|
* @return float: 当前速度
|
||||||
*/
|
*/
|
||||||
float FOC_Controller::velocity_control() {
|
float FOC_Controller::velocity_control() {
|
||||||
// 速度误差计算
|
// 获取电机轴角度:mode2 Uq 前馈补偿需要用物理 360° 角度查表。
|
||||||
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
|
|
||||||
|
// mode2 速度环:真实速度波动保留在反馈里,PID 继续看真实 rt_velocity。
|
||||||
float velocity_error = (target_velocity - rt_velocity) * DIR * REDUCTION_RATIO;
|
float velocity_error = (target_velocity - rt_velocity) * DIR * REDUCTION_RATIO;
|
||||||
|
|
||||||
// 目标速度突变检测:target 大幅变化时清积分
|
// mode2 使用独立速度环参数。
|
||||||
static float last_target_vel = 0.0f;
|
vel_loop.set_PID(vel_loop_p, vel_loop_Ki, vel_loop_Kd);
|
||||||
const float target_delta = target_velocity - last_target_vel;
|
vel_loop.set_limit(limit_voltage);
|
||||||
if (fabsf(target_delta) > 5.0f) {
|
float Uq_pid = vel_loop(velocity_error);
|
||||||
vel_loop.reset_integral();
|
|
||||||
}
|
|
||||||
last_target_vel = target_velocity;
|
|
||||||
|
|
||||||
// PID 控制计算
|
static float uq_ff_table[MODE2_UQ_FF_TABLE_SIZE] = {0.0f};
|
||||||
float Uq = vel_loop(velocity_error);
|
float Uq_ff = update_angle_sync_uq_feedforward(
|
||||||
|
2, uq_ff_table, MODE2_UQ_FF_TABLE_SIZE, shaft_angle,
|
||||||
|
target_velocity, rt_velocity, velocity_error);
|
||||||
|
|
||||||
|
float Uq = Uq_pid + Uq_ff;
|
||||||
|
if (Uq > limit_voltage) Uq = limit_voltage;
|
||||||
|
else if (Uq < -limit_voltage) Uq = -limit_voltage;
|
||||||
CAN0_transmiter.testfloat_union.f = Uq;
|
CAN0_transmiter.testfloat_union.f = Uq;
|
||||||
|
|
||||||
// 获取电机轴角度
|
|
||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
|
||||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||||
// 设置相电压
|
// 设置相电压
|
||||||
@@ -779,14 +884,7 @@ float FOC_Controller::angle_control_with_velocity_limit() {
|
|||||||
float target_velocity = ang_inVelAngloop(angle_error);
|
float target_velocity = ang_inVelAngloop(angle_error);
|
||||||
|
|
||||||
// 使用速度PID控制器计算最终输出电压
|
// 使用速度PID控制器计算最终输出电压
|
||||||
// 根据目标速度大小,选择不同的PID参数
|
vel_inVelAngloop.set_P(get_mode3_velocity_p(target_velocity, rt_velocity));
|
||||||
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;
|
float velocity_error = target_velocity - rt_velocity;
|
||||||
|
|
||||||
// 目标速度突变检测:target 大幅变化时清积分
|
// 目标速度突变检测:target 大幅变化时清积分
|
||||||
@@ -796,14 +894,20 @@ float FOC_Controller::angle_control_with_velocity_limit() {
|
|||||||
}
|
}
|
||||||
last_vang_target_vel = target_velocity;
|
last_vang_target_vel = target_velocity;
|
||||||
|
|
||||||
static float last_velocity_error = 0.0f;
|
float Uq_pid = vel_inVelAngloop(velocity_error) * DIR;
|
||||||
last_velocity_error = velocity_error;
|
|
||||||
|
|
||||||
float Uq = vel_inVelAngloop(velocity_error)* DIR;
|
// 获取电机轴角度:mode3 Uq 前馈补偿按物理 360° 查表。
|
||||||
|
|
||||||
// 获取电机轴角度
|
|
||||||
shaft_angle = KTH7823.getcurrent_sensorangle();
|
shaft_angle = KTH7823.getcurrent_sensorangle();
|
||||||
|
static float mode3_uq_ff_table[MODE3_UQ_FF_TABLE_SIZE] = {0.0f};
|
||||||
|
float Uq_ff = update_angle_sync_uq_feedforward(
|
||||||
|
3, mode3_uq_ff_table, MODE3_UQ_FF_TABLE_SIZE, shaft_angle,
|
||||||
|
target_velocity, rt_velocity, velocity_error);
|
||||||
|
|
||||||
|
float Uq = Uq_pid + Uq_ff;
|
||||||
|
if (Uq > limit_voltage) Uq = limit_voltage;
|
||||||
|
else if (Uq < -limit_voltage) Uq = -limit_voltage;
|
||||||
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
CAN0_transmiter.testfloat_union.f = shaft_angle;
|
||||||
|
|
||||||
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
// 电气角度(算一次,供 cal_Iq_Id / 齿槽补偿 / setSVPWM 共用)
|
||||||
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
float angle_el_cog = normalizeAngle360(shaft_angle * PP + KTH7823.calibration_angle);
|
||||||
// 获取当前实际电流值
|
// 获取当前实际电流值
|
||||||
|
|||||||
@@ -310,6 +310,11 @@ class FOC_Controller {
|
|||||||
* @return float 返回值
|
* @return float 返回值
|
||||||
*/
|
*/
|
||||||
float cal_Iq_Id(float current_a, float current_b, float current_c, float angle_el);
|
float cal_Iq_Id(float current_a, float current_b, float current_c, float angle_el);
|
||||||
|
float update_angle_sync_uq_feedforward(u8 mode, float table[],
|
||||||
|
u16 table_size, float mech_angle,
|
||||||
|
float target_vel, float actual_vel,
|
||||||
|
float velocity_error);
|
||||||
|
float get_mode3_velocity_p(float target_vel, float actual_vel);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义函数指针类型
|
// 定义函数指针类型
|
||||||
|
|||||||
@@ -96,10 +96,14 @@ class angle_sensor {
|
|||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief 快速角度归一化到 [0, 360)
|
* @brief 快速角度归一化到 [0, 360)
|
||||||
* 用 while 减法替代 fmodf,在角度变化量很小时(电机控制场景)
|
* 小角度保留 while 快路径;大角度先一次性扣掉整圈数,避免累计角很大时 while 循环过多。
|
||||||
* 通常只需 0~1 次减法,远快于 fmodf 的 ~30-50 周期开销。
|
* 不依赖 fmodf,减少嵌入式数学库开销和链接风险。
|
||||||
*/
|
*/
|
||||||
inline float normalizeAngle360(float angle) {
|
inline float normalizeAngle360(float angle) {
|
||||||
|
if (angle >= 720.0f || angle <= -360.0f) {
|
||||||
|
int turns = (int)(angle / 360.0f);
|
||||||
|
angle -= (float)turns * 360.0f;
|
||||||
|
}
|
||||||
while (angle >= 360.0f) angle -= 360.0f;
|
while (angle >= 360.0f) angle -= 360.0f;
|
||||||
while (angle < 0.0f) angle += 360.0f;
|
while (angle < 0.0f) angle += 360.0f;
|
||||||
return angle;
|
return angle;
|
||||||
|
|||||||
+30
-1
@@ -126,16 +126,45 @@ constexpr float DEFAULT_current_loop_p = 0.1f / 100 * 12; // 电流 P
|
|||||||
constexpr float current_loop_Ki = 0.55f; // 电流 P
|
constexpr float current_loop_Ki = 0.55f; // 电流 P
|
||||||
constexpr float current_loop_Kd = 3e-4f; // 电流 P
|
constexpr float current_loop_Kd = 3e-4f; // 电流 P
|
||||||
|
|
||||||
constexpr float DEFAULT_vel_loop_p = 0.018f / 100 * 12; // 速度 P
|
constexpr float DEFAULT_vel_loop_p = 0.005f / 100 * 12; // 速度 P
|
||||||
constexpr float vel_loop_Ku = 3.600000e-03 * 0.7 * 100 / 12;
|
constexpr float vel_loop_Ku = 3.600000e-03 * 0.7 * 100 / 12;
|
||||||
constexpr float vel_loop_Tu = 17.0f * 1e-3f;
|
constexpr float vel_loop_Tu = 17.0f * 1e-3f;
|
||||||
constexpr float vel_loop_Ki = 1.2 * vel_loop_Ku / vel_loop_Tu;
|
constexpr float vel_loop_Ki = 1.2 * vel_loop_Ku / vel_loop_Tu;
|
||||||
constexpr float vel_loop_Kd = 0.075 * vel_loop_Ku * vel_loop_Tu * 2;
|
constexpr float vel_loop_Kd = 0.075 * vel_loop_Ku * vel_loop_Tu * 2;
|
||||||
|
|
||||||
|
// mode2 角度同步 Uq 前馈补偿:固定 Uq 下的真实速度波动不应从反馈中滤掉,
|
||||||
|
// 而应按物理 360° 提前补偿负载/阻力差异,降低速度 PID 的周期性纠偏量。
|
||||||
|
constexpr bool MODE2_UQ_FF_ENABLE = true;
|
||||||
|
constexpr bool MODE2_UQ_FF_LEARN_ENABLE = true;
|
||||||
|
constexpr u16 MODE2_UQ_FF_TABLE_SIZE = 180;
|
||||||
|
constexpr float MODE2_UQ_FF_LEARN_ALPHA = 0.01f; // 越小越慢,避免误学瞬态
|
||||||
|
constexpr float MODE2_UQ_FF_MIN_TARGET = 1.5f; // 目标速度过低时不学习
|
||||||
|
constexpr float MODE2_UQ_FF_GAIN = 0.003f; // 速度误差(deg/s)到前馈电压(V)的学习比例
|
||||||
|
constexpr float MODE2_UQ_FF_MAX = 3.5f; // 前馈补偿电压限幅(V)
|
||||||
|
constexpr float MODE2_UQ_FF_STOP_SPEED = 2.0f; // 目标/实际速度低于该值时不输出前馈
|
||||||
|
constexpr float MODE2_UQ_FF_BRAKE_ERR = 3.0f; // 明显超速/刹车时不输出前馈,单位同 velocity_error
|
||||||
|
|
||||||
|
// mode3 角度同步 Uq 前馈补偿:单独建表,避免和 mode2 互相污染。
|
||||||
|
constexpr bool MODE3_UQ_FF_ENABLE = true;
|
||||||
|
constexpr bool MODE3_UQ_FF_LEARN_ENABLE = true;
|
||||||
|
constexpr u16 MODE3_UQ_FF_TABLE_SIZE = 180;
|
||||||
|
constexpr float MODE3_UQ_FF_LEARN_ALPHA = 0.01f;
|
||||||
|
constexpr float MODE3_UQ_FF_MIN_TARGET = 2.5f; // mode3 内部目标速度过低时不学习
|
||||||
|
constexpr float MODE3_UQ_FF_GAIN = 0.3f; // mode3 速度误差未乘减速比,故增益独立于 mode2
|
||||||
|
constexpr float MODE3_UQ_FF_MAX = 3.5f;
|
||||||
|
constexpr float MODE3_UQ_FF_STOP_SPEED = 2.0f; // mode3 内部目标/实际速度低于该值时不输出前馈
|
||||||
|
constexpr float MODE3_UQ_FF_BRAKE_ERR = 3.0f; // 明显超速/刹车时不输出前馈,单位同 velocity_error
|
||||||
|
|
||||||
constexpr float DEFAULT_vel_angloop_p = 0.4f / 100; // 速度 速度 - 角度 P
|
constexpr float DEFAULT_vel_angloop_p = 0.4f / 100; // 速度 速度 - 角度 P
|
||||||
constexpr float vel_angloop_Ki = 5.0f; // 速度 速度 - 角度 I
|
constexpr float vel_angloop_Ki = 5.0f; // 速度 速度 - 角度 I
|
||||||
constexpr float vel_angloop_Kd = 5e-05f; // 速度 速度 - 角度 D
|
constexpr float vel_angloop_Kd = 5e-05f; // 速度 速度 - 角度 D
|
||||||
|
|
||||||
|
// mode3 低速/静止附近速度 P 降低,减少速度反馈噪声、齿槽和摩擦导致的来回拉扯。
|
||||||
|
constexpr bool MODE3_LOW_SPEED_P_SCALE_ENABLE = true;
|
||||||
|
constexpr float MODE3_LOW_SPEED_P_MIN_SCALE = 0.2f;
|
||||||
|
constexpr float MODE3_LOW_SPEED_P_LOW = 1.0f;
|
||||||
|
constexpr float MODE3_LOW_SPEED_P_FULL = 5.0f;
|
||||||
|
|
||||||
constexpr float DEFAULT_angle_angloop_p =
|
constexpr float DEFAULT_angle_angloop_p =
|
||||||
150.0f / 100 * 12; // 角度 速度 - 角度 P
|
150.0f / 100 * 12; // 角度 速度 - 角度 P
|
||||||
constexpr float ang_angloop_Ki = 0.00f; // 角度 速度 - 角度 I
|
constexpr float ang_angloop_Ki = 0.00f; // 角度 速度 - 角度 I
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ void power_manage(void) {
|
|||||||
sampler.update_vbus_voltage();
|
sampler.update_vbus_voltage();
|
||||||
float vbus = sampler.get_vbus_voltage();
|
float vbus = sampler.get_vbus_voltage();
|
||||||
|
|
||||||
// 更新FOC的电源电压参数
|
// 更新FOC的电源电压参数:使用本周期刚采到的 vbus,避免上一拍电压滞后放大速度/电流耦合。
|
||||||
FOC.update_power(last_vbus_slow);
|
FOC.update_power(vbus);
|
||||||
last_vbus_slow = vbus;
|
last_vbus_slow = vbus;
|
||||||
|
|
||||||
// 如果快速检测已触发紧急关机,执行保存
|
// 如果快速检测已触发紧急关机,执行保存
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
# A solution is a collection of related projects that share same base configuration.
|
|
||||||
solution:
|
|
||||||
created-for: CMSIS-Toolbox@2.12.0
|
|
||||||
cdefault: # use CMSIS-Toolbox default Compiler options
|
|
||||||
|
|
||||||
# Compilers that can be selected
|
|
||||||
select-compiler:
|
|
||||||
- compiler: AC6
|
|
||||||
- compiler: GCC
|
|
||||||
- compiler: IAR
|
|
||||||
- compiler: CLANG
|
|
||||||
|
|
||||||
# List of miscellaneous tool-specific controls
|
|
||||||
misc:
|
|
||||||
- for-compiler: AC6 # GDB requires DWARF 5, remove when using uVision Debugger
|
|
||||||
C-CPP:
|
|
||||||
- -gdwarf-5
|
|
||||||
ASM:
|
|
||||||
- -gdwarf-5
|
|
||||||
|
|
||||||
# List the packs that define the device and/or board.
|
|
||||||
packs:
|
|
||||||
- pack: GigaDevice::GD32C10x_DFP
|
|
||||||
- pack: ARM::CMSIS
|
|
||||||
|
|
||||||
# List different hardware targets that are used to deploy the solution.
|
|
||||||
target-types:
|
|
||||||
- type: GD32C103CB
|
|
||||||
device: GD32C103CB
|
|
||||||
target-set:
|
|
||||||
- set:
|
|
||||||
images:
|
|
||||||
- project-context: Robot_V2.Release
|
|
||||||
debugger:
|
|
||||||
name: ST-Link@pyOCD
|
|
||||||
clock: 10000000
|
|
||||||
protocol: swd
|
|
||||||
|
|
||||||
# List of different build configurations.
|
|
||||||
build-types:
|
|
||||||
- type: Debug
|
|
||||||
debug: on
|
|
||||||
optimize: none
|
|
||||||
|
|
||||||
- type: Release
|
|
||||||
debug: off
|
|
||||||
optimize: balanced
|
|
||||||
|
|
||||||
# List related projects.
|
|
||||||
projects:
|
|
||||||
- project: Robot_V2/Robot_V2.cproject.yml
|
|
||||||
compiler: AC6
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file sys/initial.h
|
|
||||||
* @brief 系统服务与平台支持源文件
|
|
||||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INITIAL_H
|
|
||||||
#define _INITIAL_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "gd32c10x_eval.h"
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
// 任务标志定义
|
|
||||||
/**
|
|
||||||
* @brief 匿名枚举 枚举定义
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
TASK_MOTOR_CONTROL = 0,
|
|
||||||
TASK_CURRENT_UPDATE,
|
|
||||||
TASK_VELOCITY_UPDATE,
|
|
||||||
TASK_ANGLE_UPDATE,
|
|
||||||
TASK_MCU_TEMP_UPDATE,
|
|
||||||
TASK_DRV_TEMP_UPDATE,
|
|
||||||
TASK_VBUS_UPDATE,
|
|
||||||
TASK_THERMAL_CONTROL,
|
|
||||||
TASK_CAN_TRANSMIT,
|
|
||||||
TASK_MAGNETIC_CHECK,
|
|
||||||
TASK_COUNT
|
|
||||||
} SystemTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief rcu_config 函数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void rcu_config(void);
|
|
||||||
static volatile uint32_t timer_delay_count = 0; // volatile 很重要!
|
|
||||||
/**
|
|
||||||
* @brief fputc 函数
|
|
||||||
* @param[in] ch 参数
|
|
||||||
* @param[in] f 参数
|
|
||||||
* @return int 返回值
|
|
||||||
*/
|
|
||||||
int fputc(int ch, FILE *f); // 声明fputc函数以重载标准库实现
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化 USART0 调试串口
|
|
||||||
* @return u8 返回值
|
|
||||||
*/
|
|
||||||
u8 USART0_init(void);
|
|
||||||
/**
|
|
||||||
* @brief 初始化独立看门狗
|
|
||||||
* @param[in] time 参数
|
|
||||||
* @return u8 返回值
|
|
||||||
*/
|
|
||||||
u8 watchdog_init(u32 time);
|
|
||||||
/**
|
|
||||||
* @brief 获取复位原因
|
|
||||||
* @return u16 返回值
|
|
||||||
*/
|
|
||||||
u16 get_reset_cause(void);
|
|
||||||
/**
|
|
||||||
* @brief 初始化未使用引脚状态
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void unused_pin_init();
|
|
||||||
/**
|
|
||||||
* @brief 初始化 OTA 与 A/B 分区状态
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void OTA_initial(void);
|
|
||||||
|
|
||||||
// 任务管理结构
|
|
||||||
typedef struct {
|
|
||||||
volatile u32 taskFlags; // 任务标志位(每个位代表一个任务)
|
|
||||||
} TaskScheduler;
|
|
||||||
|
|
||||||
// 版本管理类
|
|
||||||
/**
|
|
||||||
* @brief VersionManager 类或结构体
|
|
||||||
*/
|
|
||||||
class VersionManager {
|
|
||||||
public:
|
|
||||||
// 版本信息结构体
|
|
||||||
typedef struct {
|
|
||||||
u16 major;
|
|
||||||
u16 minor;
|
|
||||||
u16 patch;
|
|
||||||
u16 build;
|
|
||||||
} VersionInfo;
|
|
||||||
|
|
||||||
// 构造函数
|
|
||||||
VersionManager();
|
|
||||||
|
|
||||||
// 获取软件版本
|
|
||||||
/**
|
|
||||||
* @brief 获取 getSoftwareVersion 对应的数据或状态
|
|
||||||
* @return VersionInfo 返回值
|
|
||||||
*/
|
|
||||||
VersionInfo getSoftwareVersion() const;
|
|
||||||
|
|
||||||
// 获取硬件版本
|
|
||||||
/**
|
|
||||||
* @brief 获取 getHardwareVersion 对应的数据或状态
|
|
||||||
* @return VersionInfo 返回值
|
|
||||||
*/
|
|
||||||
VersionInfo getHardwareVersion() const;
|
|
||||||
|
|
||||||
// 获取BOOT版本
|
|
||||||
/**
|
|
||||||
* @brief 获取 getBootVersion 对应的数据或状态
|
|
||||||
* @return VersionInfo 返回值
|
|
||||||
*/
|
|
||||||
VersionInfo getBootVersion() const;
|
|
||||||
|
|
||||||
// 设置软件版本
|
|
||||||
/**
|
|
||||||
* @brief 设置 setSoftwareVersion 对应的参数或状态
|
|
||||||
* @param[in] major 参数
|
|
||||||
* @param[in] minor 参数
|
|
||||||
* @param[in] patch 参数
|
|
||||||
* @param[in] build 参数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void setSoftwareVersion(u16 major, u16 minor, u16 patch, u16 build);
|
|
||||||
|
|
||||||
// 设置硬件版本
|
|
||||||
/**
|
|
||||||
* @brief 设置 setHardwareVersion 对应的参数或状态
|
|
||||||
* @param[in] major 参数
|
|
||||||
* @param[in] minor 参数
|
|
||||||
* @param[in] patch 参数
|
|
||||||
* @param[in] build 参数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void setHardwareVersion(u16 major, u16 minor, u16 patch, u16 build);
|
|
||||||
|
|
||||||
// 设置BOOT版本
|
|
||||||
/**
|
|
||||||
* @brief 设置 setBootVersion 对应的参数或状态
|
|
||||||
* @param[in] major 参数
|
|
||||||
* @param[in] minor 参数
|
|
||||||
* @param[in] patch 参数
|
|
||||||
* @param[in] build 参数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void setBootVersion(u16 major, u16 minor, u16 patch, u16 build);
|
|
||||||
|
|
||||||
// 将版本信息转换为字符串
|
|
||||||
char *versionToString(const VersionInfo &version, char *buffer,
|
|
||||||
size_t bufSize) const;
|
|
||||||
|
|
||||||
// 打印所有版本信息
|
|
||||||
/**
|
|
||||||
* @brief printVersions 函数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void printVersions() const;
|
|
||||||
|
|
||||||
// 通过CAN发送版本信息
|
|
||||||
/**
|
|
||||||
* @brief sendVersionInfoViaCan 函数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void sendVersionInfoViaCan() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
VersionInfo softwareVersion;
|
|
||||||
VersionInfo hardwareVersion;
|
|
||||||
VersionInfo bootVersion;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file main.cpp
|
|
||||||
* @brief 应用程序主流程源文件
|
|
||||||
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "Can.h"
|
|
||||||
#include "FOC.h"
|
|
||||||
#include "Filter.h"
|
|
||||||
#include "Timer.h"
|
|
||||||
#include "adc.h"
|
|
||||||
#include "ang_sensor.h"
|
|
||||||
#include "flash.h"
|
|
||||||
#include "health.h"
|
|
||||||
#include "initial.h"
|
|
||||||
#include "systick.h"
|
|
||||||
|
|
||||||
// MAIN 调试宏定义
|
|
||||||
#if MAIN_DEBUG
|
|
||||||
/** @brief MAIN_DEBUG_PRINT 宏定义 */
|
|
||||||
#define MAIN_DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
/** @brief MAIN_DEBUG_PRINT 宏定义 */
|
|
||||||
#define MAIN_DEBUG_PRINT(fmt, ...) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern CAN_transmiter CAN0_transmiter; // CAN 初始化
|
|
||||||
extern sampler sampler; // 采样器
|
|
||||||
extern angle_sensor KTH7823; // 角度传感器
|
|
||||||
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
|
|
||||||
extern EncoderAngleKalman Angle_kalman; // 角度滤波
|
|
||||||
extern ThermalController thermalController; // 热量控制器
|
|
||||||
extern FOC_Controller FOC; // FOC 控制
|
|
||||||
extern FlashEEPROM flashEEP; // EEPROM 类
|
|
||||||
extern VersionManager Version;
|
|
||||||
|
|
||||||
// 主任务调度共享位图:TIMER2 ISR 置位任务,main 循环短关中断后取快照并清位。
|
|
||||||
TaskScheduler scheduler = {0};
|
|
||||||
// 电机 50us 控制周期计数:主循环电机任务递增,观测器/计时逻辑读取。
|
|
||||||
u32 motor_runtime_50us = 0;
|
|
||||||
// 负载检测/通信心跳计数:主循环递增,CAN 周期发送任务清零。
|
|
||||||
u32 cnt_test = 0;
|
|
||||||
|
|
||||||
// 函数指针数组,包含各种控制模式对应的函数
|
|
||||||
static FOCFunctionPtr control_functions[] = {
|
|
||||||
&FOC_Controller::drv_hold, // 0: 占空比置
|
|
||||||
&FOC_Controller::angle_control, // 1: 位置闭环控制
|
|
||||||
&FOC_Controller::velocity_control, // 2: 速度闭环控制
|
|
||||||
&FOC_Controller::
|
|
||||||
angle_control_with_velocity_limit, // 3:
|
|
||||||
// 角度闭环控制,带速度限制
|
|
||||||
&FOC_Controller::MIT_Mode, // 4: MIT 模式
|
|
||||||
&FOC_Controller::current_control, // 5: 电流闭环控制
|
|
||||||
&FOC_Controller::velocity_open_loop, // 6: 速度开环控制
|
|
||||||
&FOC_Controller::PWM_out, // 0: 占空比置
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 判断任务标志中是否包含指定任务
|
|
||||||
* @param[in] currentTasks 当前任务位图快照
|
|
||||||
* @param[in] task 待检查任务枚举
|
|
||||||
* @return bool true 表示该任务需要执行
|
|
||||||
*/
|
|
||||||
static bool has_task(u32 currentTasks, SystemTask task) {
|
|
||||||
return (currentTasks & (1u << task)) != 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 控制模式变化时复位所有控制环,避免积分项跨模式继承
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static void reset_control_loops_on_mode_change(void) {
|
|
||||||
static int last_control_mode = -1;
|
|
||||||
if (FOC.control_mode == last_control_mode) return;
|
|
||||||
|
|
||||||
FOC.vel_loop.reset();
|
|
||||||
FOC.angle_loop.reset();
|
|
||||||
FOC.current_loop.reset();
|
|
||||||
FOC.vel_inVelAngloop.reset();
|
|
||||||
FOC.ang_inVelAngloop.reset();
|
|
||||||
FOC.ang_inMITloop.reset();
|
|
||||||
FOC.vel_inMITloop.reset();
|
|
||||||
FOC.current_inMITloop.reset();
|
|
||||||
last_control_mode = FOC.control_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行 50us 电机控制任务,包含快速电压检测和控制函数派发
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static void run_motor_control_task(void) {
|
|
||||||
motor_runtime_50us++;
|
|
||||||
|
|
||||||
static u8 vcheck_div = 0;
|
|
||||||
// 快速电压检测每 100us 执行一次,避免每 50us 都读取处理。
|
|
||||||
if (++vcheck_div >= 2u) {
|
|
||||||
vcheck_div = 0;
|
|
||||||
FOC.fast_voltage_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FOC.control_mode >= 8) return;
|
|
||||||
|
|
||||||
// 模式合法时再派发控制函数,防止数组越界。
|
|
||||||
reset_control_loops_on_mode_change();
|
|
||||||
if (!FOC.is_shut_down) {
|
|
||||||
(FOC.*control_functions[FOC.control_mode])();
|
|
||||||
} else {
|
|
||||||
FOC.drv_stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行高频采样和电机控制相关任务
|
|
||||||
* @param[in] currentTasks 当前任务位图快照
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static void run_fast_sample_tasks(u32 currentTasks) {
|
|
||||||
if (has_task(currentTasks, TASK_CURRENT_UPDATE)) {
|
|
||||||
sampler.update_current();
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_ANGLE_UPDATE)) {
|
|
||||||
KTH7823.update();
|
|
||||||
FOC.rt_angle = Angle_kalman.update(KTH7823.getAngle());
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_VELOCITY_UPDATE)) {
|
|
||||||
FOC.rt_velocity = Angle_kalman.getVelocity();
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_MOTOR_CONTROL)) {
|
|
||||||
run_motor_control_task();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行温度、热管理、磁检测和母线电压等低频维护任务
|
|
||||||
* @param[in] currentTasks 当前任务位图快照
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static void run_housekeeping_tasks(u32 currentTasks) {
|
|
||||||
if (has_task(currentTasks, TASK_MCU_TEMP_UPDATE)) {
|
|
||||||
sampler.update_mcu_temp();
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_DRV_TEMP_UPDATE)) {
|
|
||||||
sampler.update_drv_temp();
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_THERMAL_CONTROL)) {
|
|
||||||
thermalController.update();
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_MAGNETIC_CHECK)) {
|
|
||||||
angsens_MG_check();
|
|
||||||
}
|
|
||||||
if (has_task(currentTasks, TASK_VBUS_UPDATE)) {
|
|
||||||
power_manage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行 CAN 周期发送任务并喂狗
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static void run_can_task(void) {
|
|
||||||
CAN0_transmiter.test_u16 = CAN0_transmiter.get_node_id();
|
|
||||||
cnt_test = 0;
|
|
||||||
CAN0_transmiter.can0_send_flag = SET;
|
|
||||||
CAN0_transmiter.communication_check();
|
|
||||||
fwdgt_counter_reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 应用程序入口函数
|
|
||||||
* @return int 返回值
|
|
||||||
*/
|
|
||||||
int main(void) {
|
|
||||||
u8 init_status = hardware_init();
|
|
||||||
|
|
||||||
while (init_status) { // 初始化检测
|
|
||||||
MAIN_DEBUG_PRINT("初始化失败\r\n");
|
|
||||||
}
|
|
||||||
OTA_initial(); // OTA 初始化,A/B 分区处理
|
|
||||||
|
|
||||||
angsens_MG_check(); // 角度传感器磁感应强度测试
|
|
||||||
watchdog_init(50); // 看门狗初始化
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
__disable_irq();
|
|
||||||
u32 currentTasks =
|
|
||||||
scheduler.taskFlags; // 保存当前任务标志快照以提高效率并确保一致性
|
|
||||||
scheduler.taskFlags &= ~currentTasks; // 一次性清除所有已处理的任务标志
|
|
||||||
__enable_irq();
|
|
||||||
|
|
||||||
if (currentTasks == 0U) {
|
|
||||||
idle_task_count();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_task(currentTasks);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化应用层使用的硬件与软件模块
|
|
||||||
* @return u8 返回值
|
|
||||||
*/
|
|
||||||
u8 hardware_init(void) {
|
|
||||||
__enable_irq();
|
|
||||||
systick_config(); // 系统时钟初始化
|
|
||||||
unused_pin_init(); // 未使用引脚初始化
|
|
||||||
USART0_init(); // 调试串口初始化
|
|
||||||
User_timer_init(); // 任务 Timer 初始化
|
|
||||||
|
|
||||||
u8 init_status = 0;
|
|
||||||
init_status += KTH7823.init(); // 角度传感器初始化
|
|
||||||
init_status += sampler.init(); // 采样器初始化
|
|
||||||
|
|
||||||
// EEPROM 初始化 (必须在 CAN 初始化之前,因为 CAN 会从 Flash 读取节点 ID)
|
|
||||||
flashEEP.init(); // EEPROM 初始化
|
|
||||||
|
|
||||||
// CAN 初始化 (会先设置默认节点 ID,然后从 Flash 加载已保存的节点 ID)
|
|
||||||
init_status += CAN0_transmiter.init(); // CAN 初始化
|
|
||||||
|
|
||||||
init_status += Angle_kalman.init(KTH7823.getAngle()); // 角度滤波初始化
|
|
||||||
init_status += Vel_kalman.init(0.0f); // 速度滤波初始化
|
|
||||||
init_status += FOC.init(); // FOC 初始化
|
|
||||||
return init_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 根据任务标志调度周期性业务任务
|
|
||||||
* @param[in] currentTasks 参数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void do_task(u32 currentTasks) {
|
|
||||||
busy_task_enter(); // DWT: 记录忙碌起始周期
|
|
||||||
cnt_test++;
|
|
||||||
|
|
||||||
// 高频任务先执行,保持电机控制优先级。
|
|
||||||
run_fast_sample_tasks(currentTasks);
|
|
||||||
|
|
||||||
// 齿槽转矩校准 tick(DEBUG,平时不启用)
|
|
||||||
#if FOC_DEBUG
|
|
||||||
FOC.calibrate_cogging_tick();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
run_housekeeping_tasks(currentTasks);
|
|
||||||
|
|
||||||
// CAN 发送放在最后,避免通信处理影响前面的实时控制任务。
|
|
||||||
if (has_task(currentTasks, TASK_CAN_TRANSMIT)) {
|
|
||||||
run_can_task();
|
|
||||||
}
|
|
||||||
busy_task_exit(); // DWT: 累加忙碌周期
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/*!
|
|
||||||
\file main.h
|
|
||||||
\brief the header file of main
|
|
||||||
|
|
||||||
\version 2025-06-20, V1.5.1, firmware for GD32C10x
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from this
|
|
||||||
software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MAIN_H
|
|
||||||
#define MAIN_H
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 根据任务标志调度周期性业务任务
|
|
||||||
* @param[in] currentTasks 参数
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void do_task(u32 currentTasks);
|
|
||||||
/**
|
|
||||||
* @brief 初始化应用层使用的硬件与软件模块
|
|
||||||
* @return u8 返回值
|
|
||||||
*/
|
|
||||||
u8 hardware_init(void);
|
|
||||||
|
|
||||||
#endif /* MAIN_H */
|
|
||||||
Reference in New Issue
Block a user