[ROS2] (14)-C++로 퍼블리셔와 서브스크라이버 만들기

퍼블리셔와 서브스크라이버 만들기

이번 포스팅에서는 토픽을 통해 정보를 전달하는 간단한 “talker”, “listner” 시스템을 만들어볼 것이다.

패키지 만들기

먼저, dev_ws 폴더에 cpp_pubsub이라는 새로운 패키지를 만든다.

$ cd ~/dev_ws/src
$ ros2 pkg create --build-type ament_cmake cpp_pubsub

퍼블리셔 노드 작성하기

dev_ws/src/cpp_pubsub/src 폴더에 아래의 예제 코드를 다운로드 받는다.

$ wget -O publisher_member_function.cpp https://raw.githubusercontent.com/ros2/examples/foxy/rclcpp/topics/minimal_publisher/member_function.cpp

dev_ws/src/cpp_pubsub/src 폴더에 publisher_member_function.cpp라는 파일이 다운로드 받아졌다. 이 파일을 열어서 코드를 확인해보자.

#include <chrono>
#include <memory>

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

using namespace std::chrono_literals;

먼저, 필요한 헤더파일을 포함시키고 있다. 여기서 rclcpp/rclcpp.hpp는 ROS2 시스템을 사용할 수 있게 해주는 헤더이고, std_msgs/msg/string.hpp는 데이터를 퍼블리시할 때 사용하는 메시지 타입을 포함하고 있는 헤더이다. 여기에 포함된 헤더들은 package.xml, CMakeLists.txt 파일에 추가되어야 한다.

class MinimalPublisher : public rclcpp::Node

노드 클래스인 MinimalPublisherrclcpp::Node로부터 상속받아서 생성하고 있다. 코드에서 this라고 하는 것은 모두 이 노드를 의미한다.

public:
  MinimalPublisher()
  : Node("minimal_publisher"), count_(0)
  {
    publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
    timer_ = this->create_wall_timer(
      500ms, std::bind(&MinimalPublisher::timer_callback, this));
  }

생성자에서 노드 이름을 minimal_publisher로, count_를 0으로 초기화하고 있다. 생성자 내부에서는 publisherString 메시지 타입, topic이라는 이름의 토픽, 10의 queue 사이즈로 초기화되었다. timer_도 역시 초기화 되었다.

private:
  void timer_callback()
  {
    auto message = std_msgs::msg::String();
    message.data = "Hello, world! " + std::to_string(count_++);
    RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
    publisher_->publish(message);
  }

timer_callback 함수가 메세지가 설정되고, 실제로 퍼블리시 되는 곳이다. RCLCPP_INFO는 퍼블리시되는 모든 메시지를 콘솔창에 출력해준다.

  rclcpp::TimerBase::SharedPtr timer_;
  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
  size_t count_;

타이머, 퍼블리셔, 그리고 카운터 영역을 정의해준다.

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalPublisher>());
  rclcpp::shutdown();
  return 0;
}

rclcpp::init은 ROS2를 시작시켜주고, rclcpp::spin은 노드로부터 데이터를 처리하는 것을 시작하는 것이다.

퍼블리셔 노드 dependency 추가하기

dev_ws/src/cpp_pubsub 폴더에서 package.xml 파일을 열어서 dependency를 추가해보자.

$ cd ~/dev_ws/src/cpp_pubsub
$ gedit package.xml

아래와 같이 buildtool dependency 아래에 2가지 dependency를 추가해준다.

<buildtool_depend>ament_cmake</buildtool_depend>
  
<depend>rclcpp</depend>
<depend>std_msgs</depend>

이제 dev_ws/src/cpp_pubsub 폴더에서 CMakeLists.txt 파일을 열어보자. 마찬가지로 아래와 같이 dependency 부분에 2줄을 추가해준다.

# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

find_package(rclcpp REQUIRED)
find_package(str_msgs REQUIRED)

이제 아래와 같이 talker라는 이름의 실행파일을 만드는 부분도도 추가해준다.

add_executable(talker src/publisher_member_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)

마지막으로 ros2 run이 실행파일을 찾을 수 있도록 아래의 내용도 추가해준다.

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

이제 퍼블리셔 노드는 완성되었다. 서브스크라이브 노드도 비슷한 방법으로 만들어보자.

서브스크라이브 노드 작성하기

퍼블리셔 노드와 유사하게 예제 코드를 다운로드하자.

$ cd ~/dev_ws/src/cpp_pubsub/src
$ wget -O subscriber_member_function.cpp https://raw.githubusercontent.com/ros2/examples/foxy/rclcpp/topics/minimal_subscriber/member_function.cpp

역시 간단하게 코드 내용을 분석해보자.

public:
  MinimalSubscriber()
  : Node("minimal_subscriber")
  {
    subscription_ = this->create_subscription<std_msgs::msg::String>(
    "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
  }

대부분 퍼블리셔 노드와 유사하고, 다만 서브스크라이브 노드는 timer가 없다. 왜냐하면 서브스크라이브 노드는 단순히 토픽이 퍼블리시될 때에만 응답하면 되기 때문이다.

서브스크라이브 노드는 퍼블리셔 노드와 의존성이 동일하기 때문에 package.xml파일에 추가할 내용은 없다. CMakeLists.txt 파일에만 아래와 같이 실행파일을 만드는 부분을 추가하자. install() 에는 기존에 적혀있던 내용에 더하여 listener만 한 줄 추가해주면 된다.

add_executable(listener src/subscriber_member_function.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
install(TARGETS
  talker
  listener
  DESTINATION lib/${PROJECT_NAME})

노드 빌드 및 실행하기

먼저, 빌드하기 전에 workspace에 모든 dependency가 있는지 확인해보자.

$ cd ~/dev_ws
$ rosdep install -i --from-path src --rosdistro foxy -y

이제 cpp_pubsub 패키지만 빌드해보자.

$ cd ~/dev_ws
$ colcon build --packages-select cpp_pubsub

설정파일을 source 하고 talker노드를 실행해보자.

$ cd ~/dev_ws
$ source install/setup.bash
$ ros2 run cpp_pubsub talker

터미널 창에 메시지를 출력하는 것을 확인할 수 있다. 이제 listener 노드도 실행해보자.

$ cd ~/dev_ws
$ source install/setup.bash
$ ros2 run cpp_pubsub listener

talker노드에서 퍼블리시한 토픽을 listener노드에서 수신하는 것을 확인할 수 있다.

댓글남기기