ArduPilot开源飞控之AP_Compass

news/2024/7/10 19:58:22 标签: 开源, Ardupilot

ArduPilot开源飞控之AP_Compass

  • 1. 源由
  • 2. 框架设计
    • 2.1 启动代码
    • 2.2 任务代码
  • 3. 重要例程
    • 3.1 init
    • 3.2 read
    • 3.3 _detect_backends
    • 3.4 _probe_external_i2c_compasses
  • 4. 总结
  • 5. 参考资料

1. 源由

磁力计应该不是一个非常复杂的传感器,但是确实是一个非常重要的感知机头(飞行)方向的部件。

在实际应用过程中需要考虑霍尔的物理原理。因此,该传感 器件周边要减少电磁场,以减小对罗盘的影响。

主要方法:

  1. 避开RF信号发射源
  2. 避开大电流线缆
  3. 尽量原理EMC发射源
  4. 供电电源尽量减少纹波信号
  5. 适当的线缆屏蔽有一定效果

APM在校准磁力计有时确实存在一定的难度,始终无法得到好的效果,可以借鉴:ArduPilot开源飞控之磁力计校准

2. 框架设计

2.1 启动代码

Copter::init_ardupilot
 └──> Compass::init
     └──> Compass::_detect_backends
         └──> Compass::_probe_external_i2c_compasses

2.2 任务代码

FAST_TASK(read_AHRS)
 └──> Copter::read_AHRS
     └──> AP_AHRS::update
         └──> AP_AHRS::update_DCM
             └──> AP_AHRS_DCM::update
                 └──> AP_AHRS_DCM::drift_correction
                     └──> AP_AHRS_DCM::drift_correction_yaw
                         └──> Compass::read

3. 重要例程

3.1 init

Ardupilot关于芯片方向的配置有以下几种:

// these rotations form a full set - every rotation in the following
// list when combined with another in the list forms an entry which is
// also in the list. This is an important property. Please run the
// rotations test suite if you add to the list.

// NOTE!! these rotation values are stored to EEPROM, so be careful not to
// change the numbering of any existing entry when adding a new entry.
enum Rotation : uint8_t {
    ROTATION_NONE                = 0,
    ROTATION_YAW_45              = 1,
    ROTATION_YAW_90              = 2,
    ROTATION_YAW_135             = 3,
    ROTATION_YAW_180             = 4,
    ROTATION_YAW_225             = 5,
    ROTATION_YAW_270             = 6,
    ROTATION_YAW_315             = 7,
    ROTATION_ROLL_180            = 8,
    ROTATION_ROLL_180_YAW_45     = 9,
    ROTATION_ROLL_180_YAW_90     = 10,
    ROTATION_ROLL_180_YAW_135    = 11,
    ROTATION_PITCH_180           = 12,
    ROTATION_ROLL_180_YAW_225    = 13,
    ROTATION_ROLL_180_YAW_270    = 14,
    ROTATION_ROLL_180_YAW_315    = 15,
    ROTATION_ROLL_90             = 16,
    ROTATION_ROLL_90_YAW_45      = 17,
    ROTATION_ROLL_90_YAW_90      = 18,
    ROTATION_ROLL_90_YAW_135     = 19,
    ROTATION_ROLL_270            = 20,
    ROTATION_ROLL_270_YAW_45     = 21,
    ROTATION_ROLL_270_YAW_90     = 22,
    ROTATION_ROLL_270_YAW_135    = 23,
    ROTATION_PITCH_90            = 24,
    ROTATION_PITCH_270           = 25,
    ROTATION_PITCH_180_YAW_90    = 26, // same as ROTATION_ROLL_180_YAW_270
    ROTATION_PITCH_180_YAW_270   = 27, // same as ROTATION_ROLL_180_YAW_90
    ROTATION_ROLL_90_PITCH_90    = 28,
    ROTATION_ROLL_180_PITCH_90   = 29,
    ROTATION_ROLL_270_PITCH_90   = 30,
    ROTATION_ROLL_90_PITCH_180   = 31,
    ROTATION_ROLL_270_PITCH_180  = 32,
    ROTATION_ROLL_90_PITCH_270   = 33,
    ROTATION_ROLL_180_PITCH_270  = 34,
    ROTATION_ROLL_270_PITCH_270  = 35,
    ROTATION_ROLL_90_PITCH_180_YAW_90 = 36,
    ROTATION_ROLL_90_YAW_270     = 37,
    ROTATION_ROLL_90_PITCH_68_YAW_293 = 38, // this is actually, roll 90, pitch 68.8, yaw 293.3
    ROTATION_PITCH_315           = 39,
    ROTATION_ROLL_90_PITCH_315   = 40,
    ROTATION_PITCH_7             = 41,
    ROTATION_ROLL_45             = 42,
    ROTATION_ROLL_315            = 43,
    ///
    // Do not add more rotations without checking that there is not a conflict
    // with the MAVLink spec. MAV_SENSOR_ORIENTATION is expected to match our
    // list of rotations here. If a new rotation is added it needs to be added
    // to the MAVLink messages as well.
    ///
    ROTATION_MAX,
    ROTATION_CUSTOM_OLD          = 100,
    ROTATION_CUSTOM_1            = 101,
    ROTATION_CUSTOM_2            = 102,
    ROTATION_CUSTOM_END,
};

整个初始化过程涉及: 芯片方向,主芯片选择,驱动初始化等。

