px4_simple_example和uorb机制

2023-05-16

    px4_simple_app(PX4-Autopilot/src/exampes/px4_simple_app)这个程序是用c语言调用orb APIpoll机制订阅和发布通讯数据,但是这个例子并不是既有接收又有发送的完整例子。例子中订阅了主题vehicle_acceleration,但是程序中没有发布(publish)这个主题数据的程序。反过来,这个程序advertise/publish主题vehicle_attitude,但是没有subscribe/copy这个主题的程序。所以,这个例子是不完整的。

    这个例子不好做,因为如果从自己建立主题开始可能其过程过于复杂了。介绍建立主题本身就是一个过程,因为这里面有代码自动生成的软件。

    传统的基于clientserver通讯方法是clientserver请求发送数据,server接收请求,然后把请求的数据发送给client。这个没有问题,但是,反过来做双向通讯,就需要两边都有clientserver,这就增加了程序的复杂性了。确实,orb机制就是想解决任意两个程序模块之间的双向通讯。

    有了orb机制,你并不需要自己做client/serverorb帮助你做了,当然也是用了client/server的办法,只是隐藏在了底层。

    在orb机制中,被传输数据的数据结构在发送端和接收端都是已知的,或者说,数据结构在两边是共享的。比如:要传输的是一个整形数或者字符串,或者一个复杂的数据结构,数据可以是任意的,但结构是确定的。一个数据结构是一个数据实体的描述,它有自己的名字。比如:这里为了便于理解,我们把例子中的vehicle_acceleration(数据本身有点复杂)的主题名字改成position。对于数据实体为position的数据,我们用数据结构描述如下:

struct position{ int xint yint z};

position描述了一个飞行器在三维空间中的坐标。

    一个程序A请求另一个叫orb的程序将position数据发送给A,请求发送数据的程序A只需要把这个数据结构的名字发送给程序orb,然后等待(px4_poll)数据更新通知事件发生(POLLIN)。

    orb程序在接到A的请求后知道了请求发送的数据的名字是positionorb不是直接将position这个名字对应的数据发送给A,而是注册position这个名字和请求程序A的名字,这个注册记载了A程序想得到position数据。然而真正产生position数据的程序不是orb这个程序,而是程序C。程序C定期从传感器获取当前的position数据并向数据交换存储区发送数据,当然在此之前,也要注册一下postition数据的名字以及发送程序C的名字,这个注册与ORBA的请求注册是一个地方,不一样的是,possition名字后还有个发送程序的名字。这样,这个注册表除了position名字,还有请求者的名字(多个,可以想象成一个链表)和发送者的名字(多个,可以想象成一个链表)。

    一旦position数据更新,由于orb可以从注册表中知道“A想拿到position数据”,所以,可以通知(触发POLLIN事件)程序A取走数据。另外更新position的程序会在注册表中标识它更新了当前数据,所以,orb也可以让A程序知道当前的position数据是哪个程序发送的,供A选择。

    orb_advertise_multi中的instance是输出参数这个instanceorb程序产生并返回给应用程序,应用程序可以用这个instanceorb程序说明我要哪个主题数据

   想象一个两个程序都在更新position数据的例子:

北斗模块

pub_handle = orb_advertise_multi(ORB_ID(position), &beidou_position, &instance_beidou, 1));

---将北斗传感器数据存到beidou_speed变量中,然后

publishORB_ID(position), pub_handle, &beidou_position);

负责发送北斗数据的程序执行上面语句,则instance_beidou就存储了标识北斗数据发送者的信息

gps模块

pub_handle = orb_advertise_multi(ORB_ID(position), &gps_position, &instance_gps1));

---gps传感器数据存到gps_position变量中,然后

publishORB_ID(position), pub_handle, &beidou_position);

负责发送GPS数据的程序执行上述语句,则instance_gps就存储了标识GPS数据发送者的信息;

A程序如果想得到北斗数据,则

sub_fd = orb_subscribe_multi(ORB_ID(position), instance_beidou);

copy(ORB_ID(position), sub_fd, &beidou_position);

想得到GPS数据,则

