꾸준하고 즐겁게

ROS message 패키지를 만들어보았다. - [1 of 2] 본문

Hardware/ROS

ROS message 패키지를 만들어보았다. - [1 of 2]

wj9183 2021. 6. 11. 17:58
728x90

나는 내 문제도 간신히 해결한다.

누군가에게 도움을 줄 만큼 잘 알지 못한다.

내 글은 내가 공부한 내용을 기록할 뿐이니, 그저 참고하는 정도면 좋겠다.

꾹 참고 하라고 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 죄송...

 

아무튼 가능한 자세히 설명하지만 많이 미흡할테니,

역시 가장 제대로된 정보는 공식 레퍼런스에서 얻는 것이 좋다.

 

http://wiki.ros.org/msg

 

msg - ROS Wiki

ROS uses a simplified messages description language for describing the data values (aka messages) that ROS nodes publish. This description makes it easy for ROS tools to automatically generate source code for the message type in several target languages. M

wiki.ros.org

 

 

 

 

ROS 패키지

 

리눅스 디렉토리 최상위는 root이다.

하위에 여러 디렉토리가 있겠지만 로스에서 중요한 건 opt이다.

/opt/ros/share 에는 ROS의 패키지가 들어있다.

 

우리의 워크스페이스는 /home/username 하위에 workspace(이하 "ws")가 있다.

ws 하위에 src 디렉토리가 있다.

src에도 패키지가 들어있다.

ROS의 패키지는 저 두곳에 들어있다.

패키지일 수도 있고 메타패키지일 수도 있다.

노드를 모은게 패키지, 패키지를 모은게 메타패키지이다.

 

그리고 빌드라는 기능이 있다.

건물을 짓는 역할이라고 보면 쉽다.

빌드를 하면, ws 밑에 build와 devel 디렉토리가 생긴다.
ws 아래 build와 devel, src 디렉토리가 있게 된다.

src 밑에는 CMakelist가 있다.

CMakelist는 설계도면 같은 것이다.
builder가 catkin을 사용하고 있고, catkin이 CMakelist의 내용을 바탕으로 빌딩을 하고, 빌딩 하니까 build와 devel이 나오는 것이다.

build를 할 때 명령어가 catkin_make인 이유다.

이 명령어를 워크스페이스에서 실행해야한다.
그러니까 ROS 워크스페이스 내부에서 한 것이다.

워크스페이스 외부는 리눅스의 영역이고, 워크스페이스 안은 ros의 영역이다. 우리가 만들어낸 영역이다.

리눅스에도 따로 빌더를 갖고 있겠지만, 로스에서 catkin이라는 빌더를 가지고 있기 때문에 ROSS에만 영향을 미쳐야한다.

그러니까 ws로 디렉토리를 옮겨가서 catkin_make를 하는 것이다.

src 디렉토리 하위에 CMakelist와 패키지들이 있다. 내가 만들고 싶은 이름으로 만들어진 패키지들이다.

패키지일 수도 있고 메타패키지일 수도 있다.

cmake 빌드를 하려고 해도 경로를 먼저 이동해야하고, 경로 이동이 아무튼 첫번째 조건이다.

 

 

 

 

 

 

 

패키지 만들기

 

 

1. catkin_create_pkg [패키지 이름] message_generation std_msgs roscpp

 

명령어나 함수의 이름을 짓는 룰들이 많다. 로스에서는 언더바를 많이 사용한다.

catkin_create_pkg에 catkin을 쓴 이유는, 빌드로 catkin을 쓴 패키지를 만든다는 의미이다.

catkin_create_pkg [패키지이름] std_msgs roscpp

패키지 이름은 우리 맘대로 만들 수 있다. 다만 숫자는 넣지 않는 것이 좋다고 한다.

그 뒤에는 의존성에 관한 내용이 들어간다. 하드웨어에서는 의존성을 헤더라고 하고, 소프트웨어에서는 의존성이라고 한다.
어떤 언어로 짜든 로스가 번역기 역할을 하는데, 그래서 확장자가 로스 C++인 것이다.

 

 

 