Compass::init
 │
 │  /********************************************************************************
 │   * Pre-check: Ability Configuration                                             *
 │   ********************************************************************************/
 ├──> <!_enabled>
 │   └──> return;
 │
 │  /********************************************************************************
 │   * convert to new custom rotation method.                                       *
 │   ********************************************************************************/
 ├──> <!APM_BUILD_TYPE(APM_BUILD_AP_Periph)> <for (StateIndex i(0); i<COMPASS_MAX_INSTANCES; i++)>
 │   ├──> <_state[i].orientation != ROTATION_CUSTOM_OLD>
 │   │   └──> continue;
 │   │
 │   │    // ROTATION_CUSTOM_2 for compass, ROTATION_CUSTOM_1 for board orientation
 │   ├──> _state[i].orientation.set_and_save(ROTATION_CUSTOM_2);
 │   │
 │   │    // Get rotation configuration and custom rotation convert
 │   ├──> AP_Param::ConversionInfo info;
 │   ├──> <AP_Param::find_top_level_key_by_pointer(this, info.old_key)>
 │   │   ├──> info.type = AP_PARAM_FLOAT;
 │   │   ├──> float rpy[3] = {};
 │   │   ├──> AP_Float rpy_param;
 │   │   ├──> <for (info.old_group_element=49; info.old_group_element<=51; info.old_group_element++)>
 │   │   │   └──> <AP_Param::find_old_parameter(&info, &rpy_param)>
 │   │   │       └──> rpy[info.old_group_element-49] = rpy_param.get();
 │   │   └──> AP::custom_rotations().convert(ROTATION_CUSTOM_2, rpy[0], rpy[1], rpy[2]);
 │   └──> break;
 │
 │  /********************************************************************************
 │   * select primary compass for multi-compass                                     *
 │   ********************************************************************************/
 ├──> <COMPASS_MAX_INSTANCES > 1>
 │   │
 │   │    // Look if there was a primary compass setup in previous version
 │   │    // if so and the primary compass is not set in current setup
 │   │    // make the devid as primary.
 │   ├──> <_priority_did_stored_list[Priority(0)] == 0>
 │   │   ├──> uint16_t k_param_compass;
 │   │   └──> <AP_Param::find_top_level_key_by_pointer(this, k_param_compass)>
 │   │       ├──> const AP_Param::ConversionInfo primary_compass_old_param = {k_param_compass, 12, AP_PARAM_INT8, ""};
 │   │       ├──> AP_Int8 value;
 │   │       ├──> value.set(0);
 │   │       ├──> bool primary_param_exists = AP_Param::find_old_parameter(&primary_compass_old_param, &value);
 │   │       ├──> int8_t oldvalue = value.get();
 │   │       └──> <(oldvalue!=0) && (oldvalue<COMPASS_MAX_INSTANCES) && primary_param_exists>
 │   │           └──> _priority_did_stored_list[Priority(0)].set_and_save_ifchanged(_state[StateIndex(oldvalue)].dev_id);
 │   │
 │   │    // Load priority list from storage, the changes to priority list
 │   │    // by user only take effect post reboot, after this
 │   └──> <for (Priority i(0); i<COMPASS_MAX_INSTANCES; i++)>
 │       ├──> <_priority_did_stored_list[i] != 0>
 │       │    └──> _priority_did_list[i] = _priority_did_stored_list[i];
 │       └──> < else > <for (Priority j(i+1); j<COMPASS_MAX_INSTANCES; j++)> // Maintain a list without gaps and duplicates
 │           ├──> int32_t temp;
 │           ├──> if (_priority_did_stored_list[j] == _priority_did_stored_list[i]) {
 │           │   └──> __priority_did_stored_list[j].set_and_save_ifchanged(0);
 │           ├──> if (_priority_did_stored_list[j] == 0) {
 │           │   └──> _continue;
 │           ├──> temp = _priority_did_stored_list[j];
 │           ├──> _priority_did_stored_list[j].set_and_save_ifchanged(0);
 │           ├──> _priority_did_list[i] = temp;
 │           ├──> _priority_did_stored_list[i].set_and_save_ifchanged(temp);
 │           └──> break;
 │
 │    // cache expected dev ids for use during runtime detection
 ├──> <for (StateIndex i(0); i<COMPASS_MAX_INSTANCES; i++) >
 │   └──> _state[i].expected_dev_id = _state[i].dev_id;
 ├──> <COMPASS_MAX_UNREG_DEV>
 │   │   // set the dev_id to 0 for undetected compasses. extra_dev_id is just an
 │   │   // interface for users to see unreg compasses, we actually never store it
 │   │   // in storage.
 │   └──> <for (uint8_t i=_unreg_compass_count; i<COMPASS_MAX_UNREG_DEV; i++) >
 │       │   // cache the extra devices detected in last boot
 │       │   // for detecting replacement mag
 │       ├──> _previously_unreg_mag[i] = extra_dev_id[i];
 │       └──> extra_dev_id[i].set_and_save(0);
 │
 ├──> <COMPASS_MAX_INSTANCES > 1
 │   │   // This method calls set_and_save_ifchanged on parameters
 │   │   // which are set() but not saved() during normal runtime,
 │   │   // do not move this call without ensuring that is not happening
 │   │   // read comments under set_and_save_ifchanged for details
 │   └──> _reorder_compass_params();
 │
 │  /********************************************************************************
 │   * Detect sensors                                                               *
 │   ********************************************************************************/
 ├──> <_compass_count == 0> // detect available backends. Only called once
 │   └──> _detect_backends();
 │
 ├──> <COMPASS_MAX_UNREG_DEV>
 │   │   // We store the list of unregistered mags detected here,
 │   │   // We don't do this during runtime, as we don't want to detect
 │   │   // compasses connected by user as a replacement while the system
 │   │   // is running
 │   └──> <for (uint8_t i=0; i<COMPASS_MAX_UNREG_DEV; i++)>
 │       └──> extra_dev_id[i].save();
 │
 ├──> <_compass_count != 0> // get initial health status  
 │   ├──> hal.scheduler->delay(100);
 │   └──> read();
 │
 │  // set the dev_id to 0 for undetected compasses, to make it easier
 │  // for users to see how many compasses are detected. We don't do a
 │  // set_and_save() as the user may have temporarily removed the
 │  // compass, and we don't want to force a re-cal if they plug it
 │  // back in again
 ├──> <for (StateIndex i(0); i<COMPASS_MAX_INSTANCES; i++)> <!_state[i].registered>
 │   └──> _state[i].dev_id.set(0);
 │
 ├──> <HAL_BUILD_AP_PERIPH>  // updating the AHRS orientation updates our own orientation:
 │   └──> _AP::ahrs().update_orientation();
 └──> init_done = true;

3.2 read

Compass::read
 │
 │  /********************************************************************************
 │   * Pre-check: Availability                                                      *
 │   ********************************************************************************/
 ├──> <!available()>
 │   └──> return false;
 │
 ├──> <HAL_LOGGING_ENABLED>
 │   └──> const bool old_healthy = healthy();
 │
 ├──> <HAL_BUILD_AP_PERIPH> <!_initial_location_set>
 │   └──> try_set_initial_location();
 ├──> _detect_runtime();
 │
 │  /********************************************************************************
 │   * Compass data read                                                            *
 │   ********************************************************************************/
 ├──> <for (uint8_t i=0; i< _backend_count; i++)>
 │   └──> _backends[i]->read(); // call read on each of the backend. This call updates field[i]
 │
 │  // health status update
 ├──> uint32_t time = AP_HAL::millis();
 ├──> bool any_healthy = false;
 ├──> <for (StateIndex i(0); i < COMPASS_MAX_INSTANCES; i++)>
 │   ├──> _state[i].healthy = (time - _state[i].last_update_ms < 500);
 │   └──> any_healthy |= _state[i].healthy;
 │
 │  // health status update
 ├──> <COMPASS_LEARN_ENABLED>
 │   ├──> <_learn == LEARN_INFLIGHT && !learn_allocated>
 │   │   ├──> learn_allocated = true;
 │   │   └──> learn = new CompassLearn(*this);
 │   └──> <_learn == LEARN_INFLIGHT && learn != nullptr>
 │       └──> learn->update();
 │
 ├──> <HAL_LOGGING_ENABLED> <any_healthy && _log_bit != (uint32_t)-1 && AP::logger().should_log(_log_bit)>
 │   └──> AP::logger().Write_Compass();
 │
 │  // Set _first_usable parameter
 ├──> <for (Priority i(0); i<COMPASS_MAX_INSTANCES; i++)>
 │   └──> <_use_for_yaw[i]>
 │       ├──> _first_usable = uint8_t(i);
 │       └──> break;
 ├──> const bool new_healthy = healthy();
 │
 ├──> <HAL_LOGGING_ENABLED>
 │   ├──> #define MASK_LOG_ANY                    0xFFFF
 │   └──> <new_healthy != old_healthy> <AP::logger().should_log(MASK_LOG_ANY)>
 │       ├──> const LogErrorCode code = new_healthy ? LogErrorCode::ERROR_RESOLVED : LogErrorCode::UNHEALTHY;
 │       └──> AP::logger().Write_Error(LogErrorSubsystem::COMPASS, code);
 └──> return new_healthy;

3.3 _detect_backends

支持类型:

  1. AP_Compass_ExternalAHRS
  2. AP_Compass_SITL
  3. AP_Compass_MSP
  4. AP_Compass_BMM150
  5. AP_Compass_HMC5843
  6. AP_Compass_LSM303D
  7. AP_Compass_AK8963
  8. AP_Compass_AK09916
  9. AP_Compass_IST8310
  10. AP_Compass_LIS3MDL
  11. AP_Compass_DroneCAN
/*
  detect available backends for this board
 */
void Compass::_detect_backends(void)
{
#if AP_COMPASS_EXTERNALAHRS_ENABLED
    const int8_t serial_port = AP::externalAHRS().get_port(AP_ExternalAHRS::AvailableSensor::COMPASS);
    if (serial_port >= 0) {
        ADD_BACKEND(DRIVER_EXTERNALAHRS, new AP_Compass_ExternalAHRS(serial_port));
    }
#endif
    
#if AP_FEATURE_BOARD_DETECT
    if (AP_BoardConfig::get_board_type() == AP_BoardConfig::PX4_BOARD_PIXHAWK2) {
        // default to disabling LIS3MDL on pixhawk2 due to hardware issue
#if AP_COMPASS_LIS3MDL_ENABLED
    _driver_type_mask.set_default(1U<<DRIVER_LIS3MDL);
#endif
    }
#endif

#if AP_COMPASS_SITL_ENABLED && !AP_TEST_DRONECAN_DRIVERS
    ADD_BACKEND(DRIVER_SITL, new AP_Compass_SITL());
#endif

#ifdef HAL_PROBE_EXTERNAL_I2C_COMPASSES
    // allow boards to ask for external probing of all i2c compass types in hwdef.dat
    _probe_external_i2c_compasses();
    CHECK_UNREG_LIMIT_RETURN;
#endif

#if AP_COMPASS_MSP_ENABLED
    for (uint8_t i=0; i<8; i++) {
        if (msp_instance_mask & (1U<<i)) {
            ADD_BACKEND(DRIVER_MSP, new AP_Compass_MSP(i));
        }
    }
#endif

#if defined(HAL_MAG_PROBE_LIST)
    // driver probes defined by COMPASS lines in hwdef.dat
    HAL_MAG_PROBE_LIST;
#elif AP_FEATURE_BOARD_DETECT
    switch (AP_BoardConfig::get_board_type()) {
    case AP_BoardConfig::PX4_BOARD_PX4V1:
    case AP_BoardConfig::PX4_BOARD_PIXHAWK:
    case AP_BoardConfig::PX4_BOARD_PHMINI:
    case AP_BoardConfig::PX4_BOARD_AUAV21:
    case AP_BoardConfig::PX4_BOARD_PH2SLIM:
    case AP_BoardConfig::PX4_BOARD_PIXHAWK2:
    case AP_BoardConfig::PX4_BOARD_MINDPXV2:
    case AP_BoardConfig::PX4_BOARD_FMUV5:
    case AP_BoardConfig::PX4_BOARD_FMUV6:
    case AP_BoardConfig::PX4_BOARD_PIXHAWK_PRO:
    case AP_BoardConfig::PX4_BOARD_AEROFC:
        _probe_external_i2c_compasses();
        CHECK_UNREG_LIMIT_RETURN;
        break;

    case AP_BoardConfig::PX4_BOARD_PCNC1:
#if AP_COMPASS_BMM150_ENABLED
        ADD_BACKEND(DRIVER_BMM150,
                    AP_Compass_BMM150::probe(GET_I2C_DEVICE(0, 0x10), false, ROTATION_NONE));
#endif
        break;
    case AP_BoardConfig::VRX_BOARD_BRAIN54:
    case AP_BoardConfig::VRX_BOARD_BRAIN51: {
#if AP_COMPASS_HMC5843_ENABLED
        // external i2c bus
        ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(GET_I2C_DEVICE(1, HAL_COMPASS_HMC5843_I2C_ADDR),
                    true, ROTATION_ROLL_180));

        // internal i2c bus
        ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(GET_I2C_DEVICE(0, HAL_COMPASS_HMC5843_I2C_ADDR),
                    false, ROTATION_YAW_270));
#endif  // AP_COMPASS_HMC5843_ENABLED
    }
    break;

    case AP_BoardConfig::VRX_BOARD_BRAIN52:
    case AP_BoardConfig::VRX_BOARD_BRAIN52E:
    case AP_BoardConfig::VRX_BOARD_CORE10:
    case AP_BoardConfig::VRX_BOARD_UBRAIN51:
    case AP_BoardConfig::VRX_BOARD_UBRAIN52: {
#if AP_COMPASS_HMC5843_ENABLED
        // external i2c bus
        ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(GET_I2C_DEVICE(1, HAL_COMPASS_HMC5843_I2C_ADDR),
                    true, ROTATION_ROLL_180));
#endif  // AP_COMPASS_HMC5843_ENABLED
    }
    break;

    default:
        break;
    }
    switch (AP_BoardConfig::get_board_type()) {
    case AP_BoardConfig::PX4_BOARD_PIXHAWK:
#if AP_COMPASS_HMC5843_ENABLED
        ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(hal.spi->get_device(HAL_COMPASS_HMC5843_NAME),
                    false, ROTATION_PITCH_180));
