본문 바로가기

FOSCAR-(Autonomous Driving)/ROS 스터디

[2025 ROS 스터디] 이호휘 #3주차-ROS 기본 프로그래밍

반응형

ROS 기본 프로그래밍

목차
- ROS 프로그래밍 전에 알아둬야 할 사항
- 퍼블리셔와 서브스크라이버 노드 작성 및 실행
- 서비스 서버와 클라이언트 노드 작성 및 실행
- 액션 서버와 클라이언트 노드 작성 및 실행 -> 잘 사용하지 않아서 강의 X
- 파라미터 사용법
- Roslaunch 사용법

1. ROS 프로그래밍 전에 알아둬야할 사항
 - 표준 단위 : SI 단위 사용
 


  
 - 좌표 표현 방식
  - x : forward / y : left / z : up
   -> 정회전 : left -> (+) / 역회전 : right -> (-)
  - 오른손 법칙
  
 - 프로그래밍 법칙


2. 메시지 통신의 종류
 - topic
  - 퍼블리셔가 서브스크라이버에게 메시지를 전달하는 방식
 - 서비스
  - 서비스 클라이언트가 서비스 서버에 서비스를 요청하면 서비스 응답을 받는 방식
  - 양방향 일회성
 - 매개변수
  - roscore 실행하면 ros master의 역할
  - ros log를 저장
  - 파라미터 서버를 구동
  - 사용자가 입력한 파라미터를 저장
  
 - 토픽 작성
  1) 패키지 생성
   - $cd ~/catkin_ws/src
   - ~의 역할 : 홈 폴더
    ex) 전체 리눅스 폴더 > home > user의 폴더
   - catkin_ws : catkin workspace

  2) catkin_create_pkg ros_tutorials_topic message_generation std_msg roscpp
   - 자동적으로 패키지 생성
   - include 폴더 (만든 당시에는 빈 폴더) + src 폴더 (소스코드 파일)
   - CMakeLists.txt / package.xml -> 가장 기본적인 폴더 생성
   - 명령어 실행 시
    - create_pkg : 패키지 생성
    - ros_tutorials_topic : 패키지 이름
    - message_generation std_msg roscpp : 세가지 패키지를 사용한다는 의미
    
  3) cd ros_tutorials_topic 
   - 데릭토리 변경
   
  4) ls
   - list를 의미
   - 생성 파일 보기
   
  5) 패키지 설정 파일(pakage.xml) 수정
   - ros의 필수 설정 파일 중 하나인 pakage.xml은 패키지 정보를 담은 XML 파일로서 패키지 이름, 저작자, 라이선스, 의존성 패키지 등을 기술
   - gedit package.xml
   - editor 화면 / 기본 메모장
 

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>
 - 패키지의 간략한 설명 넣어주기 / 검색키로도 사용 / 위키페이지로 연결
<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>
<build_depend>message_generation</build_depend>
 - 메시지 만들기
<run_depend>roscpp</run_depend>
 - 실행 시 의존성
<run_depend>std_msgs</run_depend>
<run_depend>message_runtime</run_depend>
<export></export >
</package>
   
  6) 빌드 설정 파일(CMakeLists.txt)
   - 노드 빌드 시 사용되는 옵션의 집합
  

CMakeLists.txt 파일 작성


cmake_minimum_required(VERSION 2.8.3)
 - 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)
 - 의존하는 메시지를 설정하는 옵션
 -std_msgs가 설치되어 있지 않다면 빌드 도중에 에러 발생

catkin_package(
LIBRARIES ros_tutorials_topic - 패키지 이름
CATKIN_DEPENDS std_msgs roscpp - 의존성 기술
)
 - 캐킨 패키지 옵션으로 라이브러리, 캐킨 빌드 의존성, 시스템 의존 패키지를 기술

include_directories(${catkin_INCLUDE_DIRS}) - include 헤더 파일 추가 할 땐 뒤에 include를 적어주면 됨
 - 인클루드 디렉터리 설정
 
add_executable(topic_publisher src/topic_publisher.cpp) - 실행파일에 대한 정보 기술 / 생성 노드 : topic_publisher / 참고 : src/topic_publisher.cpp
add_dependencies(topic_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) - 퍼블리셔 노드를 만들 때 참조할 내용
target_link_libraries(topic_publisher ${catkin_LIBRARIES}) - 
 - topic_publisher 노드에 대한 빌드 옵션
 - 실행 파일, 타깃 링크 라이브러리, 추가 의존성 등을 설정
 
