Pixhawk uORB通信

2023-05-16

Pixhawk 飞控系统是基于ARM的四轴以上飞行器的飞行控制器, 它的前身是PX4-IMU,Pixhawk 把之前的IMU进行了完整的重构,最新版本是2.4.3。而对应的Pixhawk 1.x版本与2.x版本的区别在于,I/O板与FMU是否整合在一起。

uORB是Pixhawk系统中非常重要且关键的一个模块,它肩负了整个系统的数据传输任务,所有的传感器数据、GPS、PPM信号等都要从芯片获取后通过uORB进行传输到各个模块进行计算处理。

 

uORB 的架构简述

uORB全称为micro object request broker (uORB),即 微对象请求代理器,实际上uORB是一套跨进程的IPC通讯模块。在Pixhawk中, 所有的功能被独立以进程模块为单位进行实现并工作。而进程间的数据交互就由为重要,必须要能够符合实时、有序的特点。

 

Pixhawk 使用NuttX实时ARM系统, 而uORB对于NuttX而言,它仅仅是一个普通的文件设备对象,这个设备支持Open、Close、Read、Write、Ioctl以及Poll机制。 通过这些接口的实现,uORB提供了一套“点对多”的跨进程广播通讯机制, “点”指的是通讯消息的“源”,“多”指的是一个源可以有多个用户来接收、处理。而“源”与“用户”的关系在于,源不需要去考虑用户是否可以收到某条被广播的消息或什么时候收到这条消息。它只需要单纯的把要广播的数据推送到uORB的消息“总线”上。对于用户而言,源推送了多少次的消息也不重要,重要的是取回最新的这条消息。

 

uORB实际上是多个进程打开同一个设备文件,进程间通过此文件节点进行数据交互和共享。

 

uORB 的系统实现

uORB的实现位于固件源码的src/modules/uORB/uORB.cpp文件,它通过重载CDev基类来组织一个uORB的设备实例。并且完成Read/Write等功能的重载。uORB 的入口点是uorb_main函数,在这里它检查uORB的启动参数来完成对应的功能,uORB支持start/test/status这3条启动参数,在Pixhawk的rcS启动脚本中,使用start参数来进行初始化,其他2个参数分别用来进行uORB功能的自检和列出uORB的当前状态。

在rcS中使用start参数启动uORB后,uORB会创建并初始化它的设备实例, 其中的实现大部分都在CDev基类完成。这个过程类似于Linux设备驱动中的Probe函数,或者Windows 内核的DriverEntry,通过init调用完成设备的创建,节点注册以及派遣例程的设置等。

 

uORB 源码分析之Open

    uORB 的Open接口实现了“源”或“用户” 打开uORB句柄的功能,打开uORB的句柄就意味着一个源的创建或把一个用户关联到某个源。我在这以源的创建为开端,逐步讲解Open的过程:


  
  
orb_advert_t orb_advertise ( const  struct orb_metadata  *meta,  const  void  *data ) {     int result, fd ;     orb_advert_t advertiser ;     /* open the node as an advertiser */     fd  = node_open (PUBSUB, meta, data,  true ) ;     if  (fd  == ERROR )         return ERROR ;     /* get the advertiser handle and close the node */     result  = ioctl (fd, ORBIOCGADVERTISER,  ( unsigned  long ) &advertiser ) ;     close (fd ) ;     if  (result  == ERROR )         return ERROR ;     /* the advertiser must perform an initial publish to initialise the object */     result = orb_publish (meta, advertiser, data ) ;     if  (result  == ERROR )         return ERROR ;     return advertiser ; }

orb_advertise 其实就是一个int,  meta是一个已定义好的源描述信息,里面就2个成员,分别为name以及size。保存了通讯的名称以及每次发送数据的长度。 创建源的过程为3个步骤, 打开uORB的设备节点, 获取设备实例, 推送第一条消息。

 

	/*
	 * Generate the path to the node and try to open it.
	 */
	ret = node_mkpath(path, f, meta);

	if (ret != OK) {
		errno = -ret;
		return ERROR;
	}

	/* open the path as either the advertiser or the subscriber */
	fd = open(path, (advertiser) ? O_WRONLY : O_RDONLY);

