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() 函数调用。

void Copter::setup()
{// Load the default values of variables listed in var_info[]sAP_Param::setup_sketch_defaults();// setup storage layout for copterStorageManager::set_layout_copter();init_ardupilot();// initialise the main loop schedulerscheduler.init(&scheduler_tasks[0], ARRAY_SIZE(scheduler_tasks), MASK_LOG_PM);
}

2 system.cpp

2.1 void Copter::init_ardupilot()

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

void Copter::init_ardupilot()
{...// init the optical flow sensorinit_optflow();...
}

3 sensors.cpp

3.1 void Copter::init_optflow()

初始化光流传感器。

// initialise optical flow sensor
void Copter::init_optflow()
{
#if OPTFLOW == ENABLED// initialise optical flow sensoroptflow.init(MASK_LOG_OPTFLOW);
#endif      // OPTFLOW == ENABLED
}

3.2 对象optflow说明

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

    // Optical flow sensor
#if OPTFLOW == ENABLEDOpticalFlow optflow;
#endif

4 OpticalFlow.cpp

4.1 void OpticalFlow::init(uint32_t log_bit)

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

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

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

void OpticalFlow::init(uint32_t log_bit)
{_log_bit = log_bit;// return immediately if not enabled or backend already createdif ((_type == (int8_t)OpticalFlowType::NONE) || (backend != nullptr)) {return;}switch ((OpticalFlowType)_type.get()) {case OpticalFlowType::NONE:break;case OpticalFlowType::PX4FLOW:backend = AP_OpticalFlow_PX4Flow::detect(*this);break;case OpticalFlowType::PIXART:backend = AP_OpticalFlow_Pixart::detect("pixartflow", *this);if (backend == nullptr) {backend = AP_OpticalFlow_Pixart::detect("pixartPC15", *this);}break;case OpticalFlowType::BEBOP:
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOPbackend = new AP_OpticalFlow_Onboard(*this);
#endifbreak;case OpticalFlowType::CXOF:backend = AP_OpticalFlow_CXOF::detect(*this);break;case OpticalFlowType::MAVLINK:backend = AP_OpticalFlow_MAV::detect(*this);break;case OpticalFlowType::UAVCAN:
#if HAL_WITH_UAVCANbackend = new AP_OpticalFlow_HereFlow(*this);
#endifbreak;case OpticalFlowType::SITL:
#if CONFIG_HAL_BOARD == HAL_BOARD_SITLbackend = new AP_OpticalFlow_SITL(*this);
#endifbreak;}if (backend != nullptr) {backend->init();}
}

5 AP_OpticalFlow_Pixart.cpp

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

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

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

// detect the device
AP_OpticalFlow_Pixart *AP_OpticalFlow_Pixart::detect(const char *devname, OpticalFlow &_frontend)
{AP_OpticalFlow_Pixart *sensor = new AP_OpticalFlow_Pixart(devname, _frontend);if (!sensor) {return nullptr;}if (!sensor->setup_sensor()) {delete sensor;return nullptr;}return sensor;
}

5.2 bool AP_OpticalFlow_Pixart::setup_sensor(void)

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

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

// setup the device
bool AP_OpticalFlow_Pixart::setup_sensor(void)
{...// check product IDuint8_t id1 = reg_read(PIXART_REG_PRODUCT_ID);uint8_t id2;if (id1 == 0x3f) {id2 = reg_read(PIXART_REG_INV_PROD_ID);} else {id2 = reg_read(PIXART_REG_INV_PROD_ID2);}debug("id1=0x%02x id2=0x%02x ~id1=0x%02x\n", id1, id2, uint8_t(~id1));if (id1 == 0x3F && id2 == uint8_t(~id1)) {model = PIXART_3900;} else if (id1 == 0x49 && id2 == uint8_t(~id1)) {model = PIXART_3901;} else {debug("Not a recognised device\n");return false;}if (model == PIXART_3900) {srom_download();id = reg_read(PIXART_REG_SROM_ID);if (id != srom_id) {debug("Pixart: bad SROM ID: 0x%02x\n", id);return false;}reg_write(PIXART_REG_SROM_EN, 0x15);hal.scheduler->delay(10);crc = reg_read16u(PIXART_REG_DOUT_L);if (crc != 0xBEEF) {debug("Pixart: bad SROM CRC: 0x%04x\n", crc);return false;}}if (model == PIXART_3900) {load_configuration(init_data_3900, ARRAY_SIZE(init_data_3900));} else {load_configuration(init_data_3901_1, ARRAY_SIZE(init_data_3901_1));hal.scheduler->delay(100);load_configuration(init_data_3901_2, ARRAY_SIZE(init_data_3901_2));}hal.scheduler->delay(50);debug("Pixart %s ready\n", model==PIXART_3900?"3900":"3901");integral.last_frame_us = AP_HAL::micros();_dev->register_periodic_callback(2000, FUNCTOR_BIND_MEMBER(&AP_OpticalFlow_Pixart::timer, void));return true;
}

