[ros2] custom msg type 만들기!

About_work·2024년 3월 3일
0

ros2

목록 보기
22/41

0. 읽을거리

1. 설명

  • ROS 2에서 사용자 정의 메시지 타입을 생성하여, bounding box 데이터를 publish하는 과정은 몇 가지 단계를 포함
  • 여기서는 (k, 4) 형태의 bounding box 데이터 (x, y, w, h)를 publish하기 위해
  • 사용자 정의 메시지 타입을 정의하고, 이를 이용하는 publisher 코드를 작성하는 방법을 소개

0단계: ROS2 패키지 생성

ros2 pkg create --build-type ament_cmake <패키지_이름>
ros2 pkg create --build-type ament_cmake nav_temp_interfaces
  • 아래와 같이, nav_temp_interfaces 이름을 가진 ros2 package를 생성합니다.
    • msg 폴더를 생성합니다.

1단계: 사용자 정의 메시지 타입 정의

  • 먼저, bounding box 데이터를 위한 사용자 정의 메시지 타입을 정의
  • 이 예시에서는 메시지 타입을 BoundingBoxArray
  • 패키지 내에 msg 디렉토리를 생성하고, 그 안에 BoundingBoxArray.msg 파일을 생성합니다.
# BoundingBoxArray.msg
float32[] x
float32[] y
float32[] width
float32[] height
  • 이 메시지 정의는 각 bounding box의 x, y 좌표와 너비(width), 높이(height)를 나타내는 실수형 배열을 포함합니다. 각 배열의 길이는 bounding box의 개수(k)와 동일합니다.

2단계: CMakeLists.txt와 package.xml 파일을 수정

2.1. CMakeLists.txt 파일을 수정

    1. find_package() 함수 수정
    • 위 명령어는 CMake 빌드 프로세스 중에 특정 패키지를 찾고,
      • 그 패키지가 제공하는 라이브러리, 툴, 기타 파일들을 사용할 수 있도록 설정하는 역할
    • find_package() 함수를 사용하여 메시지 생성에 필요한 패키지들을 찾도록 명시
    • rosidl_default_generators, builtin_interfaces는 메시지를 정의하고 사용하기 위해 필요한 패키지
    • 이에 더불어, 새로운 msg type이 이용하는 기 정의된 msg type에 대한 패키지들도 찾을 수 있도록 해야 함
find_package(builtin_interfaces REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(sensor_msgs REQUIRED)
    • A. find_package(builtin_interfaces REQUIRED):
      • builtin_interfaces 패키지는 ROS 2 시스템에서 기본적으로 제공되는 메시지 타입과 서비스 타입의 집합
      • 이들은 대부분의 사용자 정의 메시지가 의존하는 기본 타입들(예: time, duration)을 포함
      • 이 명령은 사용자 정의 메시지 내에서 ROS 2 기본 인터페이스 타입을 사용할 수 있게 함
    • B. find_package(rosidl_default_generators REQUIRED)
      • rosidl_default_generatorsROS 2 인터페이스 정의 언어(IDL) 파일(.msg, .srv, .action)로부터,
        • C++, Python 등의 프로그래밍 언어로 코드를 생성하는 데 필요한 기본 제너레이터를 제공
      • 이 명령은 사용자가 정의한 메시지, 서비스, 액션 타입을 위한 소스 코드 생성을 활성화
      • REQUIRED 키워드는 이 패키지가 없으면 프로젝트 빌드가 불가능함을 의미합니다.
      1. rosidl_generate_interfaces() 함수 호출
      • 메시지 파일을 ROS 2 시스템에서 사용할 수 있도록 rosidl_generate_interfaces() 함수를 호출하여 메시지, 서비스, 액션 인터페이스를 생성
      • 이 함수에는 패키지의 이름과 함께 생성하려는 메시지 파일의 목록을 전달
      • 여기서는 MyCustomMessage.msg 파일을 사용
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/MyCustomMessage.msg"
  DEPENDENCIES builtin_interfaces sensor_msgs
)
    1. ament_export_dependencies(rosidl_default_runtime) 추가하기
    • 이 명령의 역할은
      • ROS2 패키지가 메시지, 서비스, 액션 정의에서 생성된 코드를 사용할 수 있도록 하며,
      • 이러한 의존성을 ROS2 생태계 내의 다른 패키지와 올바르게 공유하고 관리할 수 있게 함
      • 패키지 A(nav_temp_interfaces)가 ament_export_dependencies를 통해 rosidl_default_runtime을 내보낸다면,
        • 패키지 A에 의존하는 다른 패키지들도 자동적으로 rosidl_default_runtime을 사용할 수 있게 됩니다.
      • 이는 복잡한 의존성 체인에서 유용하게 사용됩니다.