#endif
#if AP_COMPASS_LSM303D_ENABLED
        ADD_BACKEND(DRIVER_LSM303D, AP_Compass_LSM303D::probe(hal.spi->get_device(HAL_INS_LSM9DS0_A_NAME), ROTATION_NONE));
#endif
        break;

    case AP_BoardConfig::PX4_BOARD_PIXHAWK2:
#if AP_COMPASS_LSM303D_ENABLED
        ADD_BACKEND(DRIVER_LSM303D, AP_Compass_LSM303D::probe(hal.spi->get_device(HAL_INS_LSM9DS0_EXT_A_NAME), ROTATION_YAW_270));
#endif
#if AP_COMPASS_AK8963_ENABLED
        // we run the AK8963 only on the 2nd MPU9250, which leaves the
        // first MPU9250 to run without disturbance at high rate
        ADD_BACKEND(DRIVER_AK8963, AP_Compass_AK8963::probe_mpu9250(1, ROTATION_YAW_270));
#endif
#if AP_COMPASS_AK09916_ENABLED && AP_COMPASS_ICM20948_ENABLED
        ADD_BACKEND(DRIVER_AK09916, AP_Compass_AK09916::probe_ICM20948(0, ROTATION_ROLL_180_YAW_90));
#endif
        break;

    case AP_BoardConfig::PX4_BOARD_FMUV5:
    case AP_BoardConfig::PX4_BOARD_FMUV6:
