[ROS2] (19)-패키지 내에서 msg파일 만들어 사용하기

패키지 내에서 msg 파일 만들기

.msg, .srv 파일들은 별도의 패키지로 구성하는 것이 선호되지만, 때로는 같은 패키지 내에서 해당 파일들을 만들어서 사용해야 하는 경우도 있다. 다만, 이전 포스팅에서 언급한 것처럼 CMake 패키지로만 메시지 파일들을 정의할 수 있다. 여기서는 .msg 파일만 만들어 보기로 한다.

패키지 만들기

src 폴더에 more_interfaces라는 패키지를 만들고, 패키지 내에 msg 폴더를 생성한다.

$ cd ~/dev_ws/src
$ ros2 pkg create --build-type ament_cmake more_interfaces
$ mkdir more_interfaces/msg

메시지 파일 생성 및 빌드하기

more_interfaces/msg 폴더 내에 AddressBook.msg 파일을 생성하고 아래 내용을 붙여넣는다.

bool FEMALE=true
bool MALE=false

string first_name
string last_name
bool gender
uint8 age
string address

여기서는 first_name, last_name, gender, age, address 5가지 영역과 2개의 상수(constant) 값 FEMALE, MALE 을 정의하고 있다.

.msg 파일 빌드를 위해 의존성을 추가해줘야 한다. 먼저, package.xml 파일을 열어 아래 내용을 추가해준다.

<buildtool_depend>rosidl_default_generators</buildtool_depend>

<exec_depend>rosidl_default_runtime</exec_depend>

<member_of_group>rosidl_interface_packages</member_of_group>

다음으로 CMakeLists.txt 파일을 열어서 아래 내용을 추가해준다.

find_package(rosidl_default_generators REQUIRED)

set(msg_files
  "msg/AddressBook.msg"
)

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
)

ament_export_dependencies(rosidl_default_runtime)

메시지 파일이 여러 개인 경우, 아래와 같이 모두 추가해주어야 한다.

set(msg_files
  "msg/Message1.msg"
  "msg/Message2.msg"
  # etc
  )

set(srv_files
  "srv/Service1.srv"
  "srv/Service2.srv"
   # etc
  )

패키지 내에서 msg 파일 사용하기

more_interfaces/src 폴더에 publish_address_book.cpp 파일을 생성하고, 아래 내용을 붙여넣는다.

#include <chrono>
#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "more_interfaces/msg/address_book.hpp"

using namespace std::chrono_literals;

class AddressBookPublisher : public rclcpp::Node
{
public:
  AddressBookPublisher()
  : Node("address_book_publisher")
  {
    address_book_publisher_ =
      this->create_publisher<more_interfaces::msg::AddressBook>("address_book", 10);

    auto publish_msg = [this]() -> void {
        auto message = more_interfaces::msg::AddressBook();

        message.first_name = "John";
        message.last_name = "Doe";
        message.age = 30;
        message.gender = message.MALE;
        message.address = "unknown";

        std::cout << "Publishing Contact\nFirst:" << message.first_name <<
          "  Last:" << message.last_name << std::endl;

        this->address_book_publisher_->publish(message);
      };
    timer_ = this->create_wall_timer(1s, publish_msg);
  }

private:
  rclcpp::Publisher<more_interfaces::msg::AddressBook>::SharedPtr address_book_publisher_;
  rclcpp::TimerBase::SharedPtr timer_;
};


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

  return 0;
}

빌드를 위해 의존성을 추가해 준다. CMakeLists.txt 파일을 열고, 아래 내용을 추가해준다.

find_package(rclcpp REQUIRED)

add_executable(publish_address_book
  src/publish_address_book.cpp
)

ament_target_dependencies(publish_address_book
  "rclcpp"
)

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

패키지 내에서 만든 메시지 타입을 사용하기 위해서 아래 내용도 CMakeLists.txt 파일에 추가해준다. 별도의 패키지에서 빌드한 메시지 타입을 사용할 때는 아래 내용은 필요없다.

rosidl_target_interfaces(publish_address_book
  ${PROJECT_NAME} "rosidl_typesupport_cpp")

실행하기

먼저, 패키지를 빌드한다.

$ cd ~/dev_ws
$ colcon build --packages-up-to more_interfaces

이제 환경변수를 설정하고, publisher 노드를 실행한다.

$ source install/local_setup.bash
$ ros2 run more_interfaces publish_address_book

토픽이 제대로 퍼블리시되고 있는지 확인하기 위해 새로운 터미널 창을 열고, 토픽을 출력해본다.

$ cd ~/dev_ws
$ source install/setup.bash
$ ros2 topic echo /address_book

메시지가 잘 출력된다면 정상 동작하고 있는 것이다.

댓글남기기