Only this pageAll pages
Powered by GitBook
1 of 21

ROS2 Tutorial (Basic)

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

토픽(Topic) 이해하기

저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

개요

ROS 2는 복잡한 시스템을 여러 모듈식 노드로 나눕니다. 주제는 노드가 메시지를 교환하는 버스 역할을 하는 ROS 그래프의 중요한 요소입니다.

https://docs.ros.org/en/foxy/_images/Topic-SinglePublisherandSingleSubscriber.gif

노드는 여러 토픽에 데이터를 게시하고 동시에 여러 토픽에 대한 구독을 가질 수 있습니다.

https://docs.ros.org/en/foxy/_images/Topic-MultiplePublisherandMultipleSubscriber.gif

토픽은 데이터가 노드 간에, 따라서 시스템의 다른 부분 간에 이동되는 주요 방법 중 하나입니다.

실습

1. 설정

새 터미널을 열고 다음을 실행합니다.

다른 터미널을 열고 다음을 실행합니다.

turtlesim_node와 turtle_teleop_key 두개의 노드를 실행 했습니다.

2. rqt_graph

rqt_graph는 이 튜토리얼 전체에서 변화하는 노드와 주제, 그리고 이들 사이의 연결을 시각화하는 데 사용할 것입니다 .

rqt_graph를 실행하려면 새 터미널을 열고 다음 명령을 입력하십시오.

rqt를 실행하고 Plugins > Introspection > Node Graph 를 선택하여 rqt_graph를 열 수도 있습니다 .

위의 노드와 주제, 그래프 주변의 두 가지 작업이 표시되어야 합니다(지금은 무시하겠습니다). 중앙의 주제에 마우스를 올리면 위 이미지와 같이 색상이 강조되는 것을 볼 수 있습니다.

그래프는 /turtlesim노드와 /teleop_turtle노드가 토픽을 통해 서로 통신하는 방법을 보여줍니다. 노드 /teleop_turtle는 토픽에데이터(거북이를 움직이기 위해 입력하는 키 입력)를 게시하고 /turtle1/cmd_vel있으며 /turtlesim노드는 데이터를 수신하기 위해 해당 토픽을 구독합니다.

rqt_graph의 강조 표시 기능은 다양한 방식으로 연결된 많은 노드와 항목이 있는 보다 복잡한 시스템을 검사할 때 매우 유용합니다.

rqt_graph는 그래픽 검사 도구입니다. 이제 주제를 조사하기 위한 몇 가지 명령줄 도구를 살펴보겠습니다.

3. ros2 topic list

새 터미널에서 명령을 실행하면 시스템에서 현재 활성화된 모든 토픽 목록이 반환됩니다.

ros2 topic list -t

이번에는 괄호 안에 추가된 주제 유형과 함께 동일한 토픽 목록을 반환합니다.

이러한 속성, 특히 유형은 노드가 주제를 이동할 때 동일한 정보에 대해 이야기하고 있음을 아는 방법입니다.

이러한 모든 항목이 rqt_graph에 있는 위치가 궁금하다면 Hide: 아래의 모든 상자를 선택 취소할 수 있습니다.

4. ros2 topic echo

토픽에 게시되는 데이터를 보려면 다음을 사용하세요.

/teleop_turtle가 /turtlesim/turtle1/cmd_velecho 토픽에 대해 데이터를 게시한다는 것을 알고 있으므로 해당 토픽을 출력해 보겠습니다.

처음에 이 명령은 데이터를 반환하지 않습니다. 무언가를 게시하기를 기다리고 있기 때문입니다 .

실행 중인 터미널로 돌아가서 turtle_teleop_key화살표를 사용하여 거북이를 이동합니다. 동시에 실행 중인 터미널을 보면 모든 움직임에 대해 위치 데이터가 게시되는 것을 볼 수 있습니다.

이제 rqt_graph로 돌아가 Debug 상자를 선택 해제하십시오.

/_ros2cli_26646 는방금 실행한 echo 명령 으로 생성된 노드입니다. (숫자는 다를 수 있음). 이제 게시자가 cmd_vel 토픽에 대한 데이터를 게시하고 두 명의 구독자가 이를 구독하고 있음을 알 수 있습니다 .

5. ros2 topic info

토픽이 일대일 커뮤니케이션일 필요는 없습니다. 일대다, 다대일 또는 다대다일 수 있습니다.

이것을 보는 또 다른 방법은 다음을 실행하는 것입니다.

6. ros2 interface show

노드는 메시지를 사용하여 토픽을 통해 데이터를 보냅니다. 게시자와 구독자가 통신하려면 동일한 유형의 메시지를 보내고 받아야 합니다.

ros2 topic list -t 실행 후 앞서 본 cmd_vel토픽 유형은 각 토픽에 어떤 메시지 유형이 사용되는지 알려줍니다. 토픽의 유형은 다음과 같습니다 .

이제 이 ros2 interface show <msg type>유형을 실행하여 세부 정보를 알아볼 수 있습니다. 특히 메시지가 기대하는 데이터 구조.

위의 메시지 유형에 대해 다음을 생성합니다.

/tutlesim 노드가 linear와 angular 두개의 백터 타입 엘레멘트를 가지고 있음을 보여줍니다. echo 코맨드를 이용하여 실제 전달되는 데이터를 보면 위와 동일함을 볼 수 있습니다.

7. ros2 topic pub

이제 메시지 구조를 알고 있으므로 다음을 사용하여 명령줄에서 직접 토픽에 데이터를 게시할 수 있습니다.

인수 '<args>'는 이전 섹션에서 방금 발견한 구조로 주제에 전달할 실제 데이터입니다.

이 인수는 YAML 구문으로 입력해야 한다는 점에 유의해야 합니다. 다음과 같이 전체 명령을 입력하십시오.

--once는 "하나의 메시지를 게시한 다음 종료"를 의미하는 선택적 인수입니다.

터미널에 다음 출력이 표시됩니다.

그러면 거북이가 다음과 같이 움직이는 것을 볼 수 있습니다.

거북이(및 일반적으로 에뮬레이션하려는 실제 로봇)는 지속적으로 작동하기 위해 꾸준한 명령 스트림이 필요합니다. 따라서 거북이를 계속 움직이게 하려면 다음을 실행할 수 있습니다.

기서 차이점은 --once옵션을 제거 하고 --rate 1옵션을 추가하여 명령을 1Hz의 꾸준한 스트림으로 게시하도록 지시한다는 것입니다 .

rqt_graph를 새로 고쳐서 무슨 일이 일어나고 있는지 그래픽으로 볼 수 있습니다. 이제 노드(/_ros2cli_30358)에서수신 중인 /turtle1/cmd_vel 토픽을통해 노드(/_ros2cli_26646, /turtlesim)에 게시하는 것을 볼 수 있습니다 .

마지막으로 echo 명령을 통해 pose 토픽을 rqt_graph를 통해 다시한번 확인해 보겠습니다.

/turtlesim 노드가 발행한 pose 토픽을 새로운 노드 /ros2cli1682 가 구독하고 있음을 볼 수 있습니다.

8. ros2 topic hz

이 프로세스에 대한 마지막 검사를 위해 다음을 사용하여 데이터가 게시되는 속도를 볼 수 있습니다.

/turtlesim노드가 pose 토픽에 데이터를 게시하는 속도에 대한 데이터를 반환합니다.

ros2 topic pub --rate 1 를 사용하여 turtle1/cmd_vel게시 속도를 일정한 1Hz로 설정했음을 기억하십시오 . 대신에 위의 명령을 실행하면 해당 속도를 반영하는 평균이 표시됩니다.

9. 종료

이 시점에서 많은 노드가 실행 중입니다. Ctrl+C각 터미널에 입력하여 중지하는 것을 잊지 마십시오.

ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
rqt_graph
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/color_sensor [turtlesim/msg/Color]
/turtle1/pose [turtlesim/msg/Pose]
ros2 topic echo <topic_name>
ros2 topic echo /turtle1/cmd_vel
linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0
  ---
ros2 topic info /turtle1/cmd_vel

Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscription count: 2
geometry_msgs/msg/Twist
ros2 interface show geometry_msgs/msg/Twist
# This expresses velocity in free space broken into its linear and angular parts.

    Vector3  linear
    Vector3  angular
linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0
  ---
ros2 topic pub <topic_name> <msg_type> '<args>'
ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))
ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
ros2 topic echo /turtle1/pose
ros2 topic hz /turtle1/pose
average rate: 59.354
  min: 0.005s max: 0.027s std dev: 0.00284s window: 58

ROS2 개요

저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

개요

ROS2는 ROS(1)에 비해 어플리케이션 레이어에서 마스터 노드를 없애고 미들웨어 레이어에 토픽/메시지 전송의 신뢰성과 보안성을 제공하기 위해 DDS(데이터 분산 서비스)와 RTPS(실시간 Publish/Subscribe) 기술을 추가하 였으며, Windows, Mac, RTOS와 같은 범용 OS에도 활용할 수 있도록 플랫폼의 범위를 확장 하였습니다.

rqt_console 을 이용해 로그 보기

저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

개요

rqt_console은ROS 2에서 로그 메시지를 검사하는 데 사용되는 GUI 도구입니다. 일반적으로 로그 메시지는 터미널에 표시됩니다. rqt_console을(를) 사용하면 시간이 지남에 따라 이러한 메시지를 수집하고, 자세히 보다 체계적으로 보고, 필터링하고, 저장하고, 저장된 파일을 다시 로드하여 다른 시간에 검사할 수 있습니다.

노드는 로그를 사용하여 이벤트 및 상태에 관한 메시지를 다양한 방식으로 출력합니다. 그들의 콘텐츠는 일반적으로 사용자를 위한 정보 제공용입니다.

실습

1. 설정

다음 명령을 사용하여 새 터미널에서 시작합니다 .

rqt_console 창이 열립니다.

콘솔의 첫 번째 섹션은 시스템의 로그 메시지가 표시되는 곳입니다.

중간에는 심각도 수준을 제외하여 메시지를 필터링하는 옵션이 있습니다. 오른쪽에 있는 더하기 기호 버튼을 사용하여 더 많은 제외 필터를 추가할 수도 있습니다.

아래쪽 섹션은 입력한 문자열을 포함하는 메시지를 강조 표시하기 위한 것입니다. 이 섹션에 더 많은 필터를 추가할 수도 있습니다.

이제 다음 명령을 사용하여 새 터미널에서 turtlesim 을시작합니다.

2. rqt_console의 메세지

rqt_console에 표시할 로그 메시지를 생성하기 위해 거북이가 벽에 부딪히도록 합시다. 새 터미널에서 아래 명령을 입력합니다(자세한 내용은 토픽 에서 설명 )

위의 명령은 일정한 속도로 토픽을 게시하므로 거북이는 계속해서 벽에 부딪힙니다. 다음과 같이 심각도 수준이 계속해서 Warn 표시된 동일한 메시지가 표시됩니다.

거북이가 벽에 부딪히지 않도록 Ctrl+C명령을 실행한 터미널에 누릅니다.

3. 로그 레벨

ROS2의 로그 레벨은 심각도에 따라 정렬됩니다.

각 수준이 나타내는 정확한 기준은 없지만 다음과 같이 가정하는 것이 안전합니다.

  • Fatal메시지는 시스템이 손상으로부터 자신을 보호하기 위해 종료될 것임을 나타냅니다.

  • Error메시지는 반드시 시스템을 손상시키지는 않지만 제대로 작동하지 못하게 하는 중요한 문제를 나타냅니다.

  • Warn메시지는 더 깊은 문제를 나타낼 수 있지만 기능을 완전히 손상시키지 않는 예기치 않은 활동 또는 이상적이지 않은 결과를 나타냅니다.

기본 수준은 Info입니다. 기본 심각도 수준과 보다 심각한 수준의 메시지만 표시됩니다.

일반적으로 Debug메시지는 Info보다 심각하지 않은 유일한 수준이므로 숨겨집니다. 예를 들어 기본 수준을 Warn로 설정하면 심각도 Warn Error Fatal 메시지만 표시됩니다.

3.1 기본 로그 수준 설정

리매핑을 사용하여 노드를 처음 실행할 때 기본 로거 수준을 설정할 수 있습니다. /turtlesim 터미널에 다음 명령을 입력합니다.

이제 마지막으로 시작할 때 콘솔에 나타난 초기 수준 메시지가 표시되지 않습니다. 이는 Info메시지가 새로운 기본 심각도인 Warn보다 우선 순위가 낮기 때문입니다.

