rtthread移植实现uorb

2023-05-16

       uORB(Micro Object Request Broker,微对象请求代理器)是PX4/Pixhawk系统中非常重要且关键的一个模块,它肩负了整个系统的数据传输任务,所有的传感器数据、GPS、PPM信号等都要从芯片获取后通过uORB进行传输到各个模块进行计算处理。实际上uORB是一套跨「进程」的IPC通讯模块。所有的功能被独立以进程模块为单位进行实现并工作。而进程间的数据交互就由为重要,必须要能够符合实时、有序的特点。uORB实际上是多个进程打开同一个设备文件,进程间通过此文件节点进行数据交互和共享。进程通过命名的「总线」交换的消息称之为「主题」(topic),一个主题仅包含一种消息类型,通俗点就是数据类型。每个进程可以「订阅」或者「发布」主题,可以存在多个发布者,或者一个进程可以订阅多个主题,但是一条总线上始终只有一条消息。

       uORB的设计理念很有趣,它可以实现不同模块中的数据快速通讯,并且以异步通讯为基本原则,也就是说在通讯过程中发送者只负责发送数据,而并不关心数据由谁接收,也不关心接收者是否能将所有的数据都接收到;而对于接收者来说并不关心数据是由谁发送的,也不关心在接收过程中是否将所有数据都接收到。关于uORB的设计原理我们会在后续章节中仔细讲述。这里只做一个简单的介绍,我们来举一个简单的例子说明一下uORB的设计原理:

        有一个教室编号208,里面的黑板上可以写上一些文字内容,有一个同学名叫小强,他每隔1个小时就会来到208教室,先将黑板上原来的文字擦除,然后在黑板上写下一段新文字,之后离开208教室。而另外有一个同学叫小朋,他每隔3个小时就会来到208教室,将黑板上的文字抄写到自己的笔记本上,然后离开。我们可以用下列图例来说明一下这个过程:

                                                   ​

 

       我们可以看到,小强每次发布数据之后就会离开208教室,至于有没有人或是谁来读取他留下的文字,小强自己并不关心,也不再乎自己发布的数据是否有人收到了。而对于小朋来说,他每隔3小时来读取一次数据,至于这些数据是谁发布的他也不关心。他每隔3小时来读黑板上的文字时,其实小强已经在黑板上留言3次了,前两次的文字已经被小强擦除了,小朋看到的永远是小强留下最新的内容。

上面这个例子实际上就是uORB的实现原理:

发送者:小强每隔1小时发布一次数据orb_publish

接收者:小朋每隔3小时接收一次数据orb_copy

        uORB在在数据发布与接收过程中并不保证发送者的所有数据都可以被接收者收到,而只保证接收者在想要接收时能收到最新的数据。而发送与接收的分离可以使飞程中各个模块相互独立,互不干扰。实际上一个uORB可以由多个发送者发布,也可以被多个接收者接收。实际上同一个uORB可以由多个发布者进行发布,而也可以由多个接收者接收,也就是说他们之间是多对多的关系。

应用程序框架

 

 

     rtthread中利用事件实现uorb功能将其作为中间层,运行于操作系统之上,提供设备驱动和一个微对象请求代理(micro object request broker ,uorb)用于飞控上运行的单个任务之间的异步通信。下面是实现方式:

#define EVENT_ORB_DATA_UPDATE   	0x02
#define ORB_ID(_name)       		&__orb_##_name
#define ORB_DECLARE(_name) 			extern orb_node __orb_##_name

/* orb主题定义 */
typedef struct orb_subscriber
{
    void *update;					
    char subscriber[RT_NAME_MAX];	
    rt_list_t subscriber;	
} orb_subscriber;

/* orb节点定义 */
typedef struct orb_node
{
    const char *name;				
    uint32_t size;					
    uint32_t updated_num;			
    uint32_t subscriber_num;	
    rt_thread_t advertiser;			
    void *orb_data;					
#ifdef UORB_USING_MUTEX				
    rt_mutex_t node_lock;			
#endif
    rt_list_t sub_list;
} orb_node;

