spawn_entity.py
是一個在 ROS 2 中非常實用的工具,
它允許您將機器人模型或任何其他 SDF/URDF 格式的實體動態地載入到正在運行的 Gazebo 模擬環境中。
這對於在已經啟動的世界中添加物體或多個機器人非常有用。
spawn_entity.py
的基本概念
spawn_entity.py
實際上是一個 ROS 2 節點,它作為一個服務客戶端,向 Gazebo 提供的 /spawn_entity
服務發送請求。這個服務會接收您提供的模型定義(通常是 URDF 或 SDF 格式的 XML 字串),然後將模型添加到 Gazebo 世界中。
spawn_entity.py
的常用參數和使用範例
以下是 spawn_entity.py
腳本的一些常用參數及其使用範例:
常用參數
-entity <name>
或--entity <name>
:必填。要載入的模型在 Gazebo 中的名稱。這個名稱在 Gazebo 世界中必須是唯一的。-file <path_to_model_file>
或--file <path_to_model_file>
:指定要載入的 URDF 或 SDF 模型的檔案路徑。-topic <topic_name>
或--topic <topic_name>
:如果模型定義是通過 ROS 2 話題發布的,則指定該話題的名稱。通常用於robot_description
話題,由robot_state_publisher
發布。-x <x_pos>
、-y <y_pos>
、-z <z_pos>
:模型在世界中的初始 XYZ 座標(米)。-R <roll>
、-P <pitch>
、-Y <yaw>
:模型在世界中的初始滾轉 (Roll)、俯仰 (Pitch)、偏航 (Yaw) 角度(弧度)。-Y <yaw_deg>
或--yaw <yaw_deg>
:偏航角,可以使用角度值(度)。(注意:有-Y
和--yaw
兩種格式,-Y
是弧度,--yaw
是角度,要小心區分。)-timeout <seconds>
:等待/spawn_entity
服務可用的超時時間(秒)。預設通常是 30 秒。-robot_namespace <namespace>
或--robot-namespace <namespace>
:為模型中的所有 ROS 接口添加一個命名空間。這在多機器人模擬中非常有用,可以避免話題或服務名稱衝突。-b
或--bond
:維持與 Gazebo 的連接。如果spawn_entity.py
退出,Gazebo 中的模型也會被移除。
使用範例
範例 1:從 URDF 檔案載入機器人模型
這個範例假設您有一個名為 my_robot.urdf
的機器人模型檔案。
確保 Gazebo 正在運行: 您可以先啟動一個空白世界:
Bashros2 launch gazebo_ros gazebo.launch.py # 或您自定義的 empty_world.launch.py
在新的終端機中執行
spawn_entity.py
: 假設my_robot.urdf
位於my_robot_description
套件的urdf
目錄下。Bash# 獲取套件路徑 MY_ROBOT_DESCRIPTION_DIR=$(ros2 pkg prefix my_robot_description)/share/my_robot_description ros2 run gazebo_ros spawn_entity.py \ -entity my_robot \ -file $MY_ROBOT_DESCRIPTION_DIR/urdf/my_robot.urdf \ -x 0 -y 0 -z 0.5 \ -R 0 -P 0 -Y 0
-entity my_robot
:將模型命名為my_robot
。-file .../my_robot.urdf
:指定 URDF 檔案的路徑。-x 0 -y 0 -z 0.5
:將機器人放置在 (0, 0, 0.5) 的位置。-R 0 -P 0 -Y 0
:設置初始姿態為零角度。
範例 2:從 ROS 2 話題載入機器人模型 (robot_description
topic)
這是最常見且推薦的方式,特別是當您的機器人模型是 Xacro 格式,或需要由 robot_state_publisher
處理時。
啟動 Gazebo 和
robot_state_publisher
: 您需要一個 Launch 檔案來同時啟動這兩者。Python# my_robot_launch_package/launch/spawn_robot_in_gazebo.launch.py import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import ExecuteProcess, IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import Command from launch_ros.actions import Node from launch_ros.parameter_descriptions import ParameterValue def generate_launch_description(): # 獲取機器人描述套件的路徑 robot_description_package_dir = get_package_share_directory('ur5_description') # 請替換為您的機器人描述套件名稱 # 組合 Xacro 檔案的路徑 xacro_file = os.path.join(robot_description_package_dir, 'urdf', 'ur5.urdf.xacro') # 請替換為您的 Xacro/URDF 檔案名稱 # 使用 Command 替換 Xacro 預處理,並將結果傳遞給 robot_description robot_description_content = ParameterValue( Command(['xacro ', xacro_file]), value_type=str ) # 啟動 Gazebo 伺服器 gazebo_server_cmd = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py' )]), launch_arguments={'world': os.path.join(get_package_share_directory('gazebo_ros'), 'worlds', 'empty.world')}.items() ) # 啟動 Gazebo 客戶端 (圖形界面) gazebo_client_cmd = ExecuteProcess( cmd=['gzclient'], output='screen' ) # 啟動 robot_state_publisher 節點,發布機器人描述 robot_state_publisher_node = Node( package='robot_state_publisher', executable='robot_state_publisher', name='robot_state_publisher', output='screen', parameters=[{'robot_description': robot_description_content}], ) # 使用 spawn_entity.py 將機器人模型載入 Gazebo spawn_entity_cmd = Node( package='gazebo_ros', executable='spawn_entity.py', arguments=[ '-entity', 'my_spawned_robot', # 模型名稱 '-topic', 'robot_description', # 從 robot_description 話題讀取模型 '-x', '0', '-y', '0', '-z', '0.1', # 初始位置 # '-R', '0', '-P', '0', '-Y', '1.5708', # 初始姿態 (弧度) # '--yaw', '90' # 初始姿態 (角度) ], output='screen' ) return LaunchDescription([ gazebo_server_cmd, gazebo_client_cmd, robot_state_publisher_node, spawn_entity_cmd, ])
執行 Launch 檔案:
[Bash]ros2 launch my_robot_launch_package spawn_robot_in_gazebo.launch.py
-entity my_spawned_robot
:指定在 Gazebo 中顯示的模型名稱。-topic robot_description
:告訴spawn_entity.py
去訂閱/robot_description
話題來獲取機器人模型數據。
範例 3:在特定命名空間載入多個機器人
如果您想在同一個 Gazebo 世界中載入多個機器人,
並且希望它們的 ROS 接口(話題、服務等)是獨立的,可以使用 robot_namespace
參數。
# 假設您想載入兩個相同的機器人,分別位於不同的命名空間
# robot_1 的啟動器
robot_1_state_publisher = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
namespace='robot_1', # 注意這裡的命名空間
parameters=[{'robot_description': robot_description_content}],
output='screen',
)
spawn_robot_1 = Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=[
'-entity', 'robot_1_model',
'-topic', 'robot_1/robot_description', # 這裡的話題名也要包含命名空間
'-x', '0', '-y', '0', '-z', '0.1',
'-robot_namespace', 'robot_1' # 為 Gazebo 內的 ROS 接口應用命名空間
],
output='screen'
)
# robot_2 的啟動器 (類似於 robot_1,只是改變名稱和位置)
robot_2_state_publisher = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
namespace='robot_2',
parameters=[{'robot_description': robot_description_content}],
output='screen',
)
spawn_robot_2 = Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=[
'-entity', 'robot_2_model',
'-topic', 'robot_2/robot_description',
'-x', '1', '-y', '0', '-z', '0.1',
'-robot_namespace', 'robot_2'
],
output='screen'
)
return LaunchDescription([
gazebo_server_cmd,
gazebo_client_cmd,
robot_1_state_publisher,
spawn_robot_1,
robot_2_state_publisher,
spawn_robot_2,
])
在這個範例中,robot_1
的所有 ROS 接口都會在 /robot_1/
命名空間下,
而 robot_2
的會在 /robot_2/
命名空間下,這對於多機器人協同工作非常重要。
總結
spawn_entity.py
是一個非常靈活的工具,讓您能夠在 Gazebo 模擬中動態地控制模型的載入。最常見的用法是搭配 robot_state_publisher
來載入 URDF/Xacro 定義的機器人模型。
沒有留言:
張貼留言