5.3 void AP_OpticalFlow_Pixart::timer(void)

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

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

void AP_OpticalFlow_Pixart::timer(void)
{if (AP_HAL::micros() - last_burst_us < 500) {return;}motion_burst();last_burst_us = AP_HAL::micros();uint32_t dt_us = last_burst_us - integral.last_frame_us;float dt = dt_us * 1.0e-6;const Vector3f &gyro = AP::ahrs_navekf().get_gyro();{WITH_SEMAPHORE(_sem);integral.sum.x += burst.delta_x;integral.sum.y += burst.delta_y;integral.sum_us += dt_us;integral.last_frame_us = last_burst_us;integral.gyro += Vector2f(gyro.x, gyro.y) * dt;}#if 0static uint32_t last_print_ms;static int fd = -1;if (fd == -1) {fd = open("/dev/ttyACM0", O_WRONLY);}// used for debuggingstatic int32_t sum_x;static int32_t sum_y;sum_x += burst.delta_x;sum_y += burst.delta_y;uint32_t now = AP_HAL::millis();if (now - last_print_ms >= 100 && (sum_x != 0 || sum_y != 0)) {last_print_ms = now;dprintf(fd, "Motion: %d %d obs:0x%02x squal:%u rds:%u maxr:%u minr:%u sup:%u slow:%u\n",(int)sum_x, (int)sum_y, (unsigned)burst.squal, (unsigned)burst.rawdata_sum, (unsigned)burst.max_raw,(unsigned)burst.max_raw, (unsigned)burst.min_raw, (unsigned)burst.shutter_upper, (unsigned)burst.shutter_lower);sum_x = sum_y = 0;}
#endif
}

5.4 void AP_OpticalFlow_Pixart::motion_burst(void)

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

