본문 바로가기

Robotics

8일차 - ROS Topic 프로그래밍

반응형

표준 단위

ROS에서는 메시지에 표준 단위 사용을 권장하고 있습니다. 필요에 따라 재사용, 재정의도 가능하나 사용 단위만큼은 SI 단위를 반드시 지켜야 합니다.

Quantity Unit
length meter
mass kilogram
time second
current ampare
angle radian
frequency hertz
force newton
power watt
voltage volt
temparature celsius

REP(ROS Enhancement Proposals)

REP는 ROS 커뮤니티에서 유저들이 제안하는 규칙, 새로운 기능, 관리 방법을 담은 제안서입니다. 유저 간에 정리된 표준 문서로, 아래 링크에서 확인해 볼 수 있습니다.
http://www.ros.org/reps/rep-0000.html

axes

로봇의 회전 방향은 오른손 법칙을 따릅니다. 오른손으로 따봉을 했을 때 손가락이 감기는, 반시계 방향이 회전의 정방향(+)입니다.
회전축은 아래 사진과 같이 손가락을 펼쳤을 때, 엄지가 Z축, 검지가 X축, 중지가 Y축이 됩니다.

style guide

변수 이름을 명명할 때에도 규칙이 있습니다. 필수는 아니지만, 남의 코드를 이해할 때 도움이 됩니다.

대상 명명 규칙 예시
패키지 under_scored first_ros_package
토픽, 서비스 under_scored raw_image
파일 under_scored turtlebot3.cpp
(*단 메시지, 서비스, 액션 파일은 CamelCased)
네임스페이스 under_scored ros_awesome_package
변수 under_scored string table_name;
타입 CamelCased typedef int32_t PropertiesNumber;
클래스 CamelCased class UrlTable;
구조체 CamelCased struct UrlTableProperties;
열거형 CamelCased enum ChoiceNumber;
함수 camelCased addTableEntry();
메소드 camelCased void setNumEntries(int32_t num_entries);
상수 ALL_CAPITALS const uint8_t DAYS_IN_A_WEEK = 7;
매크로 ALL_CAPITALS #define PI_ROUNDED 3.0;

패키지 생성

이전에 했던대로 패키지를 생성해보겠습니다. 이번에 생성할 패키지의 이름은 ros_tuturials_topic으로 하겠습니다. message_generationstd_msgs, roscpp 의존성을 주입해줍니다.

# ROS 1
catkin_create_pkg ros_tutorials_topic message_generation std_msgs roscpp

다음과 같이 파일이 생성된 것을 볼 수 있습니다.

package.xml 수정

<?xml version="1.0"?>
<package format="2">
  <name>ros_tutorials_topic</name>
  <version>0.0.1</version>
  <description>publish/subscribe topic</description>
  <license>Apache License 2.0</license>
  <maintainer email="root@to.do">someone</maintainer>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>message_generation</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>

  <exec_depend>roscpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>message_runtime</exec_depend>

  <export></export>
</package>

<run_depend> 태그는 catkin format 2부터 <exec_depend>로 변경되었습니다. 개인적으로.. ROS는 버전 별로 빌드 시스템의 이름이나 이런 식의 키워드 변경이 잦아 매우 불편합니다. 이런 부분 하나하나가 하위 호환성을 망치고 생산성을 약화하는 것 같은데 왜 맨날 이름이나 바꾸고 있을까요...?

CMakeLists.txt 수정

cmake_minimum_required(VERSION 3.0.2)
project(ros_tutorials_topic)

find_package(catkin REQUIRED COMPONENTS
  message_generation
  roscpp
  std_msgs
)

add_message_files(FILES MsgTutorial.msg)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(
  LIBRARIES ros_tutorials_topic
  CATKIN_DEPENDS std_msgs roscpp
)

include_directories(${catkin_INCLUDE_DIRS})