여기서 의존성 패키지는 message_generation std_msgs roscpp 이렇게 3개다.

패키지가 쓸 참고 자료를 추가해준다고 생각하면 된다.

 


명령어를 실행하면 워닝 메세지가 뜰텐데, 무시해도 된다.

파일 폴더 다 합쳐서 4개가 자동으로 생겨났다.경로를 릴레이티브로 알려준다.

 

 

 

 

cd [패키지 이름]

패키지로 이동한다.

ls 명령어로 확인해보면, 폴더 두개 파일 두개가 만들어진 걸 직접 확인 할 수 있다.

패키지를 만들면 이 4개는 기본적으로 깔린다는 걸 까먹지 마라

 

여기 src랑 상위의 src랑 뭐가 다를까.

말장난 같지만, 경로가 다르다.

지역변수와 전역변수의 차이를 생각하면 된다.

 

CMakelist는 빌더가 참고하기 위한 설계도라고 보면 된다.
더 예를 들어보면, 아파트 단지는 패키지라고 볼 수있다.

아파트 한 동은 노드의 개념에 가깝다.

아파트 단지에 대한 설명은 catkin_ws 하위에 있던 CMakelist다.

현재 디렉토리의 CMakelist는 아파트 한 동에 대한 설명이다.

패키지 레벨에 있느냐 노드 레벨에 있느냐가 다른 것이다.

 

빌드하게 되면 상위의 CMakelist부터 참고된다.

catkin create pkg 할 때마다 패키지 단위의 CMakelist는 자동으로 수정이 된다.
패키지 레벨의 씨메이크리스트는 catkin_ws 하위에 있던 CMakelist 뿐이다.

그 밑에 노드 레벨의 씨메이크리스트들은 만드는대로 계속 생겨난다.

우리가 배우는 레벨에서는 노드 레벨의 씨메이크리스트만 수정을 하면 된다.나중엔 패키지 레벨도 건드릴 수 있다.
씨메이크리스트는 빌더가 볼 설명서다.
package.xml에는 패키지에 대한 간략한 설명이 들어가있다.

이 패키지를 누가 작성했고 누가 만들었고 누가 어써고, 누가 관리자고. 이런 속성 정보들이 들어간다.

빌더는 건물을 짓는 역할이라 상관이 없다.

사람들을 위해서 작성되는 파일이다.
include는 로스 이외에 뭔가 다른 것들을 라이브러리로 추가하고 싶을 때 사용한다.

즉 헤더 파일이 저장되는 곳이다.
src 상위의 src는 패키지가 담겼는데, 여기의 src에는 노드들이 들어간다.

src끼리 이름은 같지만 그런 부분이 다르다.

 

 

 

 

2. package.xml 수정

 

gedit package.xml

내용이 엄청 길다.

패키지 이름이 제대로 들어가있는지부터 확인한다.

컴퓨터가 스스로 알고 있는 정보들을 가지고 어느 정도 임의로 채워놓았다.

유지보수자 이메일과 이름 정도만 수정해주었다.

 

description에는 패키지에 대한 설명이 써있는데, 여기 하고 싶은말 쓰면 된다.
xml파일은 <>로 열고 </>로 닫는게 특징이다.

<!-- -->은 주석이라는 걸 알 수 있다.

다른 사람이 개발한 소스를 막 갖다 쓸 땐 존중하면서 갖다 써야한다.

저기 적어둔 연락처로 피드백도 받기도 한다.

 


여기까지는 사람을 위한 것이고, 그 다음으로 컴퓨터를 위한 부분이 나온다.

빌드를 할 때, 어떤 빌드 툴에 의존해서 빌드를 할 건지 등의 정보가 들어있다.