sub = orb_subscribe_multi(ORB_ID(position), instance_gps);

copy(ORB_ID(speed), sub_fd, &gps_position);

   如果position这个数据只有一个发送源,就不必区分了; 所谓的instance_beidouinstance_gps里面存的是什么,其实不必关心,就是一整数,是由orb程序生成的

   每个主题都有对应的instance,如果只有一个数据发送源,instance就是0。在程序语言中我们把instance叫实例,第一次调用orb_subscribe_multi给它编号为1,第二次调用orb_subscribe_multi, 编号为2,同一个程序被调用了两次,每次执行的虽然是同一个程序,但是需要当两个不同程序来看待,这样就需要区分,通常用数字区分,这就是instance里面存储内容的意义。

   从上面所述可以看出几点,首先交换数据的存储区是两个模块AC之间共享的,当前放在存储区的position数据是谁要的,是谁发的,在注册表中都有标识ORB负责告诉你position数据长什么样?因为在注册表中注册了position的名字,所以,数据结构两边都是知道的。

   另外A不需要知道C的存在,因为可能存在多个C发送position数据确实存在这样一种情况,虽然数据来源不一样,但是数据结构的名字是一样的,比如:为了获得可靠数据安装了多种传感器,传感器数据是一样的,其数据结构当然是一样的,没有必要起不同的名字)至于是哪种传感器程序发送的position数据,orb程序在C程序以及其他程序在注册position数据时加以区分。

   其次C程序不需要关心取position数据的是谁,因为可能存在多个程序在请求发送position数据,至于是程序A1还是程序A2请求发送则由orb程序在A程序注册请求position的时候加以区分

   最后可以知道ORB只是一个代理,并不真正产生position数据。

   所有PX4能传输的数据的数据结构在PX4-Autopilot/msg中都定义好了,PX4通过代码自动生成了可以用在C/C++中的数据结构定义,它们被保存在目录PX4-Autopilot/build/uORB/topics中。

   px4_poll机制是这样的poll这个动作是一个让你的线程停下来的操作,停下来的目的是与orb机制打交道的还有另外一个程序C,它将在适当的时候通知你的线程,你可以继续运行了,因为程序C已经改变了你程序中变量的值,你可以检查这个值变成什么样了,你自己做判断。通常这个值叫POLLIN,表明你想要的数据准备好了,可以把它取走了。你可以把你的程序叫client把这个C线程叫server在这个例子中,这个server是一个PX4中运行的模块,在: PX4-Autopilot/src/module/sensors/vehicle_acceration目录中。事实上,在PX4中几乎所有module(模块)都可以看作是server。

   综上所述orb机制确实在多个模块之间实现了多个client和多个server,在orb机制下,client和server两边都知道要交换的数据的数据结构。

   题外话,这自然让我想到,DDS这种机制与uorb机制本质是一样的,由于两边的数据结构都知道,因此,写和读符合这些数据结构的数据的程序也可以自动生成了,uorb没有做到这一点,然而这正是DDS的核心技术之一。ROS2已经把DDS作为offboard计算机与PX4 uORB通讯的机制,实现了两对orb机制进行通讯,进一步,ROS团队还准备把完整的DDS放进PX4,不知道何时能实现。如果真实现了,MAVSDK怎么办?mavlink团队和ROS团队竞争激烈,但是作为用户,我们只能有一种选择吧。

  • 关于ORB_ID这个宏的含义:

应用程序如果用到一个主题,比如px4的官方用例px4_simple_app.c中,一般都需要include 2个文件:

#include <uORB/uORB.h>

#include <uORB/topics/vehicle_acceleration.h>

uORB.h是在platforms/common/uORB目录中,是编译前就存在的,是uORB系统通用的一些机制的定义。vehicle_acceleration.h是在/build/uORB/topics目录中。vehicle_acceleration这个主题对应的定义是在编译过程中自动生成的。

在vehicle_acceleration.h文件中:

ORB_DECLARE(vehicle_acceleration);

ORB_DECLARE()是一个宏,它在uORB.h中定义,这句话的意思是定义一个vehicle_accelerationorb对象。我们看这个宏的定义:

