1、uORB是什么,起什么作⽤?
uORB(Micro Object Request Broker,微对象请求代理器)是PX4/Pixhawk系统中⾮常重要且关键的⼀个模块,它肩负了整个系统的数据传输任务,所有的传感器数据、GPS、PPM信号等都要从芯⽚获取后通过uORB进⾏传输到各个模块进⾏计算处理。实际上uORB是⼀套跨「进程」 的IPC通讯模块。在Pixhawk中, 所有的功能被独⽴以进程模块为单位进⾏实现并⼯作。⽽进程间的数据交互就由为重要,必须要能够符合实时、有序的特点。在PX4中,uorb是⽤于⽆⼈机模块间通信的协议机制。
Pixhawk 使⽤的是 NuttX 实时 ARM 系统,uORB 实际上是多个进程打开同⼀个设备⽂件,进程间通过此⽂件节点进⾏数据交互和共享。进程通过命名的「总线」交换的消息称之为「主题」(topic),在 Pixhawk 中,⼀个主题仅包含⼀种消息类型,通俗点就是数据类型。每个进程可以「订阅」或者「发布」主题,可以存在多个发布者,或者⼀个进程可以订阅多个主题,但是⼀条总线上始终只有⼀条消息。
2、uORB运⾏机制
⾸先,我们可以将uorb的通信机制了解⼀下。它的设计理念很有趣,它可以实现不同模块中的数据快速通讯,并且以异步通讯为基本原则,也就是说在通讯过程中发送者只负责发送数据,⽽并不关⼼数据由谁接收,也不关⼼接收者是否能将所有的数据都接收到;⽽对于接收者来说并不关⼼数据是由谁发送的,也不关⼼在接收过程中是否将所有数据都接收到。
uORB在在数据发布与接收过程中并不保证发送者的所有数据都可以被接收者收到,⽽只保证接收者在想要接收时能收到最新的数据。⽽发送与接收的分离可以使飞程中各个模块相互独⽴,互不⼲扰。实际上⼀个uORB可以由多个发送者发布,也可以被多个接收者接收,也就是说他们之间是多对多的关系。发布者以⼀定频率更新发布数据到uorb平台上,不关⼼谁来接收。订阅者可以随时来获取数据。
通俗例⼦:
有⼀个教室编号208,⾥⾯的⿊板上可以写上⼀些⽂字内容,有⼀个同学名叫⼩强,他每隔1个⼩时就会来到208教室,先将⿊板上原来的⽂字擦除,然后在⿊板上写下⼀段新⽂字,之后离开208教室。⽽另外有⼀个同学叫⼩朋,他每隔3个⼩时就会来到208教室,将⿊板上的⽂字抄写到⾃⼰的笔记本上,然后离开。我们可以⽤下列图例来说明⼀下这个过程:
我们可以看到,⼩强每次发布数据之后就会离开208教室,⾄于有没有⼈或是谁来读取他留下的⽂字,⼩强⾃⼰并不关⼼,也不再乎⾃⼰发布的数据是否有⼈收到了。⽽对于⼩朋来说,他每隔3⼩时来读取⼀次数据,⾄于这些数据是谁发布的他也不关⼼。他每隔3⼩时来读⿊板上的⽂字时,其实⼩强已经在⿊板上留⾔3次了,前两次的⽂字已经被⼩强擦除了,⼩朋看到的永远是⼩强留下最新的内容。
PX4/Pixhawk 应⽤程序框架
应⽤层中操作基础飞⾏的应⽤之间都是隔离的,这样提供了⼀种安保模式,以确保基础操作独⽴的⾼级别系统状态的稳定性。⽽沟通它们的就是 uORB。
3、uorb常见函数的使⽤
3.1 int orb_subscribe(const struct orb_metadata *meta)
功能:订阅主题(topic)
说明:即使订阅的主题没有被公告,但是也能订阅成功;但是在这种情况下,却得不到数据,直到主题被公告;参数:
meta:uORB 元对象,可以认为是主题 id,⼀般是通过 ORB_ID(主题名)来赋值;返回值:
错误则返回 ERROR;成功则返回⼀个可以读取数据、更新话题的句柄;如果待订阅的主题没有定义或声明则会返回-1,然后会将 errno 赋值为 ENOENT;eg:
int fd = orb_subscribe(ORB_ID(topicName));
3.2 int orb_set_interval(int handle, unsigned interval)
功能:设置订阅的最⼩时间间隔;
说明:如果设置了,则在这间隔内发布的数据将订阅不到;需要注意的是,设置后,第⼀次的数据订阅还是由起初设置的频率来获取,参数:
handle:orb_subscribe 函数返回的句柄;interval:间隔时间,单位 ms;
返回值:OK 表⽰成功;错误返回 ERROR;否则则有根据的去设置 errno;eg:
orb_set_interval(sensor_sub_fd, 1000);
3.3 int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)功能:从订阅的主题中获取数据并将数据保存到 buffer 中;参数:
meta:uORB 元对象,可以认为是主题 id,⼀般是通过 ORB_ID(主题名)来赋值;handle:订阅主题返回的句柄;buffer:从主题中获取的数据;返回值:
返回 OK 表⽰获取数据成功,错误返回 ERROR;否则则有根据的去设置 errno;eg:
struct sensor_combined_s raw;
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
3.4 orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)功能:公告发布者的主题;
说明:在发布主题之前是必须的;否则订阅者虽然能订阅,但是得不到数据;参数:
meta:uORB 元对象,可以认为是主题 id,⼀般是通过 ORB_ID(主题名)来赋值;data:指向⼀个已被初始化,发布者要发布的数据存储变量的指针;
返回值:错误则返回 ERROR;成功则返回⼀个可以发布主题的句柄;如果待发布的主题没有定义或声明则会返回-1,然后会将 errno 赋值为 ENOENT;eg:
struct vehicle_attitude_s att;memset(&att, 0, sizeof(att));
int att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);
3.5 int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)功能:发布新数据到主题;参数:
meta:uORB 元对象,可以认为是主题 id,⼀般是通过 ORB_ID(主题名)来赋值;handle:orb_advertise 函数返回的句柄;data:指向待发布数据的指针;
返回值:OK 表⽰成功;错误返回 ERROR;否则则有根据的去设置 errno;eg:
orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);
3.6 int poll(struct pollfd fds[], nfds_t nfds, int timeout)
功能:监控⽂件描述符(多个);
说明:timemout=0,poll()函数⽴即返回⽽不阻塞;timeout=INFTIM(-1),poll()会⼀直阻塞下去,直到检测到 return > 0;参数:
fds:struct pollfd 结构类型的数组;
nfds:⽤于标记数组 fds 中的结构体元素的总数量;timeout:是 poll 函数调⽤阻塞的时间,单位:毫秒;返回值:
>0:数组 fds 中准备好读、写或出错状态的那些 socket 描述符的总数量;==0:poll()函数会阻塞 timeout 所指定的毫秒时间长度之后返回;-1:poll 函数调⽤失败;同时会⾃动设置全局变量 errno;
3.7 orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance,int priority)
功能:设备/驱动器的多个实例实现公告,利⽤此函数可以注册多个类似的驱动程序;
说明:例如在飞⾏器中有多个相同的传感器,那他们的数据类型则类似,不必要注册⼏个不同的话题;参数:
meta:uORB 元对象,可以认为是主题 id,⼀般是通过 ORB_ID(主题名)来赋值;data:指向⼀个已被初始化,发布者要发布的数据存储变量的指针;
instance:整型指针,指向实例的 ID(从 0 开始);
priority:实例的优先级。如果⽤户订阅多个实例,优先级的设定可以使⽤户使⽤优先级⾼的最优数据源;返回值:
错误则返回 ERROR;成功则返回⼀个可以发布主题的句柄;如果待发布的主题没有定义或声明则会返回-1,然后会将 errno 赋值为 ENOENT;eg:
struct orb_test t;t.val = 0;
int instance0;
orb_advert_t pfd0 = orb_advertise_multi(ORB_ID(orb_multitest), &t, &instance0,ORB_PRIO_MAX);
3.8 int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)功能:订阅主题(topic);
说明:通过实例的 ID 索引来确定是主题的哪个实例;参数:
meta:uORB 元对象,可以认为是主题 id,⼀般是通过 ORB_ID(主题名)来赋值;instance:主题实例 ID;实例 ID=0 与 orb_subscribe()实现相同;返回值:
错误则返回 ERROR;成功则返回⼀个可以读取数据、更新话题的句柄;如果待订阅的主题没有定义或声明则会返回-1,然后会将 errno 赋值为 ENOENT;eg:
int sfd1 = orb_subscribe_multi(ORB_ID(orb_multitest), 1);
3.9 int orb_unsubscribe(int handle)
功能:取消订阅主题;参数:
handle:主题句柄;返回值:
OK 表⽰成功;错误返回 ERROR;否则则有根据的去设置 errno;eg:
ret = orb_unsubscribe(handle);
因篇幅问题不能全部显示,请点此查看更多更全内容