메세지제너레이션(메세지생성)은 한번만 하면 끝이다. 그래서 여기서 하는 것이다.
이 글에서는 있는 메세지를 사용하지 않고 직접 메세지를 만들어볼 것이다.

ctrl + s로 저장 후 창을 꺼준다.

 

 

그리고 mkdir msg를 해주었다.

디렉토리 이름은 어느정도 규칙이 정해져있다.

msg라고 쓴 건 topic을 가지고 통신하는 메세지들을 만들고 있기 때문이다.

publisher 노드와 subscriber 노드를 만들어볼 것이다.

srv와 action이 있는데, srv는 서비스의 약자고, action은 action이다.

통신 방식에 따른 것이다.

 

이전 글을 참조하면 도움이 될 듯 하다.

 

https://gradient-descent.tistory.com/66

 

ROS와 그 용어에 대해 알아보았다.

ROS의 기본 개념 ROS는 Robot Operating System으로, 로봇 응용 프로그램의 개발을 위한 운영체제와 같은 로봇 소프트웨어 플랫폼이다. Meta-Operating System에 속하며, 소프트웨어와 하드웨어의 중간 역할,

gradient-descent.tistory.com

 

이미 만들어져있는 패키지나 노드를 사용하려면 /opt/ros/share 꺼 쓰면 된다.

 

 

 

 

 

3. msg 파일 만들기

 

선행 조건은 당연히 경로를 이동해야한다.

gedit [메세지 이름].msg


gedit 등의 명령어로 없는 파일 만들고 저장하면 새로 생성이 된다.

msg 확장자를 썼다.
당연히 srv에 파일을 만들 땐 srv 파일을 만들고 action 파일을 만들 땐 action 확장자를 쓸 것이다.

 

time stamp
int32 data


msg 파일 안에 내용에 이렇게 입력해주었다.
앞은 자료형, 뒤에는 변수명이다.


확장자가 msg파일이라 변수 뒤에 세미콜론 같은 거 안붙여도 된다.

저장해주고 창을 닫는다.

당장 헤더를 추가하거나 하고 싶은 게 없기 때문에 인클루드는 건드리지 않을 것이다.

 

 

 

 

 

 


4. publisher 노드 만들기

 

cd ..

cd src/

노드에 들어간다.

또 gedit 편집기를 이용해, 퍼블리셔 노드를 만들어볼 것이다.

gedit pub_test.cpp

일단은 노드에는 한가지 기능만 넣을 것이므로 이름을 pub_test.cpp로 만들었다. (pub는 퍼블리셔를 의미한다)

 

 


로스 기본 헤더파일을 추가했다. 왜 추가할까?

기본적으로 로스가 가지고 있는 함수들을 쓸 거니까 로스 기본 헤더 파일을 추가해준 것이다.

c언어에서 stdio 헤더를 추가하고 printf 함수와 scanf 함수를 쓸 수 있게 되는 것과 같다.

msg_tutorial은 아까 만든 메세지파일 이름이다.

메세지 파일 이름이나 패키지 파일 이름은 우리가 바꾸면 바뀐다.

이미지의 두번째 줄에는 include 패키지 이름/메세지파일이름.h를 넣는다.

메세지 제너레이션을 하면서 이 헤더 파일이 생길 예정이다.

빌드할 때 생길 건데 아직 안생겼다. 그래서 이 시점에서는 컴퓨터가 저걸 못읽는다.

 


그 다음 메인함수를 작성해주었다.
ros::을 사용할 수 있는 이유는 로스 헤더를 추가해줬기 때문이다.

 

ros::init(argc, argv, "pub_test"); 에서 노드명을 초기화해주었다.
파일 이름을 정했으니까, 노드명을 초기화해주는 것이다.
ros::NodeHandle nh;에서 ROS 시스템과 통신을 위한 노드 핸들을 선언했다.
시스템과 통신을 위한 노드를 조절하여 컴퓨터가 그 노드를 잘 인식할 수 있게 노드핸들을 선언한 것이다.

