학습 목표
- Topic, Service, Action과 Parameter를 요구사항에 맞게 구분할 수 있다.
- ROS 2 Parameter의 Node 소유권, Type과 수명을 설명할 수 있다.
- CLI로 Parameter를 조회·설명·변경·저장·복원할 수 있다.
- Python Node에서 Parameter를 선언하고 Descriptor와 범위를 지정할 수 있다.
- 변경 전 검증과 변경 후 적용을 분리하여 원자적으로 처리할 수 있다.
- YAML과 Launch에서 Node 이름·Namespace·Type을 정확히 적용할 수 있다.
- 다른 Node의 Parameter를 비동기로 변경하고 Parameter Event를 관찰할 수 있다.
- 실제 Robot에서 동적 변경 가능 값과 재시작이 필요한 값을 구분하고 안전하게 적용할 수 있다.
1. Parameter란 무엇인가
Parameter는 특정 Node가 소유하며 이름, Type과 값을 가진 설정 Data입니다. 최대 속도, 정지 거리, Camera 노출, PID Gain과 Frame 이름처럼 실행 동작을 조정하는 값에 사용합니다.
/speed_governor Node
├── max_speed_mps: 0.5
├── stop_distance_m: 0.4
├── publish_rate_hz: 20.0
└── robot_name: "pinky"
ROS 2에는 ROS 1처럼 모든 설정을 보관하는 중앙 Parameter Server가 기본 구조로 존재하지 않습니다. /robot1/controller와 /robot2/controller가 같은 max_speed_mps 이름을 사용해도 서로 다른 Parameter입니다.
Parameter는 일반적으로 Node Process가 살아 있는 동안 유지됩니다. 실행 중 ros2 param set으로 바꾼 값은 자동으로 원본 YAML에 저장되지 않으며 Node를 재시작하면 Code 기본값이나 시작 시 Override 값으로 돌아갑니다.
2. Topic·Service·Action·Parameter 선택
| 요구사항 | 권장 Interface | 이유 |
|---|---|---|
| LiDAR 거리 Data가 계속 생성됨 | Topic | 시간에 따라 흐르는 Stream |
| Sensor Zeroing을 지금 수행 | Service | 짧은 명령과 한 번의 결과 |
| 목표 지점까지 이동 | Action | 진행률·취소·최종 상태 필요 |
| 최대 속도 설정을 유지·조회 | Parameter | Node가 소유하는 설정값 |
| Emergency Stop | 독립 Safety 계층 | 일반 통신 하나에 안전을 의존하면 안 됨 |
다음 질문으로 판단합니다.
시간에 따라 계속 흐르는가? ── Yes → Topic
│ No
작업을 지금 수행하라는 명령인가?
├ 짧고 단발성 → Service
└ 길고 Feedback·Cancel 필요 → Action
│ No
Node가 기억하고 조회할 설정인가? ── Yes → Parameter
Parameter를 명령처럼 사용하지 마십시오. start_motion=true처럼 값의 변화를 동작 Trigger로 사용하면 요청별 성공·실패, 중복 호출과 실행 완료를 표현하기 어렵습니다.
3. Parameter Type과 선언 규칙
ROS 2 Parameter는 다음 Type을 지원합니다.
bool,integer,double,stringbyte arraybool[],integer[],double[],string[]
기본적으로 선언 시 Type이 정해지고 실행 중 다른 Type으로 변경할 수 없습니다.
self.declare_parameter('enabled', True) # bool
self.declare_parameter('retry_count', 3) # integer
self.declare_parameter('max_speed_mps', 0.5) # double
self.declare_parameter('frame_id', 'base_link') # string
self.declare_parameter('zones', ['A', 'B']) # string array
0은 integer이고 0.0은 double입니다. 다음 변경은 Type 불일치로 거절됩니다.
# max_speed_mps가 0으로 선언됐다면 double 0.7을 받을 수 없음
ros2 param set /speed_governor max_speed_mps 0.7
dynamic_typing=True로 Type 변경을 허용할 수 있지만 Consumer Code가 모든 가능한 Type을 안전하게 처리해야 하므로 일반 Robot 설정에는 고정 Type을 권장합니다.
4. CLI로 Turtlesim Parameter 체험
Terminal A에서 Turtlesim을 실행합니다.
source /opt/ros/$ROS_DISTRO/setup.bash
ros2 run turtlesim turtlesim_node
Terminal B에서 Node와 Parameter를 조사합니다.
ros2 node list
ros2 param list /turtlesim
ros2 param get /turtlesim background_r
ros2 param describe /turtlesim background_r
배경색을 변경합니다.
ros2 param set /turtlesim background_r 30
ros2 param set /turtlesim background_g 30
ros2 param set /turtlesim background_b 120
현재 값을 저장하고 다른 값으로 바꾼 뒤 다시 불러옵니다.
ros2 param dump /turtlesim
ros2 param dump /turtlesim --output-dir /tmp
ros2 param load /turtlesim /tmp/turtlesim.yaml
배포판별 CLI 옵션은 ros2 param dump -h로 확인하십시오. dump는 현재 값을 YAML로 내보내지만 실행 중 변경을 원본 구성 파일에 자동 기록하지는 않습니다.
5. Parameter CLI 명령 전체 흐름
ros2 param list
ros2 param list /speed_governor
ros2 param get /speed_governor max_speed_mps
ros2 param describe /speed_governor max_speed_mps
ros2 param set /speed_governor max_speed_mps 0.4
ros2 param dump /speed_governor
ros2 param load /speed_governor config/tuned.yaml
| 명령 | 목적 |
|---|---|
list |
선언된 Parameter 이름 확인 |
get |
현재 Type과 값 확인 |
describe |
설명, 제약과 읽기 전용 여부 확인 |
set |
실행 중 값 변경 요청 |
dump |
현재 값들을 YAML로 출력 |
load |
YAML의 값들을 실행 중 Node에 설정 |
Parameter가 보이지 않으면 먼저 정확한 Node 이름과 Namespace를 확인합니다.
ros2 node list
ros2 node info /robot1/speed_governor
6. Python 실습 Package 생성
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create parameter_lab_py \
--build-type ament_python \
--dependencies rclpy rcl_interfaces geometry_msgs
setup.py에 실행 파일을 등록합니다.
entry_points={
'console_scripts': [
'basic_parameter = parameter_lab_py.basic_parameter:main',
'speed_governor = parameter_lab_py.speed_governor:main',
'parameter_client = parameter_lab_py.parameter_client:main',
'parameter_monitor = parameter_lab_py.parameter_monitor:main',
],
},
7. 선언·읽기·사용하는 가장 작은 Node
# parameter_lab_py/basic_parameter.py
import rclpy
from rclpy.node import Node
class BasicParameterNode(Node):
def __init__(self):
super().__init__('basic_parameter')
self.declare_parameter('greeting', '안녕하세요')
self.declare_parameter('period_sec', 1.0)
period = self.get_parameter('period_sec').value
self.timer = self.create_timer(period, self.tick)
def tick(self):
greeting = self.get_parameter('greeting').value
self.get_logger().info(greeting)
def main(args=None):
rclpy.init(args=args)
node = BasicParameterNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Build하고 실행합니다.
cd ~/ros2_ws
colcon build --packages-select parameter_lab_py --symlink-install
source install/setup.bash
ros2 run parameter_lab_py basic_parameter
다른 Terminal에서 값을 변경합니다.
ros2 param get /basic_parameter greeting
ros2 param set /basic_parameter greeting '반갑습니다'
이 예제는 tick() 때마다 값을 읽으므로 greeting 변경이 바로 반영됩니다. 그러나 period_sec는 Timer 생성 시 한 번만 읽었으므로 값만 바꿔도 주기는 달라지지 않습니다.
8. ParameterDescriptor로 문서와 범위 제공
Descriptor는 Parameter의 설명, 읽기 전용 여부와 숫자 범위를 Graph에 공개합니다.
from rcl_interfaces.msg import FloatingPointRange, ParameterDescriptor
speed_descriptor = ParameterDescriptor(
description='최대 전진 속도. 단위 m/s',
additional_constraints='Robot 사양과 운용 구역 제한 중 작은 값을 사용',
floating_point_range=[
FloatingPointRange(
from_value=0.0,
to_value=1.5,
step=0.0,
)
],
)
self.declare_parameter('max_speed_mps', 0.5, speed_descriptor)
읽기 전용 Parameter 예시입니다.
robot_descriptor = ParameterDescriptor(
description='Robot 고유 이름',
read_only=True,
)
self.declare_parameter('robot_name', 'pinky_01', robot_descriptor)
ros2 param describe /speed_governor max_speed_mps
ros2 param set /speed_governor robot_name other
Descriptor는 사용자가 범위를 발견하도록 돕고 기본 검증을 제공합니다. 두 값 사이 관계나 운용 상태에 따른 조건은 변경 Callback에서 추가로 검사합니다.
9. 안전한 SpeedGovernor 전체 예제
requested_speed Topic의 명령을 max_speed_mps로 제한해 /cmd_vel_governed로 내보냅니다. 실제 시스템에서는 이 출력도 Safety Filter와 Motor Driver를 거쳐야 합니다.
# parameter_lab_py/speed_governor.py
import math
import threading
import rclpy
from geometry_msgs.msg import Twist
from rcl_interfaces.msg import (
FloatingPointRange,
ParameterDescriptor,
SetParametersResult,
)
from rclpy.node import Node
class SpeedGovernor(Node):
def __init__(self):
super().__init__('speed_governor')
self._lock = threading.Lock()
self.declare_parameter(
'max_speed_mps',
0.5,
ParameterDescriptor(
description='전진·후진 절대 속도 제한 m/s',
floating_point_range=[FloatingPointRange(
from_value=0.0, to_value=1.5, step=0.0)],
),
)
self.declare_parameter('stop_distance_m', 0.4)
self.declare_parameter('enabled', True)
self.declare_parameter(
'output_topic',
'cmd_vel_governed',
ParameterDescriptor(
description='출력 Topic. 시작 후 변경 불가',
read_only=True,
),
)
self._apply_current_parameters()
output_topic = self.get_parameter('output_topic').value
self.publisher = self.create_publisher(Twist, output_topic, 10)
self.subscription = self.create_subscription(
Twist, 'requested_speed', self.on_command, 10)
self._on_set_handle = self.add_on_set_parameters_callback(
self.validate_parameters)
self._post_set_handle = self.add_post_set_parameters_callback(
self.apply_parameters)
def _apply_current_parameters(self):
with self._lock:
self.max_speed = self.get_parameter('max_speed_mps').value
self.stop_distance = self.get_parameter('stop_distance_m').value
self.enabled = self.get_parameter('enabled').value
def validate_parameters(self, parameters):
proposed = {
'max_speed_mps': self.get_parameter('max_speed_mps').value,
'stop_distance_m': self.get_parameter('stop_distance_m').value,
'enabled': self.get_parameter('enabled').value,
}
for parameter in parameters:
if parameter.name in proposed:
proposed[parameter.name] = parameter.value
speed = proposed['max_speed_mps']
distance = proposed['stop_distance_m']
if not isinstance(speed, float) or not math.isfinite(speed):
return SetParametersResult(
successful=False,
reason='max_speed_mps는 유한한 double이어야 합니다',
)
if not 0.0 <= speed <= 1.5:
return SetParametersResult(
successful=False,
reason='max_speed_mps 허용 범위는 0.0~1.5입니다',
)
if not isinstance(distance, float) or not math.isfinite(distance):
return SetParametersResult(
successful=False,
reason='stop_distance_m는 유한한 double이어야 합니다',
)
if not 0.1 <= distance <= 3.0:
return SetParametersResult(
successful=False,
reason='stop_distance_m 허용 범위는 0.1~3.0입니다',
)
# 여러 값의 관계도 한 번에 검증할 수 있다.
if speed > 1.0 and distance < 0.5:
return SetParametersResult(
successful=False,
reason='1.0 m/s 초과에서는 정지 거리가 0.5 m 이상이어야 합니다',
)
return SetParametersResult(successful=True)
def apply_parameters(self, parameters):
# 모든 검증을 통과해 실제 값이 반영된 뒤 호출된다.
self._apply_current_parameters()
changed = ', '.join(p.name for p in parameters)
self.get_logger().info(f'Parameter 적용 완료: {changed}')
def on_command(self, message):
output = Twist()
with self._lock:
enabled = self.enabled
limit = self.max_speed
if enabled:
output.linear.x = max(-limit, min(message.linear.x, limit))
output.angular.z = message.angular.z
self.publisher.publish(output)
def main(args=None):
rclpy.init(args=args)
node = SpeedGovernor()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
add_post_set_parameters_callback()은 비교적 최신 API입니다. 사용하는 ROS 2 배포판의 rclpy에 없다면 on-set Callback은 검증만 수행하고, Parameter Event 또는 짧은 Timer에서 성공적으로 반영된 값을 읽어 Cache를 갱신하십시오.
10. 검증과 적용을 분리해야 하는 이유
한 요청에 여러 Parameter가 들어올 수 있습니다. 원자적 요청에서 하나라도 거절되면 전체가 적용되지 않습니다.
요청: max_speed=1.2, stop_distance=0.2
↓
현재값과 요청값을 합친 후보 상태 구성
↓
두 값의 범위·관계 검증 ── 실패 → 전부 유지
↓ 성공
Parameter Store 반영 → Cache·Timer·Filter 적용
검증 Callback에서 self.max_speed = p.value처럼 Side Effect를 먼저 만들면 뒤 Parameter가 거절될 때 Parameter Store는 원래 값인데 Cache만 새 값이 되는 문제가 생깁니다.
원칙은 다음과 같습니다.
- On-set Callback에서는 후보 값만 만들어 검증합니다.
- Hardware I/O, 파일 읽기와 긴 작업을 하지 않습니다.
- 성공 후 Post-set Callback이나 별도 적용 Loop에서 Cache를 갱신합니다.
- 공유 상태는 Lock 또는 단일 실행 흐름으로 보호합니다.
11. 동적으로 Timer 주기 변경하기
Timer는 publish_rate_hz 값만 바꾼다고 자동 재생성되지 않습니다. 성공적으로 변경된 뒤 기존 Timer를 취소하고 새 Timer를 만듭니다.
def recreate_timer(self):
rate = self.get_parameter('publish_rate_hz').value
if self.timer is not None:
self.timer.cancel()
self.destroy_timer(self.timer)
self.timer = self.create_timer(1.0 / rate, self.tick)
def apply_parameters(self, parameters):
names = {p.name for p in parameters}
if 'publish_rate_hz' in names:
self.recreate_timer()
Callback 안에서 Entity 생성·파괴가 배포판과 Executor 구성에 어떤 영향을 주는지 시험하십시오. 더 안전한 구조는 Callback이 reconfigure_requested=True만 설정하고 다음 관리 Timer에서 재구성하는 방식입니다.
def apply_parameters(self, parameters):
if any(p.name == 'publish_rate_hz' for p in parameters):
self.reconfigure_requested = True
def maintenance_tick(self):
if self.reconfigure_requested:
self.reconfigure_requested = False
self.recreate_timer()
12. YAML Parameter 파일
config/speed_governor.yaml을 만듭니다.
speed_governor:
ros__parameters:
max_speed_mps: 0.6
stop_distance_m: 0.5
enabled: true
output_topic: cmd_vel_governed
실행합니다.
ros2 run parameter_lab_py speed_governor --ros-args \
--params-file ~/ros2_ws/src/parameter_lab_py/config/speed_governor.yaml
파일과 CLI Override를 함께 사용할 수 있습니다.
ros2 run parameter_lab_py speed_governor --ros-args \
--params-file config/speed_governor.yaml \
-p max_speed_mps:=0.3
YAML 확인 사항:
- Node 이름 아래에
ros__parameters가 와야 합니다. 밑줄은 두 개입니다. 1은 integer,1.0은 double입니다.true와false는 Boolean으로 씁니다.- Tab 대신 Space를 사용합니다.
- Node 이름과 Namespace가 실제 Graph 이름에 맞아야 합니다.
13. Namespace와 YAML Wildcard
Robot마다 값을 다르게 지정할 수 있습니다.
/robot1/speed_governor:
ros__parameters:
max_speed_mps: 0.4
/robot2/speed_governor:
ros__parameters:
max_speed_mps: 0.7
/**:
ros__parameters:
use_sim_time: false
/**/speed_governor:
ros__parameters:
stop_distance_m: 0.5
*는 Slash로 구분된 한 Token, **는 0개 이상의 Token과 대응합니다. 너무 넓은 /**에 max_speed_mps 같은 일반 이름을 넣으면 의도하지 않은 Node에도 Override가 전달될 수 있으므로 공통 Parameter에만 제한적으로 사용합니다.
ros2 run parameter_lab_py speed_governor --ros-args -r __ns:=/robot1 \
--params-file config/fleet.yaml
14. Python Launch에서 YAML과 Override 적용
launch/speed_governor.launch.py 예시입니다.
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
namespace = LaunchConfiguration('namespace')
params_file = LaunchConfiguration('params_file')
return LaunchDescription([
DeclareLaunchArgument('namespace', default_value='robot1'),
DeclareLaunchArgument(
'params_file',
default_value='config/speed_governor.yaml',
),
Node(
package='parameter_lab_py',
executable='speed_governor',
name='speed_governor',
namespace=namespace,
parameters=[
params_file,
{'enabled': True},
],
output='screen',
),
])
실행합니다.
ros2 launch parameter_lab_py speed_governor.launch.py \
namespace:=robot1 \
params_file:=/absolute/path/to/speed_governor.yaml
실제 Package에서는 get_package_share_directory()와 PathJoinSubstitution으로 설치된 share 경로의 YAML을 찾는 방식을 권장합니다. setup.py의 data_files에도 launch와 config 파일을 설치해야 합니다.
data_files=[
('share/ament_index/resource_index/packages',
['resource/parameter_lab_py']),
('share/parameter_lab_py', ['package.xml']),
('share/parameter_lab_py/launch', ['launch/speed_governor.launch.py']),
('share/parameter_lab_py/config', ['config/speed_governor.yaml']),
],
15. 다른 Node의 Parameter를 비동기로 변경
Parameter Service를 직접 조립하기보다 AsyncParameterClient를 사용합니다.
# parameter_lab_py/parameter_client.py
import rclpy
from rclpy.node import Node
from rclpy.parameter import Parameter
from rclpy.parameter_client import AsyncParameterClient
class ParameterClientNode(Node):
def __init__(self):
super().__init__('parameter_client')
self.client = AsyncParameterClient(self, '/speed_governor')
def set_safe_profile(self):
if not self.client.wait_for_services(timeout_sec=5.0):
raise RuntimeError('Parameter Service를 찾지 못했습니다')
parameters = [
Parameter('max_speed_mps', Parameter.Type.DOUBLE, 0.3),
Parameter('stop_distance_m', Parameter.Type.DOUBLE, 0.6),
]
future = self.client.set_parameters_atomically(parameters)
future.add_done_callback(self.on_result)
def on_result(self, future):
try:
result = future.result().result
if result.successful:
self.get_logger().info('안전 Profile 적용 완료')
else:
self.get_logger().error(f'적용 거절: {result.reason}')
except Exception as exc:
self.get_logger().error(f'Parameter 요청 실패: {exc}')
rclpy.shutdown()
def main(args=None):
rclpy.init(args=args)
node = ParameterClientNode()
node.set_safe_profile()
try:
rclpy.spin(node)
finally:
node.destroy_node()
if __name__ == '__main__':
main()
set_parameters()는 각 Parameter 결과를 개별적으로 받을 수 있고, set_parameters_atomically()는 묶음 전체를 하나의 후보 상태로 적용하거나 모두 거절합니다. 서로 의존하는 속도·정지 거리에는 원자적 설정이 적합합니다.
16. Parameter Event 관찰
Parameter가 선언·변경·삭제되면 /parameter_events에 Event가 발행됩니다.
ros2 topic echo /parameter_events
Python에서는 ParameterEventHandler로 특정 Node의 특정 Parameter를 관찰할 수 있습니다.
# parameter_lab_py/parameter_monitor.py
import rclpy
from rclpy.node import Node
from rclpy.parameter_event_handler import ParameterEventHandler
class ParameterMonitor(Node):
def __init__(self):
super().__init__('parameter_monitor')
self.handler = ParameterEventHandler(self)
self.callback_handle = self.handler.add_parameter_callback(
parameter_name='max_speed_mps',
node_name='/speed_governor',
callback=self.on_speed_change,
)
def on_speed_change(self, parameter):
self.get_logger().info(
f'{parameter.name} 변경 감지: {parameter.value}')
def main(args=None):
rclpy.init(args=args)
node = ParameterMonitor()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
반환된 callback_handle을 멤버 변수로 보관해야 Callback 등록이 유지됩니다. Event는 변경 통지에 유용하지만 중요한 동작 상태를 Parameter Event에만 의존하지 마십시오. 현재 안전 상태와 Mode는 의미가 명확한 상태 Topic으로 제공하는 편이 좋습니다.
17. 초기값 Override와 선언
Command Line과 YAML에 값을 적어도 Node가 해당 Parameter를 선언하지 않으면 일반적인 선언 기반 Node에서는 사용할 수 없습니다.
# Override가 있다면 그 값을, 없다면 0.5를 사용해 선언
self.declare_parameter('max_speed_mps', 0.5)
Node Option으로 전달된 Parameter를 자동 선언하는 기능도 있지만 오타가 새 Parameter로 조용히 등록될 수 있어 교육용·운영용 Robot Node에는 명시적 선언을 우선 권장합니다.
시작 값의 출처는 다음처럼 겹칠 수 있습니다.
Code 기본값
↓ 시작 시 Override
YAML·Launch·Command Line 인자
↓ 실행 중 변경
CLI·Parameter Client
여러 파일과 Inline Dictionary의 세부 병합 순서에 기대기보다 최종 값을 시작 Log와 ros2 param get으로 검증하고, Profile별 최종 YAML을 명확히 관리하십시오.
18. 실제 Robot에서 Parameter를 나누는 기준
| Parameter | 실행 중 변경 | 적용 방법 |
|---|---|---|
max_speed_mps |
조건부 허용 | 범위·운용 Mode 검증 후 즉시 Cache 반영 |
stop_distance_m |
조건부 허용 | 속도와 함께 원자적으로 검증 |
| PID Gain | 시험·상태 조건부 | 출력 제한, 기록과 단계적 적용 |
| Camera Exposure | Driver 지원 시 허용 | Frame 경계에서 반영 확인 |
| Serial Port | 보통 금지 | Read-only, 재시작 후 초기화 |
frame_id |
보통 금지 | TF 계약이 바뀌므로 재시작·통합 검증 |
| Wheel Radius | 운용 중 금지 권장 | Odometry 일관성을 위해 정지·재시작 |
| Emergency Stop | Parameter로 구현 금지 | 독립 안전 입력과 상태 Machine |
Parameter 범위는 Hardware 최대치만 보면 안 됩니다. Robot 사양, 하중, 바닥, 작업 구역과 현재 Mode에서 허용하는 값 중 가장 보수적인 제한을 적용합니다.
if self.robot_is_moving and parameter.name == 'wheel_radius_m':
return SetParametersResult(
successful=False,
reason='Robot 정지 후에만 wheel_radius_m를 변경할 수 있습니다',
)
안전 한계는 사용자가 Parameter를 바꾸면 사라지는 하나의 Software if에만 의존하지 않습니다. Driver의 Saturation, Watchdog와 독립 Safety Controller에서도 방어합니다.
19. 구성 Profile과 변경 이력
실제 운용에서는 환경별 YAML을 분리합니다.
config/
├── defaults.yaml
├── simulation.yaml
├── lab_low_speed.yaml
├── warehouse.yaml
└── robot_001_calibration.yaml
좋은 관리 원칙:
- YAML을 Version Control에 저장합니다.
- 단위와 허용 범위를 Code Descriptor와 문서에 기록합니다.
- Robot 개체별 Calibration과 환경별 운용 설정을 분리합니다.
- 누가, 언제, 왜 값을 바꿨는지 변경 이력을 남깁니다.
dump결과를 그대로 승인된 구성으로 간주하지 말고 검토 후 반영합니다.- Secret, Password와 API Key를 Parameter에 평문 저장하지 않습니다.
실행 시작 시 중요한 설정과 구성 Version을 Log로 남기면 현장 문제를 재현하기 쉬워집니다.
self.get_logger().info(
f'profile=warehouse-v3 max_speed={self.max_speed} '
f'stop_distance={self.stop_distance}')
20. 진단 절차
ros2 node list
ros2 param list /robot1/speed_governor
ros2 param get /robot1/speed_governor max_speed_mps
ros2 param describe /robot1/speed_governor max_speed_mps
ros2 topic echo /parameter_events
ros2 service list | grep speed_governor
| 증상 | 확인할 항목 |
|---|---|
| Parameter가 목록에 없음 | 선언 여부, 정확한 Node 이름·Namespace |
| YAML이 적용되지 않음 | ros__parameters, Node key, 경로, 설치 여부 |
set이 Type 오류 |
선언 기본값 Type과 YAML Scalar Type |
set 성공인데 동작 불변 |
Cache·Timer·Driver에 변경 후 적용했는지 |
| 여러 값 중 일부만 예상과 다름 | atomic/non-atomic API와 검증 Side Effect |
| 재시작 후 값 사라짐 | CLI 변경을 YAML에 반영했는지 |
| Parameter Service 응답 없음 | Executor Blocking, Callback의 긴 I/O |
| 다른 Robot 값이 바뀜 | 절대 Node 이름, Namespace와 Wildcard 범위 |
진단은 “설정했다고 생각한 값”이 아니라 Node가 실제 보유한 값부터 확인합니다. 이후 Parameter Store, Application Cache, 출력 Message와 Hardware 적용 상태를 차례로 비교합니다.
YAML·CLI 입력 → Node Parameter Store → Application Cache
→ 출력 Command → Driver 내부 설정 → 실제 Robot
21. 흔한 실수와 교정
- 설정 변경을 Trigger 명령으로 사용한다. 작업 요청은 Service나 Action으로 표현합니다.
- 실수 기본값을
0으로 선언한다.0.0으로 Type을 명확히 합니다. - 선언하지 않은 Parameter를 읽는다. 시작 시 명시적으로 선언합니다.
- 검증 Callback에서 Cache부터 수정한다. 검증과 성공 후 적용을 분리합니다.
- Callback에서 Hardware 재초기화를 오래 수행한다. Flag를 세우고 별도 실행 흐름에서 처리합니다.
- Parameter 값만 바꾸면 Timer도 변한다고 생각한다. 관련 Entity를 명시적으로 재구성합니다.
- YAML의
ros__parameters를 틀린다. Node 이름과 들여쓰기를 함께 확인합니다. - 광범위한
/**를 남용한다. 공통 Parameter에만 사용합니다. - CLI 변경이 영구 저장된다고 믿는다. 검토한 값을 YAML과 Version Control에 반영합니다.
- 여러 의존 값을 하나씩 변경한다.
set_parameters_atomically()를 사용합니다. read_only면 안전이 완성된다고 믿는다. Hardware·Driver 계층에서도 한계를 둡니다.- Password를 Parameter로 배포한다. Secret 관리 체계를 사용합니다.
22. 실습 체크리스트
- [ ] Turtlesim의 Parameter를 CLI로 조회하고 변경했다.
- [ ]
list·get·describe·set·dump·load를 사용했다. - [ ] Python Node에서 다섯 가지 Type을 선언했다.
- [ ] Descriptor에 설명, 읽기 전용과 숫자 범위를 지정했다.
- [ ] Type 불일치와 범위 밖 값을 시험했다.
- [ ] 검증 Callback과 성공 후 적용을 분리했다.
- [ ] 두 Parameter의 관계를 원자적으로 검증했다.
- [ ] Timer 주기를 안전하게 재구성했다.
- [ ] YAML의 Node 이름과
ros__parameters를 확인했다. - [ ] Namespace 두 개에 다른 값을 적용했다.
- [ ] Launch에서 YAML과 Inline Override를 전달했다.
- [ ] AsyncParameterClient로 묶음 설정을 적용했다.
- [ ]
/parameter_events와 Event Handler를 시험했다. - [ ] 실제 Robot의 동적·정적 Parameter를 구분했다.
- [ ] 변경값을 YAML과 Version Control에 기록했다.
23. 정리
Parameter는 Node가 소유하는 조회 가능한 설정값입니다. 선언 시 Type과 기본값을 정하고 Descriptor로 의미와 범위를 공개하며 YAML과 Launch로 재현 가능한 초기 구성을 제공합니다.
실행 중 변경에서는 검증과 적용을 분리하는 것이 핵심입니다. On-set Callback은 현재값과 요청값으로 후보 상태를 만들어 Side Effect 없이 검사하고, 성공 후에 Cache, Timer와 Filter를 갱신해야 합니다. 서로 의존하는 값은 원자적으로 설정합니다.
실제 Robot에서는 모든 설정을 동적으로 바꾸지 않습니다. Frame, Hardware Port와 Calibration처럼 System 계약을 바꾸는 값은 정지·재시작 절차를 요구하고, 속도와 안전 거리는 상태와 관계를 함께 검증합니다. Parameter는 편리한 설정 Interface이지 독립 Safety 기능이나 영구 Database가 아닙니다.
- Parameter파라미터
- 특정 ROS 2 Node가 소유하며 이름, Type과 값을 가진 조회 가능한 설정 Data입니다.
- Parameter Declaration파라미터 선언
- Node가 사용할 Parameter의 이름, 기본값, Type과 Descriptor를 등록하는 과정입니다.
- Parameter Override파라미터 덮어쓰기
- Node 시작 시 YAML, Launch 또는 Command Line 값으로 Code 기본값을 대체하는 설정입니다.
- ParameterDescriptor파라미터 설명자
- Parameter의 설명, 읽기 전용, 동적 Type과 숫자 범위 같은 Metadata와 제약을 정의합니다.
- Read-only Parameter읽기 전용 파라미터
- 시작 시 초기화할 수 있지만 Node 실행 중에는 변경 요청을 받지 않는 Parameter입니다.
- Dynamic Typing동적 타입
- 실행 중 Parameter Type 변경을 허용하는 선택 기능으로 Consumer가 모든 Type을 처리해야 합니다.
- Parameter Range파라미터 범위
- Integer 또는 Floating Point Parameter에 허용되는 최소·최대·단계 조건입니다.
- ros__parametersROS 파라미터 YAML 키
- YAML 파일에서 특정 Node에 적용할 Parameter Map을 표시하는 예약 Key입니다.
- Parameter File파라미터 파일
- Node 이름과 ros__parameters 구조로 재현 가능한 초기 설정을 기록한 YAML 파일입니다.
- Parameter Callback파라미터 콜백
- Parameter 변경 전 검증하거나 성공 후 Application 상태에 적용하기 위해 호출되는 함수입니다.
- On-set Callback변경 전 검증 콜백
- Parameter Store에 값이 반영되기 전에 후보 값을 검증하고 수락 또는 거절하는 Callback입니다.
- Post-set Callback변경 후 적용 콜백
- 모든 검증을 통과해 Parameter가 성공적으로 설정된 뒤 Cache와 실행 상태를 갱신하는 Callback입니다.
- Atomic Set원자적 설정
- 여러 Parameter를 모두 함께 적용하거나 하나라도 실패하면 전부 적용하지 않는 변경 방식입니다.
- AsyncParameterClient비동기 파라미터 클라이언트
- 다른 Node의 Parameter Service를 발견하고 비동기로 조회·설정하는 rclpy Client입니다.
- Parameter Event파라미터 이벤트
- Node에서 Parameter가 선언·변경·삭제될 때 /parameter_events로 발행되는 변경 통지입니다.
- ParameterEventHandler파라미터 이벤트 처리기
- 자신 또는 다른 Node의 특정 Parameter 변경을 Callback으로 관찰하는 rclpy 도구입니다.
- YAML WildcardYAML 와일드카드
- Parameter 파일에서 별표를 사용해 여러 Node 이름이나 Namespace에 공통 설정을 대응시키는 문법입니다.
- Configuration Profile구성 프로파일
- Simulation, 시험실, 창고 또는 Robot 개체처럼 운용 조건별로 관리하는 Parameter 설정 묶음입니다.
- Application Cache응용 캐시
- 반복 조회 비용을 줄이기 위해 Node 멤버 변수 등에 복사해 사용하는 현재 Parameter 값입니다.
- Side Effect부수 효과
- 검증 결과 반환 외에 Cache, Hardware나 외부 상태를 변경하는 동작으로 검증 Callback에서는 피해야 합니다.
연습 문제
- ROS 2 Parameter의 소유 주체와 수명을 설명하세요.
- 최대 속도에는 Parameter, 배터리 잔량에는 Topic이 적합한 이유는 무엇인가요?
0과0.0으로 선언한 Parameter의 Type 차이는 무엇인가요?declare_parameter,get_parameter와.value의 역할을 설명하세요.- ParameterDescriptor의
description,read_only, 숫자 Range가 제공하는 기능은 무엇인가요? ros2 param list·get·describe·set·dump·load의 역할을 각각 설명하세요.- YAML의 Node 이름,
ros__parameters와 값 Type을 확인해야 하는 이유는 무엇인가요? - Namespace가 있는 Node에 YAML이 적용되지 않을 때 무엇을 비교해야 하나요?
- 검증 Callback에서 Cache를 즉시 변경하면 원자적 요청에서 어떤 문제가 생기나요?
- On-set 검증과 Post-set 적용을 분리해야 하는 이유는 무엇인가요?
set_parameters()와set_parameters_atomically()의 차이를 설명하세요.publish_rate_hz값만 변경해도 기존 Timer 주기가 바뀌지 않는 이유와 해결 방법은 무엇인가요?- Parameter Event Handler의 Callback Handle을 보관해야 하는 이유는 무엇인가요?
- Wheel Radius와 Emergency Stop을 각각 Parameter로 어떻게 다뤄야 하는지 설명하세요.
- Parameter 변경 성공 후 Robot 동작이 그대로일 때 YAML부터 Hardware까지 진단 순서를 설명하세요.
COMMUNITY
강의 댓글
질문과 학습 경험을 함께 나눠보세요.댓글을 불러오는 중입니다.