본문 바로가기
Autonomous Vehicle/ROS programming

ROS에서 간단한 Topic 생성하고 받아오기 (Publisher and Subscriber)

by kim.jeff 2020. 8. 12.

ROS에서 정보를 주고 받을 때 가장 많이 사용하는 기능 중 하나인 토픽! 토픽을 생성하거나 받아드리는 과정을 퍼블리쉬 그리고 서브스크라이브 (구독) 한다고 하는데요, 관련 내용의 튜토리얼을 따라하며 정리하는 시간 갖도록 하겠습니다. 이전의 패키지 생성하는 글과 이어지니 참고하길 바랍니다.


ROS에서 간단한 토픽 생성하고 받아오기 (퍼블리셔와 서브스크리버)

Writing a Simple Publisher and Subscriber : dealing with the topics in ROS

 


$ roscd beginner_tutorials

  beginner_tutorials 패키지의 경로로 이동하는 명령

 

$ mkdir -p src

  src폴더를 만드는 명령

 

1. 간단한 토픽 생성하기 (퍼블리쉬 하기)

#include "ros/ros.h"
#include "std_msgs/String.h"

#include <sstream>
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");

  ros::NodeHandle n;

  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  int count = 0;
  while (ros::ok())
  {
   
    std_msgs::String msg;

    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    
    ++count;
  }


  return 0;
}

 

코드 브레이킹: 쪼개서 코드 설명

ros::init(argc, argv, "talker");

  ros::init 함수는 argc와 argv값을 받아와야만 ROS 관련 변수들과 이름들의 재배치가 가능하기 때문에 존재 필요가 있다. 프로그래밍적인 재배치를 위해서 다른 버전의 init()을 사용할 수 있는데, 재배치를 직접적으로 하는 방식이다. 하지만, 대부분의 프로그램들에서는 argc와 argv를 넘겨주는 것이 가장 쉬운 방법이다. 세 번째 변수는 노드의 이름이다.

 

 

ros::NodeHandle n;

  NodeHandle 은 로스 시스템과 소통하기 위한 가장 중요한 접근법이다. 첫 번째 NodeHandle 은 전체적으로 본 노드를 초기화하는 것으로 구성되어 있고 마지막 NodeHandle은 노드를 끄는 것으로 되어있다.

 

ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  advertise() 함수는 로스에게 주어진 토픽 이름으로 출판하고(퍼블리쉬)하고 싶다고 전달하는 것이다. 마스터 노드에게 알려주게 된다. 누가 출판하고 누가 구독하는지 등록을 담당하는 마스터 노드에게 말이다. 이 advertise() 전달이 완료되면, 마스터 노드는 누가 구독하려(서브 스크라이브) 하는지 알려주고 피어투피어 방식으로 협상하게 된다. advertise() 함수는 퍼블리셔 객체를 리턴하는데, publish()에 콜을 함으로써 당신이 메시지를 퍼블리시할 수 있게 허락하는 것과 같다. 모든 리턴된 퍼블리셔 객체의 복사본들이 모두 파괴되었을 때, 토픽이 자동적으로 선전되지 않을 것이다. (unadvertised)

 

  advertise()의 두 번째 변수는 메시지의 큐 사이즈이다. 메시지를 보내는 것보다 빨리 퍼블리쉬되었을 때 얼마나 많은 메시지들을 버리기 전까지 얼마나 저장할지에 대한 사이즈인 것이다.

 

int count = 0;

  얼마나 많은 메시지들을 보냈는지 카운트하는 것이다. 각각의 메시지마다 특별한 문자열을 만들 때 쓰인다.

 

std_msgs::String msg;

  메시지 오브젝트이다. 데이터와 함께 다룬다면, 출판하게 되는 것이다.

 

chatter_pub.publish(msg);

  publish() 함수는 우리가 메시지를 보내는 방법이다. 변수는 메시지 오브젝트이다. 이와 같은 방식의 오브젝트는 무조건 advertise <>() 콜에 보낸 변수 양식과 맞아야 한다. 위의 constructor에서 한 것과 같이 말이다.

 

2. 간단한 토픽 받아오기 (서브스크라이브 하기)

  src/talker.cpp 파일을 생성하고 다음의 코드를 복사 붙혀넣기 한다.

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

int main(int argc, char **argv)
{
  
  ros::init(argc, argv, "talker");

  ros::NodeHandle n;

  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  int count = 0;
  while (ros::ok())
  {
    std_msgs::String msg;

    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;
  }

  return 0;
}

 

코드 브레이킹: 쪼개서 코드 설명

ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  subscribe()는 ROS에게 메시지들을 주어진 토픽에서 받고싶다고 말을 전달하는 콜과 같은것이다. ROS의 마스터노드에게 전달한다. 메시지들이 콜백 함수에게 전달되는데, chatterCallback이라고 불린다. subscribe()는 메세지를 전달받고 싶을 때까지 갖고 있어야 할 subscriber 오브젝트의 변수의 리턴값을 갖게된다.모든 subscriber오브젝트가 범위를 넘어간다면, 이 콜백함수가 자동적으로 토픽으로부터 Unsubscribe 될것이다.

 

 

ros::spin();

  루프를 들어갈것이고 콜백들을 살려둔다. 이 버전에서는 모든 콜백들이 본 메인 쓰레드와 함께 불려질것이며 컨트롤C가 눌렸을때 혹은 노드가 마스터에 의해 꺼졌을때, 나가게 된다.

 

 


<참고문헌 및 출처>

https://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber(c++)

 

ROS/Tutorials/WritingPublisherSubscriber(c++) - ROS Wiki

Writing the Publisher Node "Node" is the ROS term for an executable that is connected to the ROS network. Here we'll create a publisher ("talker") node which will continually broadcast a message. Change directory into the beginner_tutorials package, you cr

wiki.ros.org