Simple Message Publisher 및 Subscriber 예제

|

간단하게 메시지를 발행/수신하는 예제 코드는 다음과 같습니다.

snowdeer_publisher

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>snow_publisher</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Publisher</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_publisher)

# Default to C++14
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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using namespace std;
using namespace std::chrono_literals;

int main(int argc, char * argv[]) {
  
  printf("This is SnowDeer's ROS Message Publisher.\n");

  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("snowdeer_msg_publisher");
  auto publisher = node->create_publisher<std_msgs::msg::String>("snowdeer_topic");
  auto message = std::make_shared<std_msgs::msg::String>();
  auto publish_count = 0;

  rclcpp::WallRate loop_rate(1000ms);

  while (rclcpp::ok()) {
    message->data = "Hello, SnowDeer! " + std::to_string(publish_count++);

    RCLCPP_INFO(node->get_logger(), "Publishing: '%s'", message->data.c_str())
    publisher->publish(message);
    
    rclcpp::spin_some(node);

    loop_rate.sleep();
  }

  rclcpp::shutdown();
  
  return 0;
}


snowdeer_subscriber

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>snow_subscriber</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Subscriber</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_subscriber)

# Default to C++14
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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using namespace std;

rclcpp::Node::SharedPtr node = nullptr;

void callback_from_topic(const std_msgs::msg::String::SharedPtr msg) {
  RCLCPP_INFO(node->get_logger(), "Received Message: '%s'", msg->data.c_str())
}

int main(int argc, char * argv[]) {
  
  printf("This is SnowDeer's ROS Message Subscriber.\n");

  rclcpp::init(argc, argv);
  node = rclcpp::Node::make_shared("snowdeer_msg_subscriber");

  auto subscription = node->create_subscription<std_msgs::msg::String>
      ("snowdeer_topic", callback_from_topic);

  rclcpp::spin(node);
  rclcpp::shutdown();

  node = nullptr;

  return 0;
}

Hello, ROS 예제 코드

|

패키지 구성

ROS 2.0의 각 노드의 패키지 구성은 다음과 같습니다.

  • package.xml
  • CMakeLists.txt
  • 소스 코드들

package.xml은 안드로이드의 manifest.xml과 같은 역할을 하며, 노드의 이름이나 라이센스, 설명 등의 내용이 들어있습니다.

CMakeLists.txt는 ROS2 만의 독특한 명령어가 조금 들어있긴 하지만 기본적으로 일반적인 CMakeLists 파일과 거의 유사합니다.

‘Hello, ROS’의 예제 코드는 다음과 같습니다. ROS적인 요소는 아예 들어있지 않지만 ament를 이용해서 빌드를 할 수 있다는 데 의의를 가질 수 있을 것 같습니다.


package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>hello_ros</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Publisher using class</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>

  <exec_depend>rclcpp</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_publisher)

# Default to C++14
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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

using namespace std;

int main(int argc, char * argv[]) {
  
  printf("Hello ROS. I am snowdeer.\n");

  return 0;
}

ROS2 간단한 명령어 모음

|

ROS 2.0의 실행 명령어는 ros2 입니다. ROS 1.0 버전에서의 명령어 사용법과 꽤 차이가 있습니다. 간단한 사용법을 알아놓는 편이 좋습니다.

ros2 명령어 사용법

도움말

간단한 도움말을 보기 위해서는 --help 옵션을 넣으면 됩니다.

$ ros2 --help


프로그램 실행방법

run 옵션을 이용해서 프로그램을 실행할 수 있습니다. 하지만 경험상 그냥 실행 파일만 실행해도 잘 실행이 되더군요.

ros2 run demo_nodes_cpp talker -t chatter2


Message Publish

특정 Topic으로 메시지를 발행하기 위해서는 topic pub 옵션을 사용하면 됩니다. 아래 예제는 snowdeer_topic이라는 이름의 Topic에 문자열 메시지를 보내는 예제입니다.

$ ros2 topic pub /snowdeer_topic std_msgs/String "data: Hello, snowdeer."


Message Subscribe

특정 Topic의 메시지를 수신하기 위해서는 topic echo 옵션을 사용하면 됩니다.

$ ros2 topic echo /snowdeer_topic


Topic 리스트 조회

$ ros2 topic list


Node 리스트 조회

$ ros2 node list

ROS 2.0 개발 환경 세팅

|

ROS 2.0을 기반으로 빌드 환경을 설정하는 방법입니다. 여기에서 원문을 볼 수 있으며, 저는 제 경험을 토대로 글을 작성했습니다.