从代码中可以看出, 每个源都在/PUBSUB/目录下有一个设备节点。首先通过node_mkpath来拼接好设备节点路径,然后根据要打开的是源节点还是用户节点来选择标识

 

 

int
ORBDevNode::open(struct file *filp)
{
	int ret;

	/* is this a publisher? */
	if (filp->f_oflags == O_WRONLY) {

		/* become the publisher if we can */
		lock();

		if (_publisher == 0) {
			_publisher = getpid();
			ret = OK;

		} else {
			ret = -EBUSY;
		}

		unlock();

		/* now complete the open */
		if (ret == OK) {
			ret = CDev::open(filp);

			/* open failed - not the publisher anymore */
			if (ret != OK)
				_publisher = 0;
		}

		return ret;
	}

	/* is this a new subscriber? */
	if (filp->f_oflags == O_RDONLY) {

		/* allocate subscriber data */
		SubscriberData *sd = new SubscriberData;

		if (nullptr == sd)
			return -ENOMEM;

		memset(sd, 0, sizeof(*sd));

		/* default to no pending update */
		sd->generation = _generation;

		filp->f_priv = (void *)sd;

		ret = CDev::open(filp);

		if (ret != OK)
			free(sd);

		return ret;
	}

	/* can only be pub or sub, not both */
	return -EINVAL;
}

uORB中规定了源节点只允许写打开,用户节点只允许只读打开。 我认为上面的Open代码里lock到unlock那段根本就不需要~ 那里仅仅是判断不允许重复创建同一个话题而已。而去重完全可以依赖其他的一些机制来解决, CDev::Open就不在继续往里说了。~如果oflags是RDONLY,那就表示要打开的是一个用户设备节点,sd是为这个用户准备的一个上下文结构。里面包含了一些同步计数器等信息,比如sd->generation,这里保存了当前用户读取到的消息的索引号,而_generation来源于源设备的每次写操作,每次源写入数据时,_generation会累加。每次用户读取数据时会把_generation同步到自己的sd->generation,通过这种处理,如果当前用户的sd->generation不等于全局的_generation就意味着源刚刚写入过数据,有最新的通讯消息可以供读取。

 

uORB设备的读和写

 

ssize_t
ORBDevNode::read(struct file *filp, char *buffer, size_t buflen)
{
	SubscriberData *sd = (SubscriberData *)filp_to_sd(filp);

	/* if the object has not been written yet, return zero */
	if (_data == nullptr)
		return 0;

	/* if the caller's buffer is the wrong size, that's an error */
	if (buflen != _meta->o_size)
		return -EIO;

	/*
	 * Perform an atomic copy & state update
	 */
	irqstate_t flags = irqsave();

	/* if the caller doesn't want the data, don't give it to them */
	if (nullptr != buffer)
		memcpy(buffer, _data, _meta->o_size);

	/* track the last generation that the file has seen */
	sd->generation = _generation;

	/*
	 * Clear the flag that indicates that an update has been reported, as
	 * we have just collected it.
	 */
	sd->update_reported = false;

	irqrestore(flags);

	return _meta->o_size;
}

 

读分为3步, 首先判断参数是否合理,然后屏蔽中断拷贝数据,最后更新同步信息。值得注意的是,如果没有源写数据,那么read会在第一个判断就退出,原因是_data缓冲区在首次write时才会成功申请。generation的同步这里也不在继续说了

 

