任务调度器任务流程
时间线:━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━启动阶段(只执行一次):
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 taskconst 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!