以下是 apply_params
函数的实现步骤和代码示例:
1. 定义参数结构体
在头文件中定义 PID_Params
结构体,包含需要动态调整的 PID 参数:
// ms_hal_photo_sensor.h
typedef struct {
float Kp; // 比例系数
float Ki; // 积分系数(直接使用 Ki = Kp*T/Ti)
float Kd; // 微分系数(直接使用 Kd = Kp*Td/T)
float T; // 控制周期(单位:ms)
float dead_zone; // 死区阈值
float max_delta; // 单次最大输出变化量
float output_alpha; // 输出平滑系数(0.0~1.0)
} PID_Params;
2. 定义预设参数集
在代码中预设不同场景的参数集合:
// ms_hal_photo_sensor1.c
// 快速跟踪参数(高响应速度)
static const PID_Params fast_params = {
.Kp = 0.8,
.Ki = 0.05,
.Kd = 0.1,
.T = 20,
.dead_zone = 10,
.max_delta = 20,
.output_alpha = 0.2
};
// 稳态参数(低噪声抑制)
static const PID_Params slow_params = {
.Kp = 0.3,
.Ki = 0.01,
.Kd = 0.05,
.T = 50,
.dead_zone = 20,
.max_delta = 5,
.output_alpha = 0.5
};
3. 实现 apply_params 函数
编写函数将参数应用到全局 PID 控制结构体:
// ms_hal_photo_sensor1.c
/**
* @brief 应用新的PID参数集
* @param params PID参数结构体指针
*/
void apply_params(const PID_Params* params) {
if (params == NULL) {
bk_printf("[ERROR] apply_params: NULL pointer!\r\n");
return;
}
// 原子化更新参数(根据具体平台可能需要关中断)
PID_Str_Val.Kp = params->Kp;
PID_Str_Val.Ki = params->Ki;
PID_Str_Val.Kd = params->Kd;
PID_Str_Val.T = params->T;
PID_Str_Val.dead_zone = params->dead_zone;
PID_Str_Val.max_delta = params->max_delta;
PID_Str_Val.output_alpha = params->output_alpha;
// 重置误差历史(避免参数突变导致震荡)
PID_Str_Val.En = 0;
PID_Str_Val.En_1 = 0;
PID_Str_Val.En_2 = 0;
bk_printf("PID Params Updated: Kp=%.2f Ki=%.2f Kd=%.2f T=%.0fms\r\n",
params->Kp, params->Ki, params->Kd, params->T);
}
4. 状态机集成
在定时器回调或控制循环中根据系统状态切换参数:
// ms_hal_photo_sensor1.c
typedef enum {
PID_STATE_STEADY, // 稳态
PID_STATE_TRACKING // 快速跟踪
} PID_State;
static PID_State current_state = PID_STATE_STEADY;
void photo_timer_handler(void) {
// ...原有代码...
// 动态切换参数逻辑
static uint32_t error_integral = 0;
error_integral += fabs(PID_Str_Val.En);
// 每100ms评估一次状态
static uint8_t eval_counter = 0;
if (++eval_counter >= 5) {
eval_counter = 0;
if (error_integral > 1000) { // 累计误差大,进入跟踪模式
if (current_state != PID_STATE_TRACKING) {
apply_params(&fast_params);
current_state = PID_STATE_TRACKING;
}
} else { // 误差小,进入稳态模式
if (current_state != PID_STATE_STEADY) {
apply_params(&slow_params);
current_state = PID_STATE_STEADY;
}
}
error_integral = 0; // 重置累计误差
}
}
5. 关键点说明
-
原子化操作:
在实时系统中,更新 PID 参数时可能需要关闭中断,确保参数赋值操作的完整性。 -
状态切换逻辑:
示例中通过累计误差判断系统状态,实际可根据需求使用其他指标(如误差变化率)。 -
参数平滑过渡:
若需更平滑的切换,可对参数进行插值过渡(如线性渐变)。 -
参数校验:
可在apply_params
中添加范围检查,防止非法值:if (params->Kp < 0 || params->Ki < 0 || params->Kd < 0) { bk_printf("[ERROR] Invalid PID parameters!\r\n"); return; }
完整调用示例
// 手动触发参数切换测试
void test_switch_params(void) {
if (current_state == PID_STATE_STEADY) {
apply_params(&fast_params);
current_state = PID_STATE_TRACKING;
} else {
apply_params(&slow_params);
current_state = PID_STATE_STEADY;
}
}
通过这种设计,PID 参数可以根据系统状态动态调整,在响应速度和稳定性之间取得平衡。