ssize_t
ORBDevNode::write(struct file *filp, const char *buffer, size_t buflen)
{
	/*
	 * Writes are legal from interrupt context as long as the
	 * object has already been initialised from thread context.
	 *
	 * Writes outside interrupt context will allocate the object
	 * if it has not yet been allocated.
	 *
	 * Note that filp will usually be NULL.
	 */
	if (nullptr == _data) {
		if (!up_interrupt_context()) {

			lock();

			/* re-check size */
			if (nullptr == _data)
				_data = new uint8_t[_meta->o_size];

			unlock();
		}

		/* failed or could not allocate */
		if (nullptr == _data)
			return -ENOMEM;
	}

	/* If write size does not match, that is an error */
	if (_meta->o_size != buflen)
		return -EIO;

	/* Perform an atomic copy. */
	irqstate_t flags = irqsave();
	memcpy(_data, buffer, _meta->o_size);
	irqrestore(flags);

	/* update the timestamp and generation count */
	_last_update = hrt_absolute_time();
	_generation++;

	/* notify any poll waiters */
	poll_notify(POLLIN);

	return _meta->o_size;
}

上面就是write的实现了,那个lock/unlock真心很鸡肋,我是感觉多余了,首次write会申请内存用于数据通讯, 然后关闭中断拷贝数据防止在复制的过程用有用户来read,最后是更新最后的更新时间以及同步计数器并且发送一个POLLIN的消息通知来唤醒那些还在等待uORB数据可读的用户

 

 

uORB设备的POLL状态

当用户没有指定数据读取的频率时,每次源的write都会触发一个POLLIN来唤醒用户去读取刚更新的数据。是否唤醒除了检查generation的值以外,另外一个要求就是读取频率的限制,每个用户可以单独指定自己打算读更新的频率。

 

bool
ORBDevNode::appears_updated(SubscriberData *sd)
{
	/* assume it doesn't look updated */
	bool ret = false;

	/* avoid racing between interrupt and non-interrupt context calls */
	irqstate_t state = irqsave();

	/* check if this topic has been published yet, if not bail out */
	if (_data == nullptr) {
		ret = false;
		goto out;
	}

	/*
	 * If the subscriber's generation count matches the update generation
	 * count, there has been no update from their perspective; if they
	 * don't match then we might have a visible update.
	 */
	while (sd->generation != _generation) {

		/*
		 * Handle non-rate-limited subscribers.
		 */
		if (sd->update_interval == 0) {
			ret = true;
			break;
		}

		/*
		 * If we have previously told the subscriber that there is data,
		 * and they have not yet collected it, continue to tell them
		 * that there has been an update.  This mimics the non-rate-limited
		 * behaviour where checking / polling continues to report an update
		 * until the topic is read.
		 */
		if (sd->update_reported) {
			ret = true;
			break;
		}

		/*
		 * If the interval timer is still running, the topic should not
		 * appear updated, even though at this point we know that it has.
		 * We have previously been through here, so the subscriber
		 * must have collected the update we reported, otherwise
		 * update_reported would still be true.
		 */
		if (!hrt_called(&sd->update_call))
			break;

		/*
		 * Make sure that we don't consider the topic to be updated again
		 * until the interval has passed once more by restarting the interval
		 * timer and thereby re-scheduling a poll notification at that time.
		 */
		hrt_call_after(&sd->update_call,
			       sd->update_interval,
			       &ORBDevNode::update_deferred_trampoline,
			       (void *)this);

		/*
		 * Remember that we have told the subscriber that there is data.
		 */
		sd->update_reported = true;
		ret = true;

		break;
	}

out:
	irqrestore(state);

	/* consider it updated */
	return ret;
}

uORB 根据用户指定的周期来设置hrt(实时定时器),每过一个时间间隔,hrt会被发生调用,通过hrt_called来检查这个调用。如果未发生,即便此时源的数据已经更新那么也不会返回POLLIN来唤醒用户去读。 简单来说,它通过控制POLLIN的周期来单方面控制用户的读取间隔。 如果是linux平台,当用户指定了时间间隔后, 我会为它单独初始化一个内核定时器,每次poll调用时检查完可用更新后,再次检查定时器即可。

 

 

先写这么多, 有需要再补充吧

 

 

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

