ROS 패키지 생성하기(ServiceServer, ServiceClient, Service사용)
이번에는 Service 메세지를 이용하여 패키지를 만들어 본다.
노드로는 Service Server, Service Client 의 구성이 된다.
먼저 무조건 선행되어야할 ... 워크스페이스(catkin_ws)의 src로 이동한다. ( 패키지 생성 디렉토리 )
그 다음으로는 패키지 생성 명령어를 입력한다.
$ catkin_create_pkg [패키지이름] [의존성패키지1 의존성패키지2 .....]
이번에도 메세지 파일을 내가 만들어 쓸 것 이기 때문에 message_generation 을 추가하였다.
src 하위로 yh_tuto_service 디렉토리가 생성되고 ,
하위로 package.xml , CMakeLists.txt 파일,
include, src 디렉토리가 생성된다.
패키지 디렉토리로 이동하여 작업하자!!!
먼저 안해도 상관은 없으나 , 전에 했던대로 , package.xml 파일을 수정해본다. ( 패키지 정보 파일 )
$ gedit package.xml
실행 . 에디트가 열리면 내 정보로 수정해준다.
다음으로 , 메시지 디렉토리를 생성해주자.
이전에는 topic 메시지를 사용하여서 디렉토리이름을 msg 라고 하였으나 ,
이번에는 service 메시지를 사용할 것 이기 때문에 srv 로 한다.
디렉토리를 만들고 , 디렉토리로 이동 후 에
메시지 파일을 만들어줘야 한다. 메시지 파일까지 만들어 본다.
$ mkdir srv
$ cd srv
$ gedit [서비스파일이름.srv]
** 서비스 파일이름은 yh_srv.srv 로 하였다.
서비스파일 에디터에는 topic 때와 다르게 , request 부분과 response 부분을 나누어 작업하는데
이는 --- 로 나타낸다.
작성 방법은 마찬가지로
데이터타입 변수명 으로 작성한다.
일단 예제로 간단하게 만들었다. 숫자 두개를 받아서 결과를 숫자로 응답한다는 것이다.
그 다음으로 노드를 생성한다.
노드는 패키지명디렉토리의 src 디렉토리 하위에 작업한다. 이동해준다.
그리고 노드를 두개 ( service server, service client )를 만들어 줘야하는데,
먼저 service server 노드를 만들어 주겠다.
순서는 아래와 같다.
$ cd src
$ gedit [노드이름.cpp]
*** srv_server.cpp 로 만들었다.
에디터파일은 아래와 같이 작성한다. 아래는 예제로
숫자 두개를 받아 덧셈을 하는 서비스 서버이다.
코드예제 ( srv_server.cpp )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#include "ros/ros.h"
#include "yh_tuto_service/yh_srv.h" //서비스를 사용하니까 서비스 파일.h
bool calculation(yh_tuto_service::yh_srv::Request &req, yh_tuto_service::yh_srv::Response &res) //req, res선언
// 패키지이름 , 서비스파일이름, 요청 , 응답
//메세지파일에 요청 응답이 나뉘어 있음
{
res.result = req.a + req.b; //메시지파일에 있는 변수
ROS_INFO("request : x = %ld, y = %ld",(long int)req.a, (long int)req.b);
ROS_INFO("sending back response : %ld",(long int)res.result);
return true; // bool형이기때문에 return이 true
} // 함수 만들기
//main 문 만들기
int main(int argc, char **argv)
{
ros::init(argc, argv, "srv_server"); // 초기화
ros::NodeHandle nh; // 노드핸들 선언
ros::ServiceServer server = nh.advertiseService("hamburger", calculation);
ROS_INFO("ready srv server!!");
ros::spin(); //요청이 올때까지 기다린다.spin
return 0;
}
|
cs |
여기에는 서비스파일 헤더가 들어간다. ( 메시지 파일 )
hamburger는 서비스 이름..
이렇게 서버를 만들고 , 다음으로 클라이언트 노드를 만든다.
클라이언트 노드에서는 메시지파일에 있는 것처럼 , 서버로 숫자 2개를 보내 요청하고 , 응답을 기다린다.
코드예제 ( srv_client.cpp )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#include "ros/ros.h"
#include "yh_tuto_service/yh_srv.h" // 서비스파일 헤더
#include <cstdlib> //atoll 이라는 함수를 쓰려고 넣어준 라인
int main(int argc, char **argv)
{
ros::init(argc, argv, "srv_client");
if(argc !=3) // 요청시 노드이름 , 숫자1 , 숫자2로 요청하기때문에 3개가 되어야한다.(예제)
{
ROS_INFO("cmd : rosrun yh_tuto_service srv_client arg0 arg1");
ROS_INFO("arg0 : double number, arg1 : double number");
return 1;
}
ros::NodeHandle nh;
ros::ServiceClient client = nh.serviceClient<yh_tuto_service::yh_srv>("hamburger");
yh_tuto_service::yh_srv srv;
srv.request.a = atoll(argv[1]); //atoll은 입력되는 값을 분리하는 함수.
srv.request.b = atoll(argv[2]);
if(client.call(srv)) // 요청을 보내는곳
{
ROS_INFO("send srv, srv.Request.a and b : %ld, %ld", (long int)srv.request.a, (long int)srv.request.b);
ROS_INFO("receive srv, srv.Response.result : %ld",(long int)srv.response.result);
}
else
{
ROS_ERROR("Failed to call service");
return 1;
}
return 0;
}
|
cs |
이렇게 까지 하면 노드는 완성 되었다.
클라이언트 노드는 메시지 파일 대로 숫자 2개를 요청하고 , 응답받는다.
이제 패키지의 CMakeLists.txt 파일을 수정한다.
수정은 이전 패키지 때와 같으니 아래를 참고한다.
아래를 볼때 수정된 내용, 주석이 풀린내용, 노드 이름등의 확인!!!이 중요하다.
##############
Install
##############
부분은 건드릴게 없다.
이제 끝이다 . 패키지 디렉토리에서 catkin_make 실행해서 빌드시키자!!
후에 빌드된 내용을 source devel/setup.bash 명령어로 등록시켜주고,
rospack profile 을 실행한다.
여기까지 다 됐으면, 이제 만든 서비스를 실행시켜본다.
먼저 하나의 터미널에서 roscore를 실행시키고 ,
다른 하나의 터미널로 서버노드를 실행시킨다.
마지막 다른 터미널로 클라이언트 노드를 실행시키는데 , 이때 작성한 코드에 맞게 숫자 두개를 함께 입력해줘야한다.
그러면 숫자가 코드에 맞게 덧셈이 되어 나올것이다.
확인해보자.
실행 명령어도 같이 확인!
완성!!!
서비스 메시지는 클라이언트가 요청하고 응답을 받으면 클라이언트는 연결이 해제 된다!!!!!