BetaFlight模块设计之十一:Gyro&Acc任务分析

Posted lida2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BetaFlight模块设计之十一:Gyro&Acc任务分析相关的知识,希望对你有一定的参考价值。

BetaFlight模块设计之十一:Gyro&Acc任务分析

基于BetaFlight开源代码框架简介的框架设计,逐步分析内部模块功能设计。

IMU硬件配置

KAKUTEF7 AIO硬件配置,详见\\src\\main\\target\\KAKUTEF7\\target.h; 手头的板子是ICM20689硬件。

#define USE_ACC
#define USE_GYRO
#define USE_EXTI

// ICM-20689
#define USE_ACC_SPI_ICM20689
#define USE_GYRO_SPI_ICM20689
#define GYRO_1_CS_PIN           SPI4_NSS_PIN
#define GYRO_1_SPI_INSTANCE     SPI4
#define GYRO_1_ALIGN            CW270_DEG

#define USE_GYRO_EXTI
#define GYRO_1_EXTI_PIN         PE1
#define USE_MPU_DATA_READY_SIGNAL

Gyro任务

描述:主要获取x,y,z方向gyroADC值。

 ├──> 初始化
 │   ├──> [v]硬件初始化gyroDetect(icm20689SpiGyroDetect)/mpuDetect(icm20689SpiDetect)/gyroDetectSensor()/gyroPreInit
 │   └──> [v]业务初始化pgResetFn_gyroConfig/gyroInit
 ├──> 任务
 │   ├──> [v]实时任务[TASK_GYRO] = DEFINE_TASK("GYRO", NULL, NULL, taskGyroSample, TASK_GYROPID_DESIRED_PERIOD, TASK_PRIORITY_REALTIME),
 │   ├──> [x]事件任务
 │   └──> [x]时间任务
 ├──> 驱动
 │   ├──> [v]查询mpuGyroRead
 │   └──> [x]中断
 └──> 接口
     ├──> void dynLpfGyroUpdate(float throttle);
	 ├──> float dynThrottle(float throttle);
	 ├──> void initYawSpinRecovery(int maxYawRate);
	 ├──> uint16_t gyroAbsRateDps(int axis);
	 ├──> bool gyroYawSpinDetected(void);
	 ├──> bool gyroOverflowDetected(void);
	 ├──> void gyroReadTemperature(void);
	 ├──> int16_t gyroGetTemperature(void);
	 ├──> bool isFirstArmingGyroCalibrationRunning(void);
	 ├──> void gyroStartCalibration(bool isFirstArmingCalibration);
	 ├──> FAST_CODE bool gyroFilterReady(void)
     └──> FAST_CODE bool pidLoopReady(void)

taskGyroSample函数分析

这里activePidLoopDenom和pidUpdateCounter主要把gyroFilter和pidLoop两个时间片分开来缓解MCU压力。STM32F1只有STM32F7的1/8。

taskGyroSample
 ├──> gyroUpdate
 ├──> <pidUpdateCounter % activePidLoopDenom == 0> //
 │   └──> pidUpdateCounter = 0;
 └──> pidUpdateCounter++;

注:配置PID_PROCESS_DENOM_DEFAULT,详见:\\src\\main\\flight\\pid.c

#if defined(STM32F1)
#define PID_PROCESS_DENOM_DEFAULT       8
#elif defined(STM32F3)
#define PID_PROCESS_DENOM_DEFAULT       4
#elif defined(STM32F411xE) || defined(STM32G4) //G4 sometimes cpu overflow when PID rate set to higher than 4k
#define PID_PROCESS_DENOM_DEFAULT       2
#else
#define PID_PROCESS_DENOM_DEFAULT       1
#endif

gyroUpdate函数分析