//

#if defined(__cplusplus)

# define ORB_DECLARE(_name) extern "C" const struct orb_metadata __orb_##_name __EXPORT

#else

# define ORB_DECLARE(_name) extern const struct orb_metadata __orb_##_name __EXPORT

#endif

///

在代入vehicle_acceleration这个名字后展开得到:

extern const struct orb_metadata __orb_vehicle_acceleration __EXPORT

这就是vehicle_acceleration这个orb对象的名字,叫__orb_vehicle_acceleration

    接收PX4的消息,应用程序需要订阅(subscribe)主题,订阅的目的是告诉PX4的发送方,我要你传输符合这个主题的数据,我等待接收。执行下面的API就可以订阅一个主题:

int sensor_sub_fd = orb_subscribe(ORB_ID(vehicle_acceleration));

orb_subscribePX4uORB系统提供的一个API,其他API都在uORB.h中定义了,所以,也需要include <uORB.h>API在这里都做了声明,详细的API定义可以参看:uORBManager.hpp

    在subscribe函数中,第一个参数是函数ORB_ID(),这个函数可以从主题名字获得主题id,在编译时,已经为每个主题名字编了一个序号,返回的就是这个序号,见build/px4_sitl_default/uORB/topics/uORBTopics.h

    ORB_ID()也是一个宏,它在uORB.h中定义,我们来看ORB_ID这个宏定义:

//

#define ORB_ID(_name) &__orb_##_name

///

在代入vehicle_acceleration这个名字后展开得到:

&__orb_vehicle_acceleration

这样

int sensor_sub_fd = orb_subscribe(ORB_ID(vehicle_acceleration));

就变成了

int sensor_sub_fd = orb_subscribe(&__orb_vehicle_acceleration));

这样,orb_subscribe函数传入的就是一个指向__orb_vehicle_acceleration对象的指针。

__orb_vehicle_acceleration这个对象长什么样?其实在vehicle_acceleration.cpp中已经有定义,也是在编译时自动生成的,存放在build/px4_sitl_default/msg/topics_sources中。我们来看这个文件中的内容:

#include <uORB/topics/vehicle_acceleration.h>

#include <uORB/topics/uORBTopics.hpp>

// 上述略去其他.h文件

constexpr char __orb_vehicle_acceleration_fields[] = "uint64_t timestamp;uint64_t timestamp_sample;float[3] xyz;uint8_t[4] _padding0;";

ORB_DEFINE(vehicle_acceleration, struct vehicle_acceleration_s, 28, __orb_vehicle_acceleration_fields, static_cast<uint8_t>(ORB_ID::vehicle_acceleration));

其中ORB_DEFINE是一个宏,在uORB.h中定义,我们来看这个宏:

ORB_DEFINE()宏定义:

//

#define ORB_DEFINE(_name, _struct, _size_no_padding, _fields, _orb_id_enum) \

const struct orb_metadata __orb_##_name = {

#_name,

sizeof(_struct),

_size_no_padding,

_fields,

_orb_id_enum

}; struct hack

//

ORB_DEFINE(vehicle_acceleration, struct vehicle_acceleration_s, 28, __orb_vehicle_acceleration_fields, static_cast<uint8_t>(ORB_ID::vehicle_acceleration)) 宏替换展开后

//

const struct orb_metadata __orb_vehicle_acceleration = {

vehicle_acceleration”,

sizeof(vehicle_acceleration_s),

28,

"uint64_t timestamp;uint64_t timestamp_sample;float[3] xyz;uint8_t[4] _padding0;",

150

}; struct hack

//

这里vehicle_acceleration_svehicle_acceleration.h已经定义:

struct vehicle_acceleration_s {

uint64_t timestamp;

uint64_t timestamp_sample;

float xyz[3];

uint8_t _padding0[4]; // required for logger

}

可以简单计算,这个结构的尺寸是28个字节。sizeof(struct vehicle_acceleration_s)算出来也是28,150是在uORB系统为vehecle_acceleration这种对象的一个编号,在uORBTopics.h中已经有定义。

