px4中的uorb是px4非常核心的数据通信机制,所有线程的通信都是靠uorb完成,用过的人可能,仅仅知道在想要获取orb数据的时候,先进行订阅,在发送orb消息之前,先公告主题,uorb是如何工作的?可能少于人知道。直接上代码!!
- 使用方法
1.发送orb消息: 【orb_advertise订阅】 【orb_publisb发布】
2. 获取orb消息 【orb_subscribe订阅】 【orb_check检测】【orb_copy提取】
- 单元测试代码
1. 代码架构
- 2. 编译代码调试代码
我们把这个文件放到nuttx_px4fmu-v2_default.cmake中,px4默认的已经把uorb_tests的单元测试已经放到nuttx_px4fmu-v2_default.cmake中,已经构建完成, 这个就是uorb_test就是px4自己写的uorb单元测试代码,px4的各个模块的代码都会有自己单元测试代码,这个是非常好的让我们理解模块设计者的思想。 下面我们编译下载,px4工程,同时进入nsh控制台输入uorb_tests可以看到下面的输出信息。
3. 查看设备树
我们会发现设备树下出现了很多的orb消息的节点,节点是如何生成的???
4. 分析代码,找到线程入口函数uorb_tests_main, 进入t.test()方法
- 代码分析
追踪orb公告和订阅的函数,我们可以发现这个,他们最终都调用了node_open的函数,区别在公告的时候传递参数
advertiser 是true, 在订阅的时候advertiser是flase,
函数
当我们知道最核心的代码是node_open的时候,我们查看node_open的实现方法
int uORB::Manager::node_open
(
Flavor f,
const struct orb_metadata *meta,
const void *data,
bool advertiser,
int *instance,
int priority
)
{
char path[orb_maxpath];
int fd = -1, ret;
/*
* If meta is null, the object was not defined, i.e. it is not
* known to the system. We can't advertise/subscribe such a thing.
*/
if (nullptr == meta) {
errno = ENOENT;
return ERROR;
}
/*
* Advertiser must publish an initial value.
*/
if (advertiser && (data == nullptr)) {
errno = EINVAL;
return ERROR;
}
/* if we have an instance and are an advertiser, we will generate a new node and set the instance,
* so we do not need to open here */
if (!instance || !advertiser) {
/*
* Generate the path to the node and try to open it.
*/
ret = uORB::Utils::node_mkpath(path, f, meta, instance);
if (ret != OK) {
errno = -ret;
return ERROR;
}
/* open the path as either the advertiser or the subscriber */
fd = px4_open(path, advertiser ? PX4_F_WRONLY : PX4_F_RDONLY);
} else {
*instance = 0;
}
/* we may need to advertise the node... */
这个代码也很长,我们分析这个代码
1. 首先在公告的时候,会创建路径
ret = uORB::Utils::node_mkpath(path, f, meta, instance);
2. 打开这个路径,作为文件句柄
fd = px4_open(path, advertiser ? PX4_F_WRONLY : PX4_F_RDONLY);
注意:从"advertiser ?PX4_F_WRONLY : PX4_F_RDONLY"这里我们orb最重要的思想是,订阅仅仅是读,发布仅仅是写。
3. 可能很多人都知道,orb的主题的订阅和公告是分开,也就是说没有线程公告主题,订阅也会成功,这是如何实现?
if (fd < 0) {
/* try to create the node */
ret = node_advertise(meta, instance, priority);
从这里就可以看出,订阅的时候,打开路径失败,就是公告主题,也就是这个原因,让orb不会限制线程的启动顺序导致orb订阅失败.