阅读Betaflight源码笔记第二部分

简述调度器任务部分

周五 11月 07 2025
1169 字 · 10 分钟

任务调度器任务流程

时间线:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
启动阶段(只执行一次):
0ms: main()
1ms: ├─ init()
│ ├─ systemInit()
│ ├─ tasksInitData() [关联任务属性]
│ ├─ ... 硬件初始化 ...
│ └─ tasksInit() [启用任务]
│ ├─ schedulerInit() [初始化调度器]
│ ├─ setTaskEnabled(TASK_GYRO)
│ ├─ setTaskEnabled(TASK_FILTER)
│ ├─ setTaskEnabled(TASK_PID)
│ └─ setTaskEnabled(其他任务...)
100ms: └─ run() ──┐
运行阶段(无限循环): │
├─► scheduler() ─┬─ GYRO → FILTER → PID (实时任务)
│ └─ 选择并执行1个普通任务
│ ↓ (~125us)
├─► scheduler() ─┬─ GYRO → FILTER → PID
│ └─ 选择并执行1个普通任务
│ ↓ (~125us)
└─► ... (永远循环) ...
每个 scheduler() 调用内部:
┌────── 125us 周期 ──────┐
│ │
│ ┌─GYRO─┐ │
│ │ 20us │ │
│ └──────┘ │
│ │ │
│ ├─┬─FILTER─┐ │
│ │ │ 30us │ │
│ │ └────────┘ │
│ │ │ │
│ │ └─┬─PID─┐ │
│ │ │ 50us│ │
│ │ └─────┘ │
│ │ │ │
│ └─────────┴─ [RX/SERIAL/OSD等其他任务] ─►
│ │
└─────────────────────────┘

任务主要由==task_t==和==task_attribute_t==这2个结构体数组来定义的

#define DEFINE_TASK(taskNameParam, subTaskNameParam, checkFuncParam, taskFuncParam, desiredPeriodParam, staticPriorityParam){...}
task_t tasks[TASK_COUNT];
// Task ID data in .data (initialised data)
task_attribute_t task_attributes[TASK_COUNT] //该数组定义了任务的名字,函数链接和时间优先级
//其内部是由许多 DEFINE_TASK 宏构成的
//接着在tasksInit()之前,调用的tasksInit(),把task_attributes链接到tasks数组里面了
void tasksInitData(void)
{
for (int i = 0; i < TASK_COUNT; i++) {
tasks[i].attribute = &task_attributes[i];
}
}

任务执行是由==schedulerExecuteTask()==函数来完成

//任务函数的调用通过:
// Execute task
const timeUs_t currentTimeBeforeTaskCallUs = micros();
selectedTask->attribute->taskFunc(currentTimeBeforeTaskCallUs); //其中Task->attribute->taskFunc()指代的就是DEFINE_TASK宏里面的taskFuncParam
//例如想执行陀螺仪的任务只需:schedulerExecuteTask(gyroTask, currentTimeUs);
  • 所有任务函数必须有相同的函数签名

    void (*taskFunc)(timeUs_t currentTimeUs);

陀螺仪任务

//core.c line1244-1252 任务入口
FAST_CODE void taskGyroSample(timeUs_t currentTimeUs)
{
UNUSED(currentTimeUs);//这里不需要时间的参数,所以UNUSED
gyroUpdate();
if (pidUpdateCounter % activePidLoopDenom == 0) {
pidUpdateCounter = 0;
}
pidUpdateCounter++;
}

cyclesRemaining(剩余周期)于初始化时被确认

cyclesRemaining = (gyroCalibrationDuration × 10000) / sampleLooptime

在==gyroUpdate()==阶段

gyroUpdate() │ ├─ Step 1: 根据配置选择陀螺仪(在此之前先检测校准没有) │ │ │ ├─ GYRO_1: 使用陀螺仪1 │ │ └─ 刻度转换: gyroADC = sensor1.gyroADC × scale │ │ │ ├─ GYRO_2: 使用陀螺仪2 │ │ └─ 刻度转换: gyroADC = sensor2.gyroADC × scale │ │ │ └─ GYRO_BOTH: 使用双陀螺仪 │ └─ 平均值: gyroADC = (sensor1 + sensor2) / 2 │ └─ Step 2: 降采样处理 │ ├─ 滤波降采样 (downsampleFilterEnabled = true) │ └─ sampleSum = lowpass2Filter(gyroADC) │ └─ 简单平均降采样 (downsampleFilterEnabled = false) └─ sampleSum += gyroADC └─ sampleCount++