/**
 * 定义(实例化)主题的uORB元数据。
 * 注意:对于每个主题,此宏的实例不能超过一个。
 * @param _name     主题名。
 * @param _struct   发布数据结构体。
 */
#ifdef UORB_USING_MUTEX
#define ORB_DEFINE(_name, _struct)          \
        orb_node __orb_##_name = {          \
        #_name,                             \
        sizeof(_struct),                    \
        0,                                  \
        0,                                  \
        RT_NULL,                            \
        RT_NULL,                            \
        RT_NULL,                            \
        RT_NULL,                            \
		RT_NULL
    };
#else
#define ORB_DEFINE(_name, _struct)          \
        orb_node __orb_##_name = {          \
        #_name,                             \
        sizeof(_struct),                    \
        0,                                  \
        0,                                  \
        RT_NULL,                            \
        RT_NULL,                            \
        RT_NULL,                            \
		RT_NULL
    };
#endif


/* 发布orb节点主题 */
rt_err_t orb_advertise(orb_node *node)
{
    if(node->orb_data == RT_NULL)
    {
        node->orb_data = rt_malloc(node->size);			//申请节点通讯数据空间
        node->advertiser = rt_thread_self();			
#ifdef UORB_USING_MUTEX
        node->node_lock = rt_mutex_create(node->name, RT_IPC_FLAG_FIFO);
#endif
        rt_list_init(&node->sub_list);					//订阅主题链接初始化
    }
}

/* 从节点处订阅ORB主题*/
rt_err_t orb_subscribe(orb_node *node,uint32_t *event)
{
    rt_uint32_t level;
    struct rt_event *update = RT_NULL;
    struct orb_subscriber *new_subscriber = RT_NULL;
    char name[RT_NAME_MAX+4] = "orb_";
    rt_thread_t self = rt_thread_self();
   
#ifdef UORB_USING_MUTEX
    rt_mutex_take(node->node_lock, RT_WAITING_FOREVER);
#else
    level = rt_hw_interrupt_disable();
#endif
    strcpy(&name[4],self->name);						
    update = rt_event_create(name, RT_IPC_FLAG_FIFO);	//创建跟新事件主题
    *event = (uint32_t)update;							//将当前跟新事件句柄返回应用层

    new_subscriber = (struct orb_subscriber*)rt_malloc(sizeof(struct orb_subscriber));
    strcpy(new_subscriber->subscriber,self->name);
    new_subscriber->update = update;									//记录主题
	rt_list_insert_after(&node->sub_list,&new_subscriber->subscriber)	//将主题加入到节点中
    node->subscriber_num++;
#ifdef UORB_USING_MUTEX
    rt_mutex_release(node->node_lock);
#else
    rt_hw_interrupt_enable(level);
#endif
    return RT_EOK;
}

/* 从节点处自动订阅主题 */
rt_err_t orb_subscribe_auto(orb_node *node,uint32_t *event,uint32_t time_out)
{
    while (time_out--)
    {
        if (orb_subscribe(node, event) == RT_ERROR)
        {
            rt_thread_delay(RT_TICK_PER_SECOND/5);
        }
    }
    return RT_ERROR;
}
/* 从节点处自动取消订阅主题 */
rt_err_t orb_unsubscribe_auto(orb_node *node,uint32_t *event,uint32_t time_out)
{
    while (time_out--)
    {
        if (orb_unsubscribe(node, event) == RT_ERROR)
        {
            rt_thread_delay(RT_TICK_PER_SECOND / 5);
        }
    }
    return RT_ERROR;
}
/* 从节点处取消订阅主题 */
rt_err_t orb_unsubscribe(orb_node *node,uint32_t *event)
{
    rt_uint32_t level;
    struct orb_subscriber *ptr = RT_NULL;
	struct rt_list_node *list_node;
  
#ifdef UORB_USING_MUTEX
    rt_mutex_take(node->node_lock, RT_WAITING_FOREVER);
#else
    level = rt_hw_interrupt_disable();
#endif
    if(!rt_list_isempty(&node->sub_list))					//判断节点中是否有主题订阅
    {
		for(list_node = node->sub_list.next;list_node != &(node->sub_list); list_node = list_node->next)
		{
			ptr = rt_list_entry(list_node, struct orb_subscriber, subscriber);		//查找比对主题
			if ((ptr->update == (void *)*event) == 0)
			{
				rt_list_remove(&ptr->subscriber);									//删除主题订阅
				rt_event_delete((rt_event_t)*event);								
				rt_free(ptr);
				node->subscriber_num--;
			}
		}
    }
#ifdef UORB_USING_MUTEX
    rt_mutex_release(node->node_lock);
#else
    rt_hw_interrupt_enable(level);
#endif
    return RT_EOK;
}