add_executable(topic_publisher src/publisher.cpp)
add_dependencies(topic_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(topic_publisher ${catkin_LIBRARIES})

add_executable(topic_subscriber src/subscriber.cpp)
add_dependencies(topic_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(topic_subscriber ${catkin_LIBRARIES})

메시지 파일 작성

먼저 메시지 파일이 위치할 폴더를 생성한 뒤, 메시지 파일을 생성합니다.

roscd ros_tutorials_topic
mkdir msg
vi msg/MsgTutorial.msg

메시지를 선언합니다.

time stamp
int32 data

int32 sec과 int32 nsec으로 이루어진 time 형태의 stamp와 int32 형태의 data를 선언했습니다.

topic_publisher

add_executable(topic_publisher src/publisher.cpp)

CMakeLists.txt에서 선언한대로 topic_publisher 노드를 위한 코드 publisher.cpp를 작성합니다.

#include "ros/ros.h"
#include "ros_tutorials/MsgTutorial.h"

int main(int argc, char** argv) {
  ros::init(argc, argv, "publisher");
  ros::NodeHandle nh;

  // topic name = ros_tutorial_msg
  // queue size = 100
  ros::Publisher pub = nh.advertise<ros_tutorials::MsgTutorial>("ros_tutorial_msg", 100);

  // scale_of_hz = 1
  // 1초 간격으로 처리가 반복된다
  ros::Rate loop_rate(1);
  ros_tutorials::MsgTutorial msg;
  int count = 0;

  while (ros::ok()) {
    msg.stamp = ros::Time::now();
    msg.data = count;

    ROS_INFO("send msg = %d", msg.stamp.sec);
    ROS_INFO("send msg = %d", msg.stamp.nsec);
    ROS_INFO("send msg = %d", msg.data);

    pub.publish(msg);
    loop_rate.sleep();
    count++;
  }
  return 0;
}

ROS 1에서는 ros/ros.h를 이용해 관련 함수를 포함하지만, ROS 2에서는 rclcpp/rclcpp.hpp를 이용합니다.

topic_subscriber

add_executable(topic_subscriber src/subscriber.cpp)

CMakeLists.txt에서 선언한대로 topic_subscriber 노드를 위한 코드 subscriber.cpp를 작성합니다.

#include "ros/ros.h"
#include "ros_tutorials/MsgTutorial.h"

void msgCallback(const ros_tutorials::MsgTutorial::ConstPtr& msg) {
  ROS_INFO("receive msg = %d", msg->stamp.sec);
  ROS_INFO("receive msg = %d", msg->stamp.nsec);
  ROS_INFO("receive msg = %d", msg->data);
}

int main(int argc, char** argv) {
  ros::init(argc, argv, "subscriber");
  ros::NodeHandle nh;
  // topic name = ros_tutorial_msg <- topic_publisher가 발행한 topic 이름과 같아야 합니다.
  // queue size = 100
  // callback = msgCallback <- 메시지를 받으면 실행됩니다.
  ros::Subscriber sub = nh.subscribe("ros_tutorial_msg", 100, msgCallback);

  // 메시지를 받을 때까지 대기합니다.
  // 메시지를 받으면 subscriber의 callback을 실행합니다.
  ros::spin();
  return 0;
}

빌드 및 실행

catkin_ws로 돌아와 catkin_make 명령어를 통해 패키지를 빌드합니다. 이후 아래 명령어를 실행하여 publisher/subscriber를 테스트합니다.

# one shell
rosrun ros_tutorials_topic topic_publisher
# another shell
rosrun ros_tutorials_topic topic_subscriber

아래와 같이 표시되어야 합니다.

반응형

'Robotics' 카테고리의 다른 글

9일차 - Action Demo 패키지 생성  (0) 2020.07.09
8일차 - ROS Service 프로그래밍  (0) 2020.07.08
7일차 - ROS2 camera demo  (1) 2020.07.08
6일차 - ROS tools  (0) 2020.07.06
5일차 - ros bash, catkin, rosnode 명령어 정리  (0) 2020.07.05