ROS2 Tutorial (Basic)
  • 교육 안내
  • ROS2 개요
  • ROS2 환경 구성
  • turtlesim, ROS2 rqt
  • 노드(Node) 이해하기
  • 토픽(Topic) 이해하기
  • 서비스(Service) 이해하기
  • 파라메터(Parameter) 이해하기
  • 액션(Action) 이해하기
  • rqt_console 을 이용해 로그 보기
  • 노드 실행하기(launch)
  • 데이터 기록 및 재생
  • ROS2 프로그래밍 시작
  • 작업공간 만들기
  • 패키지 만들기
  • 간단한 게시자와 구독자 노드 만들기
  • 간단한 서비스 및 클라이언트 작성
  • 사용자 정의 msg 및 srv 파일 생성
  • 사용자 정의 인터페이스 구현
  • 파라메터 사용하기
  • 문제 식별에 ros2doctor 사용하기
Powered by GitBook
On this page
  • 개요
  • 실습
  • 1. 패키지 생성
  • 2. 메시지 파일 생성
  • 3. 동일한 패키지의 인터페이스 사용
  • 4. 실행
  • 5. 기존 인터페이스 정의 사용

Was this helpful?

Export as PDF

사용자 정의 인터페이스 구현

저작권: 쿼드(QUAD) 드론연구소 https://www.youtube.com/@quad-robotics

Previous사용자 정의 msg 및 srv 파일 생성Next파라메터 사용하기

Last updated 1 year ago

Was this helpful?

개요

에서 사용자 지정 msg 및 srv 인터페이스를 만드는 방법을 배웠습니다.

가장 좋은 방법은 전용 인터페이스 패키지에서 인터페이스를 선언하는 것이지만 때로는 하나의 패키지에서 인터페이스를 모두 선언, 생성 및 사용하는 것이 편리할 수 있습니다.

인터페이스는 현재 CMake 패키지에서만 정의할 수 있음을 기억하십시오. 그러나 CMake 패키지에 Python 라이브러리와 노드가 있을 수 있으므로( 사용 ) 하나의 패키지에서 인터페이스와 Python 노드를 함께 정의할 수 있습니다. 여기서는 단순성을 위해 CMake 패키지와 C++ 노드를 사용합니다.

이 자습서는 msg 인터페이스 유형에 초점을 맞추지만 여기서 단계는 모든 인터페이스 유형에 적용할 수 있습니다.

실습

1. 패키지 생성

작업 공간 src디렉토리에서 more_interfaces패키지를 만들고 그 안에 msg 파일용 디렉토리를 만드십시오.

ros2 pkg create --build-type ament_cmake more_interfaces
mkdir more_interfaces/msg

2. 메시지 파일 생성

내부에 AddressBook.msg새 파일을 만들고 다음 코드를 붙여넣어 개인에 대한 정보를 전달하는 메시지more_interfaces/msg를 만듭니다.

uint8 PHONE_TYPE_HOME=0
uint8 PHONE_TYPE_WORK=1
uint8 PHONE_TYPE_MOBILE=2

string first_name
string last_name
string phone_number
uint8 phone_type

이 메시지는 다음 필드로 구성됩니다.

  • first_name: 문자열 유형

  • last_name: 문자열 유형

  • phone_number: 문자열 유형

  • phone_type: 여러 명명된 상수 값이 정의된 uint8 유형

다음으로 msg 파일이 C++, Python 및 기타 언어의 소스 코드로 변환되었는지 확인해야 합니다.

2.1 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>

빌드 시에는 rosidl_default_generators가 필요 하지만 런타임에는 rosidl_default_runtime가 필요 합니다.

CMakeLists.txt다음 줄을 열고 추가합니다.

파일에서 msg/srv 메시지 코드를 생성하는 패키지를 찾습니다.

find_package(rosidl_default_generators REQUIRED)

생성하려는 메시지 목록을 선언합니다.

set(msg_files
  "msg/AddressBook.msg"
)

.msg 파일을 수동으로 추가하면 다른 .msg 파일을 추가한 후 CMake가 프로젝트를 재구성해야 할 때를 알 수 있습니다.

메시지를 생성합니다.

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
)

또한 메시지 런타임 종속성을 내보내는지 확인하십시오.

ament_export_dependencies(rosidl_default_runtime)

이제 msg 정의에서 소스 파일을 생성할 준비가 되었습니다. 아래의 4단계에서 모두 함께 수행하므로 지금은 컴파일 단계를 건너뛸 것입니다.

2.2 다중 인터페이스 설정

set을 사용하여 CMakeLists.txt모든 인터페이스를 깔끔하게 나열 할 수 있습니다 .

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

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

다음과 같이 한 번에 모든 목록을 생성합니다.

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  ${srv_files}
)

3. 동일한 패키지의 인터페이스 사용

이제 이 메시지를 사용하는 코드 작성을 시작할 수 있습니다.

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.phone_number = "1234567890";
        message.phone_type = message.PHONE_TYPE_MOBILE;

        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;
}

3.1 코드 설명

새로 만든 AddressBook.msg의 헤더를 포함합니다.

