본문 바로가기

IT/ROS

[ROS] 5. 퍼블리셔-서브스크라이버 메시지 통신 분석

반응형

☞ 메인보드 : Jetson Nano Developer Kit

운영 체제 : Ubuntu 18.04 - JetPack 4.3

☞ ROS 버전 : Melodic

☞ 언어 : C++

 

 

 

<이전 포스트>

 

4. 예제를 통한 ROS 실행 : 패키지 생성

메인보드 : Jetson Nano Deverloper Kit 이미지 파일 버전 : JetPack 4.3 ROS 버전 : Ubuntu 18.04 LTS bionic > ROS Melodic 통합개발환경(IDE) : qtcreator 언어 : C++ <이전 포스트> 3. ROS Melodic 설치 메인..

95mkr.tistory.com

 

 

 

 


목차

1. 퍼블리셔 코드 분석 [talker.cpp]

2. 서브스크라이버 코드 분석 [listener.cpp]

 

 

 


 

 

 

 

 

 퍼블리셔 코드 분석 [talker.cpp]

 

 

전체 코드를 보려면 아래의 더보기를 클릭하세요.

더보기
#include "ros/ros.h"
#include "std_msgs/Int32.h"
#include <iostream>

int main(int argc, char **argv){

  ros::init(argc, argv, "talker");
	
  ros::NodeHandle n;
  ros::Publisher pub = n.advertise<std_msgs::Int32>("/numbers", 10);
    
  ros::Rate loop_rate(10);
    
  int count = 0;   
  while(ros::ok()){    
    
    std_msgs::Int32 msg;
    
    msg.data = count;
        
    ROS_INFO("%d", msg.data);
        
    pub.publish(msg);
        
    ros::spinOnce();
        
    loop_rate.sleep();
    ++count;
  }
  
  return 0;
}

 

 

#include "ros/ros.h"
#include "std_msgs/Int32.h"
#include <iostream>

 

 

ROS와 메시지의 데이터 타입 헤더파일을 불러온다.

위 라이브러리는 /opt/ros/melodic/include 폴더에서 찾아볼 수 있다.

 

 

 

 

"ros/ros.h"는 ROS에 관련된 함수 호출을 돕는 헤더 파일이다.

"std_msgs/Int32.h"는 ROS의 표준 메시지 타입 중 32비트 형 int를 사용할 때 씀 (int16 = short , int32 = int ,  int64 = long)

 

"iostream"는 input ouput stream의 줄임말임 즉, 입출력을 위한 C++ 헤더 파일이다.(C의 stdio.h)

이 헤더 파일은 hello world 출력을 위한 예제에서 사용한 cout <<  "Hello World!" <<  endl; 를 생각하면 익숙할 것이다.

 

 

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

 

 

void ros::init (int& argc, char** argv, const std::string& name, uint32_t options = 0)

 

ROS 초기화 함수이다. ROS 코드를 작성할 때 항상 처음에 사용한다. argc = argument count는 메인 함수에 전달한 데이터의 개 수를 의미하며, argv = argument vector 는 데이터를 저장한 배열을, 세 번째 인자는 노드의 이름을 의미한다.

 

 

ros::NodeHandle n;
ros::Publisher pub = n.advertise<std_msgs::Int32>("/numbers", 10);

 

 

ros::NodeHandle::advertise(const std::string& topic, uint32_t queue_size, bool latch=false)

 

발행 선언, 앞서 선언된 노드는 마스터에 연결해 "/numbers" 라는 토픽에 대해 메시지를 전달할 수 있다.

 

두 번째 인자는 queue의 크기이고, 구독자(subscriber)에게 전달하기 위해 대기 할 최대 발신 메시지 수를 나타낸다.

 

☞ queue는 받는 데이터를 차례대로 등록하며 출력 데이터 또한 차례대로 출력하는 방식을 의미한다. 보통 대기 번호표로 설명한다. 추가로 반대 개념으로 보는 stack은 queue와 다르게 받는 데이터를 차례대로 등록하되 출력 데이터는 마지막에 등록된 데이터부터 차례대로 출력한다.

 

 

ros::Rate loop_rate(10);

 

 

반복 주기 설정

 

진동수(Hz)로 호출 빈도를 설정한다.

 

 

