• Ardupilot — AP_OpticalFlow代码梳理


    文章目录

    前言

    1 Copter.cpp

    1.1 void Copter::setup()

    2 system.cpp

    2.1 void Copter::init_ardupilot()

    3 sensors.cpp

    3.1 void Copter::init_optflow()

    3.2 对象optflow说明

    4 OpticalFlow.cpp

    4.1 void OpticalFlow::init(uint32_t log_bit)

    5 AP_OpticalFlow_Pixart.cpp

    5.1 AP_OpticalFlow_Pixart *AP_OpticalFlow_Pixart::detect(...)

    5.2 bool AP_OpticalFlow_Pixart::setup_sensor(void)

    5.3 void AP_OpticalFlow_Pixart::timer(void)

    5.4 void AP_OpticalFlow_Pixart::motion_burst(void)

    5.5 SCHED_TASK_CLASS(OpticalFlow,          &copter.optflow,             update,         200, 160),

    5.6 void AP_OpticalFlow_Pixart::update(void)


    前言

    故事的开始,要从参数 FLOW_TYPE 说起。

    FLOW_TYPE:光学流量传感器类型


    RebootRequired

    Values

    True

    Value

    Meaning

    0

    None

    1

    PX4Flow

    2

    Pixart

    3

    Bebop

    4

    CXOF

    5

    MAVLink

    6

    UAVCAN

    1 Copter.cpp

    1.1 void Copter::setup()

    此函数仅在启动时调用一次。用于初始化一些必要的任务。此函数由 HAL 中的 main() 函数调用。

    1. void Copter::setup()
    2. {
    3. // Load the default values of variables listed in var_info[]s
    4. AP_Param::setup_sketch_defaults();
    5. // setup storage layout for copter
    6. StorageManager::set_layout_copter();
    7. init_ardupilot();
    8. // initialise the main loop scheduler
    9. scheduler.init(&scheduler_tasks[0], ARRAY_SIZE(scheduler_tasks), MASK_LOG_PM);
    10. }

    2 system.cpp

    2.1 void Copter::init_ardupilot()

    init_ardupilot() 函数将处理空中重启所需的一切。稍后将确定飞行器是否真的在地面上,并在这种情况下处理地面启动。

    1. void Copter::init_ardupilot()
    2. {
    3. ...
    4. // init the optical flow sensor
    5. init_optflow();
    6. ...
    7. }

    3 sensors.cpp

    3.1 void Copter::init_optflow()

    初始化光流传感器。

    1. // initialise optical flow sensor
    2. void Copter::init_optflow()
    3. {
    4. #if OPTFLOW == ENABLED
    5. // initialise optical flow sensor
    6. optflow.init(MASK_LOG_OPTFLOW);
    7. #endif // OPTFLOW == ENABLED
    8. }

    3.2 对象optflow说明

    在 Copter.h 文件中,我们用 OpticalFlow 类定义了 optflow 对象。

    1. // Optical flow sensor
    2. #if OPTFLOW == ENABLED
    3. OpticalFlow optflow;
    4. #endif

    4 OpticalFlow.cpp

    4.1 void OpticalFlow::init(uint32_t log_bit)

    所以,我们在跳转 init() 这个成员函数的时候,跳转到 OpticalFlow 类的 init() 函数。

    根据参数 FLOW_TYPE,选择不同的光流传感器进行检测。

    本例以 Pixart(2)作为示例。

    1. void OpticalFlow::init(uint32_t log_bit)
    2. {
    3. _log_bit = log_bit;
    4. // return immediately if not enabled or backend already created
    5. if ((_type == (int8_t)OpticalFlowType::NONE) || (backend != nullptr)) {
    6. return;
    7. }
    8. switch ((OpticalFlowType)_type.get()) {
    9. case OpticalFlowType::NONE:
    10. break;
    11. case OpticalFlowType::PX4FLOW:
    12. backend = AP_OpticalFlow_PX4Flow::detect(*this);
    13. break;
    14. case OpticalFlowType::PIXART:
    15. backend = AP_OpticalFlow_Pixart::detect("pixartflow", *this);
    16. if (backend == nullptr) {
    17. backend = AP_OpticalFlow_Pixart::detect("pixartPC15", *this);
    18. }
    19. break;
    20. case OpticalFlowType::BEBOP:
    21. #if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP
    22. backend = new AP_OpticalFlow_Onboard(*this);
    23. #endif
    24. break;
    25. case OpticalFlowType::CXOF:
    26. backend = AP_OpticalFlow_CXOF::detect(*this);
    27. break;
    28. case OpticalFlowType::MAVLINK:
    29. backend = AP_OpticalFlow_MAV::detect(*this);
    30. break;
    31. case OpticalFlowType::UAVCAN:
    32. #if HAL_WITH_UAVCAN
    33. backend = new AP_OpticalFlow_HereFlow(*this);
    34. #endif
    35. break;
    36. case OpticalFlowType::SITL:
    37. #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
    38. backend = new AP_OpticalFlow_SITL(*this);
    39. #endif
    40. break;
    41. }
    42. if (backend != nullptr) {
    43. backend->init();
    44. }
    45. }

    5 AP_OpticalFlow_Pixart.cpp

    5.1 AP_OpticalFlow_Pixart *AP_OpticalFlow_Pixart::detect(...)

    首先会根据传入的参数,new 一个 AP_OpticalFlow_Pixart 类对象。

    然后,检测光流传感器的产品 ID,再配置传感器(sensor->setup_sensor())。

    1. // detect the device
    2. AP_OpticalFlow_Pixart *AP_OpticalFlow_Pixart::detect(const char *devname, OpticalFlow &_frontend)
    3. {
    4. AP_OpticalFlow_Pixart *sensor = new AP_OpticalFlow_Pixart(devname, _frontend);
    5. if (!sensor) {
    6. return nullptr;
    7. }
    8. if (!sensor->setup_sensor()) {
    9. delete sensor;
    10. return nullptr;
    11. }
    12. return sensor;
    13. }

    5.2 bool AP_OpticalFlow_Pixart::setup_sensor(void)

    先读取光流传感器的产品 ID,识别光流传感器类型。再根据类型的不同,写入不同的参数配置光流传感器。

    最后,注册光流传感器的周期运行函数 timer()

    1. // setup the device
    2. bool AP_OpticalFlow_Pixart::setup_sensor(void)
    3. {
    4. ...
    5. // check product ID
    6. uint8_t id1 = reg_read(PIXART_REG_PRODUCT_ID);
    7. uint8_t id2;
    8. if (id1 == 0x3f) {
    9. id2 = reg_read(PIXART_REG_INV_PROD_ID);
    10. } else {
    11. id2 = reg_read(PIXART_REG_INV_PROD_ID2);
    12. }
    13. debug("id1=0x%02x id2=0x%02x ~id1=0x%02x\n", id1, id2, uint8_t(~id1));
    14. if (id1 == 0x3F && id2 == uint8_t(~id1)) {
    15. model = PIXART_3900;
    16. } else if (id1 == 0x49 && id2 == uint8_t(~id1)) {
    17. model = PIXART_3901;
    18. } else {
    19. debug("Not a recognised device\n");
    20. return false;
    21. }
    22. if (model == PIXART_3900) {
    23. srom_download();
    24. id = reg_read(PIXART_REG_SROM_ID);
    25. if (id != srom_id) {
    26. debug("Pixart: bad SROM ID: 0x%02x\n", id);
    27. return false;
    28. }
    29. reg_write(PIXART_REG_SROM_EN, 0x15);
    30. hal.scheduler->delay(10);
    31. crc = reg_read16u(PIXART_REG_DOUT_L);
    32. if (crc != 0xBEEF) {
    33. debug("Pixart: bad SROM CRC: 0x%04x\n", crc);
    34. return false;
    35. }
    36. }
    37. if (model == PIXART_3900) {
    38. load_configuration(init_data_3900, ARRAY_SIZE(init_data_3900));
    39. } else {
    40. load_configuration(init_data_3901_1, ARRAY_SIZE(init_data_3901_1));
    41. hal.scheduler->delay(100);
    42. load_configuration(init_data_3901_2, ARRAY_SIZE(init_data_3901_2));
    43. }
    44. hal.scheduler->delay(50);
    45. debug("Pixart %s ready\n", model==PIXART_3900?"3900":"3901");
    46. integral.last_frame_us = AP_HAL::micros();
    47. _dev->register_periodic_callback(2000, FUNCTOR_BIND_MEMBER(&AP_OpticalFlow_Pixart::timer, void));
    48. return true;
    49. }

    5.3 void AP_OpticalFlow_Pixart::timer(void)

    2ms 调用一次 timer() 函数,读取光流传感器的测量值。

    可以将 #if 0 #endif 屏蔽,打开调试信息。

    1. void AP_OpticalFlow_Pixart::timer(void)
    2. {
    3. if (AP_HAL::micros() - last_burst_us < 500) {
    4. return;
    5. }
    6. motion_burst();
    7. last_burst_us = AP_HAL::micros();
    8. uint32_t dt_us = last_burst_us - integral.last_frame_us;
    9. float dt = dt_us * 1.0e-6;
    10. const Vector3f &gyro = AP::ahrs_navekf().get_gyro();
    11. {
    12. WITH_SEMAPHORE(_sem);
    13. integral.sum.x += burst.delta_x;
    14. integral.sum.y += burst.delta_y;
    15. integral.sum_us += dt_us;
    16. integral.last_frame_us = last_burst_us;
    17. integral.gyro += Vector2f(gyro.x, gyro.y) * dt;
    18. }
    19. #if 0
    20. static uint32_t last_print_ms;
    21. static int fd = -1;
    22. if (fd == -1) {
    23. fd = open("/dev/ttyACM0", O_WRONLY);
    24. }
    25. // used for debugging
    26. static int32_t sum_x;
    27. static int32_t sum_y;
    28. sum_x += burst.delta_x;
    29. sum_y += burst.delta_y;
    30. uint32_t now = AP_HAL::millis();
    31. if (now - last_print_ms >= 100 && (sum_x != 0 || sum_y != 0)) {
    32. last_print_ms = now;
    33. dprintf(fd, "Motion: %d %d obs:0x%02x squal:%u rds:%u maxr:%u minr:%u sup:%u slow:%u\n",
    34. (int)sum_x, (int)sum_y, (unsigned)burst.squal, (unsigned)burst.rawdata_sum, (unsigned)burst.max_raw,
    35. (unsigned)burst.max_raw, (unsigned)burst.min_raw, (unsigned)burst.shutter_upper, (unsigned)burst.shutter_lower);
    36. sum_x = sum_y = 0;
    37. }
    38. #endif
    39. }

    5.4 void AP_OpticalFlow_Pixart::motion_burst(void)

    通过 SPI 读取光流传感器运动值。

    1. void AP_OpticalFlow_Pixart::motion_burst(void)
    2. {
    3. uint8_t *b = (uint8_t *)&burst;
    4. burst.delta_x = 0;
    5. burst.delta_y = 0;
    6. _dev->set_chip_select(true);
    7. uint8_t reg = model==PIXART_3900?PIXART_REG_MOT_BURST:PIXART_REG_MOT_BURST2;
    8. _dev->transfer(®, 1, nullptr, 0);
    9. hal.scheduler->delay_microseconds(150);
    10. for (uint8_t i=0; i<sizeof(burst); i++) {
    11. _dev->transfer(nullptr, 0, &b[i], 1);
    12. if (i == 0 && (burst.motion & 0x80) == 0) {
    13. // no motion, save some bus bandwidth
    14. _dev->set_chip_select(false);
    15. return;
    16. }
    17. }
    18. _dev->set_chip_select(false);
    19. }

    5.5 SCHED_TASK_CLASS(OpticalFlow,          &copter.optflow,             update,         200, 160),

    在 Copter.cpp 文件的周期任务列表中,注册了调用频率为 200Hz 的光流传感器 update() 函数。

    1. const AP_Scheduler::Task Copter::scheduler_tasks[] = {
    2. ...
    3. #if OPTFLOW == ENABLED
    4. SCHED_TASK_CLASS(OpticalFlow, &copter.optflow, update, 200, 160),
    5. #endif
    6. ...
    7. }

    5.6 void AP_OpticalFlow_Pixart::update(void)

    根据 5.1 中的返回的 AP_OpticalFlow_Pixart 对象,调用 AP_OpticalFlow_Pixart 类中的 update() 函数。

    更新 - 从传感器读取最新数值,并填入 xy 和总数。

    1. // update - read latest values from sensor and fill in x,y and totals.
    2. void AP_OpticalFlow_Pixart::update(void)
    3. {
    4. uint32_t now = AP_HAL::millis();
    5. if (now - last_update_ms < 100) {
    6. return;
    7. }
    8. last_update_ms = now;
    9. struct OpticalFlow::OpticalFlow_state state;
    10. state.surface_quality = burst.squal;
    11. if (integral.sum_us > 0) {
    12. WITH_SEMAPHORE(_sem);
    13. const Vector2f flowScaler = _flowScaler();
    14. float flowScaleFactorX = 1.0f + 0.001f * flowScaler.x;
    15. float flowScaleFactorY = 1.0f + 0.001f * flowScaler.y;
    16. float dt = integral.sum_us * 1.0e-6;
    17. state.flowRate = Vector2f(integral.sum.x * flowScaleFactorX,
    18. integral.sum.y * flowScaleFactorY);
    19. state.flowRate *= flow_pixel_scaling / dt;
    20. // we only apply yaw to flowRate as body rate comes from AHRS
    21. _applyYaw(state.flowRate);
    22. state.bodyRate = integral.gyro / dt;
    23. integral.sum.zero();
    24. integral.sum_us = 0;
    25. integral.gyro.zero();
    26. } else {
    27. state.flowRate.zero();
    28. state.bodyRate.zero();
    29. }
    30. // copy results to front end
    31. _update_frontend(state);
    32. }
  • 相关阅读:
    ES6(ECMASript 6 新特性---数值扩展,对象扩展,模块化)
    Simulink与Arduino烧录配置
    鞋业的数字化转型:3D建模与3D打印
    2020年9月大学英语六级作文
    strcmp函数详解:字符串比较的利器
    数据结构和算法——图结构
    1.MidBook项目经验之MybatisPlus
    软件测试 - 基础(软件测试的生命周期、测试报告、bug的级别、与开发人员产生争执的调解方式)
    BUUCTF 不一样的flag 1
    【修复】centos定时任务python top不能输出
  • 原文地址:https://blog.csdn.net/qq_20016593/article/details/132723033