Info메시지는 시스템이 예상대로 실행되고 있음을 시각적으로 확인하는 역할을 하는 이벤트 및 상태 업데이트를 나타냅니다.

  • Debug메시지는 시스템 실행의 전체 단계별 프로세스를 자세히 설명합니다.

  • 자습서
    ros2 run rqt_console rqt_console
    ros2 run turtlesim turtlesim_node
    ros2 topic pub -r 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.0}}"
    Fatal
    Error
    Warn
    Info
    Debug
    ros2 run turtlesim turtlesim_node --ros-args --log-level WARN

    노드(Node) 이해하기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    ROS2 그래프

    ROS 그래프는 동시에 데이터를 함께 처리하는 ROS 2 요소의 네트워크입니다. 모든 실행 파일을 매핑하고 시각화하려는 경우 모든 실행 파일과 실행 파일 간의 연결을 포함합니다.

    노드 이해하기

    ROS의 각 노드는 예를 들어 휠 모터를 제어하거나 레이저 거리 측정기에서 센서 데이터를 게시하는 것과 같은 단일 모듈 목적을 담당해야 합니다. 각 노드는 주제, 서비스, 작업 또는 매개변수를 통해 다른 노드와 데이터를 주고받을 수 있습니다.

    전체 로봇 시스템은 함께 작동하는 많은 노드로 구성됩니다. ROS 2에서 단일 실행 파일(C++ 프로그램, Python 프로그램 등)은 하나 이상의 노드를 포함할 수 있습니다.

    실습

    1. ROS2 실행

    이 명령은 패키지에서 실행 파일을 시작합니다.

    Turtlesim을 실행하려면 새 터미널을 열고 다음 명령을 입력하십시오.

    에서 본 것처럼 Turtlesim 창이 열립니다 .

    여기서 패키지 이름은 turtlesim이고 turtlesim_node는실행 파일 이름은 입니다 .

    그러나 우리는 여전히 노드 이름을 모릅니다.

    다음을 사용하여 노드 이름을 찾을 수 있습니다.ros2 node list

    2. ROS2 노드 목록

    ros2 node list

    실행 중인 모든 노드의 이름이 표시됩니다. 이는 노드와 상호 작용하려는 경우 또는 많은 노드를 실행하는 시스템이 있고 이를 추적해야 하는 경우에 특히 유용합니다.

    다른 터미널에서 turtlesim이 실행 중일 때 새 터미널을 열고 다음 명령을 입력합니다.

    터미널은 노드 이름을 반환합니다.

    다른 새 터미널을 열고 다음 명령을 사용하여 teleop 노드를 시작합니다.

    여기서는 다시 turtlesim패키지를 참조 하지만 이번에는 turtle_teleop_key이라는 실행 파일을 대상으로 합니다 .

    2.1 리매핑

    하면 노드 이름, 주제 이름, 서비스 이름 등과 같은 기본 노드 속성을 사용자 정의 값에 재할당할 수 있습니다. 지난 튜토리얼에서 remapping on을 사용하여 turtle_teleop_keycmd_vel 토픽을 변경했습니다 .

    이제 노드의 이름을 다시 할당하겠습니다 /turtlesim. 새 터미널에서 다음 명령을 실행합니다.

    다시 turtlesim을 호출하기 때문에 또 다른 turtlesim 창이 열립니다. 그러나 이제 를 실행한 터미널로 돌아가서 다시 실행하면 세 개의 노드 이름이 표시됩니다.

    3. ROS2 노드 정보

    이제 노드의 이름을 알았으므로 다음을 사용하여 노드에 대한 자세한 정보에 액세스할 수 있습니다.

    최신 my_turtle노드를 검사하려면 다음 명령을 실행하십시오.

    ros2 node info는구독자, 게시자, 서비스 및 작업 목록을 반환합니다. 즉, 해당 노드와 상호 작용하는 ROS 그래프 연결입니다. 출력은 다음과 같아야 합니다.

    이렇게노드의 정보를 볼 수 있습니다.

    이전 자습서
    재매핑을 사용
    ros2 run <package_name> <executable_name>
    ros2 run turtlesim turtlesim_node
    ros2 node list
    /turtlesim
    ros2 run turtlesim turtle_teleop_key
    /turtlesim
    /teleop_turtle
    ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle
    /turtlesim
    /teleop_turtle
    /my_turtle
    ros2 node info <node_name>
    ros2 node info /my_turtle
    /my_turtle
      Subscribers:
        /parameter_events: rcl_interfaces/msg/ParameterEvent
        /turtle1/cmd_vel: geometry_msgs/msg/Twist
      Publishers:
        /parameter_events: rcl_interfaces/msg/ParameterEvent
        /rosout: rcl_interfaces/msg/Log
        /turtle1/color_sensor: turtlesim/msg/Color
        /turtle1/pose: turtlesim/msg/Pose
      Services:
        /clear: std_srvs/srv/Empty
        /kill: turtlesim/srv/Kill
        /reset: std_srvs/srv/Empty
        /spawn: turtlesim/srv/Spawn
        /turtle1/set_pen: turtlesim/srv/SetPen
        /turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
        /turtle1/teleport_relative: turtlesim/srv/TeleportRelative
        /my_turtle/describe_parameters: rcl_interfaces/srv/DescribeParameters
        /my_turtle/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
        /my_turtle/get_parameters: rcl_interfaces/srv/GetParameters
        /my_turtle/list_parameters: rcl_interfaces/srv/ListParameters
        /my_turtle/set_parameters: rcl_interfaces/srv/SetParameters
        /my_turtle/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
      Action Servers:
        /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
      Action Clients:

    교육 안내

    본 교재는 쿼드(QUAD) 드론연구소의 오프라인 강의 교재로 무단 복제 및 사용을 금합니다.

    쿼드(QUAD) 드론연구소의 드론 개발/운용 오프라인 교육에 대한 자세한 내용은 아래 링크를 참고 하시기 바랍니다.

    교육문의 : 031-680-1311, maponarooo@naver.com

    교육용 가상환경 다운로드

    쿼드(QUAD) 드론연구소에서는 교육용 Oracle VirtualBox VM을 제공하고 있습니다.

    PC에 우분투 리눅스를 직접 설치하기 어려우신 분들은 아래 링크에서 VM을 다운받아 사용 하시기 바랍니다.

    Oracle VirtualBox는 아래 링크에서 최신 버전을 다운받아 설치 하시기 바랍니다.

    .

    액션(Action) 이해하기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    액션은 ROS2의 통신 유형 중 하나이며 장기 실행 작업을 위한 것입니다. 목표, 피드백 및 결과의 세 부분으로 구성됩니다.

    Action은 주제와 Service를 기반으로 합니다. 작업이 선점 가능하다는 점을 제외하면 해당 기능은 서비스와 유사합니다(실행 중에 취소할 수 있음). 또한 단일 응답을 반환하는 서비스와 달리 꾸준한 피드백을 제공합니다.

    작업은 게시자-구독자 모델과 유사한 클라이언트-서버 모델을 사용합니다(토픽에서 설명됨). "액션 클라이언트" 노드는 목표를 확인하고 피드백 스트림과 결과를 반환하는 "액션 서버" 노드로 목표를 보냅니다.

    실습

    1. 설정

    /turtlesim하고 /teleop_turtle두 개의 turtlesim 노드를 시작 합니다.

    다른 터미널을 열고 다음을 실행합니다.

    2. Action 사용

    노드를 시작하면 /teleop_turtle터미널에 다음 메시지가 표시됩니다.

    작업에 해당하는 두 번째 줄에 초점을 맞추겠습니다.

    문자 키는 키보드의 키 G|B|V|C|D|E|R|T주위에 "상자"를 형성합니다. 각 키의 위치는 Turtlesim의 해당 방향에 해당합니다. 예를 들어 E 키는거북이의 방향을 왼쪽 위 모서리로 회전시킵니다.

    /turtlesim노드가 실행 중인 터미널에 주의하십시오 . 이 키 중 하나를 누를 때마다 /turtlesim노드의 일부인 작업 서버에 목표를 보냅니다. 목표는 특정 방향을 향하도록 거북이를 회전시키는 것입니다. 거북이가 회전을 완료하면 목표 결과를 전달하는 메시지가 표시됩니다.

    키 F는 실행 중간에 목표를 취소하여 선점 가능한 작업 기능을 보여줍니다.

    C키를 누른 다음 거북이가 회전을 완료하기 전에 F키를 누르십시오. 노드가 실행 중인 터미널에 /turtlesim다음 메시지가 표시됩니다.

    클라이언트 측(텔레옵의 입력)이 목표를 중지할 수 있을 뿐만 아니라 서버 측(노드 /turtlesim)도 중지할 수 있습니다. 서버측에서 목표 처리를 중지하기로 선택하면 목표를 "중단"했다고 합니다.

    D키를 누른 다음 첫 번째 회전이 완료되기 전에 G키를 누르십시오 . 노드가 실행 중인 터미널에 /turtlesim다음 메시지가 표시됩니다.

    3. ros2 node info

    이 경우 /turtlesim노드가 제공하는 작업 목록을 보려면 새 터미널을 열고 다음 명령을 실행합니다.

    그러면 구독자, 게시자, 서비스, 액션 서버 및 액션 클라이언트 목록이 반환됩니다.

    RotateAbsolute 액션이 /Turlesim 노드에 있음을 알 수 있습니다. turtlesim/action/RotateAbsolute

    /teleop_turtle 노드를 살펴 봅니다.

    다음을 반환합니다.

    액션 클라이언트에 RostateAbsolute 액션이 나타난 것을 확인할 수 있습니다.

    4. ros2 action list

    ROS 그래프에서 모든 액션을 식별하려면 다음 명령을 실행합니다.

    다음을 반환합니다.

    이것은 현재 ROS 그래프의 유일한 액션입니다. 앞에서 본 것처럼 거북이의 회전을 제어합니다. 또한 명령 을 사용하여 이 작업에 대해 하나의 작업 클라이언트와 하나의 작업 서버가 있음을 이미 알고 있습니다 .

    4.1 ros2 action list -t

    작업에는 토픽 및 서비스와 유사한 유형이 있습니다. /turtle1/rotate_absolute의 유형을 찾으려면 다음 명령을 실행하십시오.

    다음을 반환합니다.

    각 액션 이름의 오른쪽에 있는 괄호 안에는 turtlesim/action/RotateAbsolute작업 유형이 있습니다 . 명령줄이나 코드에서 작업을 실행하려는 경우에 필요합니다.

    5. ros2 action info

    다음 명령을 사용하여 액션을 추가로 검사할 수 있습니다 .

    다음을 반환합니다.

    이것은 이전에 각 노드에서 "ros2 node info/teleop_turtle/turtlesim/turtle1/rotate_absolute"실행하면서 배운 내용을 알려줍니다 . 노드에는 액션 클라이언트가 있고 액션에 대한 작업 서버가 있습니다.

    6. ros2 interface show

    액션 목표를 직접 전송하거나 실행하기 전에 필요한 또 하나의 정보는 액션 유형의 구조입니다.

    ros2 action list -t명령을 실행할 때 /turtle1/rotate_absolute유형을 식별했음을 기억하십시오 . 터미널에 작업 유형과 함께 다음 명령을 입력합니다.

    다음을 반환합니다.

    첫 번째 ---위의 이 메시지 섹션은 목표 요청의 구조(데이터 유형 및 이름)입니다. 다음 섹션은 결과의 구조입니다. 마지막 섹션은 피드백의 구조입니다.

    7. ros2 action send_goal

    이제 다음 구문을 사용하여 명령줄에서 작업 목표를 전송해 보겠습니다.

    <values>는YAML 형식이어야 합니다.

    Turtlesim 창을 주시하고 터미널에 다음 명령을 입력하십시오.

    거북이가 회전하는 것과 동시에터미널에 다음 메시지가 표시되어야 합니다.

    모든 목표에는 반환 메시지에 표시되는 고유 ID가 있습니다. 시작 위치로의 변위인 이름이 있는 필드인 delta결과도 볼 수 있습니다 .

    이 목표에 대한 피드백을 보려면 실행한 마지막 명령에 --feedback 추가하십시오. 먼저 theta의 값을 변경했는지 확인하십시오 . 이전 명령을 실행한 후 거북이는 이미 라디안 방향에 있으므로 새로운 theta 값인 -1.57 을 전달하지 않으면 움직이지 않습니다.

    터미널에서 다음 메시지를 반환합니다.

    목표가 완료될 때까지 피드백(나머지 라디안)을 계속 받게 됩니다.

    ROS2 환경 구성

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

    ROS2는 셸 환경을 사용하여 작업 공간을 결합한다는 개념에 의존합니다. "workspace"은 ROS2로 개발 중인 시스템의 위치를 ​​나타내는 ROS 용어입니다. 핵심 ROS2 작업 공간을 언더레이라고 합니다. 후속 로컬 작업 공간을 오버레이라고 합니다. ROS2로 개발할 때 일반적으로 여러 작업 공간이 동시에 활성화됩니다.

    작업 공간을 결합하면 다양한 버전의 ROS2 또는 다양한 패키지 세트에 대한 개발이 더 쉬워집니다. 또한 동일한 컴퓨터에 여러 ROS2 배포판(또는 "distros", 예: Dashing 및 Eloquent)을 설치하고 배포판 간에 전환할 수 있습니다.

    1. ROS2 설치

    소스 설정

    ROS2 패키지 설치

    2. 환경 설정

    가. 설정파일 소싱

    나. 쉘 시작 스크립트에 소싱 추가

    새 셸을 열 때마다 설정 파일을 소싱하지 않으려면(작업 1 건너뛰기) 셸 시작 스크립트에 명령을 추가할 수 있습니다.

    다. 환경변수 확인

    ROS 2 설정 파일을 소싱하면 ROS 2 작동에 필요한 여러 환경 변수가 설정됩니다. ROS 2 패키지를 찾거나 사용하는 데 문제가 있는 경우 다음 명령을 사용하여 환경이 올바르게 설정되었는지 확인하십시오.

    ROS_DISTRO및 와 같은 변수가 ROS_VERSION설정되어 있는지 확인하십시오. 예를 들어 Foxy를 사용하는 경우 다음과 같이 표시됩니다.

    ROS_DOMAIN_ID변수

    ROS 2가 통신에 사용하는 기본 미들웨어는 DDS입니다. DDS에서 서로 다른 논리 네트워크가 물리적 네트워크를 공유하도록 하는 기본 메커니즘을 도메인 ID라고 합니다. 동일한 도메인에 있는 ROS 2 노드는 서로 자유롭게 메시지를 검색하고 보낼 수 있지만 다른 도메인에 있는 ROS 2 노드는 할 수 없습니다. 모든 ROS 2 노드는 기본적으로 도메인 ID 0을 사용합니다. 동일한 네트워크에서 ROS 2를 실행하는 서로 다른 컴퓨터 그룹 간의 간섭을 방지하려면 각 그룹에 대해 서로 다른 도메인 ID를 설정해야 합니다.

    ROS 2 노드 그룹의 고유한 정수를 결정했으면 다음 명령을 사용하여 환경 변수를 설정할 수 있습니다.

    ROS_LOCALHOST_ONLY변수

    기본적으로 ROS 2 통신은 localhost로 제한되지 않습니다. ROS_LOCALHOST_ONLY환경 변수를 사용하면 ROS 2 통신을 localhost로만 제한할 수 있습니다. 이는 ROS 2 시스템과 해당 항목, 서비스 및 작업이 로컬 네트워크의 다른 컴퓨터에 표시되지 않음을 의미합니다. 를 사용하는 ROS_LOCALHOST_ONLY것은 여러 로봇이 이상한 행동을 유발하는 동일한 주제에 대해 게시할 수 있는 교실과 같은 특정 설정에서 유용합니다. 다음 명령을 사용하여 환경 변수를 설정할 수 있습니다.

    ROS2 명령alias 설정

    sudo apt install software-properties-common
    sudo add-apt-repository universe
    
    sudo apt update && sudo apt install curl -y
    sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
    
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
    sudo apt update
    sudo apt upgrade
    
    sudo apt install ros-humble-desktop
    sudo apt install ros-dev-tools
    sudo apt install python3-colcon-common-extensions
    # ROS 2 명령에 액세스하려면 여는 모든 새 셸에서 이 명령을 실행해야 합니다.
    # ~/.bashrc 파일에 넣어 두면 쉘이 기동될때 자동 실행 되므로 .bashrc 파일에 넣어 놓는 것을 추천 합니다.
    source /opt/ros/humble/setup.bash
    echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
    printenv | grep -i ROS
    ROS_VERSION=2
    ROS_PYTHON_VERSION=3
    ROS_DISTRO=humble
    export ROS_DOMAIN_ID=<your_domain_id>
    
    ### 쉘 실행시 자동 시작 설정
    echo "export ROS_DOMAIN_ID=<your_domain_id>" >> ~/.bashrc
    export ROS_LOCALHOST_ONLY=1
    
    ### 쉘 실행시 자동 시작 설정
    echo "export ROS_LOCALHOST_ONLY=1" >> ~/.bashrc
    ### Alias
    alias sb="source ~/.bashrc; echo \"bashrc is reloaded\""
    
    ### ROS Evn.
    alias humble="source /opt/ros/humble/setup.bash; echo \"ROS2 Humble is activated\""
    alias cb="colcon build --symlink-install"
    alias cb+="colcon build --symlink-install --event-handlers console_direct+"
    alias cbp="colcon build --packages-up-to -symlink-install --event-handlers console_direct+"

    turtlesim, ROS2 rqt

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    Turtlesim은 ROS2 학습을 위한 경량 시뮬레이터입니다. ROS2가 가장 기본적인 수준에서 수행하는 작업을 설명하여 나중에 실제 로봇 또는 로봇 시뮬레이션으로 수행할 작업에 대한 아이디어를 제공합니다.

    ROS2 도구는 사용자가 ROS 시스템을 관리하고, 점검하고, 상호 작용하는 방법입니다. 시스템 및 해당 작업의 다양한 측면을 대상으로 하는 여러 명령을 지원합니다. 이를 사용하여 노드를 시작하고, 매개변수를 설정하고, 주제를 듣는 등의 작업을 할 수 있습니다. ROS2 도구는 핵심 ROS2 설치의 일부입니다.

    rqt는 ROS2용 그래픽 사용자 인터페이스(GUI) 도구입니다. rqt에서 수행되는 모든 작업은 명령줄에서 수행할 수 있지만 rqt는 ROS2 요소를 조작하는 보다 사용자 친화적인 방법을 제공합니다.

    이 튜토리얼은 노드, 토픽 및 서비스와 같은 핵심 ROS2 개념을 다룹니다. 이러한 모든 개념은 이후 자습서에서 자세히 설명합니다. 지금은 단순히 도구를 설정하고 그에 대한 느낌을 얻을 것입니다.

    실습

    1. Turtlesim 설치

    ROS 2 배포판용 turtlesim 패키지를 설치합니다.

    패키지가 설치되었는지 확인합니다.

    위의 명령은 Turtlesim의 실행 파일 목록을 반환해야 합니다.

    2. Turtlesim 실행

    터미널의 명령 아래에서 거북이의 이름과 그것이 생성된 좌표를 볼 수 있습니다.

    3. Turtlesim 사용

    새 터미널을 열고 ROS 2를 다시 소싱합니다.

    이제 새 노드를 실행하여 첫 번째 노드에서 거북이를 제어합니다.

    이 시점에서 세 개의 창이 열려 있어야 합니다: 터미널 실행 turtlesim_node, 터미널 실행 turtle_teleop_key및 Turtlesim 창. turtlesim 창을 볼 수 있도록 이러한 창을 배열하고, 또한 turtle_teleop_keyturtlesim에서 거북이를 제어할 수 있도록 터미널이 활성화되도록 합니다.

    거북이를 제어하려면 키보드의 화살표 키를 사용하십시오. 지금까지 따라온 경로를 그리기 위해 부착된 "펜"을 사용하여 화면 주위를 이동합니다.

    list각 명령의 하위 명령을 사용하여 노드 및 관련 항목, 서비스 및 작업을 볼 수 있습니다 .

    4. rqt 설치

    rqt를 실행하려면:

    5. rqt 사용

    rqt를 처음 실행하면 창이 비어 있습니다. 상단의 메뉴 표시줄에서 Plugins > Services > Service Caller를 선택하기만 하면 됩니다

    서비스 드롭다운 목록 왼쪽에 있는 새로 고침 버튼을 사용하여 Turtlesim 노드의 모든 서비스를 사용할 수 있는지 확인하십시오.

    서비스 드롭다운 목록을 클릭하여 turtlesim의 서비스를 보고 /spawn서비스를 선택합니다.

    5.1 스폰 서비스 사용해보기

    rqt를 사용하여 서비스를 호출해 봅시다 /spawn. /spawnTurtlesim 창에서 또 다른 거북이를 생성할 이름에서 추측할 수 있습니다 .

    Expressionturtle2 열 에서 빈 작은따옴표 사이를 두 번 클릭하여 새 거북이에 와 같은 고유한 이름을 지정합니다 . 이 표현식은 name 값에 해당 하고 string 유형임을 알 수 있습니다 .

    다음으로 새 거북이를 생성할 유효한 좌표(예: 및 )를 입력합니다 .x = 1.0 y = 1.0

    5.2 set_pen 서비스 사용해보기

    스폰하려면 rqt 창의 오른쪽 상단에 있는 call 버튼을 클릭하여 turtle2 서비스를 호출해야 합니다 .

    서비스 호출이 성공하면 x 및 y 에 대해 입력한 좌표에서 새 거북이(역시 임의 디자인으로) 생성되는 것을 볼 수 있습니다 .

    rqt에서 서비스 목록을 새로 고치면 /turtle2/... /turtle1/....

    0에서 255 사이의 r , g 및 b 값은 펜을 turtle1그리는 색상을 설정하고 너비는 선의 두께를 설정합니다.

    뚜렷한 빨간색 선으로 그리 려면 rturtle1 값을 255로, 너비 값을 5로 변경하세요. 값을 업데이트한 후 서비스를 호출하는 것을 잊지 마세요.

    가 실행되고 있는 터미널로 돌아와 turtle_teleop_key화살표 키를 누르면 turtle1의 펜이 변경된 것을 확인할 수 있습니다.

    아마도 움직일 방법이 없다는 것을 알아차렸을 것입니다. turtle2 에 대한 teleop 노드가 없기 때문입니다.

    6. 리매핑

    turtle2를 제어하려면 두 번째 teleop 노드가 필요합니다. 그러나 이전과 동일한 명령을 실행하려고 하면 cmd_vel 토픽을 다시 매핑해야 합니다.

    새 터미널에서 ROS 2를 소싱하고 다음을 실행합니다.

    이제 turtle2터미널이 활성화되어 있을 때 turtle2를 이동할 수 있습니다.

    7. turtlesim 종료하기

    시뮬레이션을 중지하려면 종료키를미널에 입력 합니다 .

    Ctrl + C

    파라메터(Parameter) 이해하기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    매개변수는 노드의 구성 값입니다. 매개변수를 노드 설정으로 생각할 수 있습니다. 노드는 매개변수를 정수, 실수, 부울, 문자열 및 목록으로 저장할 수 있습니다. ROS2에서 각 노드는 자체 매개변수를 유지합니다. 매개변수에 대한 자세한 배경 정보는 참조하십시오 .

    ros2 run turtlesim turtlesim_node
    ros2 run turtlesim turtle_teleop_key
    Use arrow keys to move the turtle.
    Use G|B|V|C|D|E|R|T keys to rotate to absolute orientations. 'F' to cancel a rotation.
    [INFO] [turtlesim]: Rotation goal completed successfully
    [INFO] [turtlesim]: Rotation goal canceled
    [WARN] [turtlesim]: Rotation goal received before a previous goal finished. Aborting previous goal
    ros2 node info /turtlesim
    /turtlesim
      Subscribers:
        /parameter_events: rcl_interfaces/msg/ParameterEvent
        /turtle1/cmd_vel: geometry_msgs/msg/Twist
      Publishers:
        /parameter_events: rcl_interfaces/msg/ParameterEvent
        /rosout: rcl_interfaces/msg/Log
        /turtle1/color_sensor: turtlesim/msg/Color
        /turtle1/pose: turtlesim/msg/Pose
      Services:
        /clear: std_srvs/srv/Empty
        /kill: turtlesim/srv/Kill
        /reset: std_srvs/srv/Empty
        /spawn: turtlesim/srv/Spawn
        /turtle1/set_pen: turtlesim/srv/SetPen
        /turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
        /turtle1/teleport_relative: turtlesim/srv/TeleportRelative
        /turtlesim/describe_parameters: rcl_interfaces/srv/DescribeParameters
        /turtlesim/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
        /turtlesim/get_parameters: rcl_interfaces/srv/GetParameters
        /turtlesim/list_parameters: rcl_interfaces/srv/ListParameters
        /turtlesim/set_parameters: rcl_interfaces/srv/SetParameters
        /turtlesim/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
      Action Servers:
        /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
      Action Clients:
    ros2 node info /teleop_turtle
    /teleop_turtle
      Subscribers:
        /parameter_events: rcl_interfaces/msg/ParameterEvent
      Publishers:
        /parameter_events: rcl_interfaces/msg/ParameterEvent
        /rosout: rcl_interfaces/msg/Log
        /turtle1/cmd_vel: geometry_msgs/msg/Twist
      Services:
        /teleop_turtle/describe_parameters: rcl_interfaces/srv/DescribeParameters
        /teleop_turtle/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
        /teleop_turtle/get_parameters: rcl_interfaces/srv/GetParameters
        /teleop_turtle/list_parameters: rcl_interfaces/srv/ListParameters
        /teleop_turtle/set_parameters: rcl_interfaces/srv/SetParameters
        /teleop_turtle/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
      Action Servers:
    
      Action Clients:
        /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
    ros2 action list
    /turtle1/rotate_absolute
    ros2 action list -t
    /turtle1/rotate_absolute [turtlesim/action/RotateAbsolute]
    ros2 action info /turtle1/rotate_absolute
    Action: /turtle1/rotate_absolute
    Action clients: 1
        /teleop_turtle
    Action servers: 1
        /turtlesim
    ros2 interface show turtlesim/action/RotateAbsolute
    # The desired heading in radians
    float32 theta
    ---
    # The angular displacement in radians to the starting position
    float32 delta
    ---
    # The remaining rotation in radians
    float32 remaining
    ros2 action send_goal <action_name> <action_type> <values>
    ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
    Waiting for an action server to become available...
    Sending goal:
       theta: 1.57
    
    Goal accepted with ID: f8db8f44410849eaa93d3feb747dd444
    
    Result:
      delta: -1.568000316619873
    
    Goal finished with status: SUCCEEDED
    ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}" --feedback
    Sending goal:
       theta: -1.57
    
    Goal accepted with ID: e6092c831f994afda92f0086f220da27
    
    Feedback:
      remaining: -3.1268222332000732
    
    Feedback:
      remaining: -3.1108222007751465
    
    …
    
    Result:
      delta: 3.1200008392333984
    
    Goal finished with status: SUCCEEDED

    ROS2 프로그래밍 시작

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

    개요

    colcon은 ROS2 패키지를 빌드하기 위한 빌드 툴 입니다.

    우리는 본 과정에서 colcon을 사용하여 ROS2 패키지를 빌드하는 방법을 배우고, 작업공간을 만들고 간단한 Python ROS2 프로그램을 이용해 우리가 지금까지 배웠던 ROS2의 노드간 토픽, 서비스, 파라메터를 사용하는 방법에 대해서 알아볼 것입니다.

    sudo apt update
    
    sudo apt install ros-humble-turtlesim
    ros2 pkg executables turtlesim
    turtlesim draw_square
    turtlesim mimic
    turtlesim turtle_teleop_key
    turtlesim turtlesim_node
    ros2 run turtlesim turtlesim_node
    [INFO] [turtlesim]: Starting turtlesim with node name /turtlesim
    [INFO] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
    ros2 run turtlesim turtle_teleop_key
    ros2 node list
    ros2 topic list
    ros2 service list
    ros2 action list
    sudo apt update
    
    sudo apt install ~nros-humble-rqt*
    rqt
    ros2 run turtlesim turtle_teleop_key --ros-args --remap turtle1/cmd_vel:=turtle2/cmd_vel
    실습

    1. 설정

    /turtlesim하고 /teleop_turtle두 개의 turtlesim 노드를 시작 합니다.

    다른 터미널을 열고 다음을 실행합니다.

    2. ros2 param list

    노드에 속한 매개변수를 보려면 새 터미널을 열고 다음 명령을 입력하십시오.

    노드 네임스페이스 /teleop_turtle및 /turtlesim각 노드의 매개변수가 뒤따르는 것을 볼 수 있습니다.

    모든 노드에는 use_sim_time매개변수가 있습니다. 그것은 Turtlesim에 고유하지 않습니다.

    이름에 따라 의 /turtlesim매개변수가 RGB 색상 값을 사용하여 turtlesim 창의 배경색을 결정하는 것처럼 보입니다.

    매개변수 유형을 확인하려면 ros2 param get를 사용할 수 있습니다.

    3. ros2 param get

    매개변수의 유형과 현재 값을 표시하려면 다음 명령을 사용하십시오.

    /turtlesim의 background_g매개변수 의 현재 값을 알아봅시다.

    값을 반환합니다.

    이제 정수 값을 보유하고 있음을 알고 있습니다.

    4. ros2 param set

    런타임 시 매개변수 값을 변경하려면 다음 명령을 사용하십시오.

    /turtlesim의 배경색을 변경해 보겠습니다 .

    터미널에서 다음 메시지를 반환해야 합니다. "파라메터 지정 성공!~~"

    거북이 시뮬레이션 창의 배경색이 변경되어야 합니다.

    set명령 으로 매개변수를 설정하면 현재 세션에서만 변경되며 영구적으로 변경되지 않습니다. 그러나 설정을 저장하고 다음에 노드를 시작할 때 다시 로드할 수 있습니다.

    5. ros2 param dump

    다음 명령을 사용하여 노드의 모든 현재 매개변수 값을 파일에 저장하여 나중에 저장할 수 있습니다.

    /turtlesim의 매개변수의 현재 구성을 저장하려면 다음 명령을 입력하십시오.

    터미널에서 다음 메시지를 반환합니다.

    쉘이 실행 중인 현재 작업 디렉토리에서 새 파일을 찾을 수 있습니다. 이 파일을 열면 다음 내용이 표시됩니다.

    나중에 동일한 매개변수로 노드를 다시 로드하려는 경우 매개변수 덤프가 유용합니다.

    6. ros2 param load

    음 명령을 사용하여 파일에서 현재 실행 중인 노드로 매개변수를 로드할 수 있습니다.

    turtlesim.yaml로 생성된 파일을 노드의 매개변수 로 로드하려면 다음 명령을 입력하십시오.

    터미널에서 다음 메시지를 반환합니다.

    7. Node 시작시 매개변수 파일 불러오기

    저장된 매개변수 값을 사용하여 동일한 노드를 시작하려면 다음을 사용하십시오.

    실행 중인 Turtlesim 노드를 중지하고 다음을 사용하여 저장된 매개변수로 다시 로드해 보십시오.

    Turtlesim 창은 평소와 같이 나타나야 하지만 이전에 설정한 보라색 배경을 사용합니다.

    개념 문서를

    서비스(Service) 이해하기

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

    개요

    서비스는 ROS 그래프의 노드에 대한 또 다른 통신 방법입니다. 서비스는 호출 및 응답 모델 대 게시자-구독자 주제 모델을 기반으로 합니다. 토픽은 노드가 데이터 스트림을 구독하고 지속적인 업데이트를 받을 수 있도록 허용하지만 서비스는 클라이언트가 구체적으로 호출할 때만 데이터를 제공합니다.

    실습

    1. 설정

    두개의 터미널에 각각 /turtlesim 과 /teleop_turtle두 개의 turtlesim 노드를 시작 합니다.

    2. ros2 service list

    새 터미널에서 ros2 service list 명령을 실행하면 시스템에서 현재 활성화된 모든 서비스 목록이 반환됩니다.

    두 노드 모두 이름에 동일한 6개의 서비스(parameters)가 있음을 알 수 있습니다 . ROS2의 거의 모든 노드에는 매개변수가 구축되는 이러한 인프라 서비스가 있습니다. 다음 자습서에서 매개 변수에 대해 자세히 설명합니다. 이 자습서에서는 매개 변수 services가 논의에서 생략됩니다.

    3. ros2 service type

    서비스에는 서비스의 요청 및 응답 데이터가 구성되는 방식을 설명하는 유형이 있습니다. 서비스 유형은 토픽 유형과 유사하게 정의되지만 서비스 유형은 요청에 대한 메시지와 응답에 대한 메시지의 두 부분으로 구성됩니다.

    서비스 유형을 찾으려면 다음 명령을 사용하십시오.

    터틀심의 /clear서비스를 살펴보겠습니다. 새 터미널에서 다음 명령을 입력합니다.

    다음을 반환해야 합니다.

    유형 Empty은 서비스 호출이 요청을 할 때 데이터를 보내지 않고 응답을 받을 때 데이터를 받지 않음을 의미합니다.

    3.1 ros2 service list -t

    모든 활성 서비스의 유형을 동시에 보려면 다음 과 같이 명령 에 --show-types약어로 표시되는 -t 옵션을 추가할 수 있습니다 .

    다음을 반환합니다.

    4. ros2 service find

    특정 유형의 모든 서비스를 찾으려면 다음 명령을 사용할 수 있습니다.

    예를 들어 다음과 같이 입력된 모든 Empty 서비스를 찾을 수 있습니다.

    다음을 반환합니다.

    5. ros2 interface show

    명령줄에서 서비스를 호출할 수 있지만 먼저 입력 인수의 구조를 알아야 합니다.

    Empty 서비스 유형의 인터페이스를알아 보겠습니다.

    다음을 반환합니다.

    요청 구조(위)와 응답 구조(아래)를 "---" 를리이용하여 분리합니다 . 그러나 앞에서 배운 것처럼 Empty형식은 데이터를 보내거나 받지 않습니다. 따라서 당연히 그 구조는 비어 있습니다.

    이번엔 Empty 서비스 유형의 인터페이스를알아 보겠습니다.

    ros2 interface show turtlesim/srv/Spawn

    다음을 반환합니다.

    ---줄 위의 정보는 /spawn서비스를 호출하는 데 필요한 인수(x, y그리고 theta)를 알려줍니다 . 생성된 거북이의 2D 위치를 결정하고 name 은선택 사항입니다.

    줄 아래에 있는 정보는 이 경우 알아야 할 정보는 아니지만 서비스에요청서 받은 응답의 데이터 유형을 이해하는 데 도움이 될 수 있습니다.

    6. ros2 service call

    이제 서비스 유형이 무엇인지, 서비스 유형을 찾는 방법 및 해당 유형의 인수 구조를 찾는 방법을 알았으므로 다음을 사용하여 서비스를 호출할 수 있습니다.

    <arguments>부분은 선택 사항입니다. 예를 들어 Empty 유형이 지정된 서비스에는 인수가 없다는 것을 알고 있습니다.

    이 명령은 거북이가 그린 선의 turtlesim 창을 지웁니다.

    이제 <arguments>인수를 넣고/spawn 서비스를 호출하여 새 거북이를 생성해 보겠습니다. 명령줄에서 서비스 호출의 입력은 YAML 구문이어야 합니다.

    무슨 일이 일어나고 있는지에 대한 이 메서드 스타일 보기와 서비스 응답을 얻을 수 있습니다.

    Turtlesim 창이 새로 생성된 거북이로 바로 업데이트됩니다.

    ros2 run turtlesim turtlesim_node
    ros2 run turtlesim turtle_teleop_key
    ros2 param list
    /teleop_turtle:
      scale_angular
      scale_linear
      use_sim_time
    /turtlesim:
      background_b
      background_g
      background_r
      use_sim_time
    ros2 param get <node_name> <parameter_name>
    ros2 param get /turtlesim background_g
    Integer value is: 86
    ros2 param set <node_name> <parameter_name> <value>
    ros2 param set /turtlesim background_r 150
    Set parameter successful
    ros2 param dump <node_name>
    ros2 param dump /turtlesim
    Saving to:  ./turtlesim.yaml
    turtlesim:
      ros__parameters:
        background_b: 255
        background_g: 86
        background_r: 150
        use_sim_time: false
    ros2 param load <node_name> <parameter_file>
    ros2 param load /turtlesim ./turtlesim.yaml
    Set parameter background_b successful
    Set parameter background_g successful
    Set parameter background_r successful
    Set parameter use_sim_time successful
    ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>
    ros2 run turtlesim turtlesim_node --ros-args --params-file ./turtlesim.yaml

    데이터 기록 및 재생

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

    개요

    ros2 bag은시스템의 토픽에 게시된 데이터를 기록하기 위한 명령줄 도구입니다. 여러 토픽에 대해 전달된 데이터를 축적하여 데이터베이스에 저장합니다. 그런 다음 데이터를 재생하여 테스트 및 실험 결과를 재현할 수 있습니다. 토픽을 기록하는 것은 작업을 공유하고 다른 사람이 다시 만들 수 있도록 하는 좋은 방법이기도 합니다.

    # 실습

    데이터를 저장하고 재생하기 위해 시스템에 키보드 입력을 기록할 것이므로 /turtlesim및 /teleop_turtle노드를 시작하여 시작하십시오.

    새 터미널을 열고 다음을 실행합니다.

    다른 터미널을 열고 다음을 실행합니다.

    기록된 데이터를저장할 새 디렉토리를 만들어 봅시다.

    2. Topic 선택

    ros2 bag에 게시된 특정 토픽 메시지의 데이터만 기록할 수 있습니다. 시스템 토픽 목록을 보려면 새 터미널을 열고 다음 명령을 실행하십시오.

    다음을 반환합니다.

    토픽 자습서에서 /turtle_teleop노드가 거북이가 turtlesim에서 움직이도록 하는 명령을 /turtle1/cmd_vel토픽에 게시한다는 것을 배웠습니다.

    /turtle1/cmd_vel에게시 중인 데이터를 보려면 다음 명령을 실행합니다.

    Teleop에서 데이터를 게시하지 않기 때문에 처음에는 아무 것도 표시되지 않습니다. teleop을 실행한 터미널로 돌아가서 활성화되도록 선택합니다. 화살표 키를 사용하여 거북이를 움직이면 실행 중인 터미널에 데이터가 게시되는 것을 볼 수 있습니다 .

    3. ros2 bag record

    토픽에 게시된 데이터를 기록하려면 다음명령 구문을 사용합니다.

    선택한 항목에서 이 명령을 실행하기 전에 새 터미널을 열고 이전에 만든 bag_files디렉터리로 이동합니다. 왜냐하면 rosbag 파일은 디렉터리에 저장되기 때문입니다.

    다음 명령을 실행합니다.

    터미널에 다음 메시지가 표시됩니다(날짜와 시간은 다를 수 있음).

    이제 토픽에 게시된 데이터를 기록하고 있습니다. teleop 터미널로 돌아가 거북이를 다시 움직입니다. 움직임은 중요하지 않지만 나중에 /turtle1/cmd_vel데이터를 재생할 때 볼 수 있도록 인식 가능한 패턴을 만드십시오.

    기록을 중지하려면 Ctrl+C누릅니다 .

    데이터는 다음과 같은 패턴의 이름으로 백 파일에 축적됩니다.rosbag2_year_month_day-hour_minute_second

    3.1 여러 토픽 기록

    여러 토픽을 기록하고 저장할 파일의 이름을 변경할 수도 있습니다.

    다음 명령을 실행합니다.

    이 -o 옵션을 사용하면 백 파일의 고유한 이름을 선택할 수 있습니다. 다음 문자열(이 경우 subset)은 파일 이름입니다.

    한 번에 둘 이상의 주제를 기록하려면 각 주제를 공백으로 구분하여 나열하면 됩니다.

    두 주제가 모두 기록되고 있음을 확인하는 다음 메시지가 표시됩니다.

    4. ros2 bag info

    다음을 실행하여 기록에 대한 세부 정보를 볼 수 있습니다.

    bag 파일 에서 이 명령을 실행하면 subset파일에 대한 정보 목록이 반환됩니다.

    개별 메시지를 보려면 데이터베이스(이 경우 sqlite3)를 열어 검사해야 합니다. 이는 본 학습의범위를 벗어납니다.

    5. ros2 bag play

    bag 파일을 재생하기 전에 teleop이 실행되고 있는 터미널에 Ctrl+C 입력합니다. 그런 다음 작동 중인 bag 파일을 볼 수 있도록 turtlesim 창이 표시되는지 확인합니다.

    다음 명령을 입력하십시오.

    터미널은 다음 메시지를 반환합니다.

    거북이는 기록하는 동안 입력한 것과 동일한 경로를 따릅니다(정확히 100%는 아니지만 turtlesim은 시스템 타이밍의 작은 변화에 민감합니다).

    파일이 turtle1/pose 토픽을 subset기록했기 때문에 이동하지 않더라도 turtlesim을 실행하는 동안 명령이 종료되지 않습니다.

    /turtlesim 노드가 활성화되어 있는 한 일정한 간격으로 토픽에 대한 데이터를 게시하기 때문입니다. 위의 예제 결과 에서 /turtle1/pose 토픽의 정보가 9개에 불과하다는 것을 알아차렸을 것입니다. 기록하는 동안 화살표 키를 누른 횟수입니다.

    3000 이상의 값이 /turtle1/pose 에있음 을 알 수 있습니다 . 기록하는 동안 해당 토픽에 대한 데이터가 3000번 게시되었습니다.

    위치 데이터가 얼마나 자주 게시되는지 알아보려면 다음 명령을 실행할 수 있습니다.

    패키지 만들기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    1. ROS2 패키지란 무엇입니까?

    패키지는 ROS 2 코드의 컨테이너로 간주될 수 있습니다. 코드를 설치하거나 다른 사람과 공유하려면 패키지로 구성해야 합니다. 패키지를 사용하면 ROS 2 작업을 릴리스하고 다른 사람들이 쉽게 빌드하고 사용할 수 있습니다.

    ROS 2에서 패키지 생성은 빌드 시스템으로 ament를 사용하고 빌드 도구로 colcon을 사용합니다. 공식적으로 지원되는 CMake 또는 Python을 사용하여 패키지를 만들 수 있지만 다른 빌드 유형이 존재합니다.

    2. 무엇이 ROS2 패키지를 구성합니까?

    ROS 2 Python 및 CMake 패키지에는 각각 고유한 최소 필수 콘텐츠가 있습니다.

    cmake

    • package.xml패키지에 대한 메타 정보를 포함하는 파일

    • CMakeLists.txt패키지 내에서 코드를 빌드하는 방법을 설명하는 파일

    Python

    • package.xml패키지에 대한 메타 정보를 포함하는 파일

    • setup.py패키지 설치 방법에 대한 지침 포함

    • setup.cfg패키지에 실행 파일이 있는 경우 ros2 run 로 찾을 수 있습니다 .

    가능한 가장 간단한 패키지는 다음과 같은 파일 구조를 가질 수 있습니다.

    cmake

    Python

    "본 교재에서는 Python을 기준으로 학습 합니다"

    3. 작업공간의 패키지

    단일 작업 공간에는 각각 자체 폴더에 원하는 만큼 많은 패키지가 포함될 수 있습니다. 하나의 작업 공간(CMake, Python 등)에 다양한 빌드 유형의 패키지를 포함할 수도 있습니다. 패키지를 중첩할 수 없습니다.

    가장 좋은 방법은 작업 공간 src내에 폴더를 만들고 거기에 패키지를 만드는 것입니다. 이렇게 하면 작업 공간의 최상위 수준이 "깨끗한" 상태로 유지됩니다.

    간단한 작업 공간은 다음과 같습니다.

    실습

    1. 패키지 생성

    먼저 .

    에서 만든 ros2_ws작업 공간을 사용하겠습니다 .

    패키지 생성 명령을 실행하기 전에 폴더 src가 있는지 확인하십시오 .

    ROS 2에서 새 패키지를 생성하기 위한 명령 구문은 다음과 같습니다.

    src이제 작업 공간 디렉토리 내에 이라는 새 폴더가 생겼습니다 my_package.

    명령을 실행하면 터미널에서 다음 메시지를 반환합니다.

    새 패키지에 대해 자동으로 생성된 파일을 볼 수 있습니다.

    2. 패키지 빌드

    작업 공간 루트에서 실행하여 한 번에 많은 패키지를 빌드할 수 있기 때문에 작업 공간에 패키지를 배치하는 것은 특히 유용합니다 . 그렇지 않으면 각 패키지를 개별적으로 빌드해야 합니다.colcon build

    작업 공간의 루트로 돌아갑니다.

    이제 패키지를 빌드할 수 있습니다.

    실행 중 ros_tutorials패키지도 빌드되었음을 알 수 있습니다 . 작업 공간에 몇 개의 패키지만 있으면 괜찮지만 패키지가 많으면 시간이 오래 걸릴 수 있습니다.

    다음에 my_package패키지 만 빌드하려면 다음을 실행할 수 있습니다.

    3. install 파일 소싱

    새 패키지와 실행 파일을 사용하려면 먼저 새 터미널을 열고 기본 ROS2 를 소싱하십시오.

    그런 다음 디렉터리 내에서 ros2_ws다음 명령을 실행하여 작업 영역을 소싱합니다.

    이제 작업 영역이 경로에 추가되었으므로 새 패키지의 실행 파일을 사용할 수 있습니다.

    4. 패키지 사용

    패키지 생성 중 --node-name인수를 사용하여 생성한 실행 파일을 실행하려면 다음 명령을 입력합니다.

    그러면 터미널에 메시지가 반환됩니다.

    5. 패키지 내용 확인

    ros2_ws/src/my_package내부에는 ros2 pkg create에 의해자동으로 생성된 파일과 폴더가 표시됩니다.

    my_package 디렉토리 안에 my_node.py 가있습니다 . 향후 모든 사용자 지정 Python 노드가 생성될위치입니다.

    6. package.xml 사용자 지정

    패키지를 만든 후 반환 메시지에서 필드 description및 license TODO가 포함되어 있음 을 알 수 있습니다. 패키지 설명과 라이센스 선언은 자동으로 설정되지 않지만 패키지를 릴리스하려는 경우 필요하기 때문입니다. maintainer필드 를 채워야 할 수도 있습니다.

    원하는 텍스트 편집기를 사용하여 ros2_ws/src/my_package/package.xml를엽니다.

    maintainer에자동으로 입력되지 않은 경우 이름과 이메일을 라인에 입력하십시오 . 그런 다음 description행을 편집하여 패키지를 요약합니다.

    그런 다음 license라인을 업데이트하십시오. 확인할 수 있습니다 . 이 패키지는 연습용이므로 모든 라이선스를 사용해도 안전합니다. 다음을 사용합니다. Apache License 2.0

    편집이 완료되면 저장하는 것을 잊지 마십시오.

    라이센스 태그 아래에 _depend로 끝나는 일부 태그 이름이 표시됩니다 . 이것은 colcon이 검색할 수 있도록 package.xml 패키지에 대한 종속성을 나열하는 곳입니다. 현재는간단하고 종속성이 없지만 다음 자습서에서 이 공my_package간이 활용되는 것을 볼 수 있습니다.

    package.xml파일에는 와 동일한 설명, 관리자 및 라이센스 필드가 포함되어 있으므로 setup.py도 동일하게설정해야 합니다. 두 파일에서 정확히 일치해야 합니다. 버전과 이름( package_name)도 정확히 일치해야 합니다.

    setup.py를선호하는 텍스트 편집기로 엽니다 .

    일치하도록 maintainer, maintainer_email항목을편집합니다 .

    파일을 저장하는 것을 잊지 마십시오.

    노드 실행하기(launch)

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    대부분의 소개 자습서에서는 실행하는 모든 새 노드에 대해 새 터미널을 열었습니다. 점점 더 많은 노드가 동시에 실행되는 더 복잡한 시스템을 만들면 터미널을 열고 구성 세부 정보를 다시 입력하는 것이 지루해집니다.

    시작 파일을 사용하면 ROS 2 노드를 포함하는 여러 실행 파일을 동시에 시작하고 구성할 수 있습니다.

    ros2 launch 명령 으로 단일 시작 파일을 실행하면 전체 시스템(모든 노드 및 해당 구성)이 한 번에 시작됩니다.

    실습

    새 터미널을 열고 다음을 실행합니다.

    이 명령은 다음 시작 파일을 실행합니다.

    그러면 두 개의 turtlesim 노드가 실행됩니다.

    Turtlesim 노드 제어

    이제 이러한 노드가 실행 중이므로 다른 ROS 2 노드처럼 제어할 수 있습니다. 예를 들어 두 개의 추가 터미널을 열고 다음 명령을 실행하여 거북이가 반대 방향으로 운전하도록 할 수 있습니다.

    두 번째 터미널에서:

    세 번째 터미널에서:

    이 명령을 실행하면 다음과 같은 내용이 표시됩니다.

    간단한 서비스 및 클라이언트 작성

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    사용하여 통신 할 때 데이터 요청을 보내는 노드를 클라이언트 노드라고 하고 요청에 응답하는 노드를 서비스 노드라고 합니다. srv요청 및 응답의 구조는 파일에 의해 결정됩니다.

    여기에 사용된 예제는 간단한 정수 추가 시스템입니다. 한 노드는 두 정수의 합을 요청하고 다른 노드는 결과로 응답합니다.

    ros2 run turtlesim turtlesim_node
    ros2 run turtlesim turtle_teleop_key
    /clear
    /kill
    /reset
    /spawn
    /teleop_turtle/describe_parameters
    /teleop_turtle/get_parameter_types
    /teleop_turtle/get_parameters
    /teleop_turtle/list_parameters
    /teleop_turtle/set_parameters
    /teleop_turtle/set_parameters_atomically
    /turtle1/set_pen
    /turtle1/teleport_absolute
    /turtle1/teleport_relative
    /turtlesim/describe_parameters
    /turtlesim/get_parameter_types
    /turtlesim/get_parameters
    /turtlesim/list_parameters
    /turtlesim/set_parameters
    /turtlesim/set_parameters_atomically
    ros2 service type <service_name>
    ros2 service type /clear
    std_srvs/srv/Empty
    ros2 service list -t
    /clear [std_srvs/srv/Empty]
    /kill [turtlesim/srv/Kill]
    /reset [std_srvs/srv/Empty]
    /spawn [turtlesim/srv/Spawn]
    ...
    /turtle1/set_pen [turtlesim/srv/SetPen]
    /turtle1/teleport_absolute [turtlesim/srv/TeleportAbsolute]
    /turtle1/teleport_relative [turtlesim/srv/TeleportRelative]
    ...
    ros2 service find <type_name>
    ros2 service find std_srvs/srv/Empty
    /clear
    /reset
    ros2 interface show <type_name>.srv
    ros2 interface show std_srvs/srv/Empty.srv
    ---
    float32 x
    float32 y
    float32 theta
    string name # Optional.  A unique name will be created and returned if this is empty
    ---
    string name
    ros2 service call <service_name> <service_type> <arguments>
    ros2 service call /clear std_srvs/srv/Empty
    ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: ''}"
    requester: making request: turtlesim.srv.Spawn_Request(x=2.0, y=2.0, theta=0.2, name='')
    
    response:
    turtlesim.srv.Spawn_Response(name='turtle2')

    <package_name> 디렉토리에는 __init__.py이 포함됩니다.

    ROS 2 설치 소스를 찾습니다
    새 패키지에 대해 이전 자습서
    오픈 소스 라이선스에 대한 자세한 내용은 여기에서
    실습

    1. 패키지 생성

    ros2명령이 작동하도록 새 터미널을 열고 ROS 2 설치를 소싱합니다.

    이전 자습서 에서 만든 디렉터리 ros2_ws로 이동합니다 .

    패키지는 작업 영역의 루트가 아닌 src디렉터리 에 만들어야 한다는 점을 기억하십시오 . 새 패키지 로 이동하여 생성합니다.

    터미널은 패키지 py_srvcli와 필요한 모든 파일 및 폴더 생성을 확인하는 메시지를 반환합니다.

    인수 --dependencies는 필요한 종속성 줄을 package.xml에 자동으로 추가합니다. 요청 및 응답을 구조화하는 데 필요한example_interfaces 가포함된 패키지입니다 .

    처음 두 줄은 요청의 매개변수이고 대시 아래는 응답의입매개변수니입다.

    1.1 package.xml업데이트

    패키지 생성 중에 --dependencies이 옵션을 사용했기 때문에 수동으로 package.xml에 종속성을 추가할 필요가 없습니다.

    하지만 항상 그렇듯이 설명, 관리자 이메일, 이름, 라이선스 정보를 package.xml에 추가해야 합니다 .

    1.2 setup.py 업데이트

    setup.py파일에 동일한 정보를 추가 합니다

    2. 서비스 노드 쓰기

    ros2_ws/src/py_srvcli/py_srvcli디렉터리 내에서 service_member_function.py라는 새 파일을 만들고 다음 코드를 붙여넣습니다.

    2.1 코드 검토

    첫 번째 명령문import은 example_interfaces 패키지 에서 AddTwoInts서비스 유형을 가져옵니다 . 다음 명령문import은 ROS2 Python 클라이언트 라이브러리, 특히 Node클래스를 가져옵니다.

    클래스 MinimalService생성자는 minimal_service 노드를 초기화합니다. 그런 다음 서비스를 생성하고 유형, 이름 및 콜백을 정의합니다.

    서비스 콜백의 정의는 요청 데이터를 수신하고 합산하여 응답으로 반환합니다.

    마지막으로 메인 클래스는 ROS2 Python 클라이언트 라이브러리를 초기화하고 MinimalService클래스를 인스턴스화하여 서비스 노드를 생성하고 노드를 spin 시켜 콜백을 처리합니다.

    2.2 진입점 추가

    ros2 run명령이 노드를 실행하도록 허용하려면 진입점을 setup.py(ros2_ws/src/py_srvcli디렉토리에 있음 )에 추가해야 합니다.

    'console_scripts'대괄호 사이에 다음 줄을 추가합니다 :.

    3. 클라이언트 노드 작성하기

    ros2_ws/src/py_srvcli/py_srvcli디렉터리 내에서 client_member_function.py라는 새 파일을 만들고 다음 코드를 붙여넣습니다.

    3.1 코드 검토

    클라이언트에 대한 유일한 다른 코드는 import sys입니다 . 클라이언트 노드 코드는 sys.argv를 사용하여 요청에 대한 명령줄 입력 인수에 대한 액세스 권한을 얻습니다.

    생성자 정의는 서비스 노드와 동일한 유형 및 이름으로 클라이언트를 생성합니다. 유형과 이름은 클라이언트와 서비스가 통신할 수 있도록 일치해야 합니다.

    생성자의 루프 while는 클라이언트의 유형 및 이름과 일치하는 서비스가 1초에 한 번씩 사용 가능한지 확인합니다.

    생성자 아래에는 요청 정의와 main.

    클라이언트의 main 함수의유일한 중요한 차이점은 while루프 입니다. 루프는 시스템이 실행되는 동안 서비스의 응답이 있는지 future 변수를확인합니다. 서비스에서 응답을 보낸 경우 결과는 로그 메시지에 기록됩니다.

    3.2 진입점 추가

    서비스 노드와 마찬가지로 클라이언트 노드를 실행할 수 있도록 진입점도 추가해야 합니다.

    setup.py파일의 entry_points필드는 다음 과 같아야 합니다.

    4. 빌드 및 실행

    작업 공간의 루트( ros2_ws)에서 rosdep를실행하여 빌드하기 전에 누락된 종속성을 확인하는 것이 좋습니다 .

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

    새 터미널을 열고 로 이동하여 ros2_ws설정 파일을 찾습니다.

    이제 서비스 노드를 실행합니다.

    노드는 클라이언트의 요청을 기다립니다.

    다른 터미널을 열고 ros2_ws내부에서 설정 파일을 다시 소싱합니다. 클라이언트 노드를 시작하고 그 뒤에 공백으로 구분된 두 개의 정수를 입력합니다.

    클라이언트는 다음과 같은 응답을 받습니다.

    서비스 노드가 실행 중인 터미널로 돌아갑니다. 요청을 받았을 때 로그 메시지를 게시한 것을 볼 수 있습니다.

    노드가 더이상하 spin 하지 않도록 서버 터미널에 Ctrl+C입력하십시오 .

    노드가
    서비스를
    ros2 run turtlesim turtlesim_node
    ros2 run turtlesim turtle_teleop_key
    mkdir bag_files
    cd bag_files
    ros2 topic list
    /parameter_events
    /rosout
    /turtle1/cmd_vel
    /turtle1/color_sensor
    /turtle1/pose
    ros2 topic echo /turtle1/cmd_vel
    linear:
      x: 2.0
      y: 0.0
      z: 0.0
    angular:
      x: 0.0
      y: 0.0
      z: 0.0
      ---
    ros2 bag record <topic_name>
    ros2 bag record /turtle1/cmd_vel
    [INFO] [rosbag2_storage]: Opened database 'rosbag2_2019_10_11-05_18_45'.
    [INFO] [rosbag2_transport]: Listening for topics...
    [INFO] [rosbag2_transport]: Subscribed to topic '/turtle1/cmd_vel'
    [INFO] [rosbag2_transport]: All requested topics are subscribed. Stopping discovery...
    ros2 bag record -o subset /turtle1/cmd_vel /turtle1/pose
    [INFO] [rosbag2_storage]: Opened database 'subset'.
    [INFO] [rosbag2_transport]: Listening for topics...
    [INFO] [rosbag2_transport]: Subscribed to topic '/turtle1/cmd_vel'
    [INFO] [rosbag2_transport]: Subscribed to topic '/turtle1/pose'
    [INFO] [rosbag2_transport]: All requested topics are subscribed. Stopping discovery...
    ros2 bag info <bag_file_name>
    ros2 bag info subset
    Files:             subset.db3
    Bag size:          228.5 KiB
    Storage id:        sqlite3
    Duration:          48.47s
    Start:             Oct 11 2019 06:09:09.12 (1570799349.12)
    End                Oct 11 2019 06:09:57.60 (1570799397.60)
    Messages:          3013
    Topic information: Topic: /turtle1/cmd_vel | Type: geometry_msgs/msg/Twist | Count: 9 | Serialization Format: cdr
                     Topic: /turtle1/pose | Type: turtlesim/msg/Pose | Count: 3004 | Serialization Format: cdr
    ros2 bag play subset
    [INFO] [rosbag2_storage]: Opened database 'subset'.
    ros2 topic hz /turtle1/pose
    my_package/
         CMakeLists.txt
         package.xml
    my_package/
          setup.py
          package.xml
          resource/my_package 
    workspace_folder/
        src/
          package_1/
              CMakeLists.txt
              package.xml
    
          package_2/
              setup.py
              package.xml
              resource/package_2
          ...
          package_n/
              CMakeLists.txt
              package.xml
    cd ~/ros2_ws/src
    ros2 pkg create --build-type ament_python --node-name my_node my_package
    going to create a new package
    package name: my_package
    destination directory: /home/user/ros2_ws/src
    package format: 3
    version: 0.0.0
    description: TODO: Package description
    maintainer: ['<name> <email>']
    licenses: ['TODO: License declaration']
    build type: ament_python
    dependencies: []
    node_name: my_node
    creating folder ./my_package
    creating ./my_package/package.xml
    creating source folder
    creating folder ./my_package/my_package
    creating ./my_package/setup.py
    creating ./my_package/setup.cfg
    creating folder ./my_package/resource
    creating ./my_package/resource/my_package
    creating ./my_package/my_package/__init__.py
    creating folder ./my_package/test
    creating ./my_package/test/test_copyright.py
    creating ./my_package/test/test_flake8.py
    creating ./my_package/test/test_pep257.py
    creating ./my_package/my_package/my_node.py
    cd ~/ros2_ws
    colcon build
    colcon build --packages-select my_package
    source install/local_setup.bash
    ros2 run my_package my_node
    Hi from my_package.
    my_package  package.xml  resource  setup.cfg  setup.py  test
    <?xml version="1.0"?>
    <?xml-model
       href="http://download.ros.org/schema/package_format3.xsd"
       schematypens="http://www.w3.org/2001/XMLSchema"?>
    <package format="3">
     <name>my_package</name>
     <version>0.0.0</version>
     <description>TODO: Package description</description>
     <maintainer email="user@todo.todo">user</maintainer>
     <license>TODO: License declaration</license>
    
     <test_depend>ament_copyright</test_depend>
     <test_depend>ament_flake8</test_depend>
     <test_depend>ament_pep257</test_depend>
     <test_depend>python3-pytest</test_depend>
    
     <export>
       <build_type>ament_python</build_type>
     </export>
    </package>
    <description>Beginner client libraries tutorials practice package</description>
    <license>Apache License 2.0</license>
    from setuptools import setup
    
    package_name = 'my_py_pkg'
    
    setup(
     name=package_name,
     version='0.0.0',
     packages=[package_name],
     data_files=[
         ('share/ament_index/resource_index/packages',
                 ['resource/' + package_name]),
         ('share/' + package_name, ['package.xml']),
       ],
     install_requires=['setuptools'],
     zip_safe=True,
     maintainer='TODO',
     maintainer_email='TODO',
     description='TODO: Package description',
     license='TODO: License declaration',
     tests_require=['pytest'],
     entry_points={
         'console_scripts': [
                 'my_node = my_py_pkg.my_node:main'
         ],
       },
    )
    ros2 launch turtlesim multisim.launch.py
    # turtlesim/launch/multisim.launch.py
    
    from launch import LaunchDescription
    import launch_ros.actions
    
    def generate_launch_description():
        return LaunchDescription([
            launch_ros.actions.Node(
                namespace= "turtlesim1", package='turtlesim', executable='turtlesim_node', output='screen'),
            launch_ros.actions.Node(
                namespace= "turtlesim2", package='turtlesim', executable='turtlesim_node', output='screen'),
        ])
    메모
    
    위의 실행 파일은 Python으로 작성되었지만 XML 및 YAML을 사용하여 실행 파일을 만들 수도 있습니다. Using Python, XML, and YAML for ROS 2 Launch Files 에서 다양한 ROS 2 실행 형식을 비교할 수 있습니다 .
    ros2 topic pub  /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
    ros2 topic pub  /turtlesim2/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}"
    ros2 pkg create --build-type ament_python py_srvcli --dependencies rclpy example_interfaces
    int64 a
    int64 b
    ---
    int64 sum
    <description>Python client server tutorial</description>
    <maintainer email="you@email.com">Your Name</maintainer>
    <license>Apache License 2.0</license>
    maintainer='Your Name',
    maintainer_email='you@email.com',
    description='Python client server tutorial',
    license='Apache License 2.0',
    from example_interfaces.srv import AddTwoInts
    
    import rclpy
    from rclpy.node import Node
    
    
    class MinimalService(Node):
    
        def __init__(self):
            super().__init__('minimal_service')
            self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
    
        def add_two_ints_callback(self, request, response):
            response.sum = request.a + request.b
            self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
    
            return response
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_service = MinimalService()
    
        rclpy.spin(minimal_service)
    
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    from example_interfaces.srv import AddTwoInts
    
    import rclpy
    from rclpy.node import Node
    def __init__(self):
        super().__init__('minimal_service')
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
    def add_two_ints_callback(self, request, response):
        response.sum = request.a + request.b
        self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
    
        return response
    'service = py_srvcli.service_member_function:main',
    import sys
    
    from example_interfaces.srv import AddTwoInts
    import rclpy
    from rclpy.node import Node
    
    
    class MinimalClientAsync(Node):
    
        def __init__(self):
            super().__init__('minimal_client_async')
            self.cli = self.create_client(AddTwoInts, 'add_two_ints')
            while not self.cli.wait_for_service(timeout_sec=1.0):
                self.get_logger().info('service not available, waiting again...')
            self.req = AddTwoInts.Request()
    
        def send_request(self, a, b):
            self.req.a = a
            self.req.b = b
            self.future = self.cli.call_async(self.req)
            rclpy.spin_until_future_complete(self, self.future)
            return self.future.result()
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_client = MinimalClientAsync()
        response = minimal_client.send_request(int(sys.argv[1]), int(sys.argv[2]))
        minimal_client.get_logger().info(
            'Result of add_two_ints: for %d + %d = %d' %
            (int(sys.argv[1]), int(sys.argv[2]), response.sum))
    
        minimal_client.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    entry_points={
        'console_scripts': [
            'service = py_srvcli.service_member_function:main',
            'client = py_srvcli.client_member_function:main',
        ],
    },
    rosdep install -i --from-path src --rosdistro humble -y
    colcon build --packages-select py_srvcli
    source install/setup.bash
    ros2 run py_srvcli service
    ros2 run py_srvcli client 2 3
    [INFO] [minimal_client_async]: Result of add_two_ints: for 2 + 3 = 5
    [INFO] [minimal_service]: Incoming request
    a: 2 b: 3

    사용자 정의 msg 및 srv 파일 생성

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    이전 자습서에서는 메시지 및 서비스 인터페이스를 활용하여 주제 , 서비스 , 간단한 게시자/구독자( C++ / Python ) 및 서비스/클라이언트( C++ / Python ) 노드 에 대해 배웠습니다 . 이러한 경우에 사용한 인터페이스는 미리 정의되어 있습니다.

    미리 정의된 인터페이스 정의를 사용하는 것이 좋지만 때로는 자체 메시지와 서비스를 정의해야 할 수도 있습니다. 이 자습서에서는 사용자 지정 인터페이스 정의를 만드는 가장 간단한 방법을 소개합니다.

    이 자습서는 게시자/구독자( C++ 및 Python ) 및 서비스/클라이언트( C++ 및 Python ) 자습서에서 생성된 패키지를 사용하여 새 사용자 지정 메시지를 시험해 봅니다.

    실습

    1. 새 패키지 만들기

    이 자습서에서는 자체 패키지에 사용자 지정 .msg및.srv 파일을 만든 다음 별도의 패키지에서 활용합니다. 두 패키지는 동일한 작업 공간에 있어야 합니다.

    이전 자습서에서 만든 pub/sub 및 service/client 패키지를 사용하므로 해당 패키지( ros2_ws/src)와 동일한 작업 공간에 있는지 확인한 후 다음 명령을 실행하여 새 패키지를 만듭니다.

    tutorial_interfaces는새 패키지의 이름입니다. 이는 CMake 패키지이며 패키지일 수 있지만 메시지 및 서비스를 사용할 수 있는 패키지 유형을 제한하지는 않습니다. CMake 패키지에서 고유한 사용자 지정 인터페이스를 만든 다음 마지막 섹션에서 다룰 C++ 또는 Python 노드에서 사용할 수 있습니다.

    .msg및 .srv파일 은 각각 및 msg srv라는 디렉토리에 배치해야 합니다 . 다음 위치에 디렉토리를 생성합니다 .ros2_ws/src/tutorial_interfaces

    2. 사용자 지정 정의 만들기

    2.1 메시지 정의

    방금 만든 tutorial_interfaces/msg디렉터리 에서 데이터 구조를 선언하는 한 줄의 코드로 호출되는 새 파일Num.msg을 만듭니다.

    이것은 num이라는 단일 64비트 정수를 전송하는 사용자 지정 메시지입니다.

    또한 방금 만든 tutorial_interfaces/msg디렉토리 에서 다음 내용으로 호출되는 새 파일Sphere.msg을 만듭니다.

    이 사용자 지정 메시지는 다른 메시지 패키지( 이 경우geometry_msgs/Point) 의 메시지를 사용합니다 .

    2.2 서비스 정의

    방금 만든 tutorial_interfaces/srv디렉터리로 돌아가서 다음 요청 및 응답 구조로 호출되는 새 파일AddThreeInts.srv을 만듭니다.

    이것은a ,b,c및 라는 세 개의 정수를 요청하고, sum정수로 응답하는 사용자 지정 서비스입니다.

    3. CMakeLists.txt

    정의한 인터페이스를 해당 언어에서 사용할 수 있도록 언어별 코드(예: C++ 및 Python)로 변환하려면 다음 행을 CMakeLists.txt에 추가하십시오.

    참고

    rosidl_generate_interfaces의 첫 번째 인수(라이브러리 이름)는 ${PROJECT_NAME}과 일치해야 합니다( 참조 ).

    4. package.xml

    인터페이스는 언어별 코드를 생성하는데 의존하므로 이에 대한 빌드 도구 종속성을 선언해야 합니다. rosidl_default_generators rosidl_default_runtime은나중에 인터페이스를 사용하는 데 필요한 런타임 또는 실행 단계 종속성입니다. rosidl_interface_packages는 <member_of_group>태그를 사용하여 선언된 tutorial_interfaces패키지가 연결되어야 하는 종속성 그룹의 이름입니다 .

    package.xml의 <package>요소 내에 다음 줄을 추가합니다 .

    5. tutorial_interfaces 패키지 빌드

    이제 사용자 정의 인터페이스 패키지의 모든 부분이 준비되었으므로 패키지를 빌드할 수 있습니다. 작업 영역(~/ros2_ws)의 루트에서 다음 명령을 실행합니다.

    이제 다른 ROS2 패키지에서 인터페이스를 검색할 수 있습니다.

    6. msg 및 srv 생성 확인

    새 터미널에서 작업 공간(ros2_ws) 내에서 다음 명령을 실행하여 소싱합니다.

    이제 다음 명령ros2 interface show을 사용하여 인터페이스 생성이 작동했는지 확인할 수 있습니다 .

    다음을 반환해야 합니다.

    그리고

    다음을 반환해야 합니다.

    그리고

    다음을 반환해야 합니다.

    7. 새 인터페이스 테스트

    이 단계에서는 이전 자습서에서 만든 패키지를 사용할 수 있습니다. CMakeLists.txt와 package.xml파일에 대한 몇 가지 간단한 수정으로 새 인터페이스를 사용할 수 있습니다.

    7.1 pub/sub를 사용한 Num.msg테스트

    또는 ) 에서 만든 게시자/구독자 패키지를 약간 수정하면 Num.msg실제로 작동하는 것을 볼 수 있습니다 . 표준 문자열 msg를 숫자로 변경하기 때문에 출력이 약간 다를 것입니다.

    발행자(Publisher)

    구독자(Subscriber)

    CMakeLists.txt

    다음 줄을 추가합니다(C++만 해당).

    package.xml

    위의 편집을 수행하고 모든 변경 사항을 저장한 후 패키지를 빌드합니다.

    그런 다음 두 개의 새 터미널을 열고 각각 source 를 입력하고 다음을 실행합니다.

    정수만 릴레이 하므로 talker는 이전에 게시한 문자열과 달리 정수 Num.msg값만 게시해야 합니다.

    7.2 서비스/클라이언트 AddThreeInts.srv테스트

    또는 ) 에서 만든 서비스/클라이언트 AddThreeInts.srv패키지를 약간 수정하면 실제로 작동하는 것을 볼 수 있습니다 . 원래의 2개 정수 요청 srv를 3개 정수 요청 srv로 변경할 것이므로 출력이 약간 다를 것입니다.

    서비스

    클라이언트

    package.xml

    다음 줄을 추가합니다.

    위의 편집을 수행하고 모든 변경 사항을 저장한 후 패키지를 빌드합니다.

    그런 다음 두 개의 새 터미널을 열고 각각 source ros2_ws를 입력하고 다음을 실행합니다.

    작업공간 만들기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    작업 공간은 ROS2 패키지를 포함하는 디렉토리입니다. ROS2를 사용하기 전에 작업하려는 터미널에서 ROS2 작업 공간을 소싱해야 합니다. 이렇게 하면 해당 터미널에서 ROS2 패키지를 사용할 수 있습니다.

    확장하려는 기존 ROS2 작업 공간 또는 "언더레이"를 방해하지 않고 새 패키지를 추가할 수 있는 보조 작업 공간인 "오버레이"를 소싱하는 옵션도 있습니다. 언더레이는 오버레이에 있는 모든 패키지의 종속성을 포함해야 합니다. 오버레이의 패키지는 언더레이의 패키지를 재정의합니다. 상위 언더레이의 패키지를 사용하는 각 연속 오버레이와 함께 여러 레이어의 언더레이 및 오버레이를 가질 수도 있습니다.

    실습

    1. ROS2 환경 소싱

    기본 ROS 2 설치가 이 튜토리얼의 기반이 됩니다. (언더레이가 반드시 기본 ROS2 설치일 필요는 없음을 명심하십시오.)

    (소스 또는 바이너리에서) ROS2를 설치한 방법과 사용 중인 플랫폼에 따라 정확한 소스 명령이 달라집니다.

    이러한 명령이 작동하지 않는 경우 따랐던 참조하십시오.

    2. 새 디렉토리 생성

    모범 사례는 모든 새 작업 공간에 대해 새 디렉터리를 만드는 것입니다. 이름은 중요하지 않지만 작업 공간의 용도를 나타내면 유용합니다.

    또 다른 모범 사례는 작업 공간에 있는 모든 패키지를 src디렉토리에 넣는 것입니다. 위의 코드는 ros2_ws내부에 디렉토리를 생성한 다음 해당 src디렉토리로 이동합니다.

    3. 샘플 리포지토리 복제

    복제하기 전에 아직 ros2_ws/src 디렉토리에 있는지 확인하십시오 .

    초보자 개발자 자습서의 나머지 부분에서는 고유한 패키지를 만들지만 지금은 기존 패키지를 사용하여 작업 공간을 함께 배치하는 연습을 하게 됩니다.

    자습서를 살펴본 경우 의 패키지 중 하나 인 turtlesim에 익숙할 것입니다 .

    리포지토리에는 여러 분기가 있을 수 있습니다. 설치된 ROS 2 배포판을 대상으로 하는 것을 확인해야 합니다. 이 리포지토리를 복제할 때 -b 인수 뒤에 해당 분기를 추가합니다.

    디렉터리 ros2_ws/src에서 다음 명령을 실행합니다.

    이제 ros_tutorials작업 공간에 복제됩니다. ros_tutorials리포지토리 에는 이 자습서의 나머지 부분에서 사용할 turtlesim패키지가 포함되어 있습니다 . 이 저장소의 다른 패키지는COLCON_IGNORE 파일 을 포함하고 있기 때문에 빌드되지 않습니다.

    지금까지 샘플 패키지로 작업공간을 채웠지만 아직 완전한 기능을 갖춘 작업공간은 아닙니다. 먼저 종속성을 해결한 다음 작업 영역을 빌드해야 합니다.

    4. 종속성 해결

    작업 영역을 빌드하기 전에 패키지 종속성을 해결해야 합니다. 모든 종속성이 이미 있을 수 있지만 모범 사례는 복제할 때마다 종속성을 확인하는 것입니다. 종속성이 누락되었음을 깨닫기 위해 오랜 시간을 기다린 후 빌드가 실패하는 것을 원하지 않을 것입니다.

    작업공간(ros2_ws )의 루트에서 다음 명령을 실행하십시오.

    소스 또는 "fat" 아카이브에서 Linux에 ROS2를 설치한 경우 설치 지침에서 rosdep 명령을 사용해야 합니다. 과 입니다 .

    이미 모든 종속성이 있는 경우 콘솔에서 다음을 반환합니다.

    패키지는 package.xml 파일에서 종속성을 선언합니다(다음 자습서에서 패키지에 대해 자세히 알아볼 것입니다). 이 명령은 해당 선언을 살펴보고 누락된 선언을 설치합니다. rosdep는다른 튜토리얼(출시 예정)에서 자세히 알아볼 수 있습니다 .

    rosdep

    rosdep은 ROS2 작업공간 안의 소스에 빌드에 필요한 종속성을 자동으로 설치하는 유용한 툴 입니다.

    최초 실행시 다음과 같이 초기와 작업을 수행해 주어야 합니다.

    5. colcon 으로 작업공간 구축

    이제 작업 공간의 루트( ros2_ws)에서 다음 명령을 사용하여 패키지를 빌드할 수 있습니다.

    콘솔은 다음 메시지를 반환합니다.

    메모

    colcon build다음에 대한 기타 유용한 인수 :

    • --packages-up-to원하는 패키지와 모든 종속성을 빌드하지만 전체 작업 공간은 빌드하지 않음(시간 절약)

    • --symlink-install파이썬 스크립트를 조정할 때마다 다시 빌드하지 않아도 됩니다.

    • --event-handlers console_direct+빌드하는 동안 콘솔 출력을 보여줍니다(그렇지 않으면 디렉토리에서 찾을 수 있음 log).

    빌드가 완료되면 ls를작업 공간 루트( ~/ros2_ws)에서 입력하면 colcon이 새 디렉토리를 생성한 것을 볼 수 있습니다.

    이 install디렉토리는 오버레이를 소싱하는 데 사용할 수 있는 작업 공간의 설정 파일이 있는 곳입니다.

    6. 오버레이 소싱

    오버레이를 소싱하기 전에 작업 공간을 구축한 터미널과 별도로 새 터미널을 여는 것이 매우 중요합니다. 빌드한 동일한 터미널에서 오버레이를 소싱하거나 마찬가지로 오버레이가 소싱된 위치에서 빌드하면 복잡한 문제가 발생할 수 있습니다.

    새 터미널에서 기본 ROS2 환경을 "언더레이"로 소싱하여 "위에" 오버레이를 구축할 수 있습니다.

    작업 공간의 루트로 이동합니다.

    루트에서 오버레이를 소싱합니다.

    그러나 이것이 메인 설치의 turtlesim이 아니라 오버레이 turtlesim이 실행되고 있다는 것을 어떻게 알 수 있습니까?

    효과를 볼 수 있도록 오버레이에서 turtlesim을 수정해 보겠습니다.

    • 언더레이와 별도로 오버레이에서 패키지를 수정하고 다시 빌드할 수 있습니다.

    • 오버레이는 언더레이보다 우선합니다.

    7. 오버레이 수정

    Turtlesim 창의 제목 표시줄을 편집하여 오버레이에서 turtlesim을수정할 수 있습니다 . 이렇게 하려면~/ros2_ws/src/ros_tutorials/turtlesim/src 에서 turtle_frame.cpp파일을 찾습니다 . 선호하는 텍스트 편집기로 turtle_frame.cpp 파일을엽니다 .

    52행에서 setWindowTitle("TurtleSim");함수를 볼 수 있습니다 . "TurtleSim"값을 "MyTurtleSim"로 변경 하고 파일을 저장합니다.

    이전에 실행한 첫 번째 터미널로 돌아가서 colcon build다시 실행합니다.

    두 번째 터미널(오버레이 소스)로 돌아가서 turtlesim을 다시 실행합니다.

    이제 Turtlesim 창의 제목 표시줄에 "MyTurtleSim"이 표시됩니다.

    기본 ROS2 환경이 이전에 이 터미널에서 소싱되었지만 ros2_ws환경의 오버레이가 언더레이의 내용보다 우선합니다.

    언더레이가 여전히 손상되지 않았는지 확인하려면 새 터미널을 열고 ROS 2 설치만 소싱하십시오. Turtlesim을 다시 실행하십시오

    오버레이의 수정 사항이 실제로 언더레이의 어떤 항목에도 영향을 미치지 않았음을 확인할 수 있습니다.

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

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

    개요

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

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

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

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

    파라메터 사용하기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    개요

    자체 만들 때 때때로 시작 파일에서 설정할 수 있는 매개변수를 추가해야 합니다.

    이 자습서에서는 Python 클래스에서 이러한 매개 변수를 생성하는 방법과 시작 파일에서 매개 변수를 설정하는 방법을 보여줍니다.

    간단한 게시자와 구독자 노드 만들기

    저작권: 쿼드(QUAD) 드론연구소 https://smartstore.naver.com/maponarooo

    토픽을 통해 문자열 메시지 형식으로 정보를 서로 전달하는 만듭니다 . 여기에 사용된 예는 간단한 "talker" 및 "listener" 시스템입니다. 한 노드는 데이터를 게시하고 다른 노드는 해당 데이터를 받을 수 있도록 주제를 구독합니다.

    이 예제에 사용된 코드는 찾을 수 있습니다 .

    실습

    https://github.com/ros2/rosidl/issues/441#issuecomment-591025515
    이전 자습서( C++
    Python
    이전 자습서( C++
    Python
    설치 가이드를
    초보자: CLI 도구
    ros_tutorials
    다음은 원본 rosdep 섹션
    "fat" 아카이브 rosdep 섹션
    실습

    1. 패키지 생성

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

    2. 메시지 파일 생성

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

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

    • first_name: 문자열 유형

    • last_name: 문자열 유형

    • phone_number: 문자열 유형

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

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

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

    2.1 msg 파일 빌드

    package.xml다음 줄을 열고 추가합니다.

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

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

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

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

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

    메시지를 생성합니다.

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

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

    2.2 다중 인터페이스 설정

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

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

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

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

    more_interfaces/src 아래에 publish_address_book.cpp라는 파일을 만들고 다음 코드를 붙여 넣습니다.

    3.1 코드 설명

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

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

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

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

    AddressBook필드를 채웁니다.

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

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

    3.2 게시자 빌드

    CMakeLists.txt에서 이 노드에 대한 새 대상을 생성해야 합니다.

    3.3 인터페이스에 대한 링크

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

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

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

    4. 실행

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

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

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

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

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

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

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

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

    그리고 CMakeLists.txt:

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

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

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

    이전 자습서
    ament_cmake_python
    실습

    1. 패키지 생성

    ros2명령이 작동하도록 새 터미널을 열고 ROS2 환경을 소싱합니다.

    패키지는 작업 영역의 루트가 아닌 src디렉터리 에 만들어야 한다는 점을 기억하십시오 . 새 패키지를 ros2_ws/src로 이동하여 생성합니다.

    터미널은 패키지 python_parameters와 필요한 모든 파일 및 폴더 생성을 확인하는 메시지를 반환합니다.

    인수 --dependencies는 필요한 종속성 줄을 package.xml및 CMakeLists.txt에 자동으로 추가합니다 .

    1.1 업데이트

    패키지 생성 중에 이 --dependencies옵션을 사용했으므로 수동으로 package.xml또는 CMakeLists.txt에 종속성을 추가할 필요가 없습니다 .

    하지만 항상 그렇듯이 설명, 관리자 이메일, 이름, 라이선스 정보를 에 추가해야 합니다 package.xml.

    2. Python 노드 작성

    ros2_ws/src/python_parameters디렉터리 내에서 python_parameters_node.py라는 새 파일을 만들고 다음 코드를 붙여넣습니다.

    2.1 코드 검토

    상단의 import명령문은 패키지 종속성을 가져오는 데 사용됩니다 .

    다음 코드는 클래스와 생성자를 만듭니다. 생성자의 행은 이름 과 기본값이 인 매개변수를 생성합니다 . 매개변수 유형은 기본값에서 유추되므로 이 경우 문자열 유형으로 설정됩니다. self.declare_parameter('my_parameter', 'world')다음으로 초기화되어 함수 my_parameterworldtimertimer_callback가 1초에 한 번 실행됩니다.

    timer_callback함수 의 첫 번째 줄은 노드에서 매개변수를 가져 와서 에 저장합니다. 다음으로 함수는 이벤트가 기록되는지 확인합니다. 그런 다음 함수 는 my_parameter매개변수를 다시 기본 문자열 값으로 설정합니다 . 사용자가 매개변수를 외부에서 변경한 경우 항상 원래대로 재설정 되도록 합니다.

    다음은 우리의main입니다 . 여기에서 ROS2가 초기화되고 MinimalParam클래스의 node 인스턴스가 구성되며 노드에서 데이터 처리를 시작합니다.

    2.1.1 파라메터 설명자 추가

    선택적으로 매개변수에 대한 설명자를 설정할 수 있습니다. 디스크립터를 사용하면 매개변수에 대한 텍스트 설명과 읽기 전용으로 설정, 범위 지정 등과 같은 제약 조건을 지정할 수 있습니다. 작동하려면 __init__코드를 다음과 같이 변경해야 합니다.

    나머지 코드는 동일하게 유지됩니다. /minimal_param_node노드를 실행하면 my_parameter유형 및 설명을 보기 위해 실행할 수 있습니다.

    2. 진입점 추가

    package.xml, setup.py파일을 엽니다 . 다시 description, maintainer,license및 maintainer_email필드 를 다음과 일치시킵니다 .

    entry_points필드 console_scripts의 대괄호 안에 다음 줄을 추가합니다 .

    저장하는 것을 잊지 마십시오.

    3. 빌드 및 실행

    rosdep작업 공간의 루트( ros2_ws)에서 실행하여 빌드하기 전에 누락된 종속성을 확인하는 것이 좋습니다 .

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

    새 터미널을 열고 ros2_ws로 이동하여 설정 파일을 소싱합니다.

    이제 노드를 실행합니다.

    터미널은 매초 다음 메시지를 반환해야 합니다.

    이제 매개변수의 기본값을 볼 수 있지만 직접 설정할 수 있기를 원합니다. 이를 수행하는 방법에는 두 가지가 있습니다.

    3.1 콘솔을 통한 변경

    이 부분에서는 매개변수에 대한 자습서 에서 얻은 지식을 사용 하고 방금 만든 노드에 적용합니다.

    노드가 실행 중인지 확인합니다.

    다른 터미널을 열고 ROS2 환경을 다시 소싱한 후 다음 행을 입력하십시오.

    거기에 맞춤 매개변수my_parameter가 표시됩니다 . 이를 변경하려면 콘솔에서 다음 행을 실행하십시오.

    출력을 얻을 경우 잘 실행되었다는 것을 알고 있습니다 . 다른 터미널을 보면 출력이 다음으로 변경되는 것을 볼 수 있습니다.Set parameter successful[INFO] [minimal_param_node]: Hello earth!

    나중에 노드가 매개변수를 다시 world로 설정하므로 추가 출력이 표시됩니다. [INFO] [minimal_param_node]: Hello world!

    3.2 런치 파일을 통한 변경

    시작 파일에서 매개변수를 설정할 수도 있지만 먼저 시작 디렉터리를 추가해야 합니다. ros2_ws/src/python_parameters/디렉토리 안에 launch이라는 새 디렉토리를 만듭니다. 거기에 python_parameters_launch.py라는 새 파일을 만듭니다.

    아래 두 줄을 추가하여 출력이 콘솔에 출력되도록 합니다.

    이제 setup.py파일을 엽니다. 파일 맨 위에 import명령문을 추가 하고 모든 실행 파일을 포함하도록 다른 새 명령문을 data_files매개변수에 추가하십시오.

    콘솔을 열고 작업 공간의 루트ros2_ws로 이동하여 새 패키지를 빌드합니다.

    그런 다음 새 터미널에서 설정 파일을 소싱합니다.

    이제 방금 만든 실행 파일을 사용하여 노드를 실행합니다.

    터미널은 매초 다음 메시지를 반환해야 합니다.

    노드를
    1. 패키지 생성

    명령이 작동하도록 새 터미널을 열고 ROS 2 설치를 소싱합니다 .ros2

    이전 자습서에서 만든 ros2_ws 디렉터리 로 이동합니다 .

    패키지는 작업 영역의 루트가 아닌 src디렉터리 에 만들어야 한다는 점을 기억하십시오. 따라서 ros2_ws/src로 이동하여 패키지 생성 명령을 실행합니다.

    터미널은 패키지 py_pubsub와 필요한 모든 파일 및 폴더 생성을 확인하는 메시지를 반환합니다.

    2. 게시자 노드 작성하기

    ros2_ws/src/py_pubsub/py_pubsub로 이동합니다. 이 디렉터리는 중첩된 ROS2 패키지와 이름이 같은 Python 패키지 라는 점을 기억하세요.

    다음 명령을 입력하여 예제 Talker 코드를 다운로드합니다.

    이제 __init__.py인접한 이름의 새 파일 publisher_member_function.py 가 생긴걸 볼 수 있습니다.

    원하는 텍스트 편집기를 사용하여 파일을 엽니다.

    2.1 코드 검토

    주석 import 이후의 첫 번째 코드 줄은 rclpy의 Node클래스를 사용할 수 있도록 합니다.

    다음 명령문은 노드가 주제에서 전달하는 데이터를 구조화하는 데 사용하는 기본 제공 문자열 메시지 유형을 가져옵니다.

    이들은 라인들은 노드의 종속성을 나타냅니다. package.xml에 종속성을 추가해야 하며 다음 섹션에서 수행할 것임을 기억하십시오.

    다음으로 MinimalPublisher에서 상속하는(또는 하위 클래스인) Node클래스가 생성됩니다.

    다음은 클래스 생성자의 정의입니다. super().__init__은 Node클래스의 생성자를 호출하고 여기에 노드 이름(minimal_publisher)을 제공합니다

    create_publisher를 통해 String 유형의 메시지를 게시 하고 "대기열 크기"가 10인 토픽을 선언합니다. 대기열 크기는 구독자가 빠르게 처리하지 못할 경우를 대비해 준비할 메세지의 양을 제한하는 필수 QoS(서비스 품질) 설정입니다.

    다음으로 0.5초마다 실행되는 콜백과 함께 타이머가 생성됩니다. self.i는 콜백에 사용되는 카운터입니다.

    timer_callback는 카운터 값이 추가된 메시지를 0.5초 마다 생성 합니다. self.i는 콜백에 사용되는 카운터 입니다.

    마지막으로 main 함수를 정의합니다.

    먼저 rclpy라이브러리가 초기화되고 minimal_publisher 노드가 생성된 다음 콜백이 호출되도록 노드를 "spin" 합니다.

    2.2 종속성 추가

    setup.py, setup.cfg 그리고 package.xml 파일이 있는 ros2_ws/src/py_pubsub 디렉토리로 이동 합니다.

    package.xml 파일을 편집기로엽니다.

    이전 튜토리얼 에서 언급했듯이 <description>, <maintainer>및 <license>태그를 입력해야 합니다.

    위 줄 뒤에 노드의 가져오기 문에 해당하는 다음 종속성을 추가합니다.

    이것은 해당 코드가 실행되는 시기에 rclpy과 std_msgs 가 필요함을 선언합니다.

    파일을 저장하십시오.

    2.3 진입점 추가

    setup.py 파일을 편집기로 엽니다. 다시한번 package.xml 파일의 maintainer, maintainer_email, description ,license 필드를 확인 합니다.

    entry_points필드의 console_scripts 대괄호 안에 다음 줄을 추가합니다 .

    저장하는 것을 잊지 마십시오.

    2.4 setup.cfg 확인

    setup.cfg파일의 내용은 다음과 같이 자동으로 올바르게 채워져야 합니다.

    이것은 단순히 setuptools에게 ros2 run실행 파일을 찾기 위해 lib에 넣도록 지시하는 것 입니다 .

    지금 패키지를 빌드하고 로컬 설정 파일을 소싱하여 실행할 수 있지만 작업 중인 전체 시스템을 볼 수 있도록 구독자 노드를 먼저 생성해 보겠습니다.

    3. 구독자 노드 작성하기

    구독자 노드를 생성하려면 ros2_ws/src/py_pubsub/py_pubsub로 돌아갑니다 . 터미널에 다음 코드를 입력하십시오.

    이제 디렉토리에 다음 파일이 있어야 합니다.

    3.1 코드 검토

    subscriber_member_function.py을 텍스트 편집기로 를 엽니다.

    구독자 노드의 코드는 게시자의 코드와 거의 동일합니다. 생성자는 게시자와 동일한 인수를 사용하여 구독자를 만듭니다. 주제 자습서 에서 게시자와 구독자가 사용하는 주제 이름과 메시지 유형이 서로 통신할 수 있도록 일치해야 한다는 점을 상기하십시오.

    구독자의 생성자와 콜백에는 타이머 정의가 필요하지 않기 때문에 타이머 정의가 포함되어 있지 않습니다. 콜백은 메시지를 받자마자 호출됩니다.

    콜백 정의는 수신한 데이터와 함께 정보 메시지를 콘솔에 간단히 인쇄합니다. 게시자가 정의하는 것을 기억하십시오.msg.data = 'Hello World: %d' % self.i

    정의 main 은 거의 동일하며 게시자의 생성 및 spin 대상을 구독자로 대체합니다.

    이 노드는 게시자와 동일한 종속성을 가지므로 package.xml에 새로 추가할 항목이 없습니다. 파일 setup.cfg은 그대로 유지될 수도 있습니다.

    3.2 진입점 추가

    게시자의 진입점 아래에 구독자 노드에 대한 진입점을 setup.py를다시 열고 추가합니다. 이제 필드 entry_points는 다음과 같이 표시됩니다.

    파일을 저장했는지 확인하면 게시/구독 시스템이 준비 완료됩니다.

    4. 빌드 및 실행

    ROS2 시스템의 일부로 이미 rclpy및 패키지가 설치되어 있을 수 있습니다. 작업 공간의 루트(ros2_ws )에서 rosdep를 실행하여 빌드하기 전에 누락된 종속성을 확인하는 것이 좋습니다.

    작업 공간의 루트ros2_ws에서 새 패키지를 빌드합니다.

    새 터미널을 열고 ros2_ws로 이동하여 설정 파일을 소싱합니다.

    이제 talker 노드를 실행합니다.

    터미널은 다음과 같이 0.5초마다 정보 메시지 게시를 시작해야 합니다.

    다른 터미널을 열고 ros2_ws내부에서 설정 파일을 다시 소싱한 다음 리스너 노드를 시작합니다.

    리스너는 다음과 같이 해당 시점에 게시자가 사용 중인 메시지 수부터 시작하여 콘솔에 메시지 인쇄를 시작합니다.

    실행이 완료되면 노드가 더이상 spin 하지 않도록 각 터미널에 Ctrl+C 입력하십시오.

    노드를
    여기에서
    ros2 pkg create --build-type ament_cmake tutorial_interfaces
    mkdir msg srv
    int64 num
    geometry_msgs/Point center
    float64 radius
    int64 a
    int64 b
    int64 c
    ---
    int64 sum
    find_package(geometry_msgs REQUIRED)
    find_package(rosidl_default_generators REQUIRED)
    
    rosidl_generate_interfaces(${PROJECT_NAME}
      "msg/Num.msg"
      "msg/Sphere.msg"
      "srv/AddThreeInts.srv"
      DEPENDENCIES geometry_msgs # Add packages that above messages depend on, in this case geometry_msgs for Sphere.msg
    )
    <depend>geometry_msgs</depend>
    <buildtool_depend>rosidl_default_generators</buildtool_depend>
    <exec_depend>rosidl_default_runtime</exec_depend>
    <member_of_group>rosidl_interface_packages</member_of_group>
    colcon build --packages-select tutorial_interfaces
    source install/setup.bash
    ros2 interface show tutorial_interfaces/msg/Num
    int64 num
    ros2 interface show tutorial_interfaces/msg/Sphere
    geometry_msgs/Point center
            float64 x
            float64 y
            float64 z
    float64 radius
    ros2 interface show tutorial_interfaces/srv/AddThreeInts
    int64 a
    int64 b
    int64 c
    ---
    int64 sum
    import rclpy
    from rclpy.node import Node
    
    from tutorial_interfaces.msg import Num    # CHANGE
    
    
    class MinimalPublisher(Node):
    
        def __init__(self):
            super().__init__('minimal_publisher')
            self.publisher_ = self.create_publisher(Num, 'topic', 10)     # CHANGE
            timer_period = 0.5
            self.timer = self.create_timer(timer_period, self.timer_callback)
            self.i = 0
    
        def timer_callback(self):
            msg = Num()                                           # CHANGE
            msg.num = self.i                                      # CHANGE
            self.publisher_.publish(msg)
            self.get_logger().info('Publishing: "%d"' % msg.num)  # CHANGE
            self.i += 1
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_publisher = MinimalPublisher()
    
        rclpy.spin(minimal_publisher)
    
        minimal_publisher.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    import rclpy
    from rclpy.node import Node
    
    from tutorial_interfaces.msg import Num        # CHANGE
    
    
    class MinimalSubscriber(Node):
    
        def __init__(self):
            super().__init__('minimal_subscriber')
            self.subscription = self.create_subscription(
                Num,                                              # CHANGE
                'topic',
                self.listener_callback,
                10)
            self.subscription
    
        def listener_callback(self, msg):
                self.get_logger().info('I heard: "%d"' % msg.num) # CHANGE
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_subscriber = MinimalSubscriber()
    
        rclpy.spin(minimal_subscriber)
    
        minimal_subscriber.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    #...
    
    find_package(ament_cmake REQUIRED)
    find_package(rclcpp REQUIRED)
    find_package(tutorial_interfaces REQUIRED)                         # CHANGE
    
    add_executable(talker src/publisher_member_function.cpp)
    ament_target_dependencies(talker rclcpp tutorial_interfaces)         # CHANGE
    
    add_executable(listener src/subscriber_member_function.cpp)
    ament_target_dependencies(listener rclcpp tutorial_interfaces)     # CHANGE
    
    install(TARGETS
      talker
      listener
      DESTINATION lib/${PROJECT_NAME})
    
    ament_package()
    <exec_depend>tutorial_interfaces</exec_depend>
    colcon build --packages-select py_pubsub
    ros2 run py_pubsub talker
    ros2 run py_pubsub listener
    [INFO] [minimal_publisher]: Publishing: '0'
    [INFO] [minimal_publisher]: Publishing: '1'
    [INFO] [minimal_publisher]: Publishing: '2'
    from tutorial_interfaces.srv import AddThreeInts     # CHANGE
    
    import rclpy
    from rclpy.node import Node
    
    
    class MinimalService(Node):
    
        def __init__(self):
            super().__init__('minimal_service')
            self.srv = self.create_service(AddThreeInts, 'add_three_ints', self.add_three_ints_callback)        # CHANGE
    
        def add_three_ints_callback(self, request, response):
            response.sum = request.a + request.b + request.c                                                  # CHANGE
            self.get_logger().info('Incoming request\na: %d b: %d c: %d' % (request.a, request.b, request.c)) # CHANGE
    
            return response
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_service = MinimalService()
    
        rclpy.spin(minimal_service)
    
        rclpy.shutdown()
    
    if __name__ == '__main__':
        main()
    from tutorial_interfaces.srv import AddThreeInts       # CHANGE
    import sys
    import rclpy
    from rclpy.node import Node
    
    
    class MinimalClientAsync(Node):
    
        def __init__(self):
            super().__init__('minimal_client_async')
            self.cli = self.create_client(AddThreeInts, 'add_three_ints')       # CHANGE
            while not self.cli.wait_for_service(timeout_sec=1.0):
                self.get_logger().info('service not available, waiting again...')
            self.req = AddThreeInts.Request()                                   # CHANGE
    
        def send_request(self):
            self.req.a = int(sys.argv[1])
            self.req.b = int(sys.argv[2])
            self.req.c = int(sys.argv[3])                  # CHANGE
            self.future = self.cli.call_async(self.req)
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_client = MinimalClientAsync()
        minimal_client.send_request()
    
        while rclpy.ok():
            rclpy.spin_once(minimal_client)
            if minimal_client.future.done():
                try:
                    response = minimal_client.future.result()
                except Exception as e:
                    minimal_client.get_logger().info(
                        'Service call failed %r' % (e,))
                else:
                    minimal_client.get_logger().info(
                        'Result of add_three_ints: for %d + %d + %d = %d' %                               # CHANGE
                        (minimal_client.req.a, minimal_client.req.b, minimal_client.req.c, response.sum)) # CHANGE
                break
    
        minimal_client.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        mai
    <exec_depend>tutorial_interfaces</exec_depend>
    colcon build --packages-select py_srvcli
    ros2 run py_srvcli service
    ros2 run py_srvcli client 2 3 1
    source /opt/ros/humble/setup.bash
    mkdir -p ~/ros2_ws/src
    cd ~/ros2_ws/src
    git clone https://github.com/ros/ros_tutorials.git -b humble
    cd ~/ros2_ws
    rosdep install -i --from-path src --rosdistro humble -y
    #All required rosdeps installed successfully
    sudo rosdep init
    rosdep update --include-eol-distros
    colcon build
    Starting >>> turtlesim
    Finished <<< turtlesim [5.49s]
    
    Summary: 1 package finished [5.58s]
    build  install  log  src
    source /opt/ros/humble/setup.bash
    cd ~/ros2_ws
    source install/local_setup.bash
    ros2 run turtlesim turtlesim_node
    ros2 run turtlesim turtlesim_node
    ros2 pkg create --build-type ament_cmake more_interfaces
    mkdir 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
    <buildtool_depend>rosidl_default_generators</buildtool_depend>
    
    <exec_depend>rosidl_default_runtime</exec_depend>
    
    <member_of_group>rosidl_interface_packages</member_of_group>
    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
      )
    rosidl_generate_interfaces(${PROJECT_NAME}
      ${msg_files}
      ${srv_files}
    )
    #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;
    }
    #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");
    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);
    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})
    rosidl_target_interfaces(publish_address_book
      ${PROJECT_NAME} "rosidl_typesupport_cpp")
    cd ~/ros2_ws
    colcon build --packages-up-to more_interfaces
    source install/local_setup.bash
    ros2 run more_interfaces publish_address_book
    source install/setup.bash
    ros2 topic echo /address_book
    rosidl_tutorials_msgs/Contact[] address_book
    <build_depend>rosidl_tutorials_msgs</build_depend>
    
    <exec_depend>rosidl_tutorials_msgs</exec_depend>
    find_package(rosidl_tutorials_msgs REQUIRED)
    
    rosidl_generate_interfaces(${PROJECT_NAME}
      ${msg_files}
      DEPENDENCIES rosidl_tutorials_msgs
    )
    #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);
     };
    ros2 pkg create --build-type ament_python python_parameters --dependencies rclpy
    <description>Python parameter tutorial</description>
    <maintainer email="you@email.com">Your Name</maintainer>
    <license>Apache License 2.0</license>
    import rclpy
    import rclpy.node
    
    class MinimalParam(rclpy.node.Node):
        def __init__(self):
            super().__init__('minimal_param_node')
    
            self.declare_parameter('my_parameter', 'world')
    
            self.timer = self.create_timer(1, self.timer_callback)
    
        def timer_callback(self):
            my_param = self.get_parameter('my_parameter').get_parameter_value().string_value
    
            self.get_logger().info('Hello %s!' % my_param)
    
            my_new_param = rclpy.parameter.Parameter(
                'my_parameter',
                rclpy.Parameter.Type.STRING,
                'world'
            )
            all_new_parameters = [my_new_param]
            self.set_parameters(all_new_parameters)
    
    def main():
        rclpy.init()
        node = MinimalParam()
        rclpy.spin(node)
    
    if __name__ == '__main__':
        main()
    class MinimalParam(rclpy.node.Node):
        def __init__(self):
            super().__init__('minimal_param_node')
    
            self.declare_parameter('my_parameter', 'world')
    
            self.timer = self.create_timer(1, self.timer_callback)
    def timer_callback(self):
        my_param = self.get_parameter('my_parameter').get_parameter_value().string_value
    
        self.get_logger().info('Hello %s!' % my_param)
    
        my_new_param = rclpy.parameter.Parameter(
            'my_parameter',
            rclpy.Parameter.Type.STRING,
            'world'
        )
        all_new_parameters = [my_new_param]
        self.set_parameters(all_new_parameters)
    def main():
        rclpy.init()
        node = MinimalParam()
        rclpy.spin(node)
    
    if __name__ == '__main__':
        main()
    # ...
    
    class MinimalParam(rclpy.node.Node):
        def __init__(self):
            super().__init__('minimal_param_node')
    
            from rcl_interfaces.msg import ParameterDescriptor
            my_parameter_descriptor = ParameterDescriptor(description='This parameter is mine!')
    
            self.declare_parameter('my_parameter', 'world', my_parameter_descriptor)
    
            self.timer = self.create_timer(1, self.timer_callback)
    maintainer='YourName',
    maintainer_email='you@email.com',
    description='Python parameter tutorial',
    license='Apache License 2.0',
    entry_points={
        'console_scripts': [
            'minimal_param_node = python_parameters.python_parameters_node:main',
        ],
    },
    rosdep install -i --from-path src --rosdistro foxy -y
    colcon build --packages-select python_parameters
    source install/setup.bash
    ros2 run python_parameters minimal_param_node
    [INFO] [parameter_node]: Hello world!
    ros2 run python_parameters minimal_param_node
    ros2 param list
    ros2 param set /minimal_param_node my_parameter earth
    from launch import LaunchDescription
    from launch_ros.actions import Node
    
    def generate_launch_description():
        return LaunchDescription([
            Node(
                package='python_parameters',
                executable='minimal_param_node',
                name='custom_minimal_param_node',
                output='screen',
                emulate_tty=True,
                parameters=[
                    {'my_parameter': 'earth'}
                ]
            )
        ])
    output="screen",
    emulate_tty=True,
    import os
    from glob import glob
    # ...
    
    setup(
      # ...
      data_files=[
          # ...
          (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')),
        ]
      )
    colcon build --packages-select python_parameters
    source install/setup.bash
    ros2 launch python_parameters python_parameters_launch.py
    [INFO] [custom_minimal_param_node]: Hello earth!
    ros2 pkg create --build-type ament_python py_pubsub
    wget https://raw.githubusercontent.com/ros2/examples/humble/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py
    import rclpy
    from rclpy.node import Node
    
    from std_msgs.msg import String
    
    
    class MinimalPublisher(Node):
    
        def __init__(self):
            super().__init__('minimal_publisher')
            self.publisher_ = self.create_publisher(String, 'topic', 10)
            timer_period = 0.5  # seconds
            self.timer = self.create_timer(timer_period, self.timer_callback)
            self.i = 0
    
        def timer_callback(self):
            msg = String()
            msg.data = 'Hello World: %d' % self.i
            self.publisher_.publish(msg)
            self.get_logger().info('Publishing: "%s"' % msg.data)
            self.i += 1
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_publisher = MinimalPublisher()
    
        rclpy.spin(minimal_publisher)
    
        # Destroy the node explicitly
        # (optional - otherwise it will be done automatically
        # when the garbage collector destroys the node object)
        minimal_publisher.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    import rclpy
    from rclpy.node import Node
    from std_msgs.msg import String
    class MinimalPublisher(Node):
    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(String, 'topic', 10)
        timer_period = 0.5  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)
        self.i = 0
    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: %d' % self.i
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)
        self.i += 1
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_publisher = MinimalPublisher()
    
        rclpy.spin(minimal_publisher)
    
        # Destroy the node explicitly
        # (optional - otherwise it will be done automatically
        # when the garbage collector destroys the node object)
        minimal_publisher.destroy_node()
        rclpy.shutdown()
    <description>Examples of minimal publisher/subscriber using rclpy</description>
    <maintainer email="you@email.com">Your Name</maintainer>
    <license>Apache License 2.0</license>
    <exec_depend>rclpy</exec_depend>
    <exec_depend>std_msgs</exec_depend>
    maintainer='YourName',
    maintainer_email='you@email.com',
    description='Examples of minimal publisher/subscriber using rclpy',
    license='Apache License 2.0',
    entry_points={
            'console_scripts': [
                    'talker = py_pubsub.publisher_member_function:main',
            ],
    },
    [develop]
    script-dir=$base/lib/py_pubsub
    [install]
    install-scripts=$base/lib/py_pubsub
    wget https://raw.githubusercontent.com/ros2/examples/humble/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py
    __init__.py  publisher_member_function.py  subscriber_member_function.py
    import rclpy
    from rclpy.node import Node
    
    from std_msgs.msg import String
    
    
    class MinimalSubscriber(Node):
    
        def __init__(self):
            super().__init__('minimal_subscriber')
            self.subscription = self.create_subscription(
                String,
                'topic',
                self.listener_callback,
                10)
            self.subscription  # prevent unused variable warning
    
        def listener_callback(self, msg):
            self.get_logger().info('I heard: "%s"' % msg.data)
    
    
    def main(args=None):
        rclpy.init(args=args)
    
        minimal_subscriber = MinimalSubscriber()
    
        rclpy.spin(minimal_subscriber)
    
        # Destroy the node explicitly
        # (optional - otherwise it will be done automatically
        # when the garbage collector destroys the node object)
        minimal_subscriber.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    self.subscription = self.create_subscription(
        String,
        'topic',
        self.listener_callback,
        10)
    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)
    minimal_subscriber = MinimalSubscriber()
    
    rclpy.spin(minimal_subscriber)
    entry_points={
            'console_scripts': [
                    'talker = py_pubsub.publisher_member_function:main',
                    'listener = py_pubsub.subscriber_member_function:main',
            ],
    },
    rosdep install -i --from-path src --rosdistro humble -y
    colcon build --packages-select py_pubsub
    source install/setup.bash
    ros2 run py_pubsub talker
    [INFO] [minimal_publisher]: Publishing: "Hello World: 0"
    [INFO] [minimal_publisher]: Publishing: "Hello World: 1"
    [INFO] [minimal_publisher]: Publishing: "Hello World: 2"
    [INFO] [minimal_publisher]: Publishing: "Hello World: 3"
    [INFO] [minimal_publisher]: Publishing: "Hello World: 4"
    ...
    ros2 run py_pubsub listener
    [INFO] [minimal_subscriber]: I heard: "Hello World: 10"
    [INFO] [minimal_subscriber]: I heard: "Hello World: 11"
    [INFO] [minimal_subscriber]: I heard: "Hello World: 12"
    [INFO] [minimal_subscriber]: I heard: "Hello World: 13"
    [INFO] [minimal_subscriber]: I heard: "Hello World: 14"

    문제 식별에 ros2doctor 사용하기

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

    개요

    ROS2 설정이 예상대로 실행되지 않는 경우 ros2doctor도구를 사용하여 해당 설정을 확인할 수 있습니다.

    ros2doctor는플랫폼, 버전, 네트워크, 환경, 실행 중인 시스템 등 ROS2의 모든 측면을 확인하고 가능한 오류와 문제의 원인에 대해 경고합니다.

    실습

    먼저 새 터미널에서 ROS 2를 소싱한 다음 다음 명령을 입력합니다.

    이렇게 하면 모든 설정 모듈을 검사하고 경고 및 오류를 반환합니다.

    ROS2 설정이 완벽한 상태이면 다음과 유사한 메시지가 표시됩니다.

    그러나 몇 가지 경고가 반환되는 것은 드문 일이 아닙니다. 설정을 사용할 수 없다는 의미가 아닙니다. 이상적이지 않은 방식으로 구성되었다는 표시일 가능성이 더 큽니다.

    경고를 받으면 다음과 같이 표시됩니다.

    예를 들어 불안정한 ROS2 배포를 사용하는 경우 다음 경고가 표시됩니다.

    ros2doctor시스템에서 경고만 발견된 경우에도 All <n> checks passed메시지는 계속 수신됩니다.

    대부분의 검사는 오류가 아닌 경고로 분류됩니다. 피드백 반환의 중요성을 결정하는 것은 대부분 ros2doctor사용자에게 달려 있습니다. 설정에서 드문 오류(UserWarning: ERROR: 로 표시됨)가 발견되면 확인이 실패한 것으로 간주됩니다.

    다음 문제 피드백 목록과 유사한 메시지가 표시됩니다.

    오류는 시스템에 ROS2에 중요한 중요한 설정이나 기능이 없음을 나타냅니다. 시스템이 제대로 작동하려면 오류를 해결해야 합니다.

    2. 시스템 확인

    실행 중인 ROS 2 시스템을 검사하여 문제의 가능한 원인을 식별할 수도 있습니다. 실행 중인 시스템에서 작동하는 것을 보려면 서로 활발하게 통신하는 노드가 있는 turtlesim을 실행해 봅시다.

    새 터미널을 열고 ROS 2를 소싱하고 다음 명령을 입력하여 시스템을 시작합니다.

    다른 터미널과 소스 ROS 2를 열어 텔레옵 컨트롤을 실행합니다.

    이제 ros2doctor를자체 터미널에서 다시 실행하십시오. 설정에서 마지막으로 실행했을 때 발생한 경고 및 오류가 있는 경우 해당 경고 및 오류가 표시됩니다 . 다음은 시스템 자체와 관련된 몇 가지 새로운 경고입니다.

    /turtlesim노드가 구독하지 않는 두 주제에 데이터를 게시하는 것으로 보이며 ros2doctor는이로 인해 문제가 발생할 수 있다고 생각합니다.

    /color_sensor및 /pose 토픽을 에코하는 명령을 실행하면 게시자에 구독자가 있으므로 해당 경고가 사라집니다.

    Turtlesim이 실행되는 동안 두 개의 새 터미널을 열고 각각에서 ROS2를 소싱하고 자체 터미널에서 다음 각 명령을 실행하여 이를 시도할 수 있습니다.

    그런 다음 터미널에서 ros2doctor를다시 실행하십시오. publisher without subscriber경고 가 사라집니다. ( echo를실행한 터미널에 반드시 입력하세요Ctrl+C ).

    이제 Turtlesim 창을 종료하거나 Teleop을 종료하고 ros2doctor를다시 실행해 보십시오. 이제 시스템의 한 노드를 사용할 수 없음을 나타내는 또는 다른 주제에 대한 더 많은 경고(publisher without subscriber, subscriber without publisher)가 표시됩니다.

    노드가 많은 복잡한 시스템에서 ros2doctor는통신 문제의 가능한 원인을 식별하는 데 매우 중요합니다.

    3. 전체 보고서 받기

    ros2doctor는네트워크, 시스템 등에 대한 경고를 알려주지만 --report인수 와 함께 실행하면 문제를 분석하는 데 도움이 되는 훨씬 더 자세한 정보를 얻을 수 있습니다.

    네트워크 설정에 대한 경고가 표시되고 구성의 어떤 부분이 경고를 일으키는지 정확히 알고 싶을 때 사용할 수 있습니다 .

    또한 ROS2에 대한 도움을 받기 위해 지원 티켓을 열어야 할 때 매우 유용합니다. 보고서의 관련 부분을 티켓에 복사하여 붙여넣어 사람들이 환경을 더 잘 이해하고 더 나은 지원을 제공할 수 있도록 할 수 있습니다.

    전체 보고서를 얻으려면 터미널에 다음 명령을 입력하십시오.

    5개 그룹으로 분류된 정보 목록이 반환됩니다.

    를 실행할 때 표시되는 경고와 비교하여 여기에서 정보를 교차 확인할 수 있습니다 . 예를 들어 배포판이 "완전히 지원되거나 테스트되지 않았다"는 경고가 반환된 경우 보고서 섹션을 살펴볼 수 있습니다.

    여기에서 완전히 지원되지 않는 이유를 설명하는 distribution status: prerelease를 볼 수 있습니다.

    이상으로 ROS2 기본 교육을 마칩니다. 수고 하셨습니다~~~

    ros2 doctor
    All <n> checks passed
    <path>: <line>: UserWarning: <message>
    UserWarning: Distribution <distro> is not fully supported or tested. To get more consistent features, download a stable version at https://index.ros.org/doc/ros2/Installation/
    1/3 checks failed
    
    Failed modules:  network
    ros2 run turtlesim turtlesim_node
    ros2 run turtlesim turtle_teleop_key
    UserWarning: Publisher without subscriber detected on /turtle1/color_sensor.
    UserWarning: Publisher without subscriber detected on /turtle1/pose.
    ros2 topic echo /turtle1/color_sensor
    ros2 topic echo /turtle1/pose
    ros2 doctor --report
    NETWORK CONFIGURATION
    ...
    
    PLATFORM INFORMATION
    ...
    
    RMW MIDDLEWARE
    ...
    
    ROS 2 INFORMATION
    ...
    
    TOPIC LIST
    ...
    distribution name      : <distro>
    distribution type      : ros2
    distribution status    : prerelease
    release platforms      : {'<platform>': ['<version>']}
    Downloads – Oracle VirtualBoxwww.virtualbox.org
    Oracle VirtualBox Download
    Logo
    https://blog.naver.com/maponarooo/223132765367blog.naver.com
    https://drive.google.com/drive/folders/18csPme7hIWKbwYKX8gcQGiRj2KLXLvsi?usp=sharingdrive.google.com
    교육용 Oracle VirtualBox VM