
面試被問你自定義過ROS2的消息類型嗎流程是怎樣的我說寫過.msg文件。面試官說CMakeLists.txt里怎么配置自定義的消息怎么在Python和C之間互操作接口設計有什么原則自定義消息是ROS2開發的基本功但很多人只停留在會寫.msg文件的層面。今天把整個流程和接口設計的原則講清楚。為什么需要自定義消息ROS2的標準消息類型覆蓋了大部分常見場景。但你的項目總有一些特殊需求自定義的傳感器數據格式、特定的控制指令結構、業務邏輯相關的狀態信息。標準類型滿足不了的時候就需要自定義消息類型。創建消息類型第一步在包的msg/目錄下創建.msg文件# RobotStatus.msg std_msgs/Header header string robot_name float32 battery_level bool is_charging float32[] joint_positions float32[] joint_velocities uint8 state uint8 IDLE0 uint8 MOVING1 uint8 ERROR2消息類型支持的字段基本類型bool、int8-64、uint8-64、float32/64、string、數組固定長度和可變長度、其他消息類型、常量定義。第二步在CMakeLists.txt中添加依賴和配置find_package(rosidl_default_generators REQUIRED) find_package(std_msgs REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} msg/RobotStatus.msg DEPENDENCIES std_msgs )第三步在package.xml中添加依賴build_dependrosidl_default_generators/build_depend exec_dependrosidl_default_runtime/exec_depend member_of_grouprosidl_interface_packages/member_of_group dependstd_msgs/depend編譯之后ROS2會自動生成Python和C的代碼。Python中通過from my_package.msg import RobotStatus使用C中通過#include my_package/msg/robot_status.hpp使用。自定義Service和Action類型同樣的流程可以用于Service和Action# CalculatePath.srv geometry_msgs/Pose start geometry_msgs/Pose goal --- bool success geometry_msgs/Pose[] path float32 total_distance# PatrolRobot.action geometry_msgs/Pose[] waypoints float32 speed --- bool all_reached float32 total_time --- uint32 current_waypoint_index float32 distance_to_nextService用.srv文件Action用.action文件。格式都是請求和響應或目標、反饋、結果用---分隔。接口設計原則自定義消息不是隨便定義字段就行。好的接口設計能讓你的系統更易維護、更易擴展。單一職責。一個消息類型只描述一個概念。RobotStatus描述機器人狀態SensorReading描述傳感器讀數。不要把不相關的信息塞到同一個消息里。使用標準類型。能用geometry_msgs/Pose就不要自己定義float64 x, y, z, qx, qy, qz, qw。標準類型有現成的工具支持和其他包對接也方便。包含Header。如果你的消息會通過Topic傳輸加上std_msgs/Header字段。Header提供時間戳和frame_id這在調試和多傳感器融合時至關重要。版本號。如果消息類型可能會變化在名字或注釋中標注版本。RobotStatusV2比悄悄修改RobotStatus的字段要安全得多。避免過大的消息。一個消息里塞太多數據會導致序列化開銷大、傳輸延遲高。大數據比如圖像、點云用標準類型或者考慮分塊傳輸。跨語言使用ROS2的消息類型定義是語言無關的。rosidl工具鏈會自動生成Python、C甚至其他語言的綁定代碼。Python中from my_package.msg import RobotStatus msg RobotStatus() msg.robot_name robot_01 msg.battery_level 85.5 msg.state RobotStatus.MOVINGC中#include my_package/msg/robot_status.hpp auto msg my_package::msg::RobotStatus(); msg.robot_name robot_01; msg.battery_level 85.5; msg.state my_package::msg::RobotStatus::MOVING;注意C中的命名轉換msg文件中的RobotStatus在C中變成robot_status.hpp字段名從下劃線變成駝峰。rosidl自動處理這些轉換。接口版本兼容項目迭代中消息類型難免要改。加個字段、改個類型看似小事處理不好就出大問題。ROS2的消息類型兼容性有一套規則新增字段默認有初始值老代碼不填這個字段也不會報錯這叫向后兼容。但如果你改了已有字段的類型或者刪掉了某個字段老代碼就編譯不過了這叫不兼容變更。實際項目中的經驗是優先通過添加新字段來擴展消息避免修改或刪除已有字段。如果確實需要不兼容變更就創建一個新的消息類型而不是改舊的。比如RobotStatus不夠用了新建一個RobotStatusV2讓老節點繼續用舊版本新節點用新版本平滑過渡。在大型項目中接口變更應該走代碼評審流程所有依賴方都要被通知到。ROS2提供了ros2 interface相關命令可以查看消息定義對比不同版本的差異。這種接口治理的習慣在面試中很加分。面試中怎么聊面試官問自定義消息你可以說自定義消息需要在msg目錄下定義.msg文件CMakeLists.txt中配置rosidl_generate_interfacespackage.xml中添加生成器和運行時依賴。編譯后自動生成Python和C綁定。接口設計遵循單一職責、使用標準類型、包含Header、避免過大消息等原則。Service和Action類型也可以用同樣的方式自定義。自定義消息的版本管理在長期維護的項目中自定義消息接口的版本管理很重要。修改消息字段時要考慮到向后兼容性舊的bag文件可能用的是舊格式。一個實用的做法是只添加新字段不刪除或修改已有字段新字段設置默認值在消息定義中用注釋標注版本號和變更歷史。這樣即使消息格式演進舊數據仍然可以正確讀取。給你的建議在你的項目里創建一個自定義消息類型編譯通過然后在Python和C中分別使用它。跑通整個流程之后你對rosidl工具鏈的理解會上一個臺階。然后審視一下項目中現有的消息類型定義看看有沒有違反接口設計原則的地方。這種代碼審查能力在面試中很加分。最后提醒一點自定義消息類型修改之后所有依賴它的節點都要重新編譯。在大型項目中消息類型的變更要謹慎提前通知團隊成員。上一篇第121篇 ROS2消息類型——std_msgs/sensor_msgs/geometry_msgs詳解下一篇預告第123篇 URDF建模入門——從link和joint開始描述一個機器人