/* 向节点发布主题 */
rt_err_t orb_publish(orb_node *node,void *structure)
{
    rt_err_t err = RT_ERROR;
    rt_err_t err_tmp;
    struct orb_subscriber *ptr;
    rt_uint32_t level;
    rt_uint32_t subscriber_published_cnt = 0;
   struct rt_list_node *list_node;
#ifdef UORB_USING_MUTEX
    rt_mutex_take(node->node_lock, RT_WAITING_FOREVER);
#else
    level = rt_hw_interrupt_disable();
#endif
    rt_memcpy(node->orb_data,structure,node->size);
	for(list_node = node->sub_list.next;list_node != &(node->sub_list); list_node = list_node->next)
		{
			ptr = rt_list_entry(list_node, struct orb_subscriber, subscriber);
			rt_event_send((ptr->update),EVENT_ORB_DATA_UPDATE);			//向线程发送跟新事件
		}
#ifdef UORB_USING_MUTEX
    rt_mutex_release(node->node_lock);
#else
    rt_hw_interrupt_enable(level);
#endif
    return err;
}


/* 节点校验是否有跟新事件*/
rt_err_t orb_check(uint32_t *update,int32_t timeout)
{
    rt_uint32_t e;

    if(*update != RT_NULL)
        return rt_event_recv((struct rt_event*)*update, EVENT_ORB_DATA_UPDATE,
                             RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR ,
                             timeout, &e);
    else
        return -RT_ERROR;
}

/* 产生跟新事件,则拷贝跟新数据到线程 */
rt_err_t orb_copy(orb_node *node,void *buffer)
{
    rt_uint32_t level;

#ifdef UORB_USING_MUTEX
    rt_mutex_take(node->node_lock, RT_WAITING_FOREVER);
#else
    level = rt_hw_interrupt_disable();
#endif
    rt_memcpy(buffer,node->orb_data,node->size);
#ifdef UORB_USING_MUTEX
    rt_mutex_release(node->node_lock);
#else
    rt_hw_interrupt_enable(level);
#endif
    return RT_EOK;
}

uORB在rtthread中开发应用

ORB_DEFINE(mavlink_formation_read_file_info, mavlink_formation_request_info_t);
orb_advertise(ORB_ID(mavlink_formation_read_file_info));

void app_formation_point_main(void *param)
{
    orb_publish(ORB_ID(mavlink_formation_read_file_info), &mavlink_formation_read_file_info);						
    orb_publish(ORB_ID(mavlink_formation_read_mav_info), &formation_mav_file);
}


void app_log_main(void * param)
{
    uint32_t mavlink_formation_read_file_info_sub = 0;
    if(orb_subscribe_auto(ORB_ID(mavlink_formation_read_file_info), &mavlink_formation_read_file_info_sub, 10) == RT_ERROR)
    {
        rt_kprintf("[LOG]can not subscribe ORB_ID(mavlink_formation_read_file_info)\n");
    }
    
	while(run_log)
	{
        if (orb_check(&mavlink_formation_read_file_info_sub, 0) == RT_EOK)
        {
            orb_copy(ORB_ID(mavlink_formation_read_file_info), &sub.mav_formation_read_file_info);
        }
        rt_thread_delay(RT_TICK_PER_SECOND / 1000);
	}
}

 

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