#if AP_COMPASS_IST8310_ENABLED
        FOREACH_I2C_EXTERNAL(i) {
            ADD_BACKEND(DRIVER_IST8310, AP_Compass_IST8310::probe(GET_I2C_DEVICE(i, HAL_COMPASS_IST8310_I2C_ADDR),
                        true, ROTATION_ROLL_180_YAW_90));
        }
        FOREACH_I2C_INTERNAL(i) {
            ADD_BACKEND(DRIVER_IST8310, AP_Compass_IST8310::probe(GET_I2C_DEVICE(i, HAL_COMPASS_IST8310_I2C_ADDR),
                        false, ROTATION_ROLL_180_YAW_90));
        }
#endif  // AP_COMPASS_IST8310_ENABLED
        break;

    case AP_BoardConfig::PX4_BOARD_SP01:
#if AP_COMPASS_AK8963_ENABLED
        ADD_BACKEND(DRIVER_AK8963, AP_Compass_AK8963::probe_mpu9250(1, ROTATION_NONE));
#endif
        break;

    case AP_BoardConfig::PX4_BOARD_PIXHAWK_PRO:
#if AP_COMPASS_AK8963_ENABLED
        ADD_BACKEND(DRIVER_AK8963, AP_Compass_AK8963::probe_mpu9250(0, ROTATION_ROLL_180_YAW_90));
