Apollo 3.5 Cyber - 基本架構入門
簡介
終於把cyber中的主要模塊都review了,把其整體邏輯搞通了。
現在就根據個人了解,做個簡單的全局的解釋
Apollo自己也有做講解,想避免被我誤導的,建議看官方的
先上個全局圖,整個講解會圍繞這圖來說。因為圖比較大,可先下載再配合內文使用。當中只包括一些比較重要的模塊。
modules下的模塊啟動的底層流程
之前有寫過一個簡單的
https://blog.csdn.net/weixin_44450715/article/details/86075928
現把底層模塊是怎被用到的,都顯示出來
先假設沒有額外定義的
Node::Reader
和
Node::Writer
,而且是在reality mode
模塊的介紹在下面
主要模塊的用途那邊
- 用cyber_launch起動
Mainboard
Mainboard
用ClassLoader
加載shared object,並初始化
Component
的instance在上一步被生成,初始化時生成其內部Node
及其Node::Reader
,Node::Writer
Component
然後利用DataVisitor
和RoutineFactory
的組合,把自己的Proc
function變為一個任務,放到Scheduler
中
Transport
中的singleton發現有新數據來了,把數據給DataVisitor
。(Transport
中會根據Service Discovery
的資料開關回調及在特定模式下選擇實現)
DataVisitor
在做了fusion
等工作後,會叫預先定好的回調(即跟Scheduler
那邊說這個任務狀態更新了,可執行了)
Scheduler
中的singleton會不停的等任務來,當發現有任務可以執行時,就拿出來執行
- 當執行一次之後,任務重新變回等數據的狀態
- 當新數據再來時,返回 (5)
主要模塊的用途
如果我之前已經講過的,就直接發連結。
Mainboard 跟 ClassLoader
在apollo 3.5中,是先把modules中的模塊編成一個shared object,再用cyber_launch把模塊啟動。cyber_launch只是個腳本,只負責預配置(讀配置交件,設定參數等),真正用到的程式是 Mainboard。而Mainboard又用到ClassLoader去把那個shared object加載,把全局設定好,然後生成instance,執行任務。
https://blog.csdn.net/weixin_44450715/article/details/86075928
Component
modules中的模塊都是要寫成Component或TimerComponent的sub class,再用macro註冊。而Component或TimerComponent都是ComponentBase的subclass.
Component 中的 Component
跟以前的Apollo 3.5之前的
ApolloApp
很像。在用時,都是通過繼承super class,然後再實現當中的一些virtual function去達到目的。而Component要你自己實現的function有
Init
,
Proc
。而且他背後幫你幹的事,比
ApolloApp
可是多很多。比方可以直接把數據當成
Proc
的參數傳進去等。
Component 中的 TimerComponent
Timer base 的Component,即每N個時間單位,就處理一次事情。
TimerComponent 跟 Component不管是內部實現還是設計,都是差很遠的。而兩者提供的功能更是完全不同。
- TimerComponent 的
Process
是沒有參數的。即是說你要甚麼數據,都一定要自己去拿,或另外在數據相關模塊設定回調。
- Component 中的
Process
的調用是由Scheduler模塊去安排在甚麼時侯執行的。而 TimerComponent 的Process
的調用是由Timer 按設定時間執行的。
- TimerComponent 的實現比 Component 簡單很多。
Timer
TimerComponent 有點像以前ROS中寫一個loop,在loop中間做事,然後在結尾睡一下再開始下一圈的設計。
ros::Rate r(1);
while (ros::ok()) {
....
ros::spinOnce();
r.sleep();
}
不過cyber把這一套搞得更進一步。
- 容許多任務
- 用的時候只要把任務定義好,加到Timer Manager中就可以了。不用自己寫Loop。
- 支持把任務異步執行
而Timer就是做這些事的地方了。
當然,把全部任務放一起就肯定要考慮一下性能了。當然不會說在每一個loop中都把全部任務檢查一次這麼粗糙的做法了。
它內部用了一個time wheel,基本就把任務按應該被執行的時間(因為空間有限,時間無限,當中還有一個取模運算),分在這個輪子中的slot。加速每次去查找當前要執行的任務的時間。
這個輪子會隨著時間而轉動,當前指向的slot也隨輪子轉動而改變,那只要判斷在當前slot中的一堆任務。那些是要執行的就好了。
Transport
低層的數據傳輸系統
https://blog.csdn.net/weixin_44450715/article/details/86314193
https://blog.csdn.net/weixin_44450715/article/details/86479466
Data Visitor
把Transport再包一層,提供專為數據訪問的接口。也是一個計設用來跟RoutineFactory配合一起用的接口。
https://blog.csdn.net/weixin_44450715/article/details/86149041
Node
Node 跟rosnode在定位上有點像,都是負責上層的讀寫功能。
可以用
Node::Reader
在某channel (topic)中註冊回調,可以用
Node::Writer
把新的數據寫到channel中。
開發者基本只要用到
Component
跟
Node
,就能滿足一切需求。
Service 跟 Service Discovery
利用Node跟Transport提供的功能,實現一個Service的抽象功能。(Service就像一個伺服器,接收數據,處理,然後返回結果)
Service Discovery則負責節點的監察
https://blog.csdn.net/weixin_44450715/article/details/86514423
Scheduler 跟 CRoutine
Cyber中的dag文件可定義多個Component,那如何調度多個Component的運行就靠Scheduler
https://blog.csdn.net/weixin_44450715/article/details/86538575
那ros 中的/tf, /tf_static是由誰負責呢?
是由
modules/transform
下面做的,而不是由cyber提供的,不過內部實現也是
Node::Reader
跟
Node::Writer