Ament

ROS 1.0에서는 빌드 시스템으로 catkin을 이용했었는데, ROS 2.0에서는 ament를 이용합니다. ament를 사용하기 위해서는 먼저 빌드 환경을 설정해주어야 합니다.


필요한 프로그램 설치

만약 vcs 프로그램이 설치되어 있지 않다면 vcstool을 설치합니다.

다음 명령어를 이용해서 ‘vcstool’을 쉽게 설치할 수 있습니다.

$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

$ sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv-key 0xB01FA116

$ sudo apt-get update

$ sudo apt-get install python3-vcstool

$ source /usr/share/vcstool-completion/vcs.bash


폴더 생성

아래 명령어를 이용해서 폴더 생성을 해줍니다.

$ mkdir -p ~/ros2_ws/src


소스 다운로드

$ cd ~/ros2_ws

$ wget https://raw.githubusercontent.com/ros2/ros2/master/ros2.repos

$ vcs import ~/ros2_ws/src < ros2.repos


빌드

$ src/ament/ament_tools/scripts/ament.py build --build-tests --symlink-install

꽤 오랜 시간이 걸리기 때문에 인내력을 갖고 기다려줍니다. 만약 중간에 응답이 없거나 타임아웃(Timeout)이 발생한 경우는 Ctrl + C키를 눌러서 종료한 다음 위 명령어를 다시 입력하면 작업을 이어서 진행합니다.

저 같은 경우는 중간에 너무 오래 걸려서 타임아웃 설정값을 바꿔야 하는 경우도 있었습니다.


설치

빌드가 다 끝나면 install 디렉토리에 결과물이 만들어집니다. 다음 명령어를 이용해서 설치를 해줍니다.

$ . install/local_setup.bash


샘플 코드 빌드 테스트

이제 ament를 이용해서 빌드가 잘 되는지 확인을 해야 합니다. 샘플 코드를 빌드해서 잘 되는지 확인합니다.

$ mkdir -p ~/ros2_overlay_ws/src

$ cd ~/ros2_overlay_ws/src

$ git clone https://github.com/ros2/examples.git

$ cd ~/ros2_overlay_ws

$ ament build

ROS 2.0 설치 방법

|

ROS 2.0을 설치하는 방법입니다. ROS 2.0 공식 페이지에서 더 자세히 볼 수 있으며, 여기서는 제 경험을 토대로 다시 정리했습니다.

ROS 2.0 설치

저는 Ubuntu 16.04 LTS에 ROS 2.0을 설치했습니다.

필요한 라이브러리 설치

다음 명령어를 이용해서 필요한 라이브러리들을 먼저 설치합니다.

$ sudo apt-get update && sudo apt-get install -q -y \
     libopencv-core2.4v5 \
     libhighgui2.4 \
     libopencv-imgproc2.4v5 \
     libasio-dev \
     libeigen3-dev \
     libtinyxml-dev \
     libtinyxml2-dev \
     libcurl4-openssl-dev \
     libqt5core5a \
     libqt5gui5 \
     libqt5opengl5 \
     libqt5widgets5 \
     libxaw7-dev \
     libgles2-mesa-dev \
     libglu1-mesa-dev \
     python3-pip \
     python3-setuptools \
     python3-yaml \
     wget \
     tree

$ sudo apt-get update && sudo apt-get install -q -y \
    libboost-thread-dev

$ sudo pip3 install argcomplete


ROS 2.0 바이너리 패키지 다운로드

다음 경로에서 ROS 2.0 최신 바이너리 패키지를 다운 받습니다.

저는 ‘ros2-ardent-package-linux-fastrtps-opensplice-x86_64.tar.bz2’ 파일을 다운받았습니다.

그런 다음 다음 명령어를 통해 압축 파일을 해제합니다.

$ mkdir -p ~/ros2_install

$ cd ~/ros2_install

$ tar xf ~/Downloads/ros2-package-linux-x86_64.tar.bz2


샘플 테스트

이제 잘 설치가 되었고 동작이 되는지 확인하기 위해서 터미널에서 다음 명령어를 실행해봅니다.

$ . ~/ros2_install/ros2-linux/setup.bash

$ ros2 run demo_nodes_cpp talker
$ . ~/ros2_install/ros2-linux/setup.bash

$ ros2 run demo_nodes_cpp listener


잘 동작이 되는 걸 확인했으면, .bashrc 파일 맨 끝에 아래 항목을 추가합니다.

. ~/ros2_install/ros2-linux/setup.bash