#endif
#if AP_COMPASS_LIS3MDL_ENABLED
        ADD_BACKEND(DRIVER_LIS3MDL, AP_Compass_LIS3MDL::probe(hal.spi->get_device(HAL_COMPASS_LIS3MDL_NAME),
                    false, ROTATION_NONE));
#endif  // AP_COMPASS_LIS3MDL_ENABLED
        break;

    case AP_BoardConfig::PX4_BOARD_PHMINI:
#if AP_COMPASS_AK8963_ENABLED
        ADD_BACKEND(DRIVER_AK8963, AP_Compass_AK8963::probe_mpu9250(0, ROTATION_ROLL_180));
#endif
        break;

    case AP_BoardConfig::PX4_BOARD_AUAV21:
#if AP_COMPASS_AK8963_ENABLED
        ADD_BACKEND(DRIVER_AK8963, AP_Compass_AK8963::probe_mpu9250(0, ROTATION_ROLL_180_YAW_90));
#endif
        break;

    case AP_BoardConfig::PX4_BOARD_PH2SLIM:
#if AP_COMPASS_AK8963_ENABLED
        ADD_BACKEND(DRIVER_AK8963, AP_Compass_AK8963::probe_mpu9250(0, ROTATION_YAW_270));
#endif
        break;

    case AP_BoardConfig::PX4_BOARD_MINDPXV2:
#if AP_COMPASS_HMC5843_ENABLED
        ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(GET_I2C_DEVICE(0, HAL_COMPASS_HMC5843_I2C_ADDR),
                    false, ROTATION_YAW_90));
#endif
#if AP_COMPASS_LSM303D_ENABLED
        ADD_BACKEND(DRIVER_LSM303D, AP_Compass_LSM303D::probe(hal.spi->get_device(HAL_INS_LSM9DS0_A_NAME), ROTATION_PITCH_180_YAW_270));
#endif
        break;

    default:
        break;
    }
#endif


#if AP_COMPASS_DRONECAN_ENABLED
    if (_driver_enabled(DRIVER_UAVCAN)) {
        for (uint8_t i=0; i<COMPASS_MAX_BACKEND; i++) {
            AP_Compass_Backend* _uavcan_backend = AP_Compass_DroneCAN::probe(i);
            if (_uavcan_backend) {
                _add_backend(_uavcan_backend);
            }
#if COMPASS_MAX_UNREG_DEV > 0
            if (_unreg_compass_count == COMPASS_MAX_UNREG_DEV)  {
                break;
            }
#endif
        }

#if COMPASS_MAX_UNREG_DEV > 0
        if (option_set(Option::ALLOW_DRONECAN_AUTO_REPLACEMENT)) {
            // check if there's any uavcan compass in prio slot that's not found
            // and replace it if there's a replacement compass
            for (Priority i(0); i<COMPASS_MAX_INSTANCES; i++) {
                if (AP_HAL::Device::devid_get_bus_type(_priority_did_list[i]) != AP_HAL::Device::BUS_TYPE_UAVCAN
                    || _get_state(i).registered) {
                    continue;
                }
                // There's a UAVCAN compass missing
                // Let's check if there's a replacement
                for (uint8_t j=0; j<COMPASS_MAX_INSTANCES; j++) {
                    uint32_t detected_devid = AP_Compass_DroneCAN::get_detected_devid(j);
                    // Check if this is a potential replacement mag
                    if (!is_replacement_mag(detected_devid)) {
                        continue;
                    }
                    // We have found a replacement mag, let's replace the existing one
                    // with this by setting the priority to zero and calling uavcan probe 
                    gcs().send_text(MAV_SEVERITY_ALERT, "Mag: Compass #%d with DEVID %lu replaced", uint8_t(i), (unsigned long)_priority_did_list[i]);
                    _priority_did_stored_list[i].set_and_save(0);
                    _priority_did_list[i] = 0;

                    AP_Compass_Backend* _uavcan_backend = AP_Compass_DroneCAN::probe(j);
                    if (_uavcan_backend) {
                        _add_backend(_uavcan_backend);
                        // we also need to remove the id from unreg list
                        remove_unreg_dev_id(detected_devid);
                    } else {
                        // the mag has already been allocated,
                        // let's begin the replacement
                        bool found_replacement = false;
                        for (StateIndex k(0); k<COMPASS_MAX_INSTANCES; k++) {
                            if ((uint32_t)_state[k].dev_id == detected_devid) {
                                if (_state[k].priority <= uint8_t(i)) {
                                    // we are already on higher priority
                                    // nothing to do
                                    break;
                                }
                                found_replacement = true;
                                // reset old priority of replacement mag
                                _priority_did_stored_list[_state[k].priority].set_and_save(0);
                                _priority_did_list[_state[k].priority] = 0;
                                // update new priority
                                _state[k].priority = i;
                            }
                        }
                        if (!found_replacement) {
                            continue;
                        }
                        _priority_did_stored_list[i].set_and_save(detected_devid);
                        _priority_did_list[i] = detected_devid;
                    }
                }
            }
        }
#endif  // #if COMPASS_MAX_UNREG_DEV > 0
    }