#include "more_interfaces/msg/address_book.hpp"

AddressBook노드와 게시자를 만듭니다.

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");

주기적으로 메시지를 게시하는 콜백을 만듭니다.

auto publish_msg = [this]() -> void {

나중에 게시할 AddressBook메시지 인스턴스를 만듭니다 .

auto message = more_interfaces::msg::AddressBook();

AddressBook필드를 채웁니다.

message.first_name = "John";
message.last_name = "Doe";
message.phone_number = "1234567890";
message.phone_type = message.PHONE_TYPE_MOBILE;

마지막으로 주기적으로 메시지를 보냅니다.

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

this->address_book_publisher_->publish(message);

초 마다 publish_msg함수를 호출하는 1초 타이머를 만듭니다 .

timer_ = this->create_wall_timer(1s, publish_msg);

3.2 게시자 빌드

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})

3.3 인터페이스에 대한 링크

동일한 패키지에서 생성된 메시지를 사용하려면 다음 CMake 코드를 사용해야 합니다.

rosidl_target_interfaces(publish_address_book
  ${PROJECT_NAME} "rosidl_typesupport_cpp")

이렇게 하면 생성된 관련 C++ 코드를 찾고 AddressBook.msg대상이 이에 대해 링크할 수 있습니다.

사용 중인 인터페이스가 독립적으로 빌드된 다른 패키지에 있는 경우 이 단계가 필요하지 않다는 것을 알 수 있습니다. 이 CMake 코드는 인터페이스가 정의된 패키지와 동일한 패키지에서 인터페이스를 사용하려는 경우에만 필요합니다.

4. 실행

작업 공간의 루트로 돌아가서 패키지를 빌드합니다.

cd ~/ros2_ws
colcon build --packages-up-to more_interfaces

그런 다음 작업 영역을 소싱하고 게시자를 실행합니다.

source install/local_setup.bash
ros2 run more_interfaces publish_address_book

publish_address_book.cpp에서 설정한 값을 포함하여 정의한 메시지를 전달하는 게시자가 표시되어야 합니다.

address_book메시지가 토픽에 게시되고 있는지 확인하려면 다른 터미널을 열고 작업 공간을 소싱하고 다음을 호출하십시오 .topic echo

source install/setup.bash
ros2 topic echo /address_book

5. 기존 인터페이스 정의 사용

새 인터페이스 정의에서 기존 인터페이스 정의를 사용할 수 있습니다. 예를 들어, Contact.msg라는 이름의 기존 ROS2 패키지rosidl_tutorials_msgs에 속하는 메시지가 있다고 가정해 보겠습니다 . AddressBook.msg그 정의가 이전의 맞춤형 인터페이스와 동일하다고 가정합니다 .

이 경우 (노드 가 있는 패키지의 인터페이스AddressBook.msg )를 유형 ( 별도 의 패키지 의 인터페이스 )으로 정의할 수 있습니다. 다음과 같이 AddressBook.msgtype 의 Contact배열 로 정의할 수도 있습니다 .

rosidl_tutorials_msgs/Contact[] address_book

이 메시지를 생성하려면 다음에서 Contact.msg's패키지 에 대한 종속성을 선언해야 합니다.

<build_depend>rosidl_tutorials_msgs</build_depend>

<exec_depend>rosidl_tutorials_msgs</exec_depend>

그리고 CMakeLists.txt:

find_package(rosidl_tutorials_msgs REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  DEPENDENCIES rosidl_tutorials_msgs
)

에 Contact.msg추가할 수 있으려면 게시자 노드에 헤더를 포함해야 합니다 .contactsaddress_book

#include "rosidl_tutorials_msgs/msg/contact.hpp"

콜백을 다음과 같이 변경할 수 있습니다.

auto publish_msg = [this]() -> void {
   auto msg = std::make_shared<more_interfaces::msg::AddressBook>();
   {
     rosidl_tutorials_msgs::msg::Contact contact;
     contact.first_name = "John";
     contact.last_name = "Doe";
     contact.phone_number = "1234567890";
     contact.phone_type = message.PHONE_TYPE_MOBILE;
     msg->address_book.push_back(contact);
   }
   {
     rosidl_tutorials_msgs::msg::Contact contact;
     contact.first_name = "Jane";
     contact.last_name = "Doe";
     contact.phone_number = "4254242424";
     contact.phone_type = message.PHONE_TYPE_HOME;
     msg->address_book.push_back(contact);
   }

   std::cout << "Publishing address book:" << std::endl;
   for (auto contact : msg->address_book) {
     std::cout << "First:" << contact.first_name << "  Last:" << contact.last_name <<
       std::endl;
   }

   address_book_publisher_->publish(*msg);
 };

이러한 변경 사항을 빌드하고 실행하면 예상대로 정의된 메시지와 위에 정의된 메시지 배열이 표시됩니다.

메시지 정의 내의 필드에 대한 기본값을 설정할 수 있습니다. 인터페이스를 사용자 정의할 수 있는 더 많은 방법은 참조하십시오 .

이전 자습서
ament_cmake_python
ROS 2 인터페이스 정보를