이번 포스팅에서는 ROS2의 파라미터(parameter)와, 메시지 통신에 사용되는 인터페이스(interface)에 대해서 다뤄보도록 하자.
참고한 링크는 다음과 같다.
https://cafe.naver.com/openrt/24165
https://cafe.naver.com/openrt/24241
그리고 해당 링크를 기반으로 작성된 서적,
"ROS2로 시작하는 로봇 프로그래밍"도 참고하였다.
ROS1에서는 파라미터 서버(param server)를 ROS Master의 일종으로 관리했음을 알 수 있다. ROS2에서도 큰 틀에서는 유사하지만, 조금 달라진 부분이 있다. 달라진 부분에 대해서 알아보자.
출처링크: https://cafe.naver.com/openrt/24165
💡 ROS2의 파라미터
ROS2에서 파라미터는 위 이미지처럼, 각 노드에서 파라미터 서버를 실행시켜, 외부의 파라미터 클라이언트(parameter client)를 통해서 파라미터를 변경할 수 있다. 이러한 점에서 서비스와 매우 유사하다고 볼 수 있다(서비스 역시 서비스 클라이언트의 요청을 받아, 서비스 응답을 수행하는 서비스 서버가 존재하므로).
다만, 완전히 동일하지는 않다. 차이점은 다음과 같이 정리할 수 있다.
💡 파라미터와 서비스의 차이
- 서비스의 경우 요청과 응답으로 구성된다. 이는 특정 요청을 수행하기 위함이다.
- 반면 파라미터의 경우 노드 내 파라미터를 서비스와 유사하게 통신하여 노드 내부 혹은 외부에서 쉽게 지정 및 변경, 사용이 가능하게 하는 목적이다.
파라미터 관련 기능은 RCL(ROS Client Library)의 기본 기능으로, 모든 노드는 자기 자신만의 파라미터 서버를 가지게 된다. 그리고 각 노드는 기본적으로 파라미터 클라이언트 기능 수행이 가능하기 때문에, 각 노드들의 매개변수를 일종의 글로벌 변수처럼 자유롭게 사용할 수 있다는 점도 특징이다.
그리고 yaml 형식의 파일로 파라미터 설정 파일을 만들어 파라미터 값 초기화 및 노드 실행 시 파라미터 설정 파일 호출이 가능하다는 점도 ROS2 기반 프로그래밍에서 매우 유리한 부분이다.
$ ros2 param list
현재 실행 중인 노드에 속해있는 모든 파라미터 목록을 확인할 수 있다. 다행히도, 각 노드별로 파라미터들이 구분지어서 출력되게 된다.
$ ros2 param describe <param_name>
다음 내용들이 출력된다.
$ ros2 param get <node_name> <param_name>
노드 이름과 파라미터 이름을 입력하면 파라미터의 현재 값을 읽어들여 확인이 가능하다.
$ ros2 param set <node_name> <param_name> <param_value>
노드 이름, 파라미터 이름, 그리고 값을 통해 원하는 파라미터에 대한 값을 변경할 수 있다.
$ ros2 param dump <node_name>
set 명령어를 통해서 파라미터 값을 변경한다고 하더라도, 노드를 종료하고 재시작한다면 다시 파라미터 값이 초기화 된다. 따라서 변화시킨 파라미터 값을 또 사용하고 싶다면 파일로 저장했다가 불러오는 식으로 기능해야 한다.
ros2 param dump 명령어는 현재 폴더에 해당 노드 이름으로 파라미터 설정 파일을 yaml 파일로 저장하게 된다.
노드 실행 시 dump 명령어를 통해서 저장한 파라미터 파일을 불러와 실행하고 싶다면, 다음과 같이 옵션을 지정해주면 된다.
$ ros2 run <pkg_name> <node_name> --ros-args --params-file <yaml_name>
yaml_name은 저장되어 있는 yaml 파일 이름이다.
$ ros2 param delete <param_name>
파라미터 이름을 지정해서 원하는 파라미터를 삭제할 수 있다.
기존 포스팅에서 다루었듯 ROS2의 노드 간의 데이터를 주고받을 때에는 메시지 통신으로 토픽, 서비스, 액션을 사용하는데, 이 때 메시지를 주고받기 위한 수단을 인터페이스라고 한다. ROS2의 인터페이스에는 ROS2에 추가된 IDL(Interface Definition Language), ROS1과 동일한 간단한 자료형(data type), 간단한 자료구조(data structure), 배열(array, rclpy의 경우 list나 dictionary도 어쩌면 포함)을 사용할 수 있다.
이에 대한 예시 링크들은 다음과 같다.
https://github.com/ros2/common_interfaces/tree/foxy/std_msgs
https://github.com/ros2/common_interfaces/blob/foxy/geometry_msgs/msg/Twist.msg
https://github.com/ros2/common_interfaces/blob/foxy/sensor_msgs/msg/LaserScan.msg
간단한 인터페이스는 다음과 같이 작성할 수 있다.
interface_type interface_name
각 자료형이 RCL에서 제공하는 대표언어(C++, 파이썬)의 어떤 자료형과 매칭되는지는 다음 링크를 참고하면 된다.
https://cafe.naver.com/openrt/24241
각 데이터 통신과 매칭하면 다음과 같다.
인터페이스는 정수, 실수(부동소수점), 논리형(bool)과 같은 단순 자료형부터, 간단한 자료구조나 메시지가 나열된 배열 등을 사용하게 된다.
이러한 인터페이스 파일은 다음과 같이 정의가 가능하다.
fieldtype fieldname
예를 들어서, geometry_msgs에 정의되어 있는 Vector3.msg 인터페이스는 당므과 같이 정의되어 있다.
float64 x
float64 y
float64 z
ROS2에서 지원하는 각 프로그래밍 언어별 인터페이스는 다음 링크를 참고하거나, 아니면 "ROS2로 시작하는 로봇 프로그래밍" 서적 p.159를 참고하면 된다.
https://cafe.naver.com/openrt/24241
$ ros2 interface show <interface_name>
원하는 인터페이스 이름을 입력하면, 각 인터페이스 형태 및 인터페이스 이름을 확인할 수 있다. 예를 들면 다음과 같다.
$ ros2 interface show geometry_msgs/msg/Twist
Vector3 linear
Vector3 angular
이 외 명령어들은 다음 것들이 있다.
먼저 토픽에 사용되는 msg를 살펴보면 다음과 같다.
fieldtype fieldname
그 다음으로, 서비스에 사용되는 srv에 대해서 살펴보면 다음과 같다.
service_type service_request
---
service_type service_result
서비스는 요청과 응답으로 구성되기 때문에, 구분자(---)에 의해서 분리되어 출력되게 된다. 예를 들면 다음과 같다.
$ ros2 interface show turtlesim/srv/Spawn.srv
float32 x
float32 y
float32 theta
string name
---
string name
이번에는 액션에 대해서 살펴보자.
액션 같은 경우 action 인터페이스를 사용하게 된다.
액션의 경우 액션 목표(goal), 중간값에 해당하는 액션 피드백(feedback), 그리고 최종 결과인 액션 결과(result)로 나누어서 표기하게 된다.
특이하게, 결과를 중간에 표기하고 피드백을 마지막에 표기한다.
action_type action_goal
---
action_type action_result
---
action_type action_feedback
예시를 들면 다음과 같다.
$ ros2 interface show turtlesim/action/RotateAbsolute.action
float32 theta
---
float32 delta
---
float32 remaining