Main Content

ROS Publisher 및 ROS Subscriber를 사용해 데이터 교환하기

이 예제에서는 ROS 네트워크에서 토픽을 퍼블리시하고 서브스크라이브하는 방법을 보여줍니다.

ROS 노드가 데이터를 교환하는 기본 메커니즘은 메시지를 주고받는 것입니다. 메시지는 토픽으로 전송되며 각 토픽은 ROS 네트워크에서 고유한 이름을 갖습니다. 정보를 공유하려는 노드는 publisher를 사용하여 데이터를 토픽으로 보냅니다. 해당 정보를 수신하려는 노드는 동일한 토픽에 대해 subscriber를 사용합니다. 각 토픽은 고유한 이름을 가질 뿐만 아니라 해당 토픽에서 전송할 수 있는 메시지 유형을 결정하는 메시지 유형도 가집니다.

publisher와 subscriber의 통신에는 다음과 같은 특성이 있습니다.

  • 토픽은 다대다 통신에 사용됩니다. 다수의 publisher가 메시지를 동일한 토픽에 보낼 수 있으며 다수의 subscriber가 메시지를 수신할 수 있습니다.

  • publisher와 subscriber는 토픽을 사이에 두고 분리되어 있으며 임의의 순서로 생성되고 소멸될 수 있습니다. 활성 subscriber가 없더라도 메시지를 토픽에 퍼블리시할 수 있습니다.

다음 그림은 토픽, publisher, subscriber의 개념을 설명하고 있습니다.

ROS 네트워크에서 토픽을 퍼블리시하고 서브스크라이브하는 방법 외에도, 이 예제에서는 다음을 수행하는 방법을 보여줍니다.

  • 새 메시지가 수신될 때까지 대기하기

  • 콜백을 사용하여 백그라운드에서 새 메시지 처리하기

서브스크라이브하고 메시지 대기하기

rosinit 명령을 사용하여 MATLAB®에서 ROS master를 시작합니다.

rosinit
Launching ROS Core...
...Done in 3.6961 seconds.
Initializing ROS master on http://172.19.136.75:56426.
Initializing global node /matlab_global_node_67357 with NodeURI http://vdi-wd1bgl-223:60706/ and MasterURI http://localhost:56426.

제공된 헬퍼 함수 exampleHelperROSCreateSampleNetwork를 사용하여 여러 publisher 및 subscriber가 있는 샘플 ROS 네트워크를 만듭니다.

exampleHelperROSCreateSampleNetwork

rostopic list를 사용하여 사용 가능한 토픽을 확인합니다.

rostopic list
/pose  
/rosout
/scan  
/tf    

rostopic info를 사용하여 /scan 토픽에 퍼블리시 중인 노드가 있는지 확인합니다. 아래의 명령은 node_3이 퍼블리시 중임을 나타냅니다.

rostopic info /scan
Type: sensor_msgs/LaserScan
 