Pixhawk uORB通信 的相关文章

  • PIXHAWK飞控固件及代码基础介绍

    PIXHAWK飞控 xff1a 固件 xff1a 开源固件PIXHAWK 软件 xff1a 两套固件代码 xff08 1 xff09 原生固件代码PIX4 xff0c 地面站采用QGC xff08 界面比较合理清晰 xff0c 易做修改 x
  • pixhawk配置垂直起降无人机

    我使用的版本里面没有找到 43 型尾座式垂直起降无人机 就先用x型无人机了 查看代码 发现在init d目录下id号为13003 待续
  • Pixhawk ulog飞行日志分析

    在python下安装pyulog xff0c 在 ulog文件目录下输入ulog2csv即可将ulog转化为csv形式输出 ulog文件的保存时间 43 8即为飞行实际的时间 timestamp为时间戳 xff0c 除以10 6后单位为秒
  • Mavros读取PixHawk硬件的IMU数据

    Ubuntu18 04 读取PixHawk硬件的IMU数据 实现方式 使用mavros话题读取到Pixhawk飞控的IMU数据 实现步骤 安装ros 检查是否安装cmake xff08 未安装根据提示安装 xff09 cmake span
  • PIXHAWK飞机侧翻原因

    转载自 xff1a http pix 1yuav com wen ti ji jin fei ji ce fan yuan yin html 飞机侧翻原因 飞机侧翻有以下几个原因 xff0c 请认真检查 1 电机顺序 xff0c 电机转向
  • pixhawk似乎也是用的四环串级

    pixhawk似乎也是用的四环串级 https blog csdn net sinat 16643223 article details 106973618 阿木社区的pixhawk的课里 https bbs amovlab com plu
  • 我发现GAAS,阿木的SLAM无人机,XTDrone都是用的pixhawk !

    我发现 xff0c 七月的GAAS xff0c 阿木的SLAM无人机 xff0c 还有这个开课吧的智能无人机的课 xff0c 这三个都是用的pixhawk飞控 xff0c 对不对 xff0c 没有一个去用上面自己写的简单飞控啥的没有 xff
  • PIXHAWK机架类型的的设置选择与电机通道顺序设置

    1 共轴直升机 main1 左侧斜盘电机 xff0c 控制俯仰 main2 xff1a 左侧斜盘电机 xff0c 控制滚转 main3 xff1a 上面旋翼 xff0c 逆时针旋转 main4 xff1a 下面旋翼 xff0c 顺时针旋转
  • 在PX4下更换pixhawk的IMU

    写在前面 出于一些原因 xff0c 这篇文章不给出具体的源码 xff0c 因此博主试着将这篇写成了一篇科普性质的文章 xff0c 如果你认真读的话 xff0c 应该会有收获的 为什么要更换pixhawk的传感器 xff1f 大多数的玩家拿到
  • apm、pixhawk、pixhack飞控航拍后pos数据提取流程

    apm pixhawk pixhack飞控pos数据提取流程 下载日志 打开log分析 区域omap地图验证 验证之前将log文件使用mission planner进行kml验证 筛选相机pos坐标 xff08 选择CAM xff09 很重
  • pixhawk日志ulg格式转matlab数据csv格式

    1 windows下打开Anconda Prompt xff0c 执行pip install pyulog安装pyulog包 2 在日志文件所在文件夹下执行ulog2csv 文件名 ulg即可生成相关的csv文件
  • PX4/PixHawk无人机飞控应用开发

    最近做的一个国防背景的field UAV项目 xff0c 细节不能多谈 xff0c 简单写点技术体会 1 PX4 Pixhawk飞控软件架构简介 PX4是目前最流行的开源飞控板之一 PX4的软件系统实际上就是一个firmware xff0c
  • pixhawk: px4代码初学分析:追溯电机控制--pwm输出

    追溯电机控制 pwm输出 正常工作状态下pwm输出过程简述 xff1a 其他状态下pwm输出 xff1a 正常工作状态下pwm输出过程简述 xff1a 姿态解算部分得出姿态控制量通过px4io cpp把姿态控制量发送给IOIO串口读取姿态控
  • PX4/Pixhawk---uORB深入理解和应用

    The Instructions of uORB PX4 Pixhawk 软件体系结构 uORB 主题发布 主题订阅 1 简介 1 1 PX4 Pixhawk的软件体系结构 PX4 Pixhawk的软件体系结构主要被分为四个层次 xff0c
  • UORB

    转载地址 xff1a http blog arm so armteg pixhawk 183 0503 html Pixhawk 飞控 系统是基于ARM的四轴以上飞行器的飞行控制器 xff0c 它的前身是PX4 IMU xff0c Pixh
  • 教程:使用树莓派连接Pixhawk飞控

    教程 xff1a 使用树莓派连接Pixhawk飞控 树莓派可以与Pixhawk飞控相连 xff0c 读取飞控中的状态信息 xff0c 同时对飞控发送指令 树莓派作为一个更高性能的计算平台 xff0c 可以运行图像识别 机器学习 实时路径规划
  • PX4模块设计之三:自定义uORB消息

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

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

    uORB uORB 是一种异步 publish subscribe 的消息传递 API xff0c 用于进程或者线程间通信 IPC 添加新的Topic xff08 主题 xff09 在msg 目录下创建一个新的 msg文件 xff0c 并将
  • pixhawk 整体架构的认识

    此篇blog的目的是对px4工程有一个整体认识 xff0c 对各个信号的流向有个了解 xff0c 以及控制算法采用的控制框架 PX4自动驾驶仪软件 可分为三大部分 xff1a 实时操作系统 中间件和飞行控制栈 1 NuttX实时操作系统 提

