iNavFlight飞控固件学习-5《IMU初始化》

发布于:2025-08-09 ⋅ 阅读:(20) ⋅ 点赞:(0)

目录

摘要

本节主要记录IMU初始化和数据更新的过程,欢迎批评指正!!!

1.IMU 原理图

在这里插入图片描述
在这里插入图片描述

从原理图可以看出ICM42688-P主要接到SPI1上面。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
本节主要用到的IMU是ICM42688和ICM42605可以完全兼容。

2.IMU 板层配置

1.在target文件下找到自己板层名称,在target.h定义使用ICM相关配置,设置SPI1总线特性。
在这里插入图片描述
在这里插入图片描述
在target.c中设置

在这里插入图片描述

3.IMU 程序初始化

#if defined(SITL_BUILD)
int main(int argc, char *argv[])
{
    parseArguments(argc, argv);
#else
int main(void)
{
#endif
	//初始化
    init();
    //循环初始化
    loopbackInit();
    //开始任务调度
    while (true)
    {
#if defined(SITL_BUILD)
        serialProxyProcess();
#endif
        //开始任务
        scheduler();
        //进程循环初始化
        processLoopback();
    }
}

在init函数中执行

void init(void)
{
  ......
      //传感器自动识别
    if (!sensorsAutodetect())
    {
        // if gyro was not detected due to whatever reason, we give up now.
        failureMode(FAILURE_MISSING_ACC);
    }
  ......
}
bool sensorsAutodetect(void)
{
	//eeprom 更新待定
    bool eepromUpdatePending = false;
    //陀螺仪初始化
    if (!gyroInit())
    {
        return false;
    }
    //加速度初始化
    accInit(getLooptime());
    ......
}

下面我们分别看加速度和陀螺仪的初始化。

1.陀螺仪初始化

bool gyroInit(void)
{
	//清空数据
    memset(&gyro, 0, sizeof(gyro));

    //设置惯性传感器标签(用于双陀螺仪选择)----- Set inertial sensor tag (for dual-gyro selection)
#ifdef USE_DUAL_GYRO
    gyroDev[0].imuSensorToUse = gyroConfig()->gyro_to_use;
#else
    gyroDev[0].imuSensorToUse = 0;
#endif

    //识别陀螺仪---- Detecting gyro0
    gyroSensor_e gyroHardware = gyroDetect(&gyroDev[0], GYRO_AUTODETECT);
    //没有陀螺仪数据
    if (gyroHardware == GYRO_NONE)
    {
        gyro.initialized = false;
        detectedSensors[SENSOR_INDEX_GYRO] = GYRO_NONE;
        return true;
    }

    // 陀螺仪初始化----Gyro is initialized
    gyro.initialized = true;
    detectedSensors[SENSOR_INDEX_GYRO] = gyroHardware;
    sensorsSet(SENSOR_GYRO);

    //驱动初始化---- Driver initialisation
    gyroDev[0].lpf = GYRO_LPF_256HZ;
    gyroDev[0].requestedSampleIntervalUs = TASK_GYRO_LOOPTIME;
    gyroDev[0].sampleRateIntervalUs = TASK_GYRO_LOOPTIME;
    //初始化函数
    gyroDev[0].initFn(&gyroDev[0]);

    // initFn will initialize sampleRateIntervalUs to actual gyro sampling rate (if driver supports it). Calculate target looptime using that value
    //initFn将把sampleRateIntervalUs初始化为实际陀螺仪采样率(如果驱动程序支持的话)。使用该值计算目标循环时间
    gyro.targetLooptime = gyroDev[0].sampleRateIntervalUs;
    //初始化滤波
    gyroInitFilters();

    //是否使用动态滤波
#ifdef USE_DYNAMIC_FILTERS
    //以PID频率运行的动态陷波--- Dynamic notch running at PID frequency
    dynamicGyroNotchFiltersInit(&dynamicGyroNotchState);

    secondaryDynamicGyroNotchFiltersInit(&secondaryDynamicGyroNotchState);
    //陀螺仪数据状态分析
    gyroDataAnalyseStateInit(
        &gyroAnalyseState,
        gyroConfig()->dynamicGyroNotchMinHz,
        getLooptime()
    );
#endif
    //返回成功
    return true;
}

我们需要重点关注: gyroSensor_e gyroHardware = gyroDetect(&gyroDev[0], GYRO_AUTODETECT);

可以看出下面就是循环识别查找我们需要的传感器。

STATIC_UNIT_TESTED gyroSensor_e gyroDetect(gyroDev_t *dev, gyroSensor_e gyroHardware)
{
	//默认对齐方式
    dev->gyroAlign = ALIGN_DEFAULT;
    //识别
    switch (gyroHardware)
    {
    case GYRO_AUTODETECT:
        FALLTHROUGH;

#ifdef USE_IMU_MPU6000 //判断是否使用mpu6000
    case GYRO_MPU6000:
        if (mpu6000GyroDetect(dev))
        {
            gyroHardware = GYRO_MPU6000;
            break;
        }
        FALLTHROUGH;
#endif

#if defined(USE_IMU_MPU6500) //MPU6500
    case GYRO_MPU6500:
        if (mpu6500GyroDetect(dev)) {
            gyroHardware = GYRO_MPU6500;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_MPU9250//MPU9250
    case GYRO_MPU9250:
        if (mpu9250GyroDetect(dev)) {
            gyroHardware = GYRO_MPU9250;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_BMI160//BMI160
    case GYRO_BMI160:
        if (bmi160GyroDetect(dev)) {
            gyroHardware = GYRO_BMI160;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_BMI088//BMI088
    case GYRO_BMI088:
        if (bmi088GyroDetect(dev)) {
            gyroHardware = GYRO_BMI088;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_ICM20689 //ICM20689
    case GYRO_ICM20689:
        if (icm20689GyroDetect(dev)) {
            gyroHardware = GYRO_ICM20689;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_ICM42605 //ICM42605
    case GYRO_ICM42605:
        if (icm42605GyroDetect(dev)) {
            gyroHardware = GYRO_ICM42605;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_BMI270 //BMI270
    case GYRO_BMI270:
        if (bmi270GyroDetect(dev)) {
            gyroHardware = GYRO_BMI270;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_LSM6DXX //LSM6DXX
    case GYRO_LSM6DXX:
        if (lsm6dGyroDetect(dev)) {
            gyroHardware = GYRO_LSM6DXX;
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_FAKE
    case GYRO_FAKE:
        if (fakeGyroDetect(dev)) {
            gyroHardware = GYRO_FAKE;
            break;
        }
        FALLTHROUGH;
#endif

    default:
    case GYRO_NONE:
        gyroHardware = GYRO_NONE;
    }

    return gyroHardware;
}

在这里插入图片描述
这里可以看出要想使用icm42688必须定义:#define USE_IMU_ICM42605

bool icm42605GyroDetect(gyroDev_t *gyro)
{
    gyro->busDev = busDeviceInit(BUSTYPE_ANY, DEVHW_ICM42605, gyro->imuSensorToUse, OWNER_MPU);
    if (gyro->busDev == NULL) {
        return false;
    }
    //重点关注的识别
    if (!icm42605DeviceDetect(gyro->busDev)) {
        busDeviceDeInit(gyro->busDev);
        return false;
    }

    // Magic number for ACC detection to indicate that we have detected icm42605 gyro
    mpuContextData_t * ctx = busDeviceGetScratchpadMemory(gyro->busDev);
    ctx->chipMagicNumber = 0x4265;

    gyro->initFn = icm42605AccAndGyroInit;
    gyro->readFn = icm42605GyroRead;
    gyro->intStatusFn = gyroCheckDataReady;
    gyro->temperatureFn = icm42605ReadTemperature;
    gyro->scale = 1.0f / 16.4f;     // 16.4 dps/lsb scalefactor
    gyro->gyroAlign = gyro->busDev->param;

    return true;
}
static bool icm42605DeviceDetect(busDevice_t * dev)
{
    uint8_t tmp;
    uint8_t attemptsRemaining = 5;

    busSetSpeed(dev, BUS_SPEED_INITIALIZATION);

    busWrite(dev, ICM42605_RA_PWR_MGMT0, 0x00);

    do {
        delay(150);
        //读取who am i
        busRead(dev, MPU_RA_WHO_AM_I, &tmp);

        switch (tmp) {
            /* ICM42605 and ICM42688P share the register structure*/
            case ICM42605_WHO_AM_I_CONST: //0x42
                is42688P = false;
                return true;
            case ICM42688P_WHO_AM_I_CONST: //0x47
                is42688P = true;
                return true;

            default:
                // Retry detection
                break;
        }
    } while (attemptsRemaining--);

    return false;
}

在这里插入图片描述
在这里插入图片描述
从这里可以看出具体就做了区分。对于其他的设置暂时不在讲解。

2.加速度初始化

bool accInit(uint32_t targetLooptime)
{
    memset(&acc, 0, sizeof(acc));

    // Set inertial sensor tag (for dual-gyro selection)
#ifdef USE_DUAL_GYRO
    acc.dev.imuSensorToUse = gyroConfig()->gyro_to_use;     // Use the same selection from gyroConfig()
#else
    acc.dev.imuSensorToUse = 0;
#endif
    //识别
    if (!accDetect(&acc.dev, accelerometerConfig()->acc_hardware))
    {
        return false;
    }

    acc.dev.acc_1G = 256; // set default
    acc.dev.initFn(&acc.dev);
    acc.accTargetLooptime = targetLooptime;
    acc.accClipCount = 0;
    accInitFilters();
    updateAccCoefficients();

    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++)
    {
        acc.extremes[axis].min = 100;
        acc.extremes[axis].max = -100;
    }

    return true;
}
static bool accDetect(accDev_t *dev, accelerationSensor_e accHardwareToUse)
{
    accelerationSensor_e accHardware = ACC_NONE;

    dev->accAlign = ALIGN_DEFAULT;

    requestedSensors[SENSOR_INDEX_ACC] = accHardwareToUse;

    switch (accHardwareToUse) {
    case ACC_AUTODETECT:
        FALLTHROUGH;

#ifdef USE_IMU_MPU6000
    case ACC_MPU6000:
        if (mpu6000AccDetect(dev)) {
            accHardware = ACC_MPU6000;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#if defined(USE_IMU_MPU6500)
    case ACC_MPU6500:
        if (mpu6500AccDetect(dev)) {
            accHardware = ACC_MPU6500;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#if defined(USE_IMU_MPU9250)
    case ACC_MPU9250:
        if (mpu9250AccDetect(dev)) {
            accHardware = ACC_MPU9250;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#if defined(USE_IMU_BMI160)
    case ACC_BMI160:
        if (bmi160AccDetect(dev)) {
            accHardware = ACC_BMI160;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#if defined(USE_IMU_BMI088)
    case ACC_BMI088:
        if (bmi088AccDetect(dev)) {
            accHardware = ACC_BMI088;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_ICM20689
    case ACC_ICM20689:
        if (icm20689AccDetect(dev)) {
            accHardware = ACC_ICM20689;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_ICM42605
    case ACC_ICM42605:
        if (icm42605AccDetect(dev)) {
            accHardware = ACC_ICM42605;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

#ifdef USE_IMU_BMI270
    case ACC_BMI270:
        if (bmi270AccDetect(dev)) {
            accHardware = ACC_BMI270;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif
#ifdef USE_IMU_LSM6DXX
    case ACC_LSM6DXX:
        if (lsm6dAccDetect(dev)) {
            accHardware = ACC_LSM6DXX;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif
#ifdef USE_IMU_FAKE
    case ACC_FAKE:
        if (fakeAccDetect(dev)) {
            accHardware = ACC_FAKE;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif

    default:
    case ACC_NONE: // disable ACC
        accHardware = ACC_NONE;
        break;
    }

    if (accHardware == ACC_NONE) {
        return false;
    }

    detectedSensors[SENSOR_INDEX_ACC] = accHardware;
    sensorsSet(SENSOR_ACC);
    return true;
}

重点关注:

#ifdef USE_IMU_ICM42605
    case ACC_ICM42605:
        if (icm42605AccDetect(dev)) {
            accHardware = ACC_ICM42605;
            break;
        }
        /* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
        if (accHardwareToUse != ACC_AUTODETECT) {
            break;
        }
        FALLTHROUGH;
#endif
bool icm42605AccDetect(accDev_t *acc)
{
    acc->busDev = busDeviceOpen(BUSTYPE_ANY, DEVHW_ICM42605, acc->imuSensorToUse);
    if (acc->busDev == NULL) {
        return false;
    }

    mpuContextData_t * ctx = busDeviceGetScratchpadMemory(acc->busDev);
    if (ctx->chipMagicNumber != 0x4265) {
        return false;
    }

    acc->initFn = icm42605AccInit;
    acc->readFn = icm42605AccRead;
    acc->accAlign = acc->busDev->param;

    return true;
}

对于其他的配置后续在深入讲解

4.IMU 程序数据更新

4.1 陀螺仪数据更新

void FAST_CODE NOINLINE gyroUpdate(void)
{
#ifdef USE_SIMULATOR
    if (ARMING_FLAG(SIMULATOR_MODE_HITL)) {
        //output: gyro.gyroADCf[axis]
        //unused: dev->gyroADCRaw[], dev->gyroZero[];
        return;
    }
#endif
    if (!gyro.initialized) {
        return;
    }

    if (!gyroUpdateAndCalibrate(&gyroDev[0], &gyroCalibration[0], gyro.gyroADCf)) {
        return;
    }

    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        // At this point gyro.gyroADCf contains unfiltered gyro value [deg/s]
        float gyroADCf = gyro.gyroADCf[axis];

        // Set raw gyro for blackbox purposes
        gyro.gyroRaw[axis] = gyroADCf;

        /*
         * First gyro LPF is the only filter applied with the full gyro sampling speed
         */
        gyroADCf = gyroLpfApplyFn((filter_t *) &gyroLpfState[axis], gyroADCf);

        gyro.gyroADCf[axis] = gyroADCf;
    }
}

最终我们得到陀螺仪数据:

 gyro.gyroADCf[axis] = gyroADCf;

下面我们看下数据如何周期性执行的

// Function for loop trigger
void FAST_CODE taskGyro(timeUs_t currentTimeUs) {
    UNUSED(currentTimeUs);
    // getTaskDeltaTime() returns delta time frozen at the moment of entering the scheduler. currentTime is frozen at the very same point.
    // To make busy-waiting timeout work we need to account for time spent within busy-waiting loop
    const timeDelta_t currentDeltaTime = getTaskDeltaTime(TASK_SELF);

    /* Update actual hardware readings */
    //更新实际的数据读取
    gyroUpdate();

#ifdef USE_OPFLOW
    if (sensors(SENSOR_OPFLOW)) {
        opflowGyroUpdateCallback(currentDeltaTime);
    }
#endif
}

在这里插入图片描述
可以看出这里在一个任务列表中。我们需要看下任务是如何启动的:

void fcTasksInit(void)
{
	//任务调度初始化
    schedulerInit();
    //PID任务
    rescheduleTask(TASK_PID, getLooptime());
    setTaskEnabled(TASK_PID, true);
    //陀螺仪任务
    rescheduleTask(TASK_GYRO, getGyroLooptime());
    setTaskEnabled(TASK_GYRO, true);
    //任务开关初始化使能
    setTaskEnabled(TASK_AUX, true);
    //串口使能
    setTaskEnabled(TASK_SERIAL, true);
#if defined(BEEPER) || defined(USE_DSHOT)
    //蜂鸣器使能
    setTaskEnabled(TASK_BEEPER, true);
#endif
#ifdef USE_LIGHTS
    setTaskEnabled(TASK_LIGHTS, true);
#endif
    //电池使能
    setTaskEnabled(TASK_BATTERY, feature(FEATURE_VBAT) || isAmperageConfigured());
    setTaskEnabled(TASK_TEMPERATURE, true);
    setTaskEnabled(TASK_RX, true);
#ifdef USE_GPS
    setTaskEnabled(TASK_GPS, feature(FEATURE_GPS));
#endif
#ifdef USE_MAG
    setTaskEnabled(TASK_COMPASS, sensors(SENSOR_MAG));
#if defined(USE_MAG_MPU9250)
    // fixme temporary solution for AK6983 via slave I2C on MPU9250
    rescheduleTask(TASK_COMPASS, TASK_PERIOD_HZ(40));
#endif
#endif
#ifdef USE_BARO
    //气压计使能
    setTaskEnabled(TASK_BARO, sensors(SENSOR_BARO));
#endif
#ifdef USE_PITOT
    //飞行传感器使能
    setTaskEnabled(TASK_PITOT, sensors(SENSOR_PITOT));
#endif
#ifdef USE_ADSB
    setTaskEnabled(TASK_ADSB, true);
#endif
#ifdef USE_RANGEFINDER
    //测距仪使能
    setTaskEnabled(TASK_RANGEFINDER, sensors(SENSOR_RANGEFINDER));
#endif
#ifdef USE_DASHBOARD
    setTaskEnabled(TASK_DASHBOARD, feature(FEATURE_DASHBOARD));
#endif
#ifdef USE_TELEMETRY
    setTaskEnabled(TASK_TELEMETRY, feature(FEATURE_TELEMETRY));
#endif
#ifdef USE_LED_STRIP
    //LED 使能
    setTaskEnabled(TASK_LEDSTRIP, feature(FEATURE_LED_STRIP));
#endif
#ifdef STACK_CHECK
    setTaskEnabled(TASK_STACK_CHECK, true);
#endif
#if defined(USE_SERVO_SBUS)
    setTaskEnabled(TASK_PWMDRIVER, (servoConfig()->servo_protocol == SERVO_TYPE_SBUS) || (servoConfig()->servo_protocol == SERVO_TYPE_SBUS_PWM));
#endif
#ifdef USE_CMS
#ifdef USE_MSP_DISPLAYPORT
    setTaskEnabled(TASK_CMS, true);
#else
    setTaskEnabled(TASK_CMS, feature(FEATURE_OSD) || feature(FEATURE_DASHBOARD));
#endif
#endif
#ifdef USE_OPFLOW
    setTaskEnabled(TASK_OPFLOW, sensors(SENSOR_OPFLOW));
#endif
#ifdef USE_VTX_CONTROL
#if defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP) || defined(USE_VTX_MSP)
    setTaskEnabled(TASK_VTXCTRL, true);
#endif
#endif
#ifdef USE_RCDEVICE
#ifdef USE_LED_STRIP
    setTaskEnabled(TASK_RCDEVICE, rcdeviceIsEnabled() || osdJoystickEnabled());
#else
    setTaskEnabled(TASK_RCDEVICE, rcdeviceIsEnabled());
#endif
#endif
#ifdef USE_PROGRAMMING_FRAMEWORK
    setTaskEnabled(TASK_PROGRAMMING_FRAMEWORK, true);
#endif
#ifdef USE_IRLOCK
    setTaskEnabled(TASK_IRLOCK, irlockHasBeenDetected());
#endif
#if defined(USE_SMARTPORT_MASTER)
    setTaskEnabled(TASK_SMARTPORT_MASTER, true);
#endif

#ifdef USE_SERIAL_GIMBAL
    setTaskEnabled(TASK_GIMBAL, true);
#endif

#ifdef USE_HEADTRACKER
    setTaskEnabled(TASK_HEADTRACKER, true);
#endif

#if defined(USE_TELEMETRY) && defined(USE_TELEMETRY_SBUS2)
    setTaskEnabled(TASK_TELEMETRY_SBUS2,feature(FEATURE_TELEMETRY) && rxConfig()->receiverType == RX_TYPE_SERIAL && rxConfig()->serialrx_provider == SERIALRX_SBUS2);
#endif

#ifdef USE_ADAPTIVE_FILTER
    setTaskEnabled(TASK_ADAPTIVE_FILTER, (
        gyroConfig()->gyroFilterMode == GYRO_FILTER_MODE_ADAPTIVE && 
        gyroConfig()->adaptiveFilterMinHz > 0 && 
        gyroConfig()->adaptiveFilterMaxHz > 0
    ));
#endif

#if defined(SITL_BUILD)
    serialProxyStart();
#endif

#ifdef USE_GEOZONE
    setTaskEnabled(TASK_GEOZONE, feature(FEATURE_GEOZONE));
#endif

}

我们只需要重点关注:

    //陀螺仪任务
    rescheduleTask(TASK_GYRO, getGyroLooptime());
    setTaskEnabled(TASK_GYRO, true);

加速度数据更新

void accUpdate(void)
{
#ifdef USE_SIMULATOR
    if (ARMING_FLAG(SIMULATOR_MODE_HITL)) {
        //output: acc.accADCf
        //unused: acc.dev.ADCRaw[], acc.accClipCount, acc.accVibeSq[]
        return;
    }
#endif
    if (!acc.dev.readFn(&acc.dev)) {
        return;
    }
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        accADC[axis] = acc.dev.ADCRaw[axis];
        DEBUG_SET(DEBUG_ACC, axis, accADC[axis]);
    }

    if (!ARMING_FLAG(SIMULATOR_MODE_SITL)) {
        performAcclerationCalibration();
        applyAccelerationZero();  
    } 

    applySensorAlignment(accADC, accADC, acc.dev.accAlign);
    applyBoardAlignment(accADC);

    // Calculate acceleration readings in G's
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        acc.accADCf[axis] = (float)accADC[axis] / acc.dev.acc_1G;
    }

    // Before filtering check for clipping and vibration levels
    if (fabsf(acc.accADCf[X]) > ACC_CLIPPING_THRESHOLD_G || fabsf(acc.accADCf[Y]) > ACC_CLIPPING_THRESHOLD_G || fabsf(acc.accADCf[Z]) > ACC_CLIPPING_THRESHOLD_G) {
        acc.isClipped = true;
        acc.accClipCount++;
    }
    else {
        acc.isClipped = false;
    }

    // Calculate vibration levels
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        // filter accel at 5hz
        const float accFloorFilt = pt1FilterApply(&accVibeFloorFilter[axis], acc.accADCf[axis]);

        // calc difference from this sample and 5hz filtered value, square and filter at 2hz
        const float accDiff = acc.accADCf[axis] - accFloorFilt;
        acc.accVibeSq[axis] = pt1FilterApply(&accVibeFilter[axis], accDiff * accDiff);
        acc.accVibe = fast_fsqrtf(acc.accVibeSq[X] + acc.accVibeSq[Y] + acc.accVibeSq[Z]);
    }

    // Filter acceleration
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        acc.accADCf[axis] = accSoftLpfFilterApplyFn(accSoftLpfFilter[axis], acc.accADCf[axis]);
    }

    if (accelerometerConfig()->acc_notch_hz) {
        for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
            acc.accADCf[axis] = accNotchFilterApplyFn(accNotchFilter[axis], acc.accADCf[axis]);
        }
    }

}
void setTaskEnabled(cfTaskId_e taskId, bool enabled)
{
    if (taskId == TASK_SELF || taskId < TASK_COUNT) {
        cfTask_t *task = taskId == TASK_SELF ? currentTask : &cfTasks[taskId];
        if (enabled && task->taskFunc) 
        {
        	//添加到消息队列中去
            queueAdd(task);
        } else 
        {
            queueRemove(task);
        }
    }
}

添加进去后,随着任务周期性执行。

在这里插入图片描述

void FAST_CODE NOINLINE scheduler(void)
{
    // Cache currentTime
    const timeUs_t currentTimeUs = micros();

    // The task to be invoked
    cfTask_t *selectedTask = NULL;
    uint16_t selectedTaskDynamicPriority = 0;
    bool forcedRealTimeTask = false;

    // Update task dynamic priorities
    uint16_t waitingTasks = 0;
    for (cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) 
    {
        // Task has checkFunc - event driven
        if (task->checkFunc) {
            const timeUs_t currentTimeBeforeCheckFuncCallUs = micros();

            // Increase priority for event driven tasks
            if (task->dynamicPriority > 0) {
                task->taskAgeCycles = 1 + ((timeDelta_t)(currentTimeUs - task->lastSignaledAt)) / task->desiredPeriod;
                task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles;
                waitingTasks++;
            } else if (task->checkFunc(currentTimeBeforeCheckFuncCallUs, currentTimeBeforeCheckFuncCallUs - task->lastExecutedAt)) {
                const timeUs_t checkFuncExecutionTime = micros() - currentTimeBeforeCheckFuncCallUs;
                checkFuncMovingSumExecutionTime -= checkFuncMovingSumExecutionTime / TASK_MOVING_SUM_COUNT;
                checkFuncMovingSumExecutionTime += checkFuncExecutionTime;
                checkFuncTotalExecutionTime += checkFuncExecutionTime;   // time consumed by scheduler + task
                checkFuncMaxExecutionTime = MAX(checkFuncMaxExecutionTime, checkFuncExecutionTime);
                task->lastSignaledAt = currentTimeBeforeCheckFuncCallUs;
                task->taskAgeCycles = 1;
                task->dynamicPriority = 1 + task->staticPriority;
                waitingTasks++;
            } else {
                task->taskAgeCycles = 0;
            }
        } else if (task->staticPriority == TASK_PRIORITY_REALTIME) {
            //realtime tasks take absolute priority. Any RT tasks that is overdue, should be execute immediately
            if (((timeDelta_t)(currentTimeUs - task->lastExecutedAt)) > task->desiredPeriod) {
                selectedTaskDynamicPriority = task->dynamicPriority;
                selectedTask = task;
                waitingTasks++;
                forcedRealTimeTask = true;
            }
        } else {
            // Task is time-driven, dynamicPriority is last execution age (measured in desiredPeriods)
            // Task age is calculated from last execution
            task->taskAgeCycles = ((timeDelta_t)(currentTimeUs - task->lastExecutedAt)) / task->desiredPeriod;
            if (task->taskAgeCycles > 0) {
                task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles;
                waitingTasks++;
            }
        }

        if (!forcedRealTimeTask && task->dynamicPriority > selectedTaskDynamicPriority) {
            selectedTaskDynamicPriority = task->dynamicPriority;
            selectedTask = task;
        }
    }

    totalWaitingTasksSamples++;
    totalWaitingTasks += waitingTasks;

    currentTask = selectedTask;

    if (selectedTask) {
        // Found a task that should be run
        selectedTask->taskLatestDeltaTime = (timeDelta_t)(currentTimeUs - selectedTask->lastExecutedAt);
        selectedTask->lastExecutedAt = currentTimeUs;
        selectedTask->dynamicPriority = 0;

        // Execute task
        const timeUs_t currentTimeBeforeTaskCall = micros();
        selectedTask->taskFunc(currentTimeBeforeTaskCall);
        const timeUs_t taskExecutionTime = micros() - currentTimeBeforeTaskCall;
        selectedTask->movingSumExecutionTime += taskExecutionTime - selectedTask->movingSumExecutionTime / TASK_MOVING_SUM_COUNT;
        selectedTask->totalExecutionTime += taskExecutionTime;   // time consumed by scheduler + task
        selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime);
    } 
    
    if (!selectedTask || forcedRealTimeTask) {
        // Execute system real-time callbacks and account for them to SYSTEM account
        const timeUs_t currentTimeBeforeTaskCall = micros();
        taskRunRealtimeCallbacks(currentTimeBeforeTaskCall);
        selectedTask = &cfTasks[TASK_SYSTEM];
        const timeUs_t taskExecutionTime = micros() - currentTimeBeforeTaskCall;
        selectedTask->movingSumExecutionTime += taskExecutionTime - selectedTask->movingSumExecutionTime / TASK_MOVING_SUM_COUNT;
        selectedTask->totalExecutionTime += taskExecutionTime;   // time consumed by scheduler + task
        selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime);
    }
}

整体思路:
在这里插入图片描述

4.2 加速度数据更新

void accUpdate(void)
{
#ifdef USE_SIMULATOR
    if (ARMING_FLAG(SIMULATOR_MODE_HITL)) {
        //output: acc.accADCf
        //unused: acc.dev.ADCRaw[], acc.accClipCount, acc.accVibeSq[]
        return;
    }
#endif
    if (!acc.dev.readFn(&acc.dev)) {
        return;
    }
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        accADC[axis] = acc.dev.ADCRaw[axis];
        DEBUG_SET(DEBUG_ACC, axis, accADC[axis]);
    }

    if (!ARMING_FLAG(SIMULATOR_MODE_SITL)) {
        performAcclerationCalibration();
        applyAccelerationZero();  
    } 

    applySensorAlignment(accADC, accADC, acc.dev.accAlign);
    applyBoardAlignment(accADC);

    // Calculate acceleration readings in G's
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        acc.accADCf[axis] = (float)accADC[axis] / acc.dev.acc_1G;
    }

    // Before filtering check for clipping and vibration levels
    if (fabsf(acc.accADCf[X]) > ACC_CLIPPING_THRESHOLD_G || fabsf(acc.accADCf[Y]) > ACC_CLIPPING_THRESHOLD_G || fabsf(acc.accADCf[Z]) > ACC_CLIPPING_THRESHOLD_G) {
        acc.isClipped = true;
        acc.accClipCount++;
    }
    else {
        acc.isClipped = false;
    }

    // Calculate vibration levels
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        // filter accel at 5hz
        const float accFloorFilt = pt1FilterApply(&accVibeFloorFilter[axis], acc.accADCf[axis]);

        // calc difference from this sample and 5hz filtered value, square and filter at 2hz
        const float accDiff = acc.accADCf[axis] - accFloorFilt;
        acc.accVibeSq[axis] = pt1FilterApply(&accVibeFilter[axis], accDiff * accDiff);
        acc.accVibe = fast_fsqrtf(acc.accVibeSq[X] + acc.accVibeSq[Y] + acc.accVibeSq[Z]);
    }

    // Filter acceleration
    for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
        acc.accADCf[axis] = accSoftLpfFilterApplyFn(accSoftLpfFilter[axis], acc.accADCf[axis]);
    }

    if (accelerometerConfig()->acc_notch_hz) {
        for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
            acc.accADCf[axis] = accNotchFilterApplyFn(accNotchFilter[axis], acc.accADCf[axis]);
        }
    }

}
void imuUpdateAccelerometer(void)
{
    if (sensors(SENSOR_ACC)) {
        accUpdate();
        isAccelUpdatedAtLeastOnce = true;
    }
}
void taskMainPidLoop(timeUs_t currentTimeUs)
{
   ......
    imuUpdateAccelerometer();
  ......
 }

在这里插入图片描述

void fcTasksInit(void)
{
	//任务调度初始化
    schedulerInit();
    //PID任务
    rescheduleTask(TASK_PID, getLooptime());
    setTaskEnabled(TASK_PID, true);
    ......
 }

这里随着任务的添加而随着任务调度执行。

5.IMU 数据怎么被使用

IMU数据正常都是在姿态解算和控制中使用:

imuUpdateAttitude(currentTimeUs);
void imuUpdateAttitude(timeUs_t currentTimeUs)
{
    /* Calculate dT */
    static timeUs_t previousIMUUpdateTimeUs;
    const float dT = (currentTimeUs - previousIMUUpdateTimeUs) * 1e-6;
    previousIMUUpdateTimeUs = currentTimeUs;

    if (sensors(SENSOR_ACC) && isAccelUpdatedAtLeastOnce) {
        gyroGetMeasuredRotationRate(&imuMeasuredRotationBF);    // Calculate gyro rate in body frame in rad/s
        accGetMeasuredAcceleration(&imuMeasuredAccelBF);  // Calculate accel in body frame in cm/s/s
        imuCheckVibrationLevels();
        imuCalculateEstimatedAttitude(dT);  // Update attitude estimate
    } else {
        acc.accADCf[X] = 0.0f;
        acc.accADCf[Y] = 0.0f;
        acc.accADCf[Z] = 0.0f;
    }
}

重点关注:

        gyroGetMeasuredRotationRate(&imuMeasuredRotationBF);    // Calculate gyro rate in body frame in rad/s
        accGetMeasuredAcceleration(&imuMeasuredAccelBF);  // Calculate accel in body frame in cm/s/s
void gyroGetMeasuredRotationRate(fpVector3_t *measuredRotationRate)
{
    for (int axis = 0; axis < 3; axis++) {
        measuredRotationRate->v[axis] = DEGREES_TO_RADIANS(gyro.gyroADCf[axis]);
    }
}

可以看出:

gyro.gyroADCf[axis]

FASTRAM gyro_t gyro; // gyro sensor object

void accGetMeasuredAcceleration(fpVector3_t *measuredAcc)
{
    arm_scale_f32(acc.accADCf, GRAVITY_CMSS, measuredAcc->v, XYZ_AXIS_COUNT);
}

FASTRAM acc_t acc; // acc access functions

到这里我们可以看出重要的就是IMU输出的数据:

gyro.gyroADCf[axis]
acc.accADCf

6.总结

本节主要对IMU的整体数据流进行了分析,很多细节梳理的还不够完善,后续会在继续分析。


网站公告

今日签到

点亮在社区的每一天
去签到