从Simulink到Ardupilot:ADRC控制器全流程开发实战
在无人机飞控开发领域,传统PID控制器虽然简单可靠,但在应对复杂扰动和模型不确定性时往往力不从心。ADRC(自抗扰控制)作为一种新兴的控制策略,通过独特的扩张状态观测器(ESO)设计,能够实时估计并补偿系统内外部扰动,显著提升控制性能。本文将手把手带你完成从Simulink建模到Ardupilot飞控集成的全流程开发,重点解决工程实现中的关键问题。
1. ADRC控制原理与Simulink建模基础
ADRC控制器的核心在于其三层结构设计:跟踪微分器(TD)用于安排过渡过程,非线性状态误差反馈(NLSEF)实现误差的动态调节,而最具创新性的扩张状态观测器(ESO)则将系统内外扰动统一视为"总扰动"进行实时估计和补偿。
在Simulink中搭建ADRC模型时,需要特别注意几个关键点:
- 参数归一化处理:ADRC参数通常具有明确的物理意义,如带宽概念。建议采用韩京清教授提出的带宽参数化方法,将多个参数简化为1-2个关键带宽参数
- 离散化匹配:Ardupilot控制器默认运行在400Hz频率下,Simulink模型的固定步长应设置为0.0025秒(1/400)
- 接口标准化:提前规划好输入输出接口,通常包括:
- 输入:期望值、反馈值
- 输出:控制量
- 参数:带宽相关参数、ESO增益等
% 典型ADRC参数设置示例 beta_01 = 100; % ESO带宽参数1 beta_02 = 300; % ESO带宽参数2 beta_03 = 1000; % ESO带宽参数3 delta = 0.01; % 非线性因子 b0 = 200; % 系统近似增益2. 嵌入式代码生成关键配置
使用Simulink Embedded Coder生成嵌入式代码时,必须进行针对性配置以确保生成的代码能够无缝集成到Ardupilot环境中。以下是关键配置步骤:
模型配置参数设置:
- 求解器类型:固定步长
- 系统目标文件:
ert.tlc(Embedded Real-Time) - 语言:C++
- 代码生成仅包含:
Generate code only
接口配置:
- 将控制器模块封装为原子子系统
- 配置函数接口为
void func(float input, float* output)形式 - 禁用动态内存分配
代码风格优化:
- 启用代码优化选项
- 设置具有工程意义的函数和变量命名规则
注意:生成代码前务必运行模型更新检查(Ctrl+D),确保没有代数环等问题
生成的典型代码结构如下:
ADRC_Controller/ ├── ADRC_Controller.cpp # 主算法实现 ├── ADRC_Controller.h # 接口声明 ├── ADRC_Controller_data.cpp # 参数存储 └── ADRC_Controller_private.h # 内部变量定义3. Ardupilot代码集成实战
将生成的ADRC代码集成到Ardupilot中需要精心设计接口和参数传递机制。以下是详细步骤:
3.1 文件组织与包含
建议在libraries/AC_PID目录下创建ADRC子目录存放生成的代码,并修改AC_PID.h添加ADRC支持:
// 在AC_PID.h中添加 #include "ADRC/ADRC_Controller.h" class AC_PID { public: // ...原有成员... void set_ADRC_params(float b, float bandwidth); private: ADRC_Controller _adrc; AP_Float _adrc_b; // 地面站可调参数 AP_Float _adrc_band; // 带宽参数 };3.2 控制器替换实现
修改AC_PID::update_all()函数,实现ADRC与原有PID的逻辑切换:
float AC_PID::update_all(float target, float measurement, bool limit) { if (_use_ADRC) { // ADRC控制逻辑 _adrc.setInput(target, measurement); _adrc.step(); return _adrc.getOutput(); } else { // 原有PID逻辑 // ...保持原有实现... } }3.3 参数地面站对接
在AC_PID.cpp的var_info[]中添加ADRC参数,使其可通过Mission Planner或QGC调整:
const AP_Param::GroupInfo AC_PID::var_info[] = { // ...原有参数... AP_GROUPINFO("ADRC_B", 12, AC_PID, _adrc_b, 200), AP_GROUPINFO("ADRC_BW", 13, AC_PID, _adrc_band, 20), AP_GROUPEND };参数命名将自动继承调用上下文,例如在姿态控制器中使用时,地面站将显示为ATC_ADRC_B和ATC_ADRC_BW。
4. 调试与性能优化技巧
ADRC调试需要系统的方法和工具支持,以下是在Ardupilot环境中调试ADRC的实用技巧:
4.1 软件在环(SITL)调试
使用Ardupilot的SITL环境可以安全高效地测试ADRC性能:
# 启动SITL仿真 sim_vehicle.py -v ArduCopter --console --map --add-param-file=ADRC_params.parm建议创建专门的参数文件ADRC_params.parm初始化ADRC参数:
ATC_ADRC_B 200 ATC_ADRC_BW 20 ATC_RATE_ADRC_ENABLE 14.2 数据日志分析
利用Ardupilot的DataFlash日志分析ADRC内部状态:
- 修改
ADRC_Controller.cpp添加日志记录:
void ADRC_Controller::step() { // ...控制计算... AP::logger().Write_DEBUG("ADRC", "eso1,eso2,eso3,u", "fff", _eso_state[0], _eso_state[1], _eso_state[2], _control_output); }- 使用Mission Planner的日志分析工具观察ESO状态变量变化
4.3 参数整定经验
根据实际项目经验,ADRC参数整定可遵循以下流程:
- 先调ESO带宽:从低频开始逐步提高,直到扰动估计响应速度满足要求
- 再调控制带宽:根据系统动态响应需求调整
- 最后微调非线性参数:如fal函数的δ和α
典型参数调整范围参考:
| 参数类型 | 初始值 | 调整范围 | 影响特性 |
|---|---|---|---|
| ESO带宽β1 | 50 | 30-100 | 扰动估计速度 |
| ESO带宽β2 | 200 | 100-500 | 扰动估计精度 |
| 控制带宽ωc | 20 | 10-50 | 系统响应速度 |
| 非线性因子δ | 0.01 | 0.001-0.1 | 控制平滑度 |
5. 飞行测试与异常处理
实际飞行测试是验证ADRC性能的关键环节,需要特别注意以下事项:
- 安全保护机制:在
AC_PID中添加ADRC运行状态监控,异常时自动切换回PID
if (!_adrc.isHealthy()) { _use_ADRC = false; Log_Write_Error(ERROR_SUBSYSTEM_ADRC, ERROR_CODE_FAILED); }参数保存与加载:通过
AP_Param系统自动保存调好的参数到EEPROM温度补偿:对于高精度应用,考虑添加温度补偿系数:
void AC_PID::set_temp_compensation(float temp) { _adrc.setGainComp(1.0 + (temp - 25.0) * 0.01); }在多次实际项目中,我们发现ADRC在以下场景表现尤为突出:
- 强风扰动下的位置保持
- 负载突变时的稳定性控制
- 模型参数不确定情况下的鲁棒性能
一个典型的调试过程往往需要3-5次迭代飞行测试,每次重点关注不同频段的控制性能。建议在地面站中预设多组参数配置,飞行中通过遥控器通道快速切换对比效果。