ROS와 연동되는 로봇 프로그램과 일반적인 로봇 프로그램과의 차이는 프로세스를 목적별로 나누어 노드(Node) 단위의 프로그램을 작성하고 노드와 노드 간의 데이터 통신을 고려하여 설계해야 한다.
이번장에서는 ROS2의 토픽, 서비스, 액션 프로그래밍을 이용해서 각 노드들이 서로 연동되어 구동하는 패키지를 설계할 것이다.
예제 패키지는 총 4개의 노드로 구성되어 있다. 아래 그림 1과 같이 각 노드에서는 1개 이상의 토픽 퍼블리셔, 토픽 서브스크라이브, 서비스 서버, 서비스 클라이언트, 액션 서버, 액션 클라이언트를 포함하고 있다. 특히 중앙에 있는 노드는 다른 노드들과의 연동에 있어서 가장 핵심적인 역할을 하도록 설계하였고 추후 강좌를 위해서 실행 인자(argument), 파라미터(parameter), 런치(launch) 파일이 추가되어 있다.
이렇게 설계한 패키지를 topic_service_action_rclcpp_example
패키지라고 하자. 해당 패키지에 포함된 각각의 노드와 토픽, 서비스, 액션도 고유의 이름을 가지고 있는데 이는 앞전의 파이썬 강의때와 같다.
argument node : arithmetic_argument 토픽으로 현재 시간과 변수 a, b 를 퍼블리시 한다.
calculator node : arithmetic_argument 토픽이 생성된 시간과 변수 a, b를 서브스크라이브 한다.
operator node : arithmetic_operator 서비스를 통해 calculator 노드에게 연산자(+,-,*,%)를 서비스 요청값으로 보낸다.
calculator node : 서브스크라이브하여 저장하고 있는 변수 a,와 operator 노드로부터 요청값으로 받은 연산자를 이용하여 계산(a 연산자 b)하고 operator 노드에게 연산의 결괏값을 arithmetic_operator 이름으로 서비스 응답값을 보낸다.
checker node : 연산값의 합계의 한계치를 arithmetic_checker 액션 이름으로 액션 목표값으로 전달한다.
calculator node : checker 노드로 부터 액션 목표값을 받은 후 부터 저장된 변수(a, b, 연산자)를 가지고 연산한 값을 합한다. 그리고 연산이 끝난 계산식을 arithmetic_checker 이름으로 액션 피드백을 checker 노드로 보낸다. 연산값의 합이 액션 목표값을 넘기면 최종 연산 합계를 arithmetic_checker 이름으로 액션 결괏값을 checker 노드로 보낸다.
topic_service_action_rclcpp_example 패키지에는 argument 노드
, operator 노드
, calculator 노드
, checker 노드
로 구성되어 있다.
topic_service_action_rclcpp_example 패키지의 설정 파일(package.xml)은 다음과 같다.
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>topic_service_action_rclcpp_example</name>
<version>0.2.0</version>
<description>ROS 2 rclcpp example package for the topic, service, action</description>
<maintainer email="passionvirus@gmail.com">Pyo</maintainer>
<license>Apache License 2.0</license>
<author email="passionvirus@gmail.com">Pyo</author>
<author email="routiful@gmail.com">Darby Lim</author>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>rclcpp_action</depend>
<depend>msg_srv_action_interface_example</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
ROS2의 패키지 설정 파일의 package format은 세 번째 버전이다.(ROS1에서는 두 번째 버전을 사용한다.)
<package format = "3">
빌드 툴은 ament_cmake
를 사용하도록 buildtool_depend 태그로 명시한다.
<buildtool_depend>ament_cmake</buildtool_depend>
소스코드 빌드에 필요한 의존성 패키지를 설정하기 위해 depend 태그로 rclcpp와 rclcpp_action 그리고 앞장에서 작성한 토픽, 서비스, 액션 인터페이스에서 작성한 토픽, 서비스, 액션 인터페이스명(패키지 명: msg_srv_acton_interface_example)를 적어준다.
<depend>rclcpp</depend>
<depend>rclcpp_action</depend>
<depend>msg_srv_action_interface_example</depend>
테스트 코드 빌드를 위한 의존성 패키지를 설정하기 위해 test_depend 태그로 사용할 린트(Lint) 패키지를 명시한다.해당 태그를 통해 테스트 코드를 빌드하기 위한 의존성 패키지도 명시해 줄 수 있다.
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
export 태그로 build_type 태그를 명시하고 build_type 태그로 ament_cmake
를 적어준다.(파이썬은 ament_python)
<export>
<build_type>ament_cmake</build_type>
</export>
topic_service_action_rclcpp_example 패키지의 빌드 설정 파일(CMakeLists.txt) 전문은 다음과 같다.
# Set minimum required version of cmake, project name and compile options
cmake_minimum_required(VERSION 3.5)
project(topic_service_action_rclcpp_example)
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# Find dependencies
find_package(ament_cmake REQUIRED)
find_package(msg_srv_action_interface_example REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_action REQUIRED)
include_directories(include)
# Build
add_executable(argument src/arithmetic/argument.cpp)
ament_target_dependencies(argument
msg_srv_action_interface_example
rclcpp
)
add_executable(calculator src/calculator/main.cpp src/calculator/calculator.cpp)
ament_target_dependencies(calculator
msg_srv_action_interface_example
rclcpp
rclcpp_action
)
add_executable(checker src/checker/main.cpp src/checker/checker.cpp)
ament_target_dependencies(checker
msg_srv_action_interface_example
rclcpp
rclcpp_action
)
add_executable(operator src/arithmetic/operator.cpp)
ament_target_dependencies(operator
msg_srv_action_interface_example
rclcpp
)
# Install
install(TARGETS
argument
calculator
checker
operator
DESTINATION lib/${PROJECT_NAME}
)
install(DIRECTORY launch param
DESTINATION share/${PROJECT_NAME}
)
# Test
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()
# Macro for ament package
ament_package()
ROS 2 빌드를 위한 CMakeList 파일은 크게 cmake 설정, 의존성 명시, 빌드, 설치, 테스트, ament package 매크로 설정 으로 나눌 수 있다.
cmake는 최소 3.5 버전 이상을 사용해야 하며, 별다른 명시가 없다면 C99와 C++14를 기본으로 사용하게 된다. GNU 컴파일러를 기본으로 사용하지만 Clang 컴파일러을 사용할 수도 있다.
cmake_minimum_required(VERSION 3.5)
project(topic_service_action_rclcpp_example)
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
ament_target_dependencies 명령어의 인자에는 프로그램 실행을 위해 필요한 의존성 패키지를 모두 적어준다.
ament_target_dependencies(argument
msg_srv_action_interface_example
rclcpp
)
launch와 param 폴더는 share 폴더에 저장해야만 한다.
install(DIRECTORY launch param
DESTINATION share/${PROJECT_NAME}
)
린트와 테스트 코드를 위한 의존성 패키지는 다음과 같이 적어준다. 이는 colcon test 명령어를 통해 실행할 수 있다.
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()
해당 패키지를 ament_index에 등록시키기 위해 ament_package() 매크로 함수를 적어주면 빌드 설정이 끝난다.
ament_package()
패키지 완성이 완료되면 빌드 설정을 하자.
$ cd ~/robot_ws
$ colcon build --symlink-install
빌드가 완려되면 install도 해주자
$ source install/setup.bash
여기까지 C++패키지 설계를 완료하였다. 다음시간부터는 토픽, 서비스, 액션, 파라미터에 대해 직접 실습을 해보겠다.