Parameter 與 Launch
本頁會在 Publisher/Subscriber 中的 Publisher 加入 Parameter,將設定移到 YAML 檔案中,並透過一個 Launch File 同時啟動兩個 Node,同時支援從命令列覆寫設定值。
概述
目前的 simple_publisher 將 Publish Rate 與 Message Text 直接寫死在程式碼中。
在本頁中,你會先在程式碼中宣告帶有預設值的 Parameter,再從 YAML 檔案載入啟動時的設定值,最後使用單一 Launch File 同時啟動 Publisher 與 Subscriber。
為什麼重要
如果設定值直接寫死在程式碼中,每次修改設定都必須重新 Build,或至少修改原始碼後重新啟動 Node。
Parameter 與 Launch File 可以讓你在不修改程式碼的情況下改變執行行為,例如 Publish Rate、Topic Name、Frame ID,以及哪些 Node 要一起啟動。
實際部署時通常就是透過這種方式進行設定,本網站後續的 Mobility 與 Manipulation 範例也會大量使用這些機制。
前置條件
已完成 Publisher/Subscriber:目前已有可正常執行的 my_ros2_tutorial Package,其中包含 simple_publisher.py 與 simple_subscriber.py。
核心概念
- 宣告 Parameter:在 Node 的
__init__中使用self.declare_parameter('name', default_value)。預設情況下,Parameter 必須先宣告,之後才能讀取或設定。 - 讀取 Parameter:使用
self.get_parameter('name').value,或使用.get_parameter_value()取得具體型別的值。 - YAML Parameter File:以 Node Name ->
ros__parameters-> Key/Value 的結構儲存設定值,可在啟動時由 Launch File 或ros2 run ... --ros-args --params-file載入。 - Launch File:ROS 2 中最常見的是 Python Script,用來描述要啟動哪些 Node,以及對應的 Parameter、Remapping 與 Argument。使用
ros2 launch <package> <file>.launch.py執行。 - Launch Argument vs. Parameter:Launch Argument 是透過
ros2 launch命令列傳入的值,Launch File 再使用該值設定一個或多個 Node Parameter。這樣可以讓同一份 Launch File 重複使用在不同設定中。
實作步驟
1. 在 Publisher 中加入 Parameter
修改 ~/ros2_ws/src/my_ros2_tutorial/my_ros2_tutorial/simple_publisher.py,讓 __init__ 宣告並使用兩個 Parameter,而不是直接使用寫死的設定值:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class SimplePublisher(Node):
def __init__(self):
super().__init__('simple_publisher')
self.declare_parameter('publish_rate', 1.0)
self.declare_parameter('message_text', 'Hello ROS 2')
publish_rate = self.get_parameter('publish_rate').value
self.message_text = self.get_parameter('message_text').value
self.publisher_ = self.create_publisher(String, 'tutorial_chatter', 10)
self.timer = self.create_timer(1.0 / publish_rate, self.timer_callback)
self.count = 0
def timer_callback(self):
msg = String()
msg.data = f'{self.message_text}: {self.count}'
self.publisher_.publish(msg)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.count += 1
def main(args=None):
rclpy.init(args=args)
node = SimplePublisher()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
publish_rate 的單位是 Hz;Timer Period 會透過 1.0 / publish_rate 計算。
2. 建立 YAML Parameter File
建立 ~/ros2_ws/src/my_ros2_tutorial/config/params.yaml:
simple_publisher:
ros__parameters:
publish_rate: 2.0
message_text: "Hello from YAML"
最上層的 Key(simple_publisher)必須與 Node Name 相同。
3. 建立 Launch File
建立 ~/ros2_ws/src/my_ros2_tutorial/launch/tutorial.launch.py:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
config_file = os.path.join(
get_package_share_directory('my_ros2_tutorial'),
'config',
'params.yaml'
)
publish_rate_arg = DeclareLaunchArgument(
'publish_rate',
default_value='2.0',
description='Publisher rate in Hz, overrides the YAML value'
)
publisher_node = Node(
package='my_ros2_tutorial',
executable='simple_publisher',
name='simple_publisher',
parameters=[
config_file,
{'publish_rate': LaunchConfiguration('publish_rate')}
]
)
subscriber_node = Node(
package='my_ros2_tutorial',
executable='simple_subscriber',
name='simple_subscriber'
)
return LaunchDescription([
publish_rate_arg,
publisher_node,
subscriber_node
])
Parameter 會依照 parameters=[...] 中列出的順序套用。
在這個範例中,會先載入 YAML 檔案,再由後面的 Dictionary 使用 Launch Argument 覆寫 publish_rate。
由於這個 Launch Argument 本身具有 Default Value,因此在此範例中,publish_rate 會永遠由 Launch File 提供。
4. 在 setup.py 中註冊 Launch 與 Config 目錄
開啟 ~/ros2_ws/src/my_ros2_tutorial/setup.py,將 launch 與 config 目錄加入 data_files,讓它們能在安裝後被 get_package_share_directory 找到:
import os
from glob import glob
from setuptools import find_packages, setup
package_name = 'my_ros2_tutorial'
setup(
# ... existing fields (name, version, packages, etc.) ...
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
(os.path.join('share', package_name, 'config'), glob('config/*.yaml')),
],
# ... remaining fields ...
)
只需要新增 launch 與 config 這兩個 Tuple;原本由 ros2 pkg create 產生的 data_files 項目要保留。
5. Build、Source 並執行 Launch File
cd ~/ros2_ws
colcon build --packages-select my_ros2_tutorial --symlink-install
source install/setup.bash
ros2 launch my_ros2_tutorial tutorial.launch.py
接著嘗試從命令列覆寫 Publish Rate:
ros2 launch my_ros2_tutorial tutorial.launch.py publish_rate:=5.0
預期成果
如果沒有從命令列覆寫,Launch Argument 的 Default Value 會是 2.0 Hz。
Message Text 會從 YAML 檔案載入。
當使用 publish_rate:=5.0 時,Publisher 會大約以 5 Hz 執行。
Useful Commands
# Parameters of a running node
ros2 param list /simple_publisher
ros2 param get /simple_publisher publish_rate
ros2 param set /simple_publisher publish_rate 3.0
ros2 param dump /simple_publisher # dump current values as YAML
# Launch
ros2 launch my_ros2_tutorial tutorial.launch.py --show-args
ros2 launch my_ros2_tutorial tutorial.launch.py publish_rate:=5.0
常見問題
ros2 param set成功,但 Node 行為沒有改變 — 這個範例只會在初始化時讀取一次 Parameter。修改publish_rate不會重新建立 Timer,而修改message_text也不會更新已經快取在 Instance 中的值。若要套用新設定,可以重新啟動 Node,或加入 Parameter Update Handling,讓 Node 支援 Runtime Change。- Launch 時出現
params.yaml的FileNotFoundError—config目錄可能沒有加入setup.py的data_files,或修改setup.py後沒有重新 Build Workspace。重新檢查步驟 4 並再次 Build。 - Launch Argument Override 沒有效果 —
parameters=[...]中的順序會影響結果。如果 Dictionary 放在 YAML 檔案之前,後載入的 YAML 反而會覆寫 Dictionary。請確認 YAML File 位於前面。 ros2 launch顯示"package not found"— 重新 Build 後可能沒有 source Overlay,或 Launch File 本身有 Syntax Error。重新執行source install/setup.bash,並檢查colcon build的輸出內容。
重點整理
- 在程式碼中宣告帶有 Default Value 的 Parameter,再視需求透過 YAML File 與 Launch Configuration 提供啟動時的 Override。
- YAML Parameter File 會依 Node Name 分組,並將設定放在
ros__parameters下。 - Launch File 可以一次啟動多個 Node,並以宣告式方式套用 Parameter、Argument 與 Remapping。
setup.py中的data_files必須包含所有非 Python Resource,例如launch/與config/,否則這些檔案不會被安裝到share/。
下一步
接著前往 TF2,了解 Coordinate Frame 如何發布與檢查。這個概念會大量出現在 Mobility 與 Manipulation 的 Launch File 中。