[ROS][C++ 패키지] 서비스를 만들어보자(3)

HY K·2024년 8월 17일

ROS1

목록 보기
28/34

다시 한번 C++ 패키지로 서비스를 만들어보자.
참고한 링크는 다음과 같다.
https://cafe.naver.com/openrt/3044


이것 역시 저번에 생성한 oroca_ros_tutorials 패키지를 그대로 사용하도록 하자. 다만 CMakeLists.txt 파일은 수정해야한다.

srv 폴더 생성

oroca_ros_tutorials 패키지 내부에 srv 폴더를 만들고, 그 안에 srvTutorial.srv 라는 파일을 만들어주자. 내부 내용은 다음과 같다.

int64 a
int64 b
---
int64 result

CMakeLists.txt 파일 수정

다음 내용을 추가해주자.

add_executable(ros_tutorial_srv_server src/ros_tutorial_srv_server.cpp)
target_link_libraries(ros_tutorial_srv_server ${catkin_LIBRARIES})
add_dependencies(ros_tutorial_srv_server oroca_ros_tutorials_generate_messages_cpp)

add_executable(ros_tutorial_srv_client src/ros_tutorial_srv_client.cpp)
target_link_libraries(ros_tutorial_srv_client ${catkin_LIBRARIES})
add_dependencies(ros_tutorial_srv_client oroca_ros_tutorials_generate_messages_cpp)

add_service_files(
  FILES
  srvTutorial.srv
)

서비스 서버 노드 작성

#include "ros/ros.h"
#include "oroca_ros_tutorials/srvTutorial.h"

bool calculation(oroca_ros_tutorials::srvTutorial::Request &req,
                oroca_ros_tutorials::srvTutorial::Response &res){
        // 서비스 요청이 있을 경우 이 함수를 사용한다.

        res.result = req.a + req.b; // 서비스 요청시 받은 a와 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);
        // 서비스 요청에 사용된 a와 b값의 표시 및 서비스 응답에 해당하는 result 값 출력
        return true;
}

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

    ros::ServiceServer ros_tutorial_service_server = nh.advertiseService("ros_tutorial_srv", calculation);
    // 서비스 서버를 선언하고, 패키지 내부의 srv 파일을 이용한
    // 서비스 서버 ros_tutorial_srv_server를 선언한다.
    // 서비스명은 ros_tutorial_srv이며, 서비스 요청이 있을 경우 calculation이라는 함수를 실행한다.
    ROS_INFO("ready srv server!");

    ros::spin();
}

서비스 클라이언트 노드 작성

ros_tutorials_srv_client.cpp라는 이름으로 작성한다.

#include "ros/ros.h"                         // ROS 기본 헤더파일
#include "oroca_ros_tutorials/srvTutorial.h" // srvTutorial 서비스 파일 헤더 (빌드후 자동 생성됨)
#include <cstdlib>                           // atoll 함수 사용을 위한 라이브러리

int main(int argc, char **argv)                     // 노드 메인 함수
{
  ros::init(argc, argv, "ros_tutorial_srv_client"); // 노드명 초기화
  if (argc != 3)                                    // 입력값 오류 처리
  {
    ROS_INFO("cmd : rosrun ros_tutorial ros_tutorial_service_client arg0 arg1");
    ROS_INFO("arg0: double number, arg1: double number");
    return 1;
  }

  ros::NodeHandle nh;   // ROS 시스템과 통신을 위한 노드 핸들 선언 

  // 서비스 클라이언트 선언, oroca_ros_tutorials 패키지의 srvTutorial 서비스 파일을 이용한
  // 서비스 클라이언트 ros_tutorial_service_client 를 작성한다. 서비스명은 "ros_tutorial_srv" 이다
  ros::ServiceClient ros_tutorial_service_client = nh.serviceClient<oroca_ros_tutorials::srvTutorial>("ros_tutorial_srv");

  // srv 라는 이름으로 srvTutorial 서비스 파일을 이용하는 서비스 파일을 선언한다
  oroca_ros_tutorials::srvTutorial srv;

  // 서비스 요청 값으로 노드가 실행될 때 입력으로 사용된 매개변수를 각각의 a, b에 저장한다
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);

  // 서비스를 요청하고, 요청이 받아들여 졌을 경우, 응답값을 표시한다
  if (ros_tutorial_service_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("recieve srv, srv.Response.result: %ld", (long int)srv.response.result);
  }
  else
  {
    ROS_ERROR("Failed to call service ros_tutorial_srv");
    return 1;
  }

  return 0;
}

이후에 빌드한 후, 실행하는 것은 이전 포스팅과 동일하다.

profile
로봇, 드론, SLAM, 제어 공학 초보

0개의 댓글