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);