一、定时器回调的核心作用
实时任务执行:
- 按固定频率(如400Hz、800Hz)周期性触发特定函数,确保任务以精确的时间间隔执行。
- 典型应用:IMU数据采样、PID控制器更新、PWM输出刷新。
低优先级任务隔离:
- 将关键任务(如姿态解算)与非关键任务(如日志写入)分离,避免相互干扰。
- 确保关键任务在固定时间内完成,提高系统稳定性。
硬件资源管理:
- 利用MCU硬件定时器实现精确计时,减少软件延时带来的误差。
二、实现机制与架构
1. 基于AP_HAL的抽象接口
// AP_HAL 中定义的定时器接口
class HAL {
public:
// 注册定时器回调函数
virtual void register_timer_process(AP_HAL::MemberProc) = 0;
// 注册高优先级定时器回调(用于最关键任务)
virtual void register_high_priority_timer_process(AP_HAL::MemberProc) = 0;
// 启动定时器
virtual void start_timers() = 0;
};
- 跨平台适配:不同硬件平台(如PX4、Linux)通过实现上述接口提供定时器功能。
2. 回调函数注册与优先级
// 在AP_InertialSensor初始化中注册IMU采样回调
void AP_InertialSensor::init()
{
// 注册IMU采样回调到高优先级定时器
hal.scheduler->register_high_priority_timer_process(
FUNCTOR_BIND_MEMBER(&AP_InertialSensor::_update, void));
}
- 优先级分类:
- 高优先级:用于最关键任务(如IMU数据读取),通常在专用定时器上运行。
- 普通优先级:用于次要任务(如电机输出更新),在主定时器循环中执行。
3. 定时器中断处理流程
- 硬件定时器触发:MCU定时器达到预设值时产生中断。
- 中断服务程序(ISR):
// 伪代码:定时器中断服务程序 void TIMER_ISR() { // 清除中断标志 clear_interrupt_flag(); // 执行高优先级回调队列 run_high_priority_callbacks(); // 执行普通优先级回调队列 run_normal_priority_callbacks(); }
- 回调函数执行:按注册顺序依次调用已注册的回调函数。
三、关键特性与设计考虑
1. 严格的时间约束
- 周期确定性:回调函数必须在指定时间内完成,否则可能导致后续任务延迟。
- 示例:400Hz的IMU采样任务必须在2.5ms内完成,否则影响姿态解算精度。
2. 回调函数设计原则
- 短小精悍:避免在回调中执行耗时操作(如文件IO、复杂计算)。
- 原子操作:确保数据访问的线程安全性,避免与主循环或其他回调冲突。
- 错误处理:回调内的异常不能导致系统崩溃,需优雅处理错误。
3. 负载平衡与调度优化
- 任务拆分:将复杂任务分解为多个小任务,分布在不同优先级回调中。
- 示例:IMU数据采样→姿态解算→控制输出,分阶段在不同回调中完成。
四、典型应用场景
1. 传感器数据采集
// IMU数据采集回调
void AP_InertialSensor::_update()
{
// 读取加速度计和陀螺仪原始数据
read_accel_raw();
read_gyro_raw();
// 应用校准参数
apply_calibration();
// 更新滤波后的数据
update_filtered_data();
}
- 频率:通常为400Hz-1kHz,确保捕获高频运动信息。
2. 姿态控制循环
// 姿态控制回调(如200Hz)
void Copter::attitude_control()
{
// 获取最新姿态
Quaternion attitude = ahrs.get_quaternion();
// 计算姿态误差
Vector3f error = calculate_attitude_error(target_attitude, attitude);
// PID控制器更新
update_pid_controllers(error);
// 生成电机输出
output_to_motors();
}
- 频率:通常为200Hz-400Hz,平衡控制响应速度与计算负载。
3. PWM输出刷新
// PWM输出回调(如50Hz-400Hz)
void AP_Motors::output()
{
// 将控制信号转换为PWM值
calculate_pwm_outputs();
// 更新硬件PWM寄存器
write_pwm_values();
}
- 频率:根据电调类型调整(普通电调50Hz,Oneshot电调400Hz)。
五、调试与性能优化
定时器负载监控:
// 计算定时器回调执行时间 uint32_t start_time = micros(); run_timer_callbacks(); uint32_t execution_time = micros() - start_time; // 记录最大执行时间,检测过载情况 if (execution_time > max_timer_load) { max_timer_load = execution_time; }
过载处理策略:
- 减少回调函数中的计算量。
- 调整任务优先级,确保关键任务优先执行。
- 增加硬件资源(如使用更高主频的MCU)。
六、与其他调度机制的对比
特性 | 定时器回调 | 主循环(Main Loop) | 任务调度器(Scheduler) |
---|---|---|---|
执行频率 | 固定频率(如400Hz) | 可变频率(依赖负载) | 可配置频率(但精度较低) |
实时性 | 高(严格时间约束) | 中(可能被耗时任务阻塞) | 低(基于时间片轮转) |
适用场景 | 传感器采样、控制输出 | 参数处理、非关键逻辑 | 低优先级后台任务 |
优先级 | 高/中(分队列执行) | 低(主循环后执行) | 低(主循环中调度) |