rtthread移植实现uorb 的相关文章

  • Win10 64位双系统UEFI官网下载镜像安装(不用PE)

    1 刻录Win10 ISO镜像 2 U盘UEFI启动 先设置BIOS xff0c Boot Mode xff1a UEFI Secure Boot OFF 3 在 要安装的语言 界面 xff0c 按shift 43 F10调出DOS窗口 4
  • FreeRTOS实验一:portYIELD_FROM_ISR()任务切换的时机分析

    分析下portYIELD FROM ISR 任务切换的时机 span class token keyword void span span class token function HAL UART RxCpltCallback span
  • HAL_DMA_IRQHandler()代码详细分析

    这里使用ADC1联动DMA1 xff0c 开启半传输中断 传输中断 debug时 xff0c dma也一直在工作 xff0c 所以半传输中断 传输中断会同时生效 1 adc1使用了DMA1 Stream0 xff0c Instance表示如
  • AD单层显示

    1 Shift 43 S实现的单层效果 xff08 其他曾黑白显示 xff09 2 隐藏其他层 xff0c 只显示一层 xff0c 这样显示直观 xff0c 效果更好
  • 解决Windows更新失败(0x8007000d)的详细方法

    Window更新时 xff0c 一直处于 正在准备windows xff0c 请不要关闭你的计算机 xff0c 时间太长了 xff0c 直接重启 xff0c 再进系统发现这样子了 此代码表示有需要更新的文件丢失或损坏 管理员方式运行cmd
  • A320M HDV 4.0主板用CH341A手动刷BIOS支持5600g,内存不兼容问题排查

    电脑从AMD 3200g 升级到5600g xff0c 主板使用的是华擎A320m HDV R4 0 xff0c BIOS从7 20开始支持5600g xff0c 在没有CPU情况下只能使用BIOS烧录器手动烧录最新BIOS文件 xff0c
  • keil4中增加新器件(厂家未提供keil4支持包)编辑CDB文件

    1 C Keil UV4 FMSH cdb CPU 61 IRAM 0x20000000 0x20003FFF IROM 0x0000000 0x001FFFF CPUTYPE Cortex M0 CLOCK 12000000 ELITTL
  • C++编译初步

    C 43 43 编程中相关文件后缀 a静态库 archive C c cc cp cpp cxx c 43 43 C 43 43 源代码 xff08 需要编译预处理 xff09 hC或者C 43 43 源代码头文件 iiC 43 43 源代
  • 使用VSCode编辑与编译WSL2下源代码

    1 安装WSL2 2 windows下安装VSCode 3 VSCode安装插件Remote Development 北京时间2019年5月3日 xff0c 在 PyCon 2019 大会上 xff0c 微软发布了 VS Code Remo
  • WSL2编译IMX6ULL裸机程序Win10通过Win32DiskImager烧录SD卡

    1 修改imxdownload c文件 完整代码见附录 gcc mixbin c span class token parameter variable o span mixbin 使用上述gcc命令编译生成mixbin可执行文件 该文件只
  • Windows10 IoT 企业版 LTSC 2021安装应用商店

    https github com kkkgo LTSC Add MicrosoftStore releases tag 2019 解压缩 使用管理员方式运行 Add Store cmd xff0c 等待安装完成 xff0c 亲测可用
  • 2020-06-08

    定义带参数的宏 define JH a b t t 61 a a 61 b b 61 t 对两个 a b的值进行交换 下列表述中 正确的是 A 不定义参数 a 和b 将导致编译错误 B 不定义参数 a b 和 t 将导致编译错误C 不定义参
  • 第一阶段C#串口上位机练习--stm32F4总结

    1 实验目的 掌握上位机编程 xff1b 掌握F4串口 xff1b 掌握两者通信数据帧的约定 xff1b 2 实验设备 stm32F4核心板 xff0c Lcd屏幕 xff0c 下载器 xff0c 电脑 3 完成的任务 xff08 1 xf
  • STM32F103同时使用串口2、串口3

    STM32F103同时使用串口2 串口3 步骤rs485 crs485 h中断处理函数 xff1a 一直在用STM32F103做项目 xff0c 记录一下 xff0c 如果觉得有用的 xff0c 也可以参考一下 步骤 IO口的初始化 xff
  • 方法区位置的演变

    Jvm内存 xff1a 方法区位置的演变 xff1a Jdk1 6时 xff0c 方法区在堆中 xff0c 运行时常量池在方法区中 1 6之前 xff0c 方法区称为永久代 1 8之后 xff0c 方法区称为元空间 真正的实现要么是方法区要
  • 线程如何在底层执行指令?

    一条线程是如何执行的呢 一条线程它有自己独立的栈和pc寄存器 xff0c 寄存器的作用来存储字节码指令地址 xff0c 它来告诉电脑要执行的下一条指令 我们通过main方法反编译出来的代码 xff0c 来详细的探究main线程执行方法中代码
  • 在Linux中如何查看文件的修改日期

    有时候可能需要检查有关文件的详细信息 xff0c 例如文件的修改日期 当你要检查文件的最后编辑时间时 xff0c 本文可能会派上用场 在本文将学习4种方法查看文件的修改日期 使用stat stat 可以显示文件属性的详细信息 xff0c 比
  • 对象的组成

    对象有两种情况 xff1b 普通对象有3部分组成 1 对象头 对象头有两部分 xff1a 1是markword xff0c 2是klass pointer 类型指针 2 示例数据 3 对齐填充 数组对象有4部分组成 1 对象头 对象头有两部
  • 符号引用&直接引用

    符号引用不会加载到虚拟机内存中 xff0c 而直接引用是在内存中的 符号引用 xff1a 在java中 xff0c 一个java类会变编译为字节码文件 xff0c 在编译时 xff0c java类并不知道所引用类的实际地址 也就是直接引用
  • 大端序发送数据

    需要发送数字 151510 大端序发送就是 xff1a 00 02 4F D6 string smallData 61 textBox1 Text 小端数据 if smallData 61 61 34 34 MessageBox Show