int count = 0;   
while(ros::ok()){    
    
	std_msgs::Int32 msg;
    
	msg.data = count;

 

 

먼저 토픽을 통해 메시지를 송수신하기 위한 int32 타입의 메시지 객체를 생성한다. 이 메시지는 count 값을 하나씩 증가시키면서 메시지 데이터에 저장되게끔 선언을 완료해준다. ROS는 Ctrl+C 키 입력을 감지하면 ros::ok()가 false를 반환한다. 이는 해당 기능을 종료하겠다는 의미이다. 위 키를 입력 받지 않은 경우에 while 반복문을 수행하고, 종료 키를 입력 받을 때까지 실행된다.

 

 

	ROS_INFO("%d", msg.data);
        
	pub.publish(msg);
        
	ros::spinOnce();
        
	loop_rate.sleep();
	++count;
}
return 0;

 

 

rosconsole 패키지에서 제공하는 ROS_INFO는 C/C++에서 흔히 사용한 printf/cout 처럼 제공되는 정보를 출력하는데 사용한다. "% d'"는 int 타입을 부호 있는 10진수 출력한다는 의미를 갖고 있다. 이로 메시지 반환 타입을 정할 수 있다.

 

pub.publish(msg); 를 통해 발행자의 msg 발행 시작을 알 수 있다.

 

발행자로부터 전송되는 데이터, 메시지를 지속적으로(이 경우에는 loop_rate라는 주기를 설정) 얻기 위해서 ros::spinOnce()는 꼭 추가해야 하는데 ros::spin() 함수는 함수 호출 후에 반환되지 않기 때문에 ros::spinOnce() 사용을 권장하고 있다.

(더 많은 정보 참고 : https://programming.vip/docs/ros-ros-spin-and-ros-spinonce-differences-and-use.html)

 

 

 

 


서브스크라이버 코드 분석 [listener.cpp]

 

전체 코드를 보려면 아래의 더보기를 클릭하세요.

더보기
#include "ros/ros.h"
#include "std_msgs/Int32.h"
#include <iostream>

void numberCallback(const std_msgs::Int32::ConstPtr& msg){
   ROS_INFO("Recieved: [%d]", msg->data);
}

int main(int argc, char **argv){

   ros::init(argc, argv, "listener");
   
   ros::NodeHandle n;
   ros::Subscriber sub = n.subscribe("/numbers", 10, numberCallback);
   
   ros::spin();
   
   return 0;
}

 

 

 

void numberCallback(const std_msgs::Int32::ConstPtr& msg){
   ROS_INFO("Recieved: [%d]", msg->data);
}

 

 

numberCallback 함수는 데이터가 /numbers 토픽에 도달하였는지 확인하기 위해 사용한다. 굳이 사용할 필요는 없으나 이러한 소박한 장치들은 이후에 있을 에러를 일찍 발견할 수 있다는 장점이 있다.

 

퍼블리셔에서 토픽을 통해 메시지를 보내고 서브스크라이버가 제대로 수신하면 콜백 기능 실행을 요청한다. ROS_INFO에 있는 Recievd와 함께 메시지 내용을 출력한다.

 

 

int main(int argc, char **argv){

   ros::init(argc, argv, "listener");
   
   ros::NodeHandle n;
   ros::Subscriber sub = n.subscribe("/numbers", 10, numberCallback);
   
   ros::spin();
   
   return 0;
}

 

 

ros::Subscriber(const std::string &topic, const NodeHandle &node_handle, const SubscriptionCallbackHelperPtr &helper)

 

초기에는 항상 ros::init을 초기화하고, 노드 핸들러와 함께 서브스크라이버가 관심을 가지는(메시지 수신받을 내용) 토픽과 queue 크기, 호출할 함수를 정의한다. 퍼블리셔로부터 메시지를 받으면 반환한다.(Ctrl+C 키가 입력되기 전까지 대기하고 반환하고를 반복한다.)

 

 

 

 

 

☞ 아래 링크에서 궁금한 함수나 명령어의 레퍼런스를 찾을 수 있다.

 

ko - ROS Wiki

한국 ROS 커뮤니티를 만들었습니다. 국내에 있는 ROS 개발자들과 소통을 원하시는 분은 다음 링크를 방문해주세요. http://www.ros.or.kr http://www.korearos.org ROS 는 로봇용 공개소스 메타 운영체제입니다. ROS는 일반 운영체제에서 제공하는 하드웨어 추상화, 저수준 기기 제어, 빈번히 사용되는 기능들이 구현되어 있으며, 프로세스간의 메시지, 패키지 관리 기능등을 제공합니다. ROS: ROS 기반 소프트웨어: ROS를

wiki.ros.org

 

반응형