gyroUpdate
 ├──> <GYRO_CONFIG_USE_GYRO_1>
 │   ├──> gyroUpdateSensor(&gyro.gyroSensor1);
 │   └──> <isGyroSensorCalibrationComplete(&gyro.gyroSensor1)>
 │       └──> 更新gyro.gyroADC[X],gyro.gyroADC[Y],gyro.gyroADC[Z]
 ├──> <USE_MULTI_GYRO><GYRO_CONFIG_USE_GYRO_2>
 │   ├──> gyroUpdateSensor(&gyro.gyroSensor2);
 │   └──> <isGyroSensorCalibrationComplete(&gyro.gyroSensor2)>
 │       └──> 更新gyro.gyroADC[X],gyro.gyroADC[Y],gyro.gyroADC[Z]
 ├──> <USE_MULTI_GYRO><GYRO_CONFIG_USE_GYRO_BOTH>
 │   ├──> gyroUpdateSensor(&gyro.gyroSensor1);
 │   ├──> gyroUpdateSensor(&gyro.gyroSensor2);
 │   └──> <isGyroSensorCalibrationComplete gyroSensor1 && gyroSensor1>
 │       └──> 根据权重更新gyro.gyroADC[X],gyro.gyroADC[Y],gyro.gyroADC[Z]
 ├──> <using gyro lowpass 2 filter for downsampling>
 │   └──> lowpass2FilterApplyFn, gyro.sampleSum[X], gyro.sampleSum[Y], gyro.sampleSum[Z]
 └──> <using simple averaging for downsampling>
     └──> gyro.sampleCount++; gyro.sampleSum[X], gyro.sampleSum[Y], gyro.sampleSum[Z]

Acc任务

描述:主要获取x,y,z方向accADC值。

 ├──> 初始化
 │   ├──> [v]硬件初始化accDetect(icm20689SpiAccDetect)/mpuDetect(icm20689SpiDetect)
 │   └──> [v]业务初始化pgResetFn_accelerometerConfig/accInit
 ├──> 任务
 │   ├──> [x]实时任务
 │   ├──> [x]事件任务
 │   └──> [v]时间任务[TASK_ACCEL] = DEFINE_TASK("ACC", NULL, NULL, taskUpdateAccelerometer, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM),
 ├──> 驱动
 │   ├──> [v]查询mpuAccReadSPI
 │   └──> [x]中断
 └──> 接口
     └──> bool accGetAccumulationAverage(float *accumulationAverage)

taskUpdateAccelerometer函数分析

这个函数太简洁了,貌似都感觉应该直接用accUpdate;不过这里的问题是任务通用函数格式与accUpdate不一样,所以有了一个转换。

注:从设计的角度,如果能够整理抽取一个private data指针指向任务各自特殊的数据区(通常OS会这么做),就更加简洁明了。

taskUpdateAccelerometer
 └──> accUpdate(currentTimeUs, &accelerometerConfigMutable()->accelerometerTrims);

accUpdate函数分析

这里的数据主要是采集获取,并未涉及到使用,所以整体结构比较清楚和容易理解。

accUpdate
 ├──> <!acc.dev.readFn(&acc.dev)>
 │   └──> return
 ├──> acc.isAccelUpdatedAtLeastOnce = true;
 ├──> 赋值acc.accADC[axis] = acc.dev.ADCRaw[axis];
 ├──> <accelerationRuntime.accLpfCutHz>
 │   └──> 滤波acc.accADC[axis] = biquadFilterApply(&accelerationRuntime.accFilter[axis], acc.accADC[axis]);
 ├──> <ALIGN_CUSTOM>
 │   └──> alignSensorViaMatrix(acc.accADC, &acc.dev.rotationMatrix);
 ├──> <其他acc.dev.accAlign>
 │   └──> alignSensorViaRotation(acc.accADC, acc.dev.accAlign);
 ├──> <!accIsCalibrationComplete()>
 │   └──> performAcclerationCalibration(rollAndPitchTrims);
 ├──> <featureIsEnabled(FEATURE_INFLIGHT_ACC_CAL)>
 │   └──> performInflightAccelerationCalibration(rollAndPitchTrims);
 ├──> applyAccelerationTrims(accelerationRuntime.accelerationTrims);
 └──> 累计测量值更新
     ├──> ++accelerationRuntime.accumulatedMeasurementCount;
     └──> accelerationRuntime.accumulatedMeasurements[axis] += acc.accADC[axis];

以上是关于BetaFlight模块设计之十一:Gyro&Acc任务分析的主要内容,如果未能解决你的问题,请参考以下文章

BetaFlight深入传感设计之十:传感器物理特性方向对齐

BetaFlight模块设计之十二:电传任务分析

BetaFlight模块设计之十四:高度计算任务分析

BetaFlight模块设计之十七:pinioBox任务分析

BetaFlight模块设计之十八:图传模块同步任务分析

BetaFlight模块设计之十:磁力计任务分析