2.2. package.xml 파일을 수정

  <build_depend>builtin_interfaces</build_depend>
  <buildtool_depend>rosidl_default_generators</buildtool_depend>

  <exec_depend>builtin_interfaces</exec_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>

  <member_of_group>rosidl_interface_packages</member_of_group>
  • package.xml 파일에서 각 태그는 패키지의 다양한 종류의 의존성과 그룹 멤버십을 선언하는 데 사용
  • 이 태그들이 가지는 역할은 다음과 같습니다:
<build_depend>
  • <build_depend>builtin_interfaces</build_depend>:
  • 이 태그는 현재 패키지가 빌드될 때 builtin_interfaces 패키지에 의존한다는 것을 나타냄
  • builtin_interfacesROS 2에서 기본 제공하는 메시지 타입들을 포함하고 있는 패키지로,
    • 시간스탬프나 기본적인 메시지 타입 같은 공통적으로 사용되는 인터페이스를 제공
  • 이 의존성은 현재 패키지가 빌드될 때 필요하며, 주로 메시지나 서비스 정의에서 builtin_interfaces의 타입을 사용하는 경우에 필요
<buildtool_depend>
  • <buildtool_depend>rosidl_default_generators</buildtool_depend>:
    • 이 태그는 현재 패키지가 빌드될 때, rosidl_default_generators 패키지를 빌드 도구로서 의존한다는 것을 나타냄
    • rosidl_default_generatorsROS 2 인터페이스 정의 언어(IDL) 파일들로부터 코드를 생성하기 위한 기본 도구들을 포함
    • 이 의존성은 현재 패키지 내에서 메시지, 서비스, 액션 인터페이스를 정의할 때 필요하며,
    • 해당 인터페이스로부터 c++, PYTHON 등의 코드를 생성하는 데 사용
<exec_depend>
  • <exec_depend>builtin_interfaces</exec_depend>:
    • 실행 시 builtin_interfaces 패키지에 대한 의존성을 나타냄
    • 이는 현재 패키지가 실행될 때 builtin_interfaces에 정의된 메시지 타입들을 사용할 수 있어야 함을 의미
    • 이는 런타임에 builtin_interfaces가 제공하는 타입들이 필요할 때 필요
  • <exec_depend>rosidl_default_runtime</exec_depend>:
    • 실행 시 rosidl_default_runtime 패키지에 대한 의존성을 나타냄
    • 이는 rosidl로 생성된 인터페이스 코드가 런타임에 필요함을 의미
    • ROS 2 런타임 중에 메시지, 서비스, 액션 인터페이스와 상호작용하는 데 필요한 라이브러리와 의존성을 포함
<member_of_group>
  • <member_of_group>rosidl_interface_packages</member_of_group>:
    • 이 태그는 현재 패키지가 rosidl_interface_packages 그룹의 멤버임을 선언
    • 이는 패키지가 ROS 2 인터페이스(메시지, 서비스, 액션 정의)를 포함하고 있으며,
    • ROS 2 시스템 내에서 인터페이스 정의로 인식되어야 함을 나타냄
    • 이 그룹의 멤버십은 ROS 2 빌드 시스템이 해당 패키지를 올바른 방식으로 처리하고,
    • 관련 인터페이스 파일로부터 코드를 생성할 수 있도록 하는 데 중요

3단계: Publisher 코드 작성

  • 이제 사용자 정의 메시지 타입을 이용하여 bounding box 데이터를 publish하는 ROS 2 노드를 작성합니다.
import rclpy
from rclpy.node import Node
from your_package_name.msg import BoundingBoxArray  # your_package_name를 실제 패키지 이름으로 변경하세요.