nh는 그냥 핸들 이름이다. 내 맘대로 정한 것이다. 이 한 줄에서 내 맘대로 쓴 건 nh 뿐이다.

 

ros::Publisher pub = nh.advertise<wooju_tutorial::wj_msg_tutorial>("wj_topic",100);
퍼블리셔 기능을 선언하는 함수를 사용했다.

ros::Publisherpub이라는 이름으로 퍼블리셔를 하나 만든 것이다. 
노드 핸들을 사용할 것이다.퍼블리셔는 발행을 한다. 

광고를 해야 노드 핸들을 타고 들어온다고 생각하자.

그게 advertise라는 기능이다. advertise가 괜히 advertise가 아니다.

 

꺽쇠 괄호 안에 <wooju_tutorial::wj_msg_tutorial>를 보자.

패키지 이름::메세지 이름("wj_topic",100); 이렇게 되어있는 것이다.
토픽 이름을 여기서 지어줬고, 그 옆에 100은 데이터를 저장할 공간을 100개를 열어준다는 뜻이다.

어떤 토픽으로 어떤 메세지를 advertise할 것인지를 선택했다.

뒤에서 부터 해석을 해보면 된다.

퍼블리셔를 만드는 과정이 한줄에 적혀있다.

 

이제 알았겠지만, init, nodehandle, publisher 얘네는 ros의 함수다. 

괄호친 부분은 우리의 설정에 따라 바뀔수 있는 것이다.

ros::Rate loop_rate(10);에서 loop_rate는 직접 이름을 지은 것으로, 바꿀 수 있다.

10은 주기를 쓴 것이다. 주기는 1초에 몇 번 진동하는지다.

1초 단위다. 10을 쓰면 1초에 10번 loop를 실행할 것이다.


wooju_tutorial::wj_msg_tutorial msg; 
메세지를 사용해서 이 안에서 msg(바꿀 수 있음)라는 이름의 내가 만든 메세지 파일 형식으로, msg라는 메세지를 선언한다.
학교 다닐 때의 반장을 생각해보자.

어떤 반에나 반장이 있고, 그 반장들의 기능과 각 반에 존재한다는 것은 똑같았다.

구분은 몇 반 반장 이런 식으로 구분을 했을 것이다.
msg가 1반 2반 같다고 보면 된다.

이 이름으로 메세지 타이틀을 활용하겠다는 의미다.


ros::ok는 로스를 실행할 때 로스가 실행이 된다 안된다의 값이 들어오는 함수이다.
msg.stamp = ros::Time::now();
msg.date = count;

msg는 yh_msg_tutorial msg에서 온 것이다. stamp라는 변수명을 바꾸고 싶으면, 이전에 수정했던 msg파일에서 변수명 stamp를 다른 걸로 바꾸면 된다.


ROS_INFO("send msg = %d", msg.stamp.sec);
ROS_INFO("send msg = %d", msg.stamp.nsec);
ROS_INFO("send msg = %d", msg.stamp.data);
printf 같은 느낌이다.

콘솔창에 이 부분을 보여줄 것이다.

 

pub.publish(msg);
퍼블리셔 이름.퍼블리시 함수(발행할 메세지)이전까지는 설정이였는데, 여기서는 메세지를 실제로 발행된다.

 

loop_rate.sleep();
루프를 잠시 죽인다.

 

++count;
카운트를 플러스플러스 해준다.주기를 10으로 했으니 0.1초에 한 번 카운트될 것임.
내가 만든 어떤 노드 안에 퍼블리셔 기능만을 넣은 것이다.다른 기능도 더 넣을 수 있다.내가 그렇게 만든 것이다.

!!!!이 텍스트파일에서 하는 모든 과정이 하나의 노드를 만들고 있는 것이다.

 

 

 

 

 

 

 

내용이 너무 길어서 다음 글로 이어진다.

 

 

https://gradient-descent.tistory.com/70

 

728x90