随机推荐

  • DSP28335笔记--SCI篇

    采用FIFO来实现数据的发送与接收 xff0c 一般就是指采用FIFO中断 在标准SCI模式下通过中断方式来接收或者发送数据可以发现 xff0c 每接收或者发送一个字符就要进一次中断 xff0c 如果发送的字符比较多的话 xff0c 很明显
  • 无人机实验笔记(2019电赛)

    刚看到题目的时候自然想到的是巡空中电缆线 思路 xff1a 用一个摄像头架高在无人机上 xff0c 与地理坐标Z成一定角度 如图 xff0c 无人机看到的电缆线是实际电缆线在地面上的投影 xff0c 而投影线在 无人机视野的位置 和 无人机
  • [CMake教程](四)CMake 配置生成lib或者so的库文件

    CMake教程 xff08 四 xff09 CMake 配置生成lib或者so的库文件 xff08 1 xff09 系列教程介绍 上面几个教程我们的程序都是生成可执行文件 但是我们在合作开发算法的时候经常需要交付的是一个模块 xff0c 该
  • SLAM问题汇总

    Issue dropped 100 00 of messages so far Resolve tf transform wrong for me change scan to robot1 scan to resolve https an
  • STL基础4:STL7个常用容器的比较

    1 STL容器分类 xff1a STL的容器可以分为以下几个大类 一 顺序 xff08 序列 xff09 容器 xff0c 有vector list deque string stack 适配器类 queue 适配器类 priority q
  • PCB布局技巧

    1 布局前丝印放器件中间 结果 xff1a 布局布线之前 xff0c 把标号位置批量修改到器件中心 丝印既不会阻挡视线 也可以分辨出丝印对应的元件 问题描述 xff1a 在PCB布局时候 xff0c 我们会发现 xff0c 刚导入PCB的元
  • 第四次游戏革命:全息游戏

    最近一个月 xff0c 把国内外十数款单机 网游大作横扫一遍 xff0c 感慨颇多 国内游戏 xff0c 抄袭遍地 xff0c 十足的坑爹 xff0c 浪费青春 反观国外 xff0c 韩国网游经典而耐玩 xff0c C9 43 洛奇英雄传
  • UART, IIC, SCI, SPI, 232, 485, 422, CAN, SDIO, GPIO, MODBUS, TCP/IP汇总简介

    UART IIC SCI SPI 232 485 422 CAN SDIO GPIO MODBUS TCP IP汇总简介 UART xff1a Universal Asynchronous Receiver Transmitter xff1
  • 二维数组的定义

    1 概念 二维数组就是一种数组的数组 xff0c 其本质上还是一个一维数组 xff0c 只是它的数据元素又是一个一维数组 如果你对这个概念想象不出来 xff0c 给大家举个栗子 xff0c 相信吸烟的同学一下子就会明白 一根烟 61 一个变
  • nginx不转发http header问题解决

    文章整理自网络 作者 64 loongshawn xff1a http blog csdn net loongshawn article details 78199977 xff0c 建议读者阅读原文 xff0c 确保获得完整的信息 1 问
  • SimpleFOC(二)—— 快速入门 (开环控制)

    目录 一 硬件介绍 1 驱动板版本说明 2 驱动板跳线 3 硬件准备 4 硬件连接 二 软件操作 1 安装Arduino IDE 2 安装SimpleFOC library 3 打开示例程序 三 电机控制 1 程序下载 2 开环速度控制 3
  • curl参数详解

    原文 xff1a http blog csdn net yanhui wei article details 21530811 cURL可以使用URL的语法模拟浏览器来传输数据 xff0c 因为它是模拟浏览器 xff0c 因此它同样支持多种
  • 嵌入式单片机基础篇(十八)之ILI9341 液晶控制器

    ILI9341 液晶控制器详解 1 ILI9341 液晶控制器简介 xff1a ILI9341 液晶控制器自带显存 xff0c 其显存总大小为 172800 xff08 24032018 8 xff09 xff0c 即 18 位模式 xff
  • LOTO 示波器软件功能演示——RS232串口解码

    LOTO 示波器软件功能演示 RS232串口解码 我们今天演示一下怎么用LOTO示波器对串口进行解码 xff0c 使用了一个USB转串口的设备 xff0c 来产生串口数据 xff0c 用OSCA02 LOTO示波器演示 示波器我们只需要建立
  • ROS 下实现相机图像采集与图像传输到服务器,socket图传

    前言 本文介绍一种Qt下进行ROS开发的完美方案 xff0c 同时给出一个使用TCPROS进行图像传输的一个例子 xff0c 使用的是ros industrial的Levi Armstrong在2015年12月开发的一个Qt插件ros qt
  • Digest来验证

    Apache默认使用basic模块验证 xff0c 但它只是明文验证 Digest验证 xff0c 是用md5摘要值进行对比 httpRequest getAuthType 方法 xff0c 可以得到网页的验证方式request BASIC
  • 使用vscode创建C++工程

    1 推荐文件目录 即一个C 43 43 工程文件中包含 vscode文件夹 build文件夹 include文件夹 src文件夹以及一个CMakeLists txt文件 2 vscode文件夹 vscode文件夹一般应该包含三个配置文件 x
  • 游戏中所存在的“真随机”与“伪随机”

    写这篇随笔的动机 xff0c 在于最近看了不少对于游戏中概率事件的提问 在这些相关讨论里 xff0c 总是能频繁看到 真随机 和 伪随机 这两个词汇 其中最常见的句子则莫过于宝典一般的 程序里没有真随机 这句话本身当然是没有问题的 但是大多
  • C语言socket编程----实现TCP通信

    TCP IP协议 xff08 Transmission Control Protocol Internet Protocol xff09 叫做传输控制 网际协议 xff0c 又叫网络通信协议 实际上 xff0c 它包含上百个功能的协议 xf
  • rtthread移植实现uorb

    uORB Micro Object Request Broker 微对象请求代理器 是PX4 Pixhawk系统中非常重要且关键的一个模块 xff0c 它肩负了整个系统的数据传输任务 xff0c 所有的传感器数据 GPS PPM信号等都要从