CD 系列相繼誕生了一系列作品,包括最早的 RS485 對等傳輸的協議 —— CDBUS、其上層協議 —— CDNET,模組免焊接裝配方式 —— CDBITE.
今天要介紹的是一個進程間通訊的庫 —— CDIPC, 其中還包含一個解析命令行參數的庫 —— CDARGS.
本來想找一個二進制版本的 JSON 序列化庫,譬如 BSON 這些,但都嫌實時性不夠、相關的解析庫龐大且複雜,準備自己再寫一個 CDSON, 不過暫時沒時間還是算了(畢竟 C 和 D 不太可能會有 SON)。
很多年前,入行機器人領域的前夕,就接觸到 ROS 這款機器人操作系統,它本質是一個 IPC 的通訊庫,然後很多第三方的程序使用其通訊, 因此構建成爲了一個系統。
ROS 的通訊有兩個核心:topic 和 service, 其中 topic 又是重中之重,它是 M-to-N 多對多的通訊方式,不同接收者收到相同的數據。 而 service 是 M-to-1 的 RPC, 類似遠程調用函數然後返回結果。
使用 IPC 的好處是便於模塊化編程,將一個大的系統劃分多個小模塊,有助於降低任務難度,且可以最大程度的復用已有模塊,而無需修改代碼。 同時,各模塊可以用不同的編程語言和技術來實現,譬如講究實時性的地方用 C/C++ 來寫,而界面部分可以用 Python、Javascript、HTML 等實現, 這樣開發效率遠遠比統一語言和庫要高的多。不同模塊是獨立的程序,可以隔離錯誤,否則類似 C/C++ 語言中用錯指針導致 bug 很難排查(除非是當時就報錯), 而且,不重要的模組出錯退出(譬如 UI 展示),不會影響到系統運作,降低事故風險。
然而,ROS 的通訊不是實時的,且十分臃腫,並不是很適合用做機器人控制。後來找了很久,找到一個實時的面向機器人的實時 IPC 庫, 叫做 ACH, 主頁:http://www.golems.org/projects/ach.html
然而 ACH 同樣不好用,首先,它不支持 service 功能,其次,它不是很穩定,譬如某個模塊程序意外退出,會導致 mutex 死鎖 (其實是 glibc 的 bug: https://sourceware.org/bugzilla/show_bug.cgi?id=21422 ). 雖然 ACH 使用的是共享內存交換數據,但是發佈數據和收取數據都要經過 memcpy 內存拷貝,很低效。
而且,無論是 ROS 還是 ACH, 它們的 topic 都不支持我想要的一款功能:可以分別爲不同接收者配置一個參數 —— 是否允許丟棄數據。 ROS 和 ACH 的 topic 所支持的模式都是發佈者可以不受限制的發佈數據,如果接收方處理不過來的話,最老的數據便會丟失。
然而有些場合我們希望當接收者處理不過來的時候,發送者予以等待。 這種情況,如果使用 ROS, 我們需要單獨再建一個 topic 或 service 讓發佈者查詢接收者是否過忙,會很麻煩。
ROS 還有一個不方便的地方是,只有 topic 支持錄製保存數據用於調試,而 service 卻不支持。
爲了解決以上種種問題,所以,我創建了 CDIPC 這個開源項目。
CDIPC 核心結構如下,topic 和 service 共用同一套,灰色部分是 service 僅有。
具體描述還請移步到項目頁面:https://github.com/dukelec/cdipc
配套有一個命令行工具,可以方便的用來測試 CDIPC, 和 dump 指定 topic 和 service 數據狀態。
最後提一下這個命令行參數解析庫,因爲使用 CDIPC 後,我準備再寫一個圖形化的工具(之前基於 ROS 寫過一款),方便配置模組、連線模組、監控模組運行狀態(譬如視覺算法模組可以實時顯示當前處理的畫面),連線信息通過命令行參數傳遞給不同的模塊程序,會涉及到動態參數,譬如我們希望某個模塊可以支持動態數量的輸入信號。
用法很簡單,例如:
cd_args_t ca;
cd_args_parse(&ca, argc, argv);
// if --id not found, use default value "0"
// --id 3, --id=3 are the same
int id = atol(cd_arg_get_def(&ca, "--id", "0"));
// -h is short version for --help, return not NULL if found of any
// return NULL if arg not found, return empty string if arg has no value
if (cd_arg_get2(&ca, "--help", "-h")) {
printf("%s", usage_dump);
exit(0);
}
// we could call cd_arg_get_left in a loop to report all left args
const char *left = cd_arg_get_left(&ca);
if (left) {
df_error("unknown arg: %s\n", left);
printf("%s", usage_dump);
exit(-1);
}
CDARGS 同時也有提供 Python 的版本,全部包含在 CDIPC 庫中。
造這個輪子之前,我同樣是苦苦找尋了很久,別人寫的都超複雜,且不滿足我的動態需求。。。
#1, Monday, September 09, 2019, WoodBridge <yu.~@m~.com> wrote:
有了解过lcm:http://lcm-proj.github.io/吗?之前看过一篇论文对其性能测试还不错。论文:http://people.csail.mit.edu/albert/pubs/2010-huang-olson-moore-lcm-iros.pdf
#2, Saturday, September 14, 2019, Duke <du~@duk~.com> wrote:
@WoodBridge 我剛看了下下,它用的是 UDP 通訊,實時性應該沒法保證。你可以看下 PREEMT-RT 對實時性的介紹。
Please visit the original link: /cdipc-zh