ros 프로그래밍 전 알아둬야 할 사항 (메시지 통신에 중요)
토픽
ros에서 사용하는 단방향 메시지 통신. 송신측이 publisher, 수신측이 subscriber.
cd ~/catkin_ws/src
cd – change directory (이동할 경로)
~ : 리눅스 - home – user 안에 있는 폴더(?)
1) 패키지 생성
$ cd ~/catkin_ws/src -> 폴더 이동
$ catkin_create_pkg ros_tutorials_topic message_generation std_msgs roscpp
->
ros_tutorials_topic이라는 패키지 생성
의존성 추가
message_generation → 사용자 정의 메시지를 생성할 때 필요
std_msgs → ROS의 기본 메시지 타입을 사용하기 위해 필요
roscpp → C++로 노드를 작성할 것이므로 필요
$ cd ros_tutorials_topic
$ ls -> (list) 현재 폴더에 있는 파일들을 보여준다
include → 헤더 파일 폴더
src → 소스 코드 폴더
CMakeLists.txt → 빌드 설정 파일
package.xml → 패키지 설정 파일
(패키지를 구성할 때 가장 기본이 되어야할 파일들)
2) 패키지 설정 파일 수정 (package.xml)
-> 패키지 이름, 저작자, 라이선스, 의존성 패키지 등을 수정
<?xml version="1.0"?>
-> 특정 버전 이상부터 사용 가능 표시
<package>
<name>ros_tutorials_topic</name>
-> 패키지의 이름
<version>0.1.0</version>
<description>ROS turtorial package to learn the topic</description>
-> 패키지의 간략한 설명 2~3줄 -> 나중에 자동변환되어 wiki에 검색 키워드로 사용.
<license>Apache 2.0</license>
<author email="pyo@robotis.com">Yoonseok Pyo</author>
-> 저자 (추가 가능)
<maintainer email="pyo@robotis.com">Yoonseok Pyo</maintainer>
-> 보통 저자와 동일인물. 지속적 업데이트? 개발이 안 될 경우 바뀔 수 있음. 관리자 개념.
<url type="website">http://www.robotis.com</url>
<url type="repository">https://github.com/ROBOTIS-GIT/ros_tutorials.git</url>
<url type="bugtracker">https://github.com/ROBOTIS-GIT/ros_tutorials/issues</url >
-> 패키지에 관련한 정보나 버그 관련 수정 요청 링크
<buildtool_depend>catkin</buildtool_depend> - 그냥 catkin 사용한다(?)
의존성 설정 부분 (다른 패키지의 기능을 가져와서 사용해야 하는 경우)
<build_depend>roscpp</build_depend>
→ C++로 노드를 작성할 것이므로 필요
<build_depend>std_msgs</build_depend>
→ 기본적인 ROS 메시지 타입을 사용하기 위해 필요
<build_depend>message_generation</build_depend>
→ 사용자 정의 메시지(Custom Message)를 만들 때 필요
<run_depend>roscpp</run_depend>
→ C++ 기반의 ROS 프로그램을 실행하려면 필요
<run_depend>std_msgs</run_depend>
→ 기본 메시지 타입 사용을 위해 필요
<run_depend>message_runtime</run_depend>
→ 사용자 정의 메시지를 실행할 때 필요
3) 빌드 설정 파일(CMakeLists.txt) 수정
-> 노드를 빌드할 때 사용되는 옵션들
cmake_minimum_required(VERSION 2.8.3)
project(ros_tutorials_topic)
-> 패키지명
find_package(catkin REQUIRED COMPONENTS message_generation std_msgs roscpp)
-> 캐킨 빌드를 할 때 요구되는 구성 요소 패키지
-> 의존성 패키지로 message_generation, std_msgs, roscpp이며 이 패키지들이 존재하지 않으면 빌드 도중에 에러 발생
add_message_files(FILES MsgTutorial.msg)
-> 메시지 선언 : MsgTutorial.msg
generate_messages(DEPENDENCIES std_msgs)
-> 위에서 선언한 메시지에는 스탠다는 메시지가 포함된다 (의존성이 있다는 뜻)
catkin_package
(
LIBRARIES ros_tutorials_topic
CATKIN_DEPENDS std_msgs roscpp
)
-> 캐킨 패키지 옵션으로 라이브러리, 캐킨 빌드 의존성, 시스템 의존 패키지를 기술한다.
include_directories(${catkin_INCLUDE_DIRS})
-> 헤더 파일을 포함할 디렉터리를 설정. (include파일을 사용하려면 뒤에 include를 적어준다)
## topic_publisher 노드에 대한 빌드 옵션이다.
add_executable(topic_publisher src/topic_publisher.cpp)
-> 토픽을 보내는 publisher 노드를 만들고 만들 때 src의 topic_publisher라는 cpp을 참고
add_dependencies(topic_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS})
-> 이를 통해 topic_publisher가 올바르게 빌드되기 전에 필요한 의존성이 먼저 처리되도록 한다.
target_link_libraries(topic_publisher ${catkin_LIBRARIES})
-> topic_publisher 실행 파일을 빌드할 때 필요한 라이브러리를 링크하는 명령
## topic_subscriber 노드에 대한 빌드 옵션이다.
add_executable(topic_subscriber src/topic_subscriber.cpp)
-> subscriber 노드를 만들고, 만들 때 뒤에 나와있는 cpp 참고.
add_dependencies(topic_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS})
target_link_libraries(topic_subscriber ${catkin_LIBRARIES})
최종 정리
CMakeLists.txt 파일은 ROS 패키지의 빌드 시스템 설정을 정의합니다.
find_package()로 의존성 패키지를 찾고,
add_message_files()로 사용자 정의 메시지를 설정하며,
generate_messages()로 메시지를 생성합니다.
catkin_package()로 패키지에 대한 설정을 지정하고,
add_executable()로 노드를 빌드하며,
target_link_libraries()로 라이브러리들을 링크합니다.
CMakeLists.txt와 package.xml 파일에서 노드에 대한 빌드 설정만 해준 것이기 때문에, 실제로 노드가 어떤 작업을 수행할지, 어떻게 동작할지에 대한 세부 구현은 별도로 작성해야 한다. (아래 4, 5, 6번)
4) 메시지 파일 작성
$mkdir msg → ros_tutorials_topic 패키지에 msg라는 메시지 폴더를 신규 작성
$cd msg → 작성한 msg 폴더로 이동
$gedit MsgTutorial.msg → MsgTutorial.msg 파일 신규 작성 및 내용 수정
time(메시지 형식) stamp(메시지 이름) -> 메시지 보낼 때 현재 시간
int32(메시지 형식) data(메시지 이름) -> 어떠한 데이터
5) 퍼블리셔 노드 작성
$cd src
→ ros_tutorials_topic 패키지의 소스 폴더인 src폴더로 이동
$gedit topic_publisher.cpp
→ 소스 파일 신규 작성 및 내용 수정
#include "ros/ros.h"
-> ROS 기본 헤더 파일 (중요)
#include "ros_tutorials_topic/MsgTutorial.h“
-> 앞서 작성한 MsgTutorial.msg 파일을 사용하기 위한 헤더 파일(빌드 후 자동 생성됨)
int main(intargc, char **argv) // 노드 메인 함수
{
ros::init(argc, argv, "topic_publisher");
-> 노드명 초기화 (노드는 고유한 이름을 가져야 하므로, 이 이름을 통해 다른 노드와 구분)
ros::NodeHandlenh;
-> 노드와 ROS 시스템 간의 통신을 담당하는 객체
ros::Publisherros_tutorial_pub
= nh.advertise<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg", 100);
->
ros::Publisher ros_tutorial_pub: 퍼블리셔 객체를 선언. 퍼블리셔는 MsgTutorial 메시지를 "ros_tutorial_msg"라는 토픽에 발행.
advertise<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg",100): "ros_tutorial_msg"라는 토픽 이름을 가진 메시지를 발행하는 퍼블리셔를 생성합니다.
100은 퍼블리셔의 큐(queue) 사이즈로, 발행된 메시지가 처리되기 전에 큐에 대기하는 최대 메시지 개수를 의미.
ros::Rate loop_rate(10);
-> 루프 주기를 설정한다. "10" 이라는것은10Hz를 말하는 것으로 0.1초간격으로 반복된다
ros_tutorials_topic::MsgTutorial msg;
-> MsgTutorial 메시지 파일 형식으로 msg라는 메시지를 선언
int count = 0; // 메시지에 사용될 변수 선언
while (ros::ok())
{
msg.stamp = ros::Time::now(); // 현재 시간을 msg의 하위 stamp 메시지에 담는다
msg.data = count; // count라는 변수 값을 msg의 하위 data 메시지에 담는다
ROS_INFO("send msg = %d", msg.stamp.sec); (ROS_INFO는 printf와 같은 개념)
ROS_INFO("send msg = %d", msg.stamp.nsec);
ROS_INFO("send msg = %d", msg.data);
ros_tutorial_pub.publish(msg); // 메시지를 발행한다.
loop_rate.sleep();
++count;
}
return 0;
}
6) 서브스크라이버 노드 작성
#include "ros/ros.h"
-> ROS 기본헤더파일
#include "ros_tutorials_topic/MsgTutorial.h"
-> MsgTutorial 메시지 파일 헤더(빌드 후 자동 생성됨)
void msgCallback(constros_tutorials_topic::MsgTutorial::ConstPtr& msg)
{
ROS_INFO("recievemsg= %d", msg->stamp.sec); // stamp.sec 메시지를 표시한다
ROS_INFO("recievemsg= %d", msg->stamp.nsec); // stamp.nsec 메시지를 표시한다
ROS_INFO("recievemsg= %d", msg->data); // data 메시지를 표시한다
}
msgCallback 함수: 서브스크라이버가 구독하는 토픽에서 메시지를 수신하면 이 함수가 콜백 함수로 호출
msg->stamp.sec와 msg->stamp.nsec은 퍼블리셔 노드에서 보낸 현재 시간을 나타내며, msg->data는 수신한 데이터 값
ROS_INFO는 수신된 메시지의 내용을 출력하는 데 사용. 이는 printf와 비슷한 역할 수행.
int main(int argc, char **argv)
{
ros::init(argc, argv, "topic_subscriber");
-> 노드명 초기화
ros::NodeHandle nh;
-> ROS 시스템과 통신을 위한 노드 핸들 선언
ros::Subscriber ros_tutorial_sub = nh.subscribe("ros_tutorial_msg", 100, msgCallback);
-> 이 노드가 서브스크라이버 노드의 역할을 함을 표시함.
"ros_tutorial_msg"는 서브스크라이버가 구독할 토픽의 이름. 퍼블리셔에서 발행한 메시지가 이 토픽으로 전송.
100은 큐(queue) 사이즈로, 수신한 메시지를 대기할 수 있는 최대 개수를 설정.
msgCallback은 메시지를 수신할 때 호출될 콜백 함수.
ros::spin();
-> 메시지 수신 대기 및 콜백 호출
return 0;
}
7) ROS 노드 빌드 (cm)
cf) 실행파일은 build랑 devel쪽에 있음
8) 퍼블리셔 실행
서비스
: ROS에서 양방향 통신이 필요할 때 사용. 요청이 있을 때만 응답하는 서비스 서버와 요청하고 응답받는 서비스 클라이언트로 나뉨.
1) 패키지 생성
$ cd ~/catkin_ws/src
$ catkin_create_pkgros_tutorials_servicemessage_generationstd_msgsroscpp
$ cd ros_tutorials_service
$ ls (현재 폴더에 있는 파일과 폴더 목록 보여줌)
include → 헤더파일폴더
src → 소스코드폴더
CMakeLists.txt → 빌드설정파일
package.xml → 패키지설정파일
2) 패키지 설정 파일(package.xml) 수정
$ gedit package.xml
3) 빌드 설정 파일(CMakeLists.txt) 수정
$ gedit CMakeLists.txt
서비스 선언
의존하는 메시지 설정 (std_msgs)
캐킨 패키지 옵션으로 라이브러리, 캐킨 빌드 의존성, 시스템 의존 패키지를 기술
실행파일노드 생성 (서비스 서버, 서비스 클라이언트)
4) 서비스 파일 작성
$ roscd ros_tutorials_service → 패키지 폴더로 이동
$ mkdirsrv → 패키지에 srv라는 서비스 폴더를 신규 작성
$ cdsrv → 작성한 srv폴더로 이동
$ geditSrvTutorial.srv → SrvTutorial.srv파일 신규 작성 및 내용 수정
int64 a
int64 b
--
int64 result
int64 (메시지형식), a, b (서비스요청: request), result (서비스응답: response),
‘---’ (요청과 응답을 구분하는 구분자)
5) 서비스 서버 노드 작성
src 폴더의 service_server.cpp라는 파일을 빌드하여 service_server라는 실행 파
일을 만들라는 이야기
$ roscd ros_tutorials_service/src → 패키지의 소스 폴더인 src폴더로 이동
$ gedit service_server.cpp → 소스 파일 신규 작성 및 내용 수정
6) 서비스 클라이언트 노드 작성
$ roscd ros_tutorials_service/src → 패키지의 소스 폴더인 src폴더로 이동
$ geditservice_client.cpp → 소스 파일 신규 작성 및 내용 수정
7) ROS 노드 빌드
$ cd ~/catkin_ws && catkin_make → catkin 폴더로 이동 후catkin 빌드 실행
8) 서비스 서버 실행
rosrun ros_tutorials_service service_server
9) 서비스 클라이언트 실행
rosrun ros_tutorials_service service_client 2 3
• 2와 3은 각각a, b 값으로 서비스를 요청하게 되고, 결과값으로 둘의합인 5를 전송받았다.
cf)
서비스는 일회성 이므로 rqt_graph를 확인할 수 없다
"rosservice call”이나 ServiceCaller를 이용해 서비스 클라이언트 노드를 실행 가능하다
cf) 하나의 노드는 복수의 퍼블리셔, 서브스크라이버, 서비스 서버, 서비스 클라이언트 역할이 가능하다
파라미터 (매개변수)
roscore를 실행하면 ros마스터 역할과 rosout에서 ros관련 log역할도 하면서 파라미터 역할도 한다.
외부의 변수를 통해 내부의 프로세서를 변화시키는 과정 (+ -> +, -, /, *)
-> service.cpp 소스를 수정하여 사용한다.
1) 파라미터를 활용한 노드 작성
수정된 부분
while (1)
{
nh.getParam("calculation_method", g_operator);
ros::spinOnce();
r.sleep();
}
-> 연산자를 매개변수로부터 받은 값으로 변경한다.
2) 노드 빌드 및 실행
3) 매개변수 목록 보기
roslaunch
rosrun은 하나의 노드를 실행하는 명령을 하는 명령어지만, roslaunch는 하나 이상의 정해진 노드를 실행시킨다.
패키지의 매개변수나 노드이름 변경, 노드 네임 스페이스 설정, 환경 변수 변경 등의 옵션을 붙일 수 있는 명령어.
roslaunch 사용법
$ roscd ros_tutorials_topic
$ mkdir launch
$ cd launch
$ gedit union.launch
<launch>
<node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher1"/>
<node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber1"/>
<node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher2"/>
<node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber2"/>
</launch>
$ roslaunch ros_tutorials_topic union.launch --screen
-> 실행
cf) info, error등 표시가 되지 않기 때문에 —screen을 사용하여 출력한다.
문제점)
퍼블리셔의 1과 2의 서로의 메시지를 서브스크라이브 1과 2가 모두 서브스크라이브하고 있다.
-> 그룹이라는 태그를 넣는다.
<launch>
<group ns="ns1">
<node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher"/>
<node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber"/>
</group>
<group ns="ns2">
<node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher"/>
<node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber"/>
</group>
</launch>
그 외의 launch tag
'FOSCAR-(Autonomous Driving) > ROS 스터디' 카테고리의 다른 글
[2025 ROS 스터디] 신채영 #3주차 - ROS 메세지 통신 프로그래밍, roslaunch (0) | 2025.01.31 |
---|---|
[2025 ROS 스터디] 황희찬 #3주차 - ROS 기본 프로그래밍 (0) | 2025.01.31 |
[2025 ROS 스터디] 이승찬 #3주차 - ROS 기본 프로그래밍 (0) | 2025.01.31 |
[2025 ROS 스터디] 홍동형 #3주차 - ROS 기본 프로그래밍 (0) | 2025.01.31 |
[2025 ROS 스터디] 이호휘 #3주차-ROS 기본 프로그래밍 (0) | 2025.01.28 |