跳至主要内容

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 中。