
上一課答案第 1 題class Dog : public Animal其中Animal → 父類 Dog → 子類第 2 題class MyNode : public rclcpp::Node表示定義一個自己的類MyNode它繼承 ROS2 的rclcpp::Node因此擁有 ROS2 節(jié)點的基礎(chǔ)能力。第 3 題MyNode()是MyNode的構(gòu)造函數(shù)。創(chuàng)建MyNode對象時會自動調(diào)用。第 4 題Node(my_node)表示調(diào)用父類Node的構(gòu)造函數(shù)并把節(jié)點名稱設(shè)置為my_node。第 5 題因為rclcpp::Node已經(jīng)提供了 ROS2 節(jié)點所需的大量基礎(chǔ)能力比如Publisher Subscriber Timer Parameter Logger Service我們繼承它就不需要自己從零實現(xiàn) ROS2 通信系統(tǒng)。上一課跳得太快了。問題不在 Publisher/Subscriber 本身而是我一口氣把ROS2、模板 、::、智能指針、this-、lambda、消息類型全塞進了一段代碼里。我們先不繼續(xù)下一課把第 31 課拆成幾節(jié)微課。今天只搞懂Publisher 到底是什么以及一條 ROS2 發(fā)布代碼怎么讀。第 31A 課先把 ROS2 Publisher 講成人話先完全忘掉這句rclcpp::Publisherstd_msgs::msg::Int32::SharedPtr publisher_;現(xiàn)在不看它。你先只理解一個現(xiàn)實場景。假設(shè)我們的機械臂程序里有兩個程序程序 AVLA 程序 B機械臂控制器VLA 算出了“機械臂第 1 軸轉(zhuǎn)到 30°”問題是程序 A 怎么把這個消息告訴程序 BROS2 提供了一套通信系統(tǒng)。最簡單可以想象成微信VLA程序 │ │ 發(fā)消息 ▼ 【機器人動作群】 │ │ 收消息 ▼ 機械臂控制程序這里發(fā)消息的人 Publisher 微信群 Topic 收消息的人 Subscriber 發(fā)送的內(nèi)容 Message今天我們只學發(fā)消息這一半Publisher ↓ Topic ↓ Message1. 如果不用 ROS2最簡單的“發(fā)消息”應該長什么樣假設(shè)我自己設(shè)計一個超級簡單的程序Publisher publisher;意思創(chuàng)建一個發(fā)布器。然后publisher.publish(100);意思發(fā)布數(shù)字 100。就這么簡單。你先把 ROS2 Publisher 的本質(zhì)理解成publisher.publish(消息);也就是讓發(fā)布器把一條消息發(fā)出去。2. ROS2 為什么看起來復雜因為 ROS2 還必須知道兩件事第一你發(fā)到哪個頻道第二你發(fā)送的是什么類型的數(shù)據(jù)比如我們說頻道number 數(shù)據(jù)類型整數(shù)所以概念上相當于創(chuàng)建發(fā)布器 我要發(fā)送 整數(shù) 發(fā)送到 number頻道真實 ROS2 才寫成create_publisherstd_msgs::msg::Int32( number, 10 );別急著整句理解。我們開始拆。3. 先看number這個最簡單number只是一個字符串。你已經(jīng)學過std::string name Robot;所以number沒什么特殊的。在這里它表示Topic 的名字。也就是頻道名稱??梢韵氤晌⑿湃好?number所以number≈我要往 number 這個頻道發(fā)東西4. Topic 到底是什么Topic 不是什么神秘對象。你現(xiàn)在先把它理解成ROS2 中用名字標識的消息頻道。比如機器人里可能有/joint_states /camera/image /vla_action /cmd_vel分別可以理解成不同頻道。例如/joint_states里面專門傳機器人關(guān)節(jié)狀態(tài)。而/vla_action里面以后可以傳VLA 產(chǎn)生的機器人動作。5. 再看這一坨std_msgs::msg::Int32第一次看肯定很煩。我們拆成std_msgs :: msg :: Int32你以前學過std::cout其中::可以先理解成“里面的”所以std::cout可以粗略讀std里面的cout一樣的std_msgs::msg::Int32可以一層層讀std_msgs 里面的 msg 里面的 Int32你現(xiàn)在不用關(guān)心為什么要分這么多層。只需要知道最終的Int32表示一種 ROS2 整數(shù)消息。6. 為什么不能直接發(fā)普通int你可能會問我已經(jīng)有int x 100;為什么 ROS2 還要搞std_msgs::msg::Int32因為 ROS2 在不同程序、甚至不同電腦之間傳數(shù)據(jù)。它需要一種大家都認識的統(tǒng)一“快遞包裝”。普通int x 100;可以理解成桌子上的數(shù)字 100。而std_msgs::msg::Int32 msg;可以理解成一個符合 ROS2 快遞標準的盒子。這個盒子里面有msg.data于是msg.data 100;就是┌─────────────┐ │ ROS2消息盒子 │ │ │ │ data 100 │ └─────────────┘這樣 ROS2 才方便把整個盒子送出去。7. 所以這兩句一定要理解std_msgs::msg::Int32 msg;意思創(chuàng)建一個 ROS2 整數(shù)消息對象名字叫msg。然后msg.data 100;意思把數(shù)字100放進這個消息對象的data成員。是不是一下簡單很多其實和你學過的 struct 很像。完全可以把它暫時想象成struct Int32 { int data; };然后Int32 msg; msg.data 100;ROS2 的Int32消息你現(xiàn)在就可以這樣理解。8. 再看 我們之前學過std::vectordouble什么意思你已經(jīng)知道一個裝double的 vector。這里同樣create_publisherstd_msgs::msg::Int32你可以理解成創(chuàng)建一個專門發(fā)送 Int32 消息的 Publisher。所以...暫時就翻譯成“我要處理什么類型的數(shù)據(jù)”比如std::vectordouble→ 裝double而create_publisherInt32→ 發(fā)布Int32先到這個深度就夠。9. 現(xiàn)在重新看這半句create_publisherstd_msgs::msg::Int32( number, 10 );現(xiàn)在你應該至少能翻譯出創(chuàng)建一個 Publisher它專門發(fā)送Int32整數(shù)消息發(fā)送到number這個 Topic。至于10今天甚至可以先不管。暫時把它記成ROS2 通信參數(shù)目前先默認寫 10。后面我們專門學 QoS 時再解釋。10. 那this-又來了完整一點this-create_publisherstd_msgs::msg::Int32( number, 10 );還記得this是什么意思嗎就是當前這個對象自己?,F(xiàn)在我們的類是class MyNode : public rclcpp::Node所以當前對象就是當前這個 ROS2 節(jié)點。那么this-create_publisher(...)就可以翻譯成讓當前這個 ROS2 節(jié)點創(chuàng)建一個 Publisher。你甚至可以把this-腦子里先翻譯成“我這個節(jié)點的……”所以this-create_publisher(...)≈“我這個節(jié)點創(chuàng)建發(fā)布器?!?1. 為什么這里是-因為this是一個指針。我們前面已經(jīng)學過普通對象 . 指針 -所以this-create_publisher(...)用的是-因為this是“當前對象的地址”??梢援嫵蓆his │ │ 地址 ▼ 當前 MyNode 對象 │ └── create_publisher()所以this-create_publisher()就是順著this找到當前 Node 對象然后調(diào)用它的create_publisher()。12. 我們現(xiàn)在已經(jīng)把右邊讀完了this-create_publisherstd_msgs::msg::Int32( number, 10 );整句話當前 ROS2 節(jié)點創(chuàng)建一個發(fā)布器這個發(fā)布器發(fā)送Int32整數(shù)消息使用numberTopic。很好。先到這里。13. 創(chuàng)建出來以后怎么辦我們需要把這個 Publisher 保存下來。就像int x 5;右邊5產(chǎn)生一個值。左邊x保存它。一樣publisher_ this-create_publisher...();左邊publisher_就是保存創(chuàng)建好的 Publisher。所以你可以暫時把整句理解成publisher_ 我剛剛創(chuàng)建的發(fā)布器14.publisher_之后怎么用比如已經(jīng)有消息std_msgs::msg::Int32 msg; msg.data 100;然后publisher_-publish(msg);又出現(xiàn)-。為什么因為publisher_是一個智能指針。所以publisher_ │ ▼ Publisher對象 │ └── publish()于是publisher_-publish(msg);翻譯找到 Publisher 對象調(diào)用它的publish()把msg發(fā)出去。最終msg.data 100 ↓ publisher_-publish(msg) ↓ number Topic ↓ 100 被發(fā)送出去15. 你今天只需要真正看懂這四步先別管整份 ROS2 代碼。只看std_msgs::msg::Int32 msg;創(chuàng)建一個整數(shù)消息盒子。然后msg.data 100;往盒子里放 100。然后 Publisher 已經(jīng)創(chuàng)建好了publisher_最后publisher_-publish(msg);讓 Publisher 把這個盒子發(fā)出去。整個邏輯就是創(chuàng)建盒子 ↓ 裝入100 ↓ 找到發(fā)布器 ↓ 發(fā)送盒子16. 和 VLA 聯(lián)系起來其實也一樣現(xiàn)在我們發(fā)的是100以后 VLA 發(fā)的是機械臂動作例如概念上VLA輸出 Joint1 30° Joint2 15° ...依舊是創(chuàng)建ROS2消息 ↓ 把VLA動作裝進去 ↓ Publisher發(fā)布 ↓ Topic ↓ 機器人控制節(jié)點收到只是消息盒子變復雜而已。17. 現(xiàn)在先別學 Subscriber上一課的問題就是Publisher 還沒吃透我馬上又加 Subscriber lambda SharedPtr。所以我們現(xiàn)在把課程拆開31APublisher 是什么——現(xiàn)在這節(jié)31BPublisher 的完整最小程序31CSubscriber 是什么31DPublisher → Topic → Subscriber 完整鏈路等這四小節(jié)真正搞懂我們再繼續(xù)spin()。先檢查你有沒有抓住核心你現(xiàn)在只需要能回答下面 4 個很小的問題std_msgs::msg::Int32 msg;是什么意思msg.data 100;是什么意思this-create_publisher...()大概是什么意思publisher_-publish(msg);大概是什么意思