void AP_OpticalFlow_Pixart::motion_burst(void)
{uint8_t *b = (uint8_t *)&burst;burst.delta_x = 0;burst.delta_y = 0;_dev->set_chip_select(true);uint8_t reg = model==PIXART_3900?PIXART_REG_MOT_BURST:PIXART_REG_MOT_BURST2;_dev->transfer(&reg, 1, nullptr, 0);hal.scheduler->delay_microseconds(150);for (uint8_t i=0; i<sizeof(burst); i++) {_dev->transfer(nullptr, 0, &b[i], 1);if (i == 0 && (burst.motion & 0x80) == 0) {// no motion, save some bus bandwidth_dev->set_chip_select(false);return;}}_dev->set_chip_select(false);
}

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

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

const AP_Scheduler::Task Copter::scheduler_tasks[] = {
...#if OPTFLOW == ENABLEDSCHED_TASK_CLASS(OpticalFlow,          &copter.optflow,             update,         200, 160),
#endif
...
}

5.6 void AP_OpticalFlow_Pixart::update(void)

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

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

// update - read latest values from sensor and fill in x,y and totals.
void AP_OpticalFlow_Pixart::update(void)
{uint32_t now = AP_HAL::millis();if (now - last_update_ms < 100) {return;}last_update_ms = now;struct OpticalFlow::OpticalFlow_state state;state.surface_quality = burst.squal;if (integral.sum_us > 0) {WITH_SEMAPHORE(_sem);const Vector2f flowScaler = _flowScaler();float flowScaleFactorX = 1.0f + 0.001f * flowScaler.x;float flowScaleFactorY = 1.0f + 0.001f * flowScaler.y;float dt = integral.sum_us * 1.0e-6;state.flowRate = Vector2f(integral.sum.x * flowScaleFactorX,integral.sum.y * flowScaleFactorY);state.flowRate *= flow_pixel_scaling / dt;// we only apply yaw to flowRate as body rate comes from AHRS_applyYaw(state.flowRate);state.bodyRate = integral.gyro / dt;integral.sum.zero();integral.sum_us = 0;integral.gyro.zero();} else {state.flowRate.zero();state.bodyRate.zero();}// copy results to front end_update_frontend(state);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/127608.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法-二叉搜索树红黑树

一&#xff1a;二叉搜索树 大家来看以下几个结构&#xff1a;下图中的 二叉搜索树又叫二叉查找树&#xff0c;二叉排序树&#xff1b; 它具有以下特点&#xff1a; 1.如果它的左子树不为空&#xff0c;则左子树上结点的值都小于根结点。 2.如果它的右子树不为空&#xff0c;则右…

Matlab图像处理-自适应阈值

自适应阈值 在许多的情况下&#xff0c;背景的灰度值并不是常数&#xff0c;物体和背景的对比度在图像中也有变化。这时&#xff0c;一个在图像中某一区域效果良好的阈值在其它区域却可能效果很差。在这种情况下&#xff0c;把灰度阈值取成一个随图像中位置缓慢变化的函数值是…

SNMP的监控

SNMP的监控 一、SNMP 介绍1.1 什么是SNMP1.2 SNMP的组件1.2.1 网络管理系统 NMS&#xff08;Network Management System&#xff09;1.2.2 代理进程&#xff08;Agent&#xff09;1.2.3 被管对象&#xff08;Managed Object&#xff09;1.2.4 管理信息库MIB&#xff08;Managem…

linux c++ 开发 - 05- 使用CMake创建一个动态库

外层CMakeList.txt中的内容&#xff1a; cmake_minimum_required(VERSION 3.16) PROJECT(HELLO) ADD_SUBDIRECTORY(lib bin)lib中CMakeLists.txt中的内容&#xff1a; SET(LIBHELLO_SRC hello.cpp) ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})hello.h: hello.cpp: ADD_LIBR…

多元共进|科技促进艺术发展,助力文化传承

科技发展助力文化和艺术的传播 融合传统与创新&#xff0c;碰撞独特魅力 一起来了解 2023 Google 开发者大会上 谷歌如何依托科技创新 推动艺术与文化连接 传承和弘扬传统文化 自 2011 年成立以来&#xff0c;谷歌艺术与文化致力于提供体验艺术和文化的新方式&#xff0c;从生成…

mysql基于AES_ENCRYPTAES_DECRYPT实现密码的加密与解密

1.直接使用AES_ENCRYPT&&AES_DECRYPT函数导致的问题。 执行语句 select AES_ENCRYPT(cd123,key) 结果 加密过后的字符串是一串很奇怪的字符。 尝试使用上面加密过后的字符解密。 select AES_DECRYPT(u5£d|#,key) 结果 并未成功的解密 2.解决办法 使用 hex(…

【漏洞复现】网互联路由器存在密码泄露

漏洞描述 蜂网互联-让链接无限可能&#xff0c;灵活的多线分流&#xff0c;强大的策略分流&#xff0c;灵活调度各种软件应用&#xff0c;深度识别系统&#xff0c;各种应用一网打尽&#xff0c;灵活调整优先级&#xff0c;最简单的路由器&#xff0c;简洁易学的配置&#xff…

MyBatisPlus 基础Mapperr接口:增删改查

MyBatisPlus 基础Mapper接口&#xff1a;增删改查 插入一条数据 代码 Testpublic void insert() {User user new User();user.setId(6L);user.setName("张三");user.setAge(25);user.setEmail("zhangsanexample.com");userMapper.insert(user);}日志 数…

单元测试与自测

单元测试在百度百科的定义&#xff1a; 自测在百度百科的定义&#xff1a; 单元测试是测一个类或一个函数&#xff0c;自立门第main函数&#xff0c;不依赖于项目&#xff0c;预期的是这个类或函数是没有问题的。程序编码完成之后至各种测试再到用户使用一二十年出现的任何bug都…

IDEA中的“Deployment“ 将项目直接部署到服务器上

ntelliJ IDEA中的"Deployment"工具栏是一个方便的工具&#xff0c;用于将你的项目直接部署到服务器上。这个工具栏提供了三种部署的方式&#xff1a; 1.Web Server在本地电脑上&#xff0c;并且服务器运行目录也在项目目录下。 2.Web Server在本地电脑上&#xff0c;…

nuxt3项目使用pdfjs-dist预览pdf

使用的包的源代码是 pdfjs - npm 但是我们实际上项目中使用的是pdfjs打包后的dist文件&#xff0c;也就是pdfjs-dist - npm 所以我们需要使用这个命令 npm i pdfjs-dist 我们可以克隆pdfjs这个包来看源代码&#xff0c;里面有使用的例子&#xff0c;也可以根据源代码自己打…

Vue中数据可视化关系图展示与关系图分析

Vue中数据可视化关系图展示与关系图分析 数据可视化是现代Web应用程序的重要组成部分之一&#xff0c;它可以帮助我们以图形的方式呈现和分析复杂的数据关系。Vue.js是一个流行的JavaScript框架&#xff0c;它提供了强大的工具来构建数据可视化应用。本文将介绍如何使用Vue.js…

JavaWeb知识梳理(后端部分)

JavaWeb 静态web资源&#xff08;如html 页面&#xff09;&#xff1a;指web页面中供人们浏览的数据始终是不变。 动态web资源&#xff1a;指web页面中供人们浏览的数据是由程序产生的&#xff0c;不同时间点访问web页面看到的内容各不相同。 静态web资源开发技术&#xff1…

Spring Data JPA:简化数据库交互的艺术

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

代码随想录第45天|70. 爬楼梯,322. 零钱兑换,279.完全平方数

70. 爬楼梯 开始按感觉做 class Solution {public int climbStairs(int n) {//第一版按感觉做//dp[i]爬到第i个台阶的方法数int[] dpnew int[n1];//初始化dp[0]1;dp[1]1;for(int i2;i<n;i){dp[i]dp[i-1]dp[i-2];}return dp[n];} } 改进-用完全背包做 这是背包里求排列问…

ubuntu server 更改时区:上海

1. 打开终端&#xff0c;在命令行中以超级用户或具有sudo权限的用户身份运行以下命令&#xff1a; sudo dpkg-reconfigure tzdata 这会打开一个对话框&#xff0c;用于选择系统的时区设置。 2. 在对话框中&#xff0c;使用上下箭头键在地区列表中选择"Asia"&#x…

vue表格不显示列号123456

我在网上找了半天&#xff0c;都是如何添加列号123456的&#xff0c;没有找到不显示列号的参考&#xff0c;现在把这个解决了&#xff0c;特此记录一下。 没有加右边的就会显示&#xff0c;加上右边的就隐藏了

npm/yarn link 测试包时报错 Warning: Invalid hook call. Hooks can only be called ...

使用 dumi 开发 React 组件库时&#xff0c;为避免每次修改都发布到 npm&#xff0c;需要在本地的测试项目中使用 npm link 为组件库建立软连接&#xff0c;方便本地调试。 结果在本地测试项目使用 $ npm link 组件库 后&#xff0c;使用内部组件确报错&#xff1a; react.dev…

Redis十大数据类型

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

腾讯音乐基于 Apache Doris + 大模型构建全新智能数据服务平台

当前&#xff0c;大语言模型的应用正在全球范围内引发新一轮的技术革命与商业浪潮。腾讯音乐作为中国领先在线音乐娱乐平台&#xff0c;利用庞大用户群与多元场景的优势&#xff0c;持续探索大模型赛道的多元应用。本文将详细介绍腾讯音乐如何基于 Apache Doris 构建查询高效、…