Publishers:
* /node_3 (http://vdi-wd1bgl-223:60722/)
 
Subscribers:
* /node_1 (http://vdi-wd1bgl-223:60711/)
* /node_2 (http://vdi-wd1bgl-223:60717/)

rossubscriber를 사용하여 /scan 토픽을 서브스크라이브합니다. (여기에서와 같이) 토픽이 이미 ROS 네트워크에 존재하는 경우 rossubscriber가 해당 메시지 유형을 자동으로 감지하므로 지정할 필요가 없습니다. 효율성을 높이기 위해 구조체 형식의 메시지를 사용합니다.

laser = rossubscriber("/scan","DataFormat","struct");
pause(2)

receive를 사용하여 새 메시지를 기다립니다. (두 번째 인수는 초 단위의 시간 제한입니다.) 출력 scandata에는 수신된 메시지 데이터가 포함됩니다.

scandata = receive(laser,10)
scandata = struct with fields:
       MessageType: 'sensor_msgs/LaserScan'
            Header: [1×1 struct]
          AngleMin: -0.5467
          AngleMax: 0.5467
    AngleIncrement: 0.0017
     TimeIncrement: 0
          ScanTime: 0.0330
          RangeMin: 0.4500
          RangeMax: 10
            Ranges: [640×1 single]
       Intensities: []

일부 메시지 유형에는 연결된 시각화가 있습니다. LaserScan 메시지의 경우 rosPlot이 스캔 데이터를 플로팅합니다. MaximumRange 이름-값 쌍은 최대 플롯 범위를 지정합니다.

figure
rosPlot(scandata,"MaximumRange",7)

콜백 함수를 사용하여 서브스크라이브하기

receive를 사용하여 데이터를 가져오는 대신 새 메시지가 수신될 때 호출될 함수를 지정할 수 있습니다. 이렇게 하면 subscriber가 새 메시지를 기다리는 동안 다른 MATLAB 코드를 실행할 수 있습니다. 여러 subscriber를 사용하려면 콜백이 필수입니다.

콜백 함수 exampleHelperROSPoseCallback을 사용하여 /pose 토픽을 서브스크라이브합니다.

robotpose = rossubscriber("/pose",@exampleHelperROSPoseCallback,"DataFormat","struct")
robotpose = 
  Subscriber with properties:

                      TopicName: '/pose'
                  LatestMessage: []
                    MessageType: 'geometry_msgs/Twist'
                     BufferSize: 1
    MessagePreprocessingEnabled: 0
                  NewMessageFcn: @exampleHelperROSPoseCallback
                     DataFormat: 'struct'

기본 작업 공간과 콜백 함수 간에 데이터를 공유하는 한 가지 방법은 전역 변수를 사용하는 것입니다. 두 전역 변수, posorient를 정의합니다.

global pos
global orient

새로운 메시지 데이터가 /pose 토픽에서 수신되면 전역 변수 posorientexampleHelperROSPoseCallback 함수에 할당됩니다.

subscriber가 메시지를 받을 수 있도록 몇 초 동안 기다립니다. 최신 위치 데이터와 방향 데이터는 항상 pos 변수와 orient 변수에 저장됩니다.

pause(2) 
pos
pos = 1×3

    0.0429    0.0230   -0.0011

orient
orient = 1×3

    0.0079   -0.0263   -0.0041

명령줄에 posorient를 몇 번 입력해 보면 해당 값이 계속 업데이트되는 것을 볼 수 있습니다.

subscriber 변수를 지워서 pose subscriber를 중지합니다.

clear robotpose

참고: 전역 변수를 사용하는 것 외에, 콜백 함수에서 정보를 추출하는 다른 방법도 있습니다. 예를 들어 핸들 객체를 추가 인수로 콜백 함수에 전달할 수 있습니다. 콜백 함수 정의에 대한 자세한 내용은 그래픽스 객체에 대한 콜백 만들기 문서를 참조하십시오.

메시지 퍼블리시하기

ROS string형 메시지를 /chatter 토픽으로 보내는 publisher를 만듭니다(Work with Basic ROS Messages 항목 참조).

chatterpub = rospublisher("/chatter","std_msgs/String","DataFormat","struct")
chatterpub = 
  Publisher with properties:

         TopicName: '/chatter'
    NumSubscribers: 0
        IsLatching: 1
       MessageType: 'std_msgs/String'
        DataFormat: 'struct'

pause(2) % Wait to ensure publisher is registered

/chatter 토픽으로 보낼 ROS 메시지를 만들고 채웁니다.

chattermsg = rosmessage(chatterpub);
chattermsg.Data = 'hello world'
chattermsg = struct with fields:
    MessageType: 'std_msgs/String'
           Data: 'hello world'

rostopic list를 사용하여 /chatter 토픽을 ROS 네트워크에서 사용할 수 있는지 확인합니다.

rostopic list
/chatter
/pose   
/rosout 
/scan   
/tf     

/chatter 토픽의 subscriber를 정의합니다. 새 메시지가 수신되면 exampleHelperROSChatterCallback이 호출되고 메시지의 문자열 내용이 표시됩니다.

chattersub = rossubscriber("/chatter",@exampleHelperROSChatterCallback,"DataFormat","struct")
chattersub = 
  Subscriber with properties:

                      TopicName: '/chatter'
                  LatestMessage: []
                    MessageType: 'std_msgs/String'
                     BufferSize: 1
    MessagePreprocessingEnabled: 0
                  NewMessageFcn: @exampleHelperROSChatterCallback
                     DataFormat: 'struct'

/chatter 토픽에 메시지를 퍼블리시합니다. 해당 문자열이 subscriber 콜백에 의해 표시됩니다.

send(chatterpub,chattermsg)
pause(2)
ans = 
'hello world'

exampleHelperROSChatterCallback 함수는 string형 메시지를 퍼블리시하는 순간 바로 호출되었습니다.

ROS 네트워크 종료하기

ROS 네트워크에서 샘플 노드, publisher, subscriber를 제거합니다. 전역 변수 posorient.를 지웁니다.

exampleHelperROSShutDownSampleNetwork
clear global pos orient

ROS master를 종료하고 전역 노드를 삭제합니다.

rosshutdown;