#endif  // AP_COMPASS_DRONECAN_ENABLED

    if (_backend_count == 0 ||
        _compass_count == 0) {
        DEV_PRINTF("No Compass backends available\n");
    }
}

3.4 _probe_external_i2c_compasses

支持类型:

  1. AP_Compass_HMC5843
  2. AP_Compass_QMC5883L
  3. AP_Compass_AK09916
  4. AP_Compass_LIS3MDL
  5. AP_Compass_IST8310
  6. AP_Compass_IST8308
  7. AP_Compass_MMC3416
  8. AP_Compass_RM3100
  9. AP_Compass_BMM150
/*
  look for compasses on external i2c buses
 */
void Compass::_probe_external_i2c_compasses(void)
{
#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    bool all_external = (AP_BoardConfig::get_board_type() == AP_BoardConfig::PX4_BOARD_PIXHAWK2);
    (void)all_external;  // in case all backends using this are compiled out
#endif
#if AP_COMPASS_HMC5843_ENABLED
    // external i2c bus
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(GET_I2C_DEVICE(i, HAL_COMPASS_HMC5843_I2C_ADDR),
                    true, ROTATION_ROLL_180));
    }

#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    if (AP_BoardConfig::get_board_type() != AP_BoardConfig::PX4_BOARD_MINDPXV2 &&
        AP_BoardConfig::get_board_type() != AP_BoardConfig::PX4_BOARD_AEROFC) {
        // internal i2c bus
        FOREACH_I2C_INTERNAL(i) {
            ADD_BACKEND(DRIVER_HMC5843, AP_Compass_HMC5843::probe(GET_I2C_DEVICE(i, HAL_COMPASS_HMC5843_I2C_ADDR),
                        all_external, all_external?ROTATION_ROLL_180:ROTATION_YAW_270));
        }
    }
#endif  // !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
#endif  // AP_COMPASS_HMC5843_ENABLED

#if AP_COMPASS_QMC5883L_ENABLED
    //external i2c bus
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_QMC5883L, AP_Compass_QMC5883L::probe(GET_I2C_DEVICE(i, HAL_COMPASS_QMC5883L_I2C_ADDR),
                    true, HAL_COMPASS_QMC5883L_ORIENTATION_EXTERNAL));
    }

    // internal i2c bus
#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    if (all_external) {
        // only probe QMC5883L on internal if we are treating internals as externals
        FOREACH_I2C_INTERNAL(i) {
            ADD_BACKEND(DRIVER_QMC5883L, AP_Compass_QMC5883L::probe(GET_I2C_DEVICE(i, HAL_COMPASS_QMC5883L_I2C_ADDR),
                        all_external,
                        all_external?HAL_COMPASS_QMC5883L_ORIENTATION_EXTERNAL:HAL_COMPASS_QMC5883L_ORIENTATION_INTERNAL));
        }
    }
#endif
#endif  // AP_COMPASS_QMC5883L_ENABLED

#ifndef HAL_BUILD_AP_PERIPH
    // AK09916 on ICM20948
#if AP_COMPASS_AK09916_ENABLED && AP_COMPASS_ICM20948_ENABLED
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_ICM20948, AP_Compass_AK09916::probe_ICM20948(GET_I2C_DEVICE(i, HAL_COMPASS_AK09916_I2C_ADDR),
                    GET_I2C_DEVICE(i, HAL_COMPASS_ICM20948_I2C_ADDR),
                    true, ROTATION_PITCH_180_YAW_90));
        ADD_BACKEND(DRIVER_ICM20948, AP_Compass_AK09916::probe_ICM20948(GET_I2C_DEVICE(i, HAL_COMPASS_AK09916_I2C_ADDR),
                    GET_I2C_DEVICE(i, HAL_COMPASS_ICM20948_I2C_ADDR2),
                    true, ROTATION_PITCH_180_YAW_90));
    }

#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    FOREACH_I2C_INTERNAL(i) {
        ADD_BACKEND(DRIVER_ICM20948, AP_Compass_AK09916::probe_ICM20948(GET_I2C_DEVICE(i, HAL_COMPASS_AK09916_I2C_ADDR),
                    GET_I2C_DEVICE(i, HAL_COMPASS_ICM20948_I2C_ADDR),
                    all_external, ROTATION_PITCH_180_YAW_90));
        ADD_BACKEND(DRIVER_ICM20948, AP_Compass_AK09916::probe_ICM20948(GET_I2C_DEVICE(i, HAL_COMPASS_AK09916_I2C_ADDR),
                    GET_I2C_DEVICE(i, HAL_COMPASS_ICM20948_I2C_ADDR2),
                    all_external, ROTATION_PITCH_180_YAW_90));
    }
#endif
#endif  // AP_COMPASS_AK09916_ENABLED && AP_COMPASS_ICM20948_ENABLED
#endif // HAL_BUILD_AP_PERIPH

#if AP_COMPASS_LIS3MDL_ENABLED
    // lis3mdl on bus 0 with default address