orb_metadata类型也已经在uORB.h中定义如下

struct orb_metadata {

const char *o_name; /**< unique object name */

const uint16_t o_size; /**< object size */

const uint16_t o_size_no_padding;

/**< object size w/o padding at the end (for logger) */

const char *o_fields;

/**< semicolon separated list of fields (with type) */

uint8_t o_id; /**< ORB_ID enum */

};

这样就知道__orb_vehicle_acceleration是一个类型为orb_metadata的对象,在uORB机制中,这个对象叫object request broker,对象请求代理。orb_subscribe要的是指向这个对象的指针,这个对象是个常量,这个常量是orb_metadata类的一个实例instance。有了这个对象请求代理,uORB机制就可以用它来读写vehicle_acceleration这个主题的数据,因为orb机制已经知道应用程序想要的数据的尺寸。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

px4_simple_example和uorb机制 的相关文章

  • PX4位置控制offboard模式说明

    offboard模式的开发及应用 一 px4固件的模式 px4固件支持10几种飞行模式 xff0c 从代码结构上分析 xff0c 分为基本模式 自定义模式和自定义子模式 1 基本模式 基本模式又分为 xff0c 位置控制模式 自稳模式 手动
  • tensorflow lite example label_image 分析【二】

    接上文 3 代码分析 main函数首先将入参写入参数结构体 Settings s struct Settings bool verbose 61 false bool accel 61 false bool input floating 6
  • 关于PX4中的高度若干问题

    飞行的高度是如何测量的 xff1f 地面的高度和海平面的高度差别很大 xff0c 飞控又是如何有效判别进行降落的 xff1f 这是我脑子里的疑问 搜索的一圈发现很少有人讨论这方面的问题 xff0c 于是本次我就直接看一下源代码 xff0c
  • UORB

    转载地址 xff1a http blog arm so armteg pixhawk 183 0503 html Pixhawk 飞控 系统是基于ARM的四轴以上飞行器的飞行控制器 xff0c 它的前身是PX4 IMU xff0c Pixh
  • Ubuntu20.04+MAVROS+PX4+Gazebo保姆级安装教程

    Ubuntu20 04 43 MAVROS 43 PX4 43 Gazebo 安装PX4步骤安装MAVROS安装QGCPX4仿真 安装PX4步骤 从github上clone源码 span class token function git s
  • PX4代码学习系列博客(6)——offboard模式位置控制代码分析

    分析offboard模式的代码需要用到以下几个模块 local position estimator mavlink mc pos control mc att control mixer 程序数据走向 mavlink 一般的offboar
  • 从Simulink到PX4——Simulink-PX4插件安装与环境搭建

    从Simulink到PX4 Simulink PX4插件安装与环境搭建 前言0 准备工作1 安装WSL2 Setting up the PX4 Toolchain on Windows3 Setting up the PX4 Tool Ch
  • PX4模块设计之三:自定义uORB消息

    PX4模块设计之三 xff1a 自定义uORB消息 1 新增自定义uORB消息步骤2 应用ext hello world消息示例3 编译执行结果4 参考资料 基于PX4开源软件框架简明简介和PX4模块设计之二 xff1a uORB消息代理
  • PX4模块设计之四:MAVLink简介

    PX4模块设计之四 xff1a MAVLink简介 1 MAVLink PX4 应用简介2 MAVLink v2 0新特性3 MAVLink协议版本4 MAVLink通信协议帧4 1 MAVLink v1 0 帧格式4 2 MAVLink
  • PX4模块设计之三十:Hysteresis类

    PX4模块设计之三十 xff1a Hysteresis类 1 Hysteresis类简介2 Hysteresis类成员变量介绍3 Hysteresis类迟滞逻辑4 Hysteresis类重要方法4 1 Hysteresis bool ini
  • PX4模块设计之三十一:ManualControl模块

    PX4模块设计之三十一 xff1a ManualControl模块 1 ManualControl模块简介2 模块入口函数2 1 主入口manual control main2 2 自定义子命令custom command 3 Manual
  • PX4模块设计之四十七:mavlink模块

    PX4模块设计之四十七 xff1a mavlink模块 1 mavlink模块简介2 模块入口函数mavlink main3 mavlink模块重要函数3 1 Mavlink start3 2 Mavlink task main3 3 Ma
  • px4_simple_example和uorb机制

    px4 simple app PX4 Autopilot src exampes px4 simple app xff0c 这个程序是用c语言调用orb API和poll机制订阅和发布通讯数据 xff0c 但是这个例子并不是既有接收又有发送
  • px4仿真无法起飞问题(Failsafe enabled: no datalink)

    报错信息 问题描述 xff1a 使用JMAVSim和gazebo仿真px4起飞时报错如下 xff1a WARN commander Failsafe enabled no datalink 说不安全 解决方法 打开QGC 就可以起飞了
  • 【px4】运行mavsdk中的offboard example

    运行MAVSDK中的offboard例子时无人机不执行 想控制无人机前后左右移动 xff0c 在按照官方教程实现offboard 插件的时候 发现用action插件能正常起飞和降落 但是一旦执行到offboard的插件代码的时候就会自动降落
  • px4下载指定版本的固件、git用法

    https hub fastgit org PX4 PX4 Autopilot git describe tag 查看当前版本号 git tag l 查看所有版本 xff0c 也就是打个tag git checkout v1 9 1 跳转到
  • the english of the simple view

    自述 xff1a 我的英语很差 xff0c 四级至今没有过 xff0c 在新东方报班学的一些东西 xff0c 只是想着简单的记录下来 xff0c 权当做新一次的整理笔记 xff0c 归纳 xff0c 希望也能帮助大家 1 200个核心词汇
  • PX4之常用函数解读

    PX4Firmware 经常有人将Pixhawk PX4 APM还有ArduPilot弄混 这里首先还是简要说明一下 xff1a Pixhawk是飞控硬件平台 xff0c PX4和ArduPilot都是开源的可以烧写到Pixhawk飞控中的
  • uORB笔记

    不同的类调用同一函数orb subscribe ORB ID vehicle gps position xff0c 来订阅GPS信息是 xff0c 该函数返回的值不同 xff0c 也就是说每个订阅者针对同一主题 xff0c 在调用函数orb
  • PX4:Policy “CMP0097“ is not known to this version of CMake.

    make px4 fmu v3 时报的错 CMake版本的问题 由https blog csdn net zhizhengguan article details 118380965推测 xff0c 删除cmake policy也没事 ma