//稍微简化了部分代码
bool isGyroSensorCalibrationComplete(const gyroSensor_t *gyroSensor)
{
return gyroSensor->calibration.cyclesRemaining == 0;
}
static FAST_CODE void gyroUpdateSensor(gyroSensor_t *gyroSensor)
{
if (!gyroSensor->gyroDev.readFn(&gyroSensor->gyroDev)) {
return;
}
gyroSensor->gyroDev.dataReady = false;
//1.进行校准
//显然开始的时候cyclesRemaining != 0,
if (isGyroSensorCalibrationComplete(gyroSensor)) {
.........
} else {
//第一次时进入该函数
performGyroCalibration(gyroSensor, gyroConfig()->gyroMovementCalibrationThreshold);
} |
} |

==performGyroCalibration()==

STATIC_UNIT_TESTED NOINLINE void performGyroCalibration(gyroSensor_t *gyroSensor, uint8_t gyroMovementCalibrationThreshold)
{
bool calFailed = false;
for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
// Reset g[axis] at start of calibration
/*第一个周期 (isOnFirstGyroCalibrationCycle()):
重置累积和为 0
清空方差计算器
设置 gyroZero 为 0*/
if (isOnFirstGyroCalibrationCycle(&gyroSensor->calibration)) {
gyroSensor->calibration.sum[axis] = 0.0f;
devClear(&gyroSensor->calibration.var[axis]);
// gyroZero is set to zero until calibration complete
gyroSensor->gyroDev.gyroZero[axis] = 0.0f;
}
/*每个周期:
累积陀螺仪原始值:sum[axis] += gyroADCRaw[axis]
推送到方差计算器:devPush()*/
// Sum up CALIBRATING_GYRO_TIME_US readings
gyroSensor->calibration.sum[axis] += gyroSensor->gyroDev.gyroADCRaw[axis];
devPush(&gyroSensor->calibration.var[axis], gyroSensor->gyroDev.gyroADCRaw[axis]);
/*最后一个周期 (isOnFinalGyroCalibrationCycle()):
计算标准差:stddev = devStandardDeviation()
检查陀螺仪是否静止(标准差是否小于阈值)
如果静止,计算零点偏移:gyroZero = sum / cycles
如果移动,校准失败,重新开始*/
if (isOnFinalGyroCalibrationCycle(&gyroSensor->calibration)) {
const float stddev = devStandardDeviation(&gyroSensor->calibration.var[axis]);
if (axis == X) {
DEBUG_SET(DEBUG_GYRO_RAW, DEBUG_GYRO_CALIBRATION_VALUE, lrintf(stddev));
}
DEBUG_SET(DEBUG_GYRO_CALIBRATION, axis, stddev);
// check deviation and startover in case the model was moved
if (gyroMovementCalibrationThreshold && stddev > gyroMovementCalibrationThreshold) {
calFailed = true;
} else {
// please take care with exotic boardalignment !!
gyroSensor->gyroDev.gyroZero[axis] = gyroSensor->calibration.sum[axis] / gyroCalculateCalibratingCycles();
if (axis == Z) {
gyroSensor->gyroDev.gyroZero[axis] -= ((float)gyroConfig()->gyro_offset_yaw / 100);
}
}
}
}
if (calFailed) {
gyroSetCalibrationCycles(gyroSensor);
return;
}
if (isOnFinalGyroCalibrationCycle(&gyroSensor->calibration)) {
schedulerResetTaskStatistics(TASK_SELF); // so calibration cycles do not pollute tasks statistics
if (!firstArmingCalibrationWasStarted || (getArmingDisableFlags() & ~ARMING_DISABLED_CALIBRATING) == 0) {
beeper(BEEPER_GYRO_CALIBRATED);
}
}
//周期一直持续,直到cyclesRemaining==0,触发isGyroSensorCalibrationComplete()
--gyroSensor->calibration.cyclesRemaining;
DEBUG_SET(DEBUG_GYRO_CALIBRATION, 3, gyroSensor->calibration.cyclesRemaining);
}

==时间线==

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第 1 次 scheduler() 调用:
├─ 开始,忙等待同步
├─ ┌─ GYRO 任务(第1次 gyroUpdate)
├─ └─ 完成
├─ ┌─ FILTER 任务(如果 ready)
├─ └─ 完成
├─ ┌─ PID 任务(如果 ready)
├─ └─ 完成,电机输出
├─ RX检查 + Failsafe检查
├─ ┌─ 普通任务调度
│ │ 选择任务(例如 SERIAL)
├─ └─ 普通任务完成
├─ scheduler() 返回
└─────────────────────────────────────────────────────────────
第 N 次 scheduler() 调用:
├─开始,忙等待同步
├─┌─ GYRO 任务(第N次 gyroUpdate) 直到cyclesRemaining==0,开始gyro数据的读取和转换
├─└─ 完成
├─ ┌─ FILTER 任务(如果 ready)
└─ ...继续循环
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

滤波器任务


Thanks for reading!

阅读Betaflight源码笔记第二部分

周五 11月 07 2025
1169 字 · 10 分钟