#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    FOREACH_I2C_INTERNAL(i) {
        ADD_BACKEND(DRIVER_LIS3MDL, AP_Compass_LIS3MDL::probe(GET_I2C_DEVICE(i, HAL_COMPASS_LIS3MDL_I2C_ADDR),
                    all_external, all_external?ROTATION_YAW_90:ROTATION_NONE));
    }

    // lis3mdl on bus 0 with alternate address
    FOREACH_I2C_INTERNAL(i) {
        ADD_BACKEND(DRIVER_LIS3MDL, AP_Compass_LIS3MDL::probe(GET_I2C_DEVICE(i, HAL_COMPASS_LIS3MDL_I2C_ADDR2),
                    all_external, all_external?ROTATION_YAW_90:ROTATION_NONE));
    }
#endif
    // external lis3mdl on bus 1 with default address
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_LIS3MDL, AP_Compass_LIS3MDL::probe(GET_I2C_DEVICE(i, HAL_COMPASS_LIS3MDL_I2C_ADDR),
                    true, ROTATION_YAW_90));
    }

    // external lis3mdl on bus 1 with alternate address
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_LIS3MDL, AP_Compass_LIS3MDL::probe(GET_I2C_DEVICE(i, HAL_COMPASS_LIS3MDL_I2C_ADDR2),
                    true, ROTATION_YAW_90));
    }
#endif  // AP_COMPASS_LIS3MDL_ENABLED

#if AP_COMPASS_AK09916_ENABLED
    // AK09916. This can be found twice, due to the ICM20948 i2c bus pass-thru, so we need to be careful to avoid that
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_AK09916, AP_Compass_AK09916::probe(GET_I2C_DEVICE(i, HAL_COMPASS_AK09916_I2C_ADDR),
                    true, ROTATION_YAW_270));
    }
#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    FOREACH_I2C_INTERNAL(i) {
        ADD_BACKEND(DRIVER_AK09916, AP_Compass_AK09916::probe(GET_I2C_DEVICE(i, HAL_COMPASS_AK09916_I2C_ADDR),
                    all_external, all_external?ROTATION_YAW_270:ROTATION_NONE));
    }
#endif
#endif  // AP_COMPASS_AK09916_ENABLED

#if AP_COMPASS_IST8310_ENABLED
    // IST8310 on external and internal bus
    if (AP_BoardConfig::get_board_type() != AP_BoardConfig::PX4_BOARD_FMUV5 &&
        AP_BoardConfig::get_board_type() != AP_BoardConfig::PX4_BOARD_FMUV6) {
        enum Rotation default_rotation = AP_COMPASS_IST8310_DEFAULT_ROTATION;

        if (AP_BoardConfig::get_board_type() == AP_BoardConfig::PX4_BOARD_AEROFC) {
            default_rotation = ROTATION_PITCH_180_YAW_90;
        }
        // probe all 4 possible addresses
        const uint8_t ist8310_addr[] = { 0x0C, 0x0D, 0x0E, 0x0F };

        for (uint8_t a=0; a<ARRAY_SIZE(ist8310_addr); a++) {
            FOREACH_I2C_EXTERNAL(i) {
                ADD_BACKEND(DRIVER_IST8310, AP_Compass_IST8310::probe(GET_I2C_DEVICE(i, ist8310_addr[a]),
                            true, default_rotation));
            }
#if !defined(HAL_COMPASS_DISABLE_IST8310_INTERNAL_PROBE) && !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
            FOREACH_I2C_INTERNAL(i) {
                ADD_BACKEND(DRIVER_IST8310, AP_Compass_IST8310::probe(GET_I2C_DEVICE(i, ist8310_addr[a]),
                            all_external, default_rotation));
            }
#endif
        }
    }
#endif  // AP_COMPASS_IST8310_ENABLED

#if AP_COMPASS_IST8308_ENABLED
    // external i2c bus
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_IST8308, AP_Compass_IST8308::probe(GET_I2C_DEVICE(i, HAL_COMPASS_IST8308_I2C_ADDR),
                    true, ROTATION_NONE));
    }
#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    FOREACH_I2C_INTERNAL(i) {
        ADD_BACKEND(DRIVER_IST8308, AP_Compass_IST8308::probe(GET_I2C_DEVICE(i, HAL_COMPASS_IST8308_I2C_ADDR),
                    all_external, ROTATION_NONE));
    }
#endif
#endif  // AP_COMPASS_IST8308_ENABLED

#if AP_COMPASS_MMC3416_ENABLED
    // external i2c bus
    FOREACH_I2C_EXTERNAL(i) {
        ADD_BACKEND(DRIVER_MMC3416, AP_Compass_MMC3416::probe(GET_I2C_DEVICE(i, HAL_COMPASS_MMC3416_I2C_ADDR),
                    true, ROTATION_NONE));
    }
#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    FOREACH_I2C_INTERNAL(i) {
        ADD_BACKEND(DRIVER_MMC3416, AP_Compass_MMC3416::probe(GET_I2C_DEVICE(i, HAL_COMPASS_MMC3416_I2C_ADDR),
                    all_external, ROTATION_NONE));
    }
#endif
#endif  // AP_COMPASS_MMC3416_ENABLED

#if AP_COMPASS_RM3100_ENABLED
#ifdef HAL_COMPASS_RM3100_I2C_ADDR
    const uint8_t rm3100_addresses[] = { HAL_COMPASS_RM3100_I2C_ADDR };