add_executable(topic_subscriber src/topic_subscriber.cpp) - 생성노드 : topic_subscriber / 참고 : src/topic_subscriber.cpp
add_dependencies(topic_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS})
target_link_libraries(topic_subscriber ${catkin_LIBRARIES})
 - topic_subscriber 노드에 대한 빌드 옵션
 
 7) 메시지 파일 작성
  - 디렉토리 변경 후 msg 메시지 폴더 생성
  - msg 폴더로 디렉토리 변경후 파인 신규 작성 및 내용 수정
   - ex) 입력한 메시지 데이터
    - time stamp / int32 data
    - 메시지 형식 + 메시지 이름
    - 메시지 타입은 위 두개를 포함한 bool, int8, int16, float32, string, time, duration 등의 메시지 기본 타입을 사용 가능
    - ROS에서 많이 사용되는 메시지를 모아놓은 common_msgs 등이 있음

 8) 퍼블리셔 노드 작성

노드 작성

 


  - 실행파일은 devel과 build에 들어가있음 // 실제로는 안들어가 있었다. gpt한테 물어봤는데 걔는 이게 잘 빌드가 되었다고 한다. 무언가 잘못되었다. 이상하다.

이상함1


  - 코드
#include "ros/ros.h" // ROS 기본 헤더파일
#include "ros_tutorials_topic/MsgTutorial.h" // MsgTutorial 메시지 파일 헤더(빌드 후 자동 생성)
int main(int argc, char **argv) // 노드 메인 함수
{
ros::init(argc, argv, "topic_publisher"); // 노드명 초기화
ros::NodeHandle nh; // ROS 시스템과 통신을 위한 노드 핸들 선언

ros::Publisher ros_tutorial_pub = nh.advertise<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg", 100);
// 퍼블리셔 선언, ros_tutorials_topic 패키지의 MsgTutorial 메시지 파일을 이용
// 퍼블리셔 ros_tutorial_pub 를 작성 
// 토픽명은 "ros_tutorial_msg"
// 퍼블리셔 큐사이즈를 100개로 설정

ros::Rate loop_rate(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); // stamp.sec 메시지를 표시
ROS_INFO("send msg = %d", msg.stamp.nsec); // stamp.nsec 메시지를 표시
ROS_INFO("send msg = %d", msg.data); // data 메시지를 표시
// ROS_INFO는 printf와 동일한 역할

ros_tutorial_pub.publish(msg); // 메시지를 발행
loop_rate.sleep(); // 위에서 정한 루프 주기에 따라 슬립에 들어감
++count; // count 변수 1씩 증가
}
return 0;
}
  
  9) 서브스크라이버노드

노드 작성


#include "ros/ros.h" // ROS 기본 헤더파일
#include "ros_tutorials_topic/MsgTutorial.h"
// MsgTutorial 메시지 파일 헤더 (빌드 후 자동 생성됨)
// 메시지 콜백 함수로써, 밑에서 설정한 ros_tutorial_msg라는 이름의 토픽
// 메시지를 수신하였을 때 동작하는 함수
// 입력 메시지로는 ros_tutorials_topic 패키지의 MsgTutorial 메시지를 수신

