马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
uORB原理与使用
李德强
欢迎关注公众号:编程外星人
飞控程序中内部消息传递采用的是异步消息机制uORB。它的设计理念很有趣,它可以实现不同模块中的数据快速通讯,并且以异步通讯为基本原则,也就是说在通讯过程中发送者只负责发送数据,而并不关心数据由谁接收,也不关心接收者是否能将所有的数据都接收到;而对于接收者来说并不关心数据是由谁发送的,也不关心在接收过程中是否将所有数据都接收到。关于uORB的设计原理我们会在后续章节中仔细讲述。这里只做一个简单的介绍,我们来举一个简单的例子说明一下uORB的设计原理: 有一个教室编号208,里面的黑板上可以写上一些文字内容,有一个同学名叫小强,他每隔1个小时就会来到208教室,先将黑板上原来的文字擦除,然后在黑板上写下一段新文字,之后离开208教室。而另外有一个同学叫小朋,他每隔3个小时就会来到208教室,将黑板上的文字抄写到自己的笔记本上,然后离开。我们可以用下列图例来说明一下这个过程:
我们可以看到,小强每次发布数据之后就会离开208教室,至于有没有人或是谁来读取他留下的文字,小强自己并不关心,也不再乎自己发布的数据是否有人收到了。而对于小朋来说,他每隔3小时来读取一次数据,至于这些数据是谁发布的他也不关心。他每隔3小时来读黑板上的文字时,其实小强已经在黑板上留言3次了,前两次的文字已经被小强擦除了,小朋看到的永远是小强留下最新的内容。 上面这个例子实际上就是uORB的实现原理: 发送者:小强每隔1小时发布一次数据orb_publish 接收者:小朋每隔3小时接收一次数据orb_copy
uORB在在数据发布与接收过程中并不保证发送者的所有数据都可以被接收者收到,而只保证接收者在想要接收时能收到最新的数据。而发送与接收的分离可以使飞程中各个模块相互独立,互不干扰。实际上一个uORB可以由多个发送者发布,也可以被多个接收者接收。实际上同一个uORB可以由多个发布者进行发布,而也可以由多个接收者接收,也就是说他们之间是多对多的关系。 下面我们来看一个具体的例子: 1.在msg文件夹中创建一个叫做extctl_sp.msg的文件,表示我们创建了一个新的uORB,它的名字叫作extctl_sp,其内容如下: bool run_pos_controlbool run_alt_controlbool run_yaw_controlfloat32 sp_yawfloat32 sp_xfloat32 sp_yfloat32 sp_zfloat32 vel_sp_xfloat32 vel_sp_yfloat32 vel_sp_z
这是作者在做“外部控制”模式下所用到的一个uORB,在本节中读者可以不用了解其中变量的具体含义,只知道我们需要在extctl_sp.msg中定义一些指定属性即可。不过需要注意其定义的语法与C/C++类似但有些不同,参考PX4中现有的msg文件内容即可。 2.在msg文件夹中的CMakeLists.txt中添加刚刚我们添加的extctl_sp.msg,表示对其做编译处理:
即程序在编译时会根据extctl_sp.msg生成extctl_sp.h和extctl_sp.cpp文件,也就是我们在程序中所用到的结构定义: #pragma once#include #ifndef __cplusplus#endif#ifdef __cplusplusstruct __EXPORT extctl_sp_s {#elsestruct extctl_sp_s {#endif uint64_t timestamp; // required for logger float sp_yaw; float sp_x; float sp_y; float sp_z; float vel_sp_x; float vel_sp_y; float vel_sp_z; bool run_pos_control; bool run_alt_control; bool run_yaw_control; uint8_t _padding0[1]; // required for logger#ifdef __cplusplus#endif};/* register this as object request broker structure */ORB_DECLARE(extctl_sp);
3.发布者发布uORB时需要做两步操作: (1)公告/多重公告uORB; (2)发布uORB。 我们来看下面的的发布者的例子: //首先在头文件中包含此uORB#include <uORB/topics/extctl_sp.h>...//uORB中msg生成后的结构体struct extctl_sp_s _orb_sp = { 0 };//公告主题int _orb_sp_instance = -1;//多重公告uORBorb_advert_t _orb_sp_topic = orb_advertise_multi(ORB_ID(extctl_sp), &_orb_sp, &_orb_sp_instance, ORB_PRIO_DEFAULT);...//对_orb_sp结构体对象进行赋值...//发布uORBint ret = orb_publish(ORB_ID(extctl_sp), _orb_sp_topic, &_orb_sp);
4.接收者接收uORB时需要做三步操作: (1)订阅uORB; (2)判断uORB数据是否有更新。 (3)复制uORB数据内容到本地内存。 我们来看下面的的者接收的例子 //首先在头文件中包含此uORB#include <uORB/topics/extctl_sp.h>...//uORB中msg生成后的结构体struct extctl_sp_s extctl_sp_s = { 0 };//订阅uORBint extctl_sp_sub = orb_subscribe(ORB_ID(extctl_sp));...bool updated = false;//判断uORB是否有更新orb_check(extctl_sp_sub, &updated);if (updated){ //复制uORB数据内容到本地内存 orb_copy(ORB_ID(extctl_sp), extctl_sp_sub, &extctl_sp_s); //使用本地内存中结构体对象 ...}
这就是uORB的使用方法,注意,发布和订阅只需要执行一次即可,而发布、检查更新和接收可以执行多次。下面我们来看看uORB中比较关键的几个函数的定义: //公告orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data, unsigned int queue_size = 1);//多重公告orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority, unsigned int queue_size = 1);//取消公告int orb_unadvertise(orb_advert_t handle);//发布int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data);//订阅int orb_subscribe(const struct orb_metadata *meta);//多重订阅int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance);//取消订阅int orb_unsubscribe(int handle);//检查是否有数据更新int orb_check(int handle, bool *updated);//接收,复制数据到本地内存int orb_copy(const struct orb_metadata *meta, int handle, void *buffer);//检查uORB是否存在int orb_exists(const struct orb_metadata *meta, int instance);//取得优先级int orb_priority(int handle, int32_t *priority);
关于这些函数的用法、参数及反回值不做过多的说明,这些函数的参数和反回值源代码中有详细的说明,还是比较容易理解和使用的。
|