随机推荐

  • 在Prezi中输入简体中文的完美解决方案

    Prezi是一种在线制作演示文档 xff08 PPT xff09 的工具 xff0c 它与传统的Powerpoint或者Keynote的表现形式完全不同 xff0c 被称为 powerpoint的颠覆者 xff0c 在36Kr上曾经有过多篇
  • C程序中头文件相互包含精华(网摘小结)

    h 中一般放的是同名 c 文件中定义的变量 数组 函数的声明 xff0c 需要让 c 外部使用的声明 1 h 文件作用 1 方便开发 包含一些文件需要的共同的常量 结构 类型定义 函数 变量申明 xff1b 2 提供接口 对一个软件包来说可
  • 【无标题】sourceTree使用教程,比TortoiseSVN小乌龟更好用的一款软件

    俗话说的好工欲善其事必先利其器 xff0c Git分布式版本控制系统是我们日常开发中不可或缺的 目前市面上比较流行的Git可视化管理工具有SourceTree Github Desktop TortoiseGit xff0c 综合网上的一些
  • Vim(gvim)配色方案推荐

    如果经常用vim进行编辑 xff0c 那么一款好的vim配色就是必然的啦 xff0c 今天我们就来介绍一下我比较喜欢的几款配色 xff08 配色效果主要针对gvim xff0c 因为在vim下工作都是终端操作 xff09 由于本人是以程序员
  • 如何定义python的全局变量

    定义全局变量 global var 61 10 def some function 在函数中使用全局变量 print 34 Global variable value 34 global var some function 在Python中
  • 网上推荐的学习ucosii的三本书

    1 xff0c 嵌入式实时操作系统uc os II教程 西安电子科技大学出版 xff0c 有流程图 2 xff0c 嵌入式实时操作系统uc os II原理与应用 xff08 第二版 xff09 任哲 北航出版 3 xff0c 基于嵌入式实时
  • UC/OSII源码阅读知识点(第一章)

    嵌入式实时操作系统uc os原理与实践 xff08 卢有亮 电子工业出版社 xff09 1 在STM32上使用的ARM CORTEX处理器中 xff0c 具有主堆栈MSP和进程堆栈PSP xff0c 具有Pendsv和Systick中断 2
  • 802.11控制帧&管理帧

    控制帧主要用于协助数据帧的传递 xff0c 可用于管理无线媒介的访问 提供MAC层的可靠性 以下只讲帧类型 xff0c 不讲帧结构 1 1 RTS帧 xff1a 用来取得媒介的控制权 xff0c 用于传送分段帧 xff0c 分段由网卡驱动程
  • linux常用变量含义

    是传给脚本的参数个数 0 是脚本本身的名字 1 是传递给该shell脚本的第一个参数 2 是传递给该shell脚本的第二个参数 64 是传给脚本的所有参数的列表 是以一个单字符串显示所有向脚本传递的参数 xff0c 与位置变量不同 xff0
  • 四核 x86 MinnowBoard 和 UP Squared 单板计算机

    MinnowBoard的 MinnowBoard Turbot Quad 和Aaeon的UP平方单板计算机开始出货 xff0c 以社区网站和运行Linux和Android的英特尔SoC为特点 5月23日 xff0c Intel支持的Minn
  • 无人机悬停 优象科技LC302 V1.1光流模块

    5月30日 xff0c 学校组织了一年一度的五月风活动 xff0c 每个社团纷纷拿出自己协会的作品 在我们科技爱好者协会中 xff0c 展示了光流模块 xff0c 特斯拉线圈 xff0c 蓝牙小车 xff0c 激光显示仪器 xff0c 空气
  • git中tag与release的创建以及两者的区别

    简介 本文辨析在参与开源项目时会遇到的tag与release的概念区别与联系 xff0c 并比较两者的创建方法 定义 标签 xff08 tag xff09 是特定提交 xff08 commit 一个指针 xff0c 也就是每个tag对应一个
  • PX4源码的Makefile详细理解(包含部分makefile语法规则和编译逻辑)

    啰嗦 xff1a 越会一件事情 xff0c 就会忘了不会一件事情的感觉 前段时间在微信上看到这句话 xff0c 深以为然 xff0c 这就是为什么很多时候懂的人觉得自己讲的很清楚了 xff0c 但是不懂的人却觉得并没有讲的清楚明了 xff0
  • c/c++语言结构体中的冒号的用法

    结构体中常见的冒号的用法是表示位域 有些信息在存储时 xff0c 并不需要占用一个完整的字节 xff0c 而只需占几个或一个二进制位 例如在存放一个开关量时 xff0c 只有0 和 1 两种状态 xff0c 用一位二进位即可 为了节省存储空
  • ubuntu 升级内核的具体步骤

    收藏于 2013 04 09 迁移自本人的百度空间 转载自 http forum ubuntu org cn viewtopic php p 61 2730876 ubuntu 12 04内核是linux 3 2 0 24 xff0c 其实
  • 不花钱的机器人——ROS机器人仿真平台 | 模拟器 | Autolabor Simulation

    没钱买机器人底盘和激光雷达 xff0c 照样也能玩转机器人 xff01 Autolabor Simulation是什么 Autolabor Simulation是由 Autolabor 推出的一款基于ROS xff08 Robot Oper
  • 分布式之数据库和缓存双写一致性方案解析

    本文转自博客园 作者 xff1a 孤独烟 原文链接 xff1a https www cnblogs com rjzheng p 9041659 html 为什么写这篇文章 首先 xff0c 缓存由于其高并发和高性能的特性 xff0c 已经在
  • TVM在Windows10下编译安装

    本教程记录了Windows端安装tvm的过程 xff0c 欢迎交流 教程参考 TVM Windows下全功能编译方法 xff1a 从入门到劝退 https blog csdn net znsoft article details 11503
  • V4L2视频驱动框架---v4l2_device管理模块简述

    v4l2框架由4个主要的部分 数据结构 组成 xff1a v4l2 devices 包括v4l2 subdev xff1a v4l2 device管理所有的设备 media device xff1a meida device框架管理运行时的
  • Pixhawk uORB通信

    Pixhawk 飞控 系统是基于ARM的四轴以上飞行器的飞行控制器 xff0c 它的前身是PX4 IMU xff0c Pixhawk 把之前的IMU进行了完整的重构 xff0c 最新版本是2 4 3 而对应的Pixhawk 1 x版本与2