2025年9月30日 星期二

轉換後的 ROS 2 Python Launch 程式碼

 arm_urdf.launch 檔案是典型的 ROS 1 XML Launch 檔案 。要將其轉換為 ROS 2 版本,我們需要從

XML 格式 遷移到 Python Launch 檔案 (推薦,因為它更具彈性和表達能力)。

ROS 2 的啟動系統(Launch System)與 ROS 1 截然不同,它使用 Python 程式碼來定義節點、參數和行為。


ROS 1 (XML) 轉換為 ROS 2 (Python) Launch 檔案

以下是將您 ROS 1 Launch 檔案中的每個組件轉換為 ROS 2 Python Launch 檔案的步驟與說明:

1. 檔案結構與依賴項

ROS 1 XML

ROS 2 Python (arm_urdf.launch.py)說明
<launch>引入 LaunchDescription 類別並定義 generate_launch_description 函式。這是 ROS 2 Launch 檔案的標準進入點。
<arg name="arg_x" default="0.00" />DeclareLaunchArgument('arg_x', default_value='0.00')ROS 2 使用 DeclareLaunchArgument 來定義啟動參數。
$(find package)get_package_share_directory('package_name')使用 ament_index_python 中的工具函數來查找套件路徑。

2. 轉換後的 ROS 2 Python Launch 程式碼

請在您的 robot_arm_urdf 套件中建立一個 launch 資料夾,並將此檔案命名為 arm_urdf.launch.py

Python
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration, Command, PythonExpression
from launch_ros.actions import Node
from launch.launch_description_sources import PythonLaunchDescriptionSource

# 主要函式:定義啟動內容
def generate_launch_description():
    # 1. 定義啟動參數 (對應 ROS 1 的 <arg>)
    arg_x = DeclareLaunchArgument('arg_x', default_value='0.00')
    arg_y = DeclareLaunchArgument('arg_y', default_value='0.00')
    arg_z = DeclareLaunchArgument('arg_z', default_value='0.00')
    arg_R = DeclareLaunchArgument('arg_R', default_value='0.00')
    arg_P = DeclareLaunchArgument('arg_P', default_value='0.00')
    arg_Y = DeclareLaunchArgument('arg_Y', default_value='0.00')

    # 獲取 robot_arm_urdf 套件的路徑
    pkg_dir = get_package_share_directory('robot_arm_urdf')
    
    # 2. 定義 robot_description 參數 (對應 ROS 1 的 <param>)
    # 使用 xacro 將 .xacro 檔案轉換為 URDF XML 內容
    # 假設您的 URDF 檔案實際上是 xacro 格式 (robot_arm_urdf.urdf 應該改名為 .xacro)
    robot_description_content = Command([
        'xacro ', os.path.join(pkg_dir, 'urdf', 'robot_arm_urdf.urdf') # 這裡路徑可能要改成 .xacro
    ])
    robot_description = {'robot_description': robot_description_content}
    
    # 3. 啟動 Gazebo 空世界 (對應 ROS 1 的 <include file="$(find gazebo_ros)/launch/empty_world.launch" />)
    gazebo_ros_dir = get_package_share_directory('gazebo_ros')
    gazebo = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([os.path.join(gazebo_ros_dir, 'launch', 'gazebo.launch.py')]),
        launch_arguments={'world': 'empty.world'}.items(), # 在 ROS 2 中,使用 gazebo.launch.py 並傳遞 world 參數
    )

    # 4. TF 靜態發佈器 (對應 ROS 1 的 <node name="tf_footprint_base" pkg="tf" type="static_transform_publisher" ...)
    static_tf = Node(
        package='tf2_ros',
        executable='static_transform_publisher',
        name='static_tf_pub',
        arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_footprint', '40'],
    )
    
    # 5. 生成模型到 Gazebo (對應 ROS 1 的 <node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" ...)
    spawn_entity = Node(
        package='gazebo_ros',
        executable='spawn_entity.py', # ROS 2 使用 spawn_entity.py
        name='urdf_spawner',
        arguments=[
            '-entity', 'robot_arm_urdf',
            '-topic', 'robot_description',
            '-x', LaunchConfiguration('arg_x'),
            '-y', LaunchConfiguration('arg_y'),
            '-z', LaunchConfiguration('arg_z'),
            '-Y', LaunchConfiguration('arg_Y'),
            # ROS 2 Gazebo 不再直接在 spawn_model 帶 -J joint 參數來初始化關節,
            # 而是透過 joint_state_broadcaster 和 robot_controller 來控制。
        ],
        output='screen'
    )
    
    # 6. 機器人狀態發佈器 (對應 ROS 1 的 <node name="robot_state_publisher" pkg="robot_state_publisher" ...)
    # 這是將 URDF 轉換為 TF 樹的核心。
    rsp = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        output='screen',
        parameters=[robot_description] # 將 robot_description 參數傳給 RSP
    )
    
    # 7. 控制器管理與啟動
    # (對應 ROS 1 的 <rosparam file="..." command="load"/> 和 <node name="controller_spawner" ...)
    
    # 7a. 加載控制器配置
    joint_traj_config = os.path.join(pkg_dir, 'config', 'joint_trajectory_controller.yaml')
    
    # 7b. 啟動關節狀態廣播器和機械手臂控制器 (ROS 2 中使用 spawner 節點)
    controller_manager = Node(
        package='controller_manager',
        executable='ros2_control_node',
        parameters=[robot_description, joint_traj_config],
        output={
            'stdout': 'screen',
            'stderr': 'screen',
        },
    )
    
    # 7c. 關節狀態廣播器
    joint_state_broadcaster_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["joint_state_broadcaster", "--controller-manager", "/controller_manager"],
    )

    # 7d. 機械手臂控制器 (您的 robot_arm_controller)
    robot_arm_controller_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["robot_arm_controller", "--controller-manager", "/controller_manager"],
    )

    # 返回所有動作的清單
    return LaunchDescription([
        arg_x,
        arg_y,
        arg_z,
        arg_R,
        arg_P,
        arg_Y,
        gazebo,
        static_tf,
        rsp,
        spawn_entity,
        joint_state_broadcaster_spawner,
        robot_arm_controller_spawner,
    ])

關鍵差異與 ROS 2 概念說明

ROS 1 XML 轉換

ROS 1 概念

ROS 2 對應與說明
$(find pkg)用來尋找套件的路徑。使用 ament_index_python.packages.get_package_share_directory('pkg')
<arg>使用 <arg> 定義變數。使用 launch.actions.DeclareLaunchArgument 進行定義,並使用 launch.substitutions.LaunchConfiguration('arg') 來引用。
robot_description使用 <param name="robot_description" textfile="..." /> 載入 URDF。通常使用 launch.substitutions.Command 結合 xacro 命令來動態處理 xacro 檔案,並將其結果作為節點參數傳遞。
<node pkg="gazebo_ros" type="spawn_model" />ROS 1 的 Gazebo 模型生成節點。ROS 2 中改用 pkg="gazebo_ros", executable="spawn_entity.py"
控制器啟動使用 rosparam 載入配置,然後使用 controller_manager 執行 spawner 節點。在 ROS 2 中,這被 ros2_control 框架取代。您需要: 1. 啟動 ros2_control_node (通常稱為 controller_manager)。 2. 使用 controller_manager 套件的 spawner 節點來單獨啟動 joint_state_broadcaster 和您的 robot_arm_controller
tf/static_transform_publisherROS 1 的靜態 TF 發佈節點。ROS 2 中改為 tf2_ros/static_transform_publisher

沒有留言:

張貼留言