随机推荐

  • linux下常用压缩命令

    一 tar命令 tar命令用来打包一个目录 xff0c 它支持三种格式 xff1a tar bz2 34 和 gz 34 1 1 压缩 tar cvf 文件名 tar 文件目录 打包成 tar文件 tar jcvf 文件名 tar bz2
  • 用vscode开发autojs,输出窗口不显示任何输出结果

    我的情况是 xff1a 我vscode开发autojs 程序 xff0c 之前在一切正常的情况下 xff0c 输出窗口可以正常显示程序运行结果 xff0c 右侧红圈里可以选择我连接的手机型号 如下图 xff1a 但是现在出现问题 xff1a
  • ubuntu开机没有ens33解决方法

    最近重新安装了VMware xff0c 使用之前的ubuntu镜像 xff0c 发现只有一个lo网卡 xff0c 没有ens33 xff0c 虚拟机无法获取ip地址 xff0c samba服务器也无法正常使用 root 64 ubuntu
  • ubuntu下arm-none-eabi-gcc安装

    一 下载安装包 下载地址 xff1a https launchpad net gcc arm embedded 43 download 选择linux版本下载 xff1a gcc arm none eabi 5 4 2016q3 20160
  • 2.4G-WiFi连接路由器过程

    一 概述 WiFi的数据通信基于802 11协议进行 xff0c 无线AP在工作时会定时向空中发送beacon数据包 xff0c 基站 xff08 STA xff09 从beacon中解析出AP的名称 加密方式等信息 xff0c 从而发起连
  • STM32f103时钟树详解

    一 概述 stm32有四种时钟信号源 xff0c HSE 高速外部时钟 HSI xff08 高速内部时钟 xff09 LSE xff08 低速外部时钟 xff09 LSI xff08 低速内部时钟 xff09 HSE通常接8M晶振 xff0
  • 头文件重复包含

    一 头文件重复包含问题分析 1 问题重现 举例说明 假设在某个C 43 43 头文件 或 源文件 中 xff0c 包含了A h和B h两个头文件 xff1a span class token macro property span clas
  • Netty 学习(六)实现自定义协议通信

    目录 前言一 通信协议设计通用协议自定义协议网络协议需要具备的要素1 魔数2 协议版本号3 序列化算法4 报文类型5 长度域字段6 请求数据7 状态8 校验字段9 保留字段 二 Netty 实现自定义通信协议Netty 中编解码器分类 三
  • ABB机器人与上位机进行Socket通信的RAPID代码实现(服务端)

    文章目录 前言1 实现的功能2 建立Socket通信2 1 ABB机器人的IP地址 xff1a 2 2 SocketAccept的说明 3 服务端接发信息3 1 核心代码3 2 CurrentPos函数 4 完整代码5 实现效果 前言 本文
  • ros使用自定义消息时,编译不成功,在Cmake中报错.

    在使用自定义消息时 xff0c 按照教程添加依赖和cmakelist文件后 xff0c 保证几条Cmake语句顺序无误的情况下 xff0c 考虑msg文件夹的位置 xff0c 应在功能包的第一级目录中
  • C语言加强--韦老师公开课

    目录 1 变量与指针 摘要 xff1a 普通变量 指针变量所占的内存空间大小 xff0c 变量在内存中的分配方式 xff08 首地址要求 长度 分配长度与实际使用长度区别 需要填充字节数 全局与局部变量在内存中的位置 xff09 xff1b
  • 大小端转换(一篇文章了解所有情况下的大小端转换方法)

    总述 xff1a 字节间字节内大端低地址的数据放在高字节位域 xff1a 先从低地址对应数据字节的高bit开始分配小端低地址的数据放在低字节位域 xff1a 先从低地址对应数据字节的低bit开始分配 注释 xff1a 对于大小端的几个结论
  • C语言程序内存四区——栈区,堆区,全局区,代码区

    1 全局区 xff1a 全局区比较特殊 xff0c 里面还分成了全局变量区 xff0c 静态变量区 xff0c 常量区 全局变量区用来存放全局变量 xff0c 静态变量区用来存放带有static修饰的变量 xff08 包括静态局部变量和静态
  • Linux 用户和组

    用户和组 前言一 查看用户二 基本操作1 添加用户2 查看3 修改密码4 切换用户5 其他6 登出 前言 一个用户可以属于多个组 xff0c 并且拥有这些组的权限 一 查看用户 输入命令 cat span class token opera
  • pip 清华镜像

    pip 清华镜像 一 地址二 使用 一 地址 https pypi tuna tsinghua edu cn simple 二 使用
  • requests库将cookieJar对象转换为cookies字典

    requests库将cookieJar对象转换为cookies字典 转字典转cookieJar 使用requests获取的resposne对象 xff0c 具有cookies属性 该属性值是一个cookieJar类型 转字典 cookies
  • mybatis-generator-core插件无法下载解决办法

    mybatis generator core插件无法下载解决办法 前言一 解决办法二 插件可用 前言 maven mybatis generator core插件无法下载 一 解决办法 二 插件可用
  • idea 去绿色波浪线

    idea 去绿色波浪线 如图 如图
  • stop-writes-on-bgsave-error

    redis RDB持久化配置 RDB持久化 配置 stop writes on bgsave error 选项 如果 61 yes xff1a redis 会创建一个新的后台进程dump rdb 假设 xff1a 创建快照 xff08 硬盘
  • px4_simple_example和uorb机制

    px4 simple app PX4 Autopilot src exampes px4 simple app xff0c 这个程序是用c语言调用orb API和poll机制订阅和发布通讯数据 xff0c 但是这个例子并不是既有接收又有发送