class BoundingBoxPublisher(Node):

    def __init__(self):
        super().__init__('bounding_box_publisher')
        self.publisher_ = self.create_publisher(BoundingBoxArray, 'bounding_boxes', 10)
        self.timer = self.create_timer(0.5, self.timer_callback)  # 0.5초마다 실행

    def timer_callback(self):
        msg = BoundingBoxArray()
        msg.x = [1.0, 2.0]  # 예시 데이터
        msg.y = [1.0, 2.0]
        msg.width = [1.0, 2.0]
        msg.height = [1.0, 2.0]

        self.publisher_.publish(msg)
        self.get_logger().info('Publishing Bounding Box Array')

def main(args=None):
    rclpy.init(args=args)
    node = BoundingBoxPublisher()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

이 코드는 BoundingBoxArray 메시지 타입을 이용하여 bounding box 데이터를 주기적으로 publish하는 노드의 기본적인 구조를 보여줍니다. 실제 사용 시에는 bounding box 데이터를 생성하거나 계산하는 로직을 timer_callback 메서드 내에 구현해야 합니다.

4단계: 빌드 및 실행

  • 빌드 전에, ROS2 환경을 소스로 가져오기
    • source /opt/ros/<ros2_distro>/setup.bash
  • Custom message가 포함된 패키지를 colcon build 명령어를 사용하여 빌드
cd ~/PycharmProjects/nl_navigation2  # 워크스페이스 루트로 이동
colcon build --packages-select nav_temp_interfaces  # 'nav_temp_interfaces' 패키지 빌드

혹은
colcon build

  • 빌드가 완료된 후, 빌드 환경을 소스로 가져와야 합니다(source install/setup.bash).
  • 이 단계는 ROS2 환경이 새로운 메시지 타입을 인식하도록 합니다.

2. 디렉토리에 대한 설명

"ROS 2 패키지 내"란, ROS 2에서 개발을 진행하는 특정 패키지의 루트 디렉토리를 의미합니다. ROS 2 패키지는 특정 기능이나 모듈을 구현하기 위한 코드, 메시지 정의, 서비스 정의, 파라미터 파일, 빌드 및 실행을 위한 설정 파일 등을 포함하는 디렉토리 구조입니다. 각 패키지는 독립적으로 빌드되고 실행될 수 있으며, 다른 패키지와의 의존성을 정의할 수 있습니다.

패키지 내부의 구조는 일반적으로 다음과 같습니다:

  • 패키지 루트 디렉토리: 패키지의 이름과 동일한 디렉토리입니다. 이 디렉토리 안에는 소스 코드, 리소스, 설정 파일 등이 포함됩니다.
  • src/ 디렉토리: 패키지의 소스 코드를 포함하는 디렉토리입니다. C++ 또는 Python 코드 파일들이 이곳에 위치합니다.
  • msg/ 디렉토리: 사용자 정의 메시지 타입 정의 파일들을 포함하는 디렉토리입니다. 이곳에 .msg 파일을 생성하여 메시지 타입을 정의합니다.
  • srv/ 디렉토리: 사용자 정의 서비스 타입 정의 파일들을 포함하는 디렉토리입니다. .srv 파일을 이용하여 서비스 타입을 정의합니다.
  • CMakeLists.txt: 빌드 설정을 포함하는 CMake 프로젝트 파일입니다. ROS 2 패키지 빌드 시 사용됩니다.
  • package.xml: 패키지의 메타데이터와 의존성 정보를 포함하는 XML 파일입니다.

예를 들어, my_robot_interfaces라는 이름의 ROS 2 패키지를 생성한 경우, 패키지의 디렉토리 구조는 대략 다음과 같을 수 있습니다:

my_robot_interfaces/
├── CMakeLists.txt
├── package.xml
├── msg/
│   └── BoundingBoxArray.msg
└── src/

여기서 "ROS 2 패키지 내에 msg 디렉토리를 생성하고, 그 안에 BoundingBoxArray.msg 파일을 생성합니다."라는 지시는, 위의 디렉토리 구조에서 my_robot_interfaces/msg/ 디렉토리 안에 BoundingBoxArray.msg 파일을 생성하라는 의미입니다.

profile
새로운 것이 들어오면 이미 있는 것과 충돌을 시도하라.

0개의 댓글