2025年12月4日 星期四

ROS(Noetic) TO ROS2 (Humble)

 這是一個重大的專案轉移,因為 ROS 2 在底層架構上與 ROS 1 有很大的不同 (例如使用 DDS 作為傳輸層,以及構建系統從 Catkin 轉為 Ament/Colcon)。

以下是將 ROS 1 Noetic 專案轉移到 ROS 2 Humble 的關鍵步驟和注意事項:


🏗️ I. 概念性差異與準備工作

在開始修改程式碼之前,必須理解 ROS 1 和 ROS 2 之間的幾個核心差異:

  • Build System (建構系統):Catkin 轉為 Ament (使用 Colcon 作為建構工具)。

  • Client Libraries (客戶端函式庫):

    • ROS 1 C++: roscpp $\rightarrow$ ROS 2 C++: rclcpp

    • ROS 1 Python: rospy $\rightarrow$ ROS 2 Python: rclpy

  • Launch Files (啟動檔案): 從 XML/Python 腳本轉為強制使用 ROS 2 Python Launch System

  • Parameters (參數系統): 從集中的參數伺服器 (Parameter Server) 轉為分散式的參數服務/客戶端 (Parameter Service/Client)。

  • Python 版本: ROS 1 Noetic 支援 Python 3,但 ROS 2 Humble 強制使用 Python 3

  • 資料包頭 (Header): ROS 2 的 std_msgs/msg/Header 結構有所改變,不再有 seq 欄位。


🛠️ II. 實際專案轉移步驟

1. 轉換建構系統 (Catkin $\rightarrow$ Ament/Colcon)

A. package.xml 調整

  1. 格式版本:<package format="2"> 升級為 <package format="3">

  2. Build Tool: 替換 ROS 1 的 buildtool_depend

    • 移除 <buildtool_depend>catkin</buildtool_depend>

    • 新增 <buildtool_depend>ament_cmake</buildtool_depend> (適用於 C++ Packages) 或使用 setup.py (適用於 Python Packages)。

  3. 依賴項 (Dependencies): 將所有 *_depend 替換為 ROS 2 的對應套件名稱 (例如:tf $\rightarrow$ tf2_ros, message_runtime $\rightarrow$ rosidl_runtime_cpp 等)。

B. CMakeLists.txt 調整 (C++ Packages)

這是最需要修改的部分:

  1. 替換函式: 替換 Catkin 相關的函式為 Ament 函式,例如:

    • find_package(catkin ...) $\rightarrow$ find_package(rclcpp REQUIRED) 和其他 ROS 2 套件。

    • catkin_package(...) $\rightarrow$ ament_package()

    • 使用 ament_target_dependencies(...) 來連結程式庫。

  2. 安裝指令: 使用 install(TARGETS ...)install(DIRECTORY ...) 搭配 ament_cmake_indexament_export_targets 進行安裝。

2. 轉換程式碼 (C++ / Python)

A. Node 初始化

將 ROS 1 的 Node 啟動模式替換為 ROS 2 的 Node 類別:

  • ROS 1 (C++):

    C++
    ros::init(argc, argv, "my_node");
    ros::NodeHandle nh;
    // ...
    ros::spin();
    
  • ROS 2 (C++):

    C++
    #include <rclcpp/rclcpp.hpp>
    int main(int argc, char * argv[]) {
        rclcpp::init(argc, argv);
        auto node = std::make_shared<rclcpp::Node>("my_node");
        rclcpp::spin(node);
        rclcpp::shutdown();
        return 0;
    }
    // 或是建議繼承 rclcpp::Node 類別來自定義 Node
    

B. Publisher/Subscriber

  1. 替換函式庫: 替換 #include <ros/ros.h> 等為 rclcpp/rclcpp.hpprclpy 相關。

  2. 創建物件: ROS 2 的 Publisher 和 Subscriber 必須從 Node 物件創建。

    • ROS 1: ros::Publisher pub = nh.advertise<std_msgs::String>("topic", 10);

    • ROS 2: auto pub = node->create_publisher<std_msgs::msg::String>("topic", 10); (使用 std_msgs::msg::String)

  3. Callback 函式: 在 C++ 中,boost::bind 通常被 C++ 標準函式庫的 std::bind 替換。

C. 參數處理

將參數從 ROS 1 的全域參數伺服器,轉移到 ROS 2 的 Node 專屬參數服務。

  • ROS 1: nh.getParam("param_name", value);

  • ROS 2: 需要先在 Node 中宣告參數,然後透過 node->get_parameter("param_name", value) 或使用參數客戶端 ParameterClient 來獲取。

3. 轉換 Launch 檔案

將 ROS 1 的 XML 或舊版 Python Launch 檔案,完全重寫為 ROS 2 Python Launch System 檔案 (.launch.py)。

  • 核心模組: 主要使用 launchlaunch_ros.actions.Node

  • 基本結構:

    Python
    from launch import LaunchDescription
    from launch_ros.actions import Node
    
    def generate_launch_description():
        return LaunchDescription([
            Node(
                package='my_pkg',
                executable='my_node',
                name='my_node_name',
                parameters=[{'param_key': 'param_value'}]
            ),
            # ... 其他 Nodes
        ])
    

🌉 III. 過渡時期工具:ros1_bridge

如果你無法一次性將所有套件都轉移,可以使用 ros1_bridge 作為一個過渡方案。

  • 功能: ros1_bridge 允許 ROS 1 和 ROS 2 之間的消息進行轉換,讓 ROS 1 節點和 ROS 2 節點能夠互相通訊。

  • 使用時機: 在大型專案中,當部分組件已經轉移到 ROS 2,而其他組件仍然在 ROS 1 上執行時,這是非常有用的。


💡 總結

整個轉移過程涉及對 ROS 2 的架構、建構系統和 API 進行深入了解。建議參考 ROS 2 官方文件中的 Migration Guide,裡面有更詳細的程式碼範例。

您目前專案中,最主要的程式碼是用 C++ 還是 Python 撰寫的? 我可以提供更具體的程式碼轉換範例。

沒有留言:

張貼留言