void msgCallback(const ros_tutorials_topic::MsgTutorial::ConstPtr& msg)
{
ROS_INFO("recieve msg = %d", msg->stamp.sec); // stamp.sec 메시지를 표시
ROS_INFO("recieve msg = %d", msg->stamp.nsec); // stamp.nsec 메시지를 표시
ROS_INFO("recieve msg = %d", msg->data); // data 메시지를 표시
}
int main(int argc, char **argv) // 노드 메인 함수
{
ros::init(argc, argv, "topic_subscriber"); // 노드명 초기화
ros::NodeHandle nh; // ROS 시스템과 통신을 위한 노드 핸들 선언
// 서브스크라이버 선언, ros_tutorials_topic 패키지의 MsgTutorial 메시지 파일을 이용
// 서브스크라이버 ros_tutorial_sub 를 작성
// 토픽명은 "ros_tutorial_msg" 이며,
// 서브스크라이버 큐사이즈를 100개로 설정
ros::Subscriber ros_tutorial_sub = nh.subscribe("ros_tutorial_msg", 100, msgCallback);
// 콜백함수 호출을 위한 함수
// 메시지가 수신을 대기
// 수신되었을 경우 콜백함수를 실행
ros::spin();
return 0;
}
  - 노드 하나당 퍼브스크라이버 한번, 서브스크라이버 한번의 역할을 하는 것은 아님
  - 복수의 역할을 할 수 있음
  
 10) 퍼블리셔 실행
  - 무언가 잘못되어 결과를 눈으로 보지 못했다.
  - cd ~/catkin_ws/src에 분명히 ros_tutorials_topic 파일이 있지만 터미널에서 없다고 나온다.
 
 - 서비스 작성
  - 요청이 있을 때만 응답하는 서비스 서버
 
 1) 패키지 생성
  - 토픽-2) 와 동일 방식
  
 2) 패키지 설정 파일 수정
  - 토픽-5) 와 동일 방식
  
 3) 빌드 설정 파일 작성
  - 토픽-6) 과 동일 방식
 
 4) 서비스 파일 작성
  - 토픽-7) 과 동일 방식
  - 차이점 : ---을 사용하여 요청과 응답을 구분하는 구분자
  
 5) 서비스 서버 노드 작성
  - 코드
   - 토픽-8과 유사하므로 생략
   
 6) 서비스 클라이언트 노드 작성
  - 코드
   -토픽-9와 유사하므로 생략
   
 7) ROS 노드 빌드
  - 예제를 따라했지만 계속 같은 문제로 실패했다.
  - rqt그래프는 사용이 불가능
  - 서비스 클라이언트 역할은 노드를 써서 만들 필요는 없다.
  - 명령어를 통하여 역할 대체 가능
  - rqt를 사용하여 역할 대체 가능
   - service caller 설정
   - 해당 srv 폴더로 이동
   - 값 선택 후 call
 
 - 파라미터 작성
  1) 파라미터를 활용한 노드 작성
   - 서비스 서버와 클라이언트 노드에서 service.cpp 소스를 수정하여 사용
    - #define을 통하여 코드 수정
   - 차이점 :
    - nh.setParam("calculation_method", PLUS); // 매개변수 초기설정
    - nh.getParam("calculation_method", g_operator); // 무조건 대기상태에서 중간중간 확인을 위해 루프 설정
    
  2) 노드 빌드 및 실행
 
  3) 매개변수 목록 보기
 
 - roslaunch
  - rosrun은 하나의 노드를 실행하는 명령을 하는 명령어
  - roslaunch는 하나 이상의 정해진 노드를 실행시킴
  - 패키지의 매개변수나 노드이름변경, 노드 네임스페이스 설정, ROS_ROOT 및 ROS_PACKAGE_PATH설정, 환경 변수 변경 등의 옵션을 붙일 수 있는 ROS 명령어
  - XML 기반
  - 사용법
   1) roslaunch의 활용
    - 디렉토리 변경
    - mkdir 통해 폴더 생성
    - 내용 기입
    - 실행
    - info, error등 표시가 되지 않아 --screen을 사용하여 출력
    - 두개의 노드를 실행하면 터미널에는 두개 다 표시되고 하나의 메시지를 두개의 서브스크라이버가 각각 받게됨
     - 개별적으로 받게하고싶으면 그룹을 넣어 실행 -> 분리적으로 서비스 전달
     - 노드의 이름이 변경됨
     
    
   2) launch 태그
<launch> - roslaunch 구문의 시작과 끝을 가리킴
<node> - 노드 실행에 대한 태그 / 패키지, 노드명, 실행명을 변경 가능
<machine> - 노드를 실행하는 PC의 이름, address, ros-root, ros-package-path 등을 설정
<include> - 다른 패키지나 같은 패키지에 속해 있는 다른 launch를 불러와 하나의 launch파일처럼 실행
<remap> - 노드 이름, 토픽 이름 등의 노드에서 사용 중인 ROS 변수의 이름을 변경
<env> - 경로, IP 등의 환경 변수를 설정 / 거의 안 쓰임
<param> - 매개변수 이름, 타이프, 값 등을 설정
<rosparam> - rosparam 명령어 처럼 load, dump, delete 등 매개변수 정보의 확인 및 수정
<group> - 실행되는 노드를 그룹화할 때 사용
<test> - 노드를 테스트할 때 사용

반응형