#else
    // RM3100 can be on 4 different addresses
    const uint8_t rm3100_addresses[] = { HAL_COMPASS_RM3100_I2C_ADDR1,
                                         HAL_COMPASS_RM3100_I2C_ADDR2,
                                         HAL_COMPASS_RM3100_I2C_ADDR3,
                                         HAL_COMPASS_RM3100_I2C_ADDR4 };
#endif
    // external i2c bus
    FOREACH_I2C_EXTERNAL(i) {
        for (uint8_t j=0; j<ARRAY_SIZE(rm3100_addresses); j++) {
            ADD_BACKEND(DRIVER_RM3100, AP_Compass_RM3100::probe(GET_I2C_DEVICE(i, rm3100_addresses[j]), true, ROTATION_NONE));
        }
    }

#if !defined(HAL_SKIP_AUTO_INTERNAL_I2C_PROBE)
    FOREACH_I2C_INTERNAL(i) {
        for (uint8_t j=0; j<ARRAY_SIZE(rm3100_addresses); j++) {
            ADD_BACKEND(DRIVER_RM3100, AP_Compass_RM3100::probe(GET_I2C_DEVICE(i, rm3100_addresses[j]), all_external, ROTATION_NONE));
        }
    }
#endif
#endif  // AP_COMPASS_RM3100_ENABLED

#if AP_COMPASS_BMM150_DETECT_BACKENDS_ENABLED
    // BMM150 on I2C
    FOREACH_I2C_EXTERNAL(i) {
        for (uint8_t addr=BMM150_I2C_ADDR_MIN; addr <= BMM150_I2C_ADDR_MAX; addr++) {
            ADD_BACKEND(DRIVER_BMM150,
                        AP_Compass_BMM150::probe(GET_I2C_DEVICE(i, addr), true, ROTATION_NONE));
        }
    }
#endif // AP_COMPASS_BMM150_ENABLED
}

4. 总结

目前,磁力计支持以下类型:

  1. AP_Compass_ExternalAHRS
  2. AP_Compass_SITL
  3. AP_Compass_MSP
  4. AP_Compass_DroneCAN
  5. AP_Compass_BMM150
  6. AP_Compass_HMC5843
  7. AP_Compass_LSM303D
  8. AP_Compass_AK8963
  9. AP_Compass_AK09916
  10. AP_Compass_IST8310
  11. AP_Compass_LIS3MDL
  12. AP_Compass_QMC5883L
  13. AP_Compass_IST8308
  14. AP_Compass_MMC3416
  15. AP_Compass_RM3100

虽然磁力计在航模的应用上就没有这么讲究,但当远航飞行的时候,如果磁罗盘故障或者校准不准时,将会影响RTL返航。

历史上,由于磁力计的使用,导致偏航的灾难!

苏联两度击落韩国客机,背后是否另有隐情

5. 参考资料

【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码Task介绍
【3】ArduPilot飞控启动&运行过程简介
【4】ArduPilot之开源代码Library&Sketches设计
【5】ArduPilot之开源代码Sensor Drivers设计


http://www.niftyadmin.cn/n/5104261.html

相关文章

嵌入式相关开源项目、库、资料-汇总 | 干货

概述 如何在github 搜索开源框架与使用 1、搜索关键字&#xff1a;cJson、http、socket、test https://github.com/zhengnianli/EmbedSummary 学习初期最难找的就是找学习资料了&#xff0c;本贴精心汇总了一些嵌入式相关资源&#xff0c;包括但不限于编程语言、单片机、开源…

Dev-C++ 软件安装教程

Dev-C 软件安装包https://download.csdn.net/download/W_Fe5/88446511&#xff08;软件包下载后&#xff0c;右键解压&#xff09; 一、打开文件夹&#xff0c;双击“Dev-C” 二、软件安装&#xff0c;点击“OK” 三、点击“I Agree” 四、点击“Next” 五、更改安装目录&…

Ruby使用类组织对象

使用Object.new创建新对象&#xff0c;但是一次只使用一种方法&#xff0c;这是感受以对象为中心的Ruby编程的最佳方式之一。不过这种方式并不能很好地扩展&#xff0c;假如有一个正在运行地在线售票网站&#xff0c;然后其数据库必须处理数以百计地售票记录&#xff0c;那么可…

MS5248数模转换器可pin对pin兼容AD5648

MS5228/5248/5268 是一款 12/14/16bit 八通道输出的电压型 DAC&#xff0c;内部集成上电复位电路、可选内部基准、接口采用四线串口模式&#xff0c;最高工作频率可以到 40MHz&#xff0c;可以兼容 SPI、QSPI、DSP 接口和 Microwire 串口。可pin对pin兼容AD5648。输出接到一个 …

基于SSM的疫情期间高校师生外出请假管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

window系统如何管理多版本node

何时需要切换node版本 如果你正在维护一个旧项目&#xff0c;同时也在进行新项目&#xff0c;两个项目所依赖的node版本害不同&#xff0c;那么你可以就需要经常切换node版本。项目中可能依赖于某些npm包&#xff0c;而这些包对特定版本的Node有要求。需要满足这些要求以确保依…

[论文精读]Graph Attention Networks

论文原文&#xff1a;[1710.10903] Graph Attention Networks (arxiv.org) 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用&am…

flex布局弹性盒子详解

它是CSS3中新增的规范 Flex布局中主要包含了以下五个概念&#xff1a; 弹性容器&#xff08;flex container&#xff09;&#xff1a;采用Flex布局的外层容器。 弹性项&#xff08;flex item&#xff09;&#xff1a;容器中的子元素。 主轴&#xff08;main axis&#xff09…