7. launch file กับ parameter
หุ่นจริงมี node สิบกว่าตัว เปิดทีละ terminal ไม่ไหว หัวข้อนี้แก้เรื่องนั้น
parameter — แยกค่าตั้งออกจากโค้ด
ใน หัวข้อ 6 ความเร็ว 0.2 ถูกเขียนตายอยู่ในโค้ด อยากเปลี่ยนต้องแก้ไฟล์
ทำให้เป็น parameter จะดีกว่า
class SpeedSender(Node):
def __init__(self):
super().__init__('speed_sender')
# ประกาศพร้อมค่าเริ่มต้น
self.declare_parameter('speed', 0.2)
self.pub = self.create_publisher(Twist, '/cmd_vel', 10)
self.timer = self.create_timer(0.1, self.tick)
def tick(self):
# อ่านทุกครั้งที่ใช้ เพื่อให้เปลี่ยนระหว่างรันได้
speed = self.get_parameter('speed').value
msg = Twist()
msg.linear.x = speed
self.pub.publish(msg)
ตอนรันกำหนดค่าได้เลย
ros2 run my_robot speed_sender --ros-args -p speed:=0.1
หรือเปลี่ยนระหว่างที่รันอยู่
ros2 param set /speed_sender speed 0.05
Tip
อ่านค่า parameter ทุกครั้งที่ใช้ อย่าอ่านครั้งเดียวใน __init__
ถ้าอ่านเก็บไว้ใน __init__ แล้วใช้ตัวแปรนั้นตลอด ros2 param set จะไม่มีผลอะไรเลย —
ค่าเปลี่ยนจริงแต่โค้ดไม่ได้ไปอ่านใหม่
เจอบ่อยตอนจูนค่าแล้วงงว่าทำไมเปลี่ยนแล้วไม่เห็นผล
เก็บค่าลงไฟล์ YAML
พอค่าเยอะขึ้นควรแยกออกเป็นไฟล์ config/robot.yaml
speed_sender:
ros__parameters:
speed: 0.15
wheel_driver:
ros__parameters:
port: /dev/ttyUSB0
baud: 115200
Warning
🔴 โครงสร้าง 2 ชั้นนี้ผิดไม่ได้ — ชื่อ node ชั้นนอก แล้ว ros__parameters ชั้นใน
(ขีดล่าง 2 ตัว ระหว่าง ros กับ parameters)
ถ้าเขียนผิด ROS 2 จะโหลดไฟล์ผ่านโดยไม่ error แต่ค่าไม่ถูกใช้เลย node จะใช้ค่าเริ่มต้นแทนแบบเงียบ ๆ
ตรวจด้วย ros2 param get หลังเปิด node เสมอว่าค่าเข้าจริง
ชื่อชั้นนอกต้องตรงกับชื่อ node ที่ตั้งใน super().__init__('speed_sender')
ไม่ใช่ชื่อไฟล์ และไม่ใช่ชื่อ package
launch file — เปิดหลาย node พร้อมกัน
สร้าง ~/ros2_ws/src/my_robot/launch/robot.launch.py
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
config = os.path.join(
get_package_share_directory('my_robot'),
'config', 'robot.yaml')
return LaunchDescription([
Node(
package='my_robot',
executable='speed_sender',
name='speed_sender', # ต้องตรงกับชื่อใน YAML
parameters=[config],
output='screen',
),
Node(
package='my_robot',
executable='speed_watcher',
name='speed_watcher',
output='screen',
),
])
บอก setup.py ให้ติดตั้งไฟล์เหล่านี้ด้วย
Danger
🔴 ขั้นนี้ลืมแล้วจะเจอ file not found แบบหาสาเหตุไม่เจอ
ไฟล์ launch กับ YAML อยู่ใน src/ แต่ตอนรันจริงระบบไปหาที่ install/
ถ้าไม่บอกให้คัดลอกไป มันจะไม่อยู่ที่นั่น
แก้ setup.py
import os
from glob import glob
setup(
# ...
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')),
],
)
Note
แก้ setup.py แล้วต้อง build ใหม่เสมอ แม้จะใช้ --symlink-install
เพราะ --symlink-install ช่วยเฉพาะไฟล์ .py ที่ลงทะเบียนไว้แล้ว
ไม่ได้ช่วยกับการเพิ่มไฟล์ใหม่หรือเปลี่ยนรายการติดตั้ง
รัน
cd ~/ros2_ws
colcon build --symlink-install --packages-select my_robot
source install/setup.bash
ros2 launch my_robot robot.launch.py
เปิดทั้ง 2 node ในคำสั่งเดียว กด Ctrl+C ครั้งเดียวปิดหมด
เปลี่ยนค่าตอนสั่ง launch ได้ด้วย
ros2 launch my_robot robot.launch.py speed:=0.05
ตรวจว่าค่าเข้าจริง
ros2 param get /speed_sender speed
Important
ทำข้อนี้ทุกครั้งหลังแก้ YAML ถ้าได้ 0.2 (ค่าเริ่มต้นในโค้ด)
ทั้งที่ YAML เขียน 0.15 แปลว่าไฟล์ไม่ได้ถูกโหลด สาเหตุมี 3 อย่างเรียงตามที่เจอบ่อย
ชื่อ node ใน YAML ไม่ตรงกับ
name=ใน launch fileลืมใส่
config/*.yamlในdata_filesแล้วไม่ได้ build ใหม่สะกด
ros__parametersผิด (ขีดล่างตัวเดียว)
ก่อนหน้า: 6. publisher กับ subscriber · ต่อไป: 8. tf2 — กรอบพิกัด