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