차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
다음 판
이전 판
activity:public:2021:ros:5 [2021/09/28 20:52:03] – [ROS STUDY #5 : ROS 기초프로그래밍 2(service, action)] yhy01625activity:public:2021:ros:5 [2021/10/03 15:47:58] (현재) yhy01625
줄 1: 줄 1:
 +======ROS STUDY #5 : ROS 기초프로그래밍 2(service)======
 +
 +{{youtube>GTkIy-NRI9c?medium}}
 +=====1. Service 패키지 생성=====
 +<sxh bash>
 +cd ~/catkin_ws/src  // 작업공간 아래 소스 폴더로 이동
 +catkin_create_pkg ros_tutorials_service message_generation message_runtime roscpp std_msgs
 +//catkin_create_pkg [만들 패키지 이름] [의존성 패키지1] [의존성 패키지2]...
 +</sxh>
 +
 +캐킨 명령어로 패키지를 생성하면 src 폴더 아래 다음과 같은 폴더와 파일들이 생성된다. 아래의 명령어로 해당 패키지 폴더로 이동하여 확인할 수 있다.
 +<sxh bash>
 +cd ros_tutorials_service
 +ls
 +</sxh>
 +
 +  include → 헤더 파일 폴더
 +  src → 소스 코드 폴더
 +  CMakeLists.txt → 빌드 설정 파일
 +  package.xml → 패키지 설정 파일
 +\\
 +====1.1. package.xml====
 +기본 뼈대만 적힌 패키지 설정 파일(package.xml)을 열어 추가 정보를 기입하자.\\
 +터미널에 다음 코드를 입력하여 파일을 열자.
 +<sxh bash>
 +gedit package.xml
 +</sxh>
 +
 +Visual Studio Code로 파일을 열고 싶다면 이 코드를 사용하자.
 +<sxh bash>
 +code package.xml
 +</sxh>
 +
 +<sxh xml; highlight: [19-19,24-24] title:package.xml>
 +<!-- 패키지 형식 -->
 +<package format="2">
 +  <!-- 패키지 이름 -->
 +  <name>ros_tutorials_service</name>
 +  <!-- 패키지 버전(나중에 배포할 시 업데이트 하며 수정하면 됨) -->
 +  <version>0.0.0</version>
 +  <!-- 패키지 설명 -->
 +  <description>The ros_tutorials_service package</description>
 +  <!-- 패키지를 유지, 보수 하는 사람의 연락처 -->
 +  <maintainer email="KAsimov@korea.ac.kr">KAsimov</maintainer>
 +  <!-- 라이센스 입력하는 곳(Apach 2.0, BSD 등) -->
 +  <license>TODO</license>
 +  
 +  <!-- 패키지를 빌드하는 데 사용되는 툴 -->
 +  <buildtool_depend>catkin</buildtool_depend>
 +
 +  <!-- 빌드시 사용되는 의존성 패키지 -->
 +  <build_depend>message_generation</build_depend>
 +  <build_depend>message_runtime</build_depend>
 +  <build_depend>roscpp</build_depend>
 +  <build_depend>std_msgs</build_depend>
 +
 +  <!-- 실행파일 빌드시 사용되는 의존성 패키지(src폴더의 파일들이 노드 실행파일로 만들어질 때 사용되는 패키지) -->
 +  <build_export_depend>message_generation</build_export_depend>
 +  <build_export_depend>roscpp</build_export_depend>
 +  <build_export_depend>std_msgs</build_export_depend>
 +
 +  <!-- 빌드 후 실행시 사용되는 의존성 패키지 -->
 +  <exec_depend>message_runtime</exec_depend>
 +  <exec_depend>roscpp</exec_depend>
 +  <exec_depend>std_msgs</exec_depend>
 +
 +  <export></export>
 +</package>
 +</sxh>
 +\\
 +====1.2. CMakeLists.txt====
 +빌드 설정 파일(CMakeLists.txt)에는 작성한 노드를 빌드할 때, 즉 소스코드 작성 후 실행파일을 만들때 사용되는 옵션들이 적혀 있다. 해당 파일을 열어 다음과 같이 수정하자.
 +<sxh bash>
 +gedit CMakeLists.txt
 +</sxh>
 +
 +<sxh cpp; highlight: [17-20],[25-28],[31-34],[45-45],[47-47],[49-49],[54-56] title:CMakeLists.txt>
 +## cmake의 최소 요구 버전
 +cmake_minimum_required(VERSION 3.0.2)
 +## 패키지 이름과 동일, 이름과 다르면 빌드가 안된다.
 +project(ros_tutorials_service)
 +
 +## 의존성 패키지
 +## 캐킨 빌드를 할 때 요구되는 구성요소 패키지이다.
 +## 의존성 패키지로 message_generation, std_msgs, roscpp이며 이 패키지들이 존재하지 않으면 빌드 도중에 에러가 난다.
 +find_package(catkin REQUIRED COMPONENTS
 +  message_generation
 +  message_runtime
 +  roscpp
 +  std_msgs
 +)
 +
 +## 새로 만들 메세지 이름 (58번째 줄 수정)
 +add_service_files(
 +  FILES
 +  SrvTutorial.srv
 +)
 +
 +## 의존성 (71번째 줄 수정)
 +## 의존하는 메시지를 설정하는 옵션이다.
 +## std_msgs가 설치되어 있지 않다면 빌드 도중에 에러가 난다.
 +generate_messages(
 +  DEPENDENCIES
 +  std_msgs
 +)
 +
 +##캐킨 패키지 옵션으로 라이브러리, 캐킨 빌드 의존성, 시스템 의존 패키지를 기술한다. (107,108번째 줄 수정)
 +catkin_package(
 +  LIBRARIES ros_tutorials_service
 +  CATKIN_DEPENDS message_generation message_runtime roscpp std_msgs
 +)
 +
 +## 인클루드 디렉터리를 설정한다.
 +include_directories(
 +  ${catkin_INCLUDE_DIRS}
 +)
 +
 +## service_server 노드에 대한 빌드 옵션이다.
 +## 실행 파일, 타겟 링크 라이브러리, 추가 의존성 등을 설정한다.
 +## service_server:노드, service_server.cpp: 노드를 만들 때 참고해야할 소스코드
 +## 136번째 줄 수정
 +add_executable(service_server src/service_server.cpp)
 +## 146번째 줄 수정
 +add_dependencies(service_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
 +## 149번째 줄 수정
 +target_link_libraries(service_server ${catkin_LIBRARIES})
 +
 +## service_client 노드에 대한 빌드 옵션이다.
 +## service_client:노드, service_client.cpp: 노드를 만들 때 참고해야할 소스코드
 +## 151번째 줄에 추가로 작성
 +add_executable(service_client src/service_client.cpp)
 +add_dependencies(service_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
 +target_link_libraries(service_client ${catkin_LIBRARIES})
 +</sxh>
 +\\
 +=====2. 서비스 파일(srv) 작성=====
 +아래 코드를 통해 srv 폴더를 만들고, 그 폴더로 이동하여 SrvTutorial.srv 파일을 새로 만들어 내용을 추가하자.
 +<sxh bash>
 +mkdir srv
 +cd srv
 +gedit SrvTutorial.srv
 +</sxh>
 +
 +<sxh cpp title:srv/SrvTutorial.srv>
 +int64 a
 +int64 b
 +---
 +int64 result
 +</sxh>
 +
 +  * int64 : 메세지 자료형
 +  * a, b : 서비스 요청(request)
 +  * result : 서비스 응답(response)
 +  * ''---'' : 요청과 응답을 구분하는 구분자
 +\\
 +=====3. 서비스 노드 코드 작성=====
 +====3.1. 서버(server)====
 +아래 코드를 통해 소스 폴더로 이동해 service_server.cpp 파일을 새로 만들고 내용을 수정하자.
 +<sxh bash>
 +roscd ros_tutorials_service/src
 +gedit service_server.cpp
 +</sxh>
 +
 +<sxh cpp title:src/service_server.cpp>
 +#include "ros/ros.h"  // ROS 기본 헤더 파일
 +#include "ros_tutorials_service/SrvTutorial.h"  // SrvTutorial 서비스 파일 헤더 (빌드 후 자동 생성됨)
 +
 +// 서비스 요청이 있을 경우, 아래의 처리를 수행한다.
 +// 서비스 요청은 req, 서비스 응답은 res로 설정하였다.
 +bool calculation(ros_tutorials_service::SrvTutorial::Request &req, ros_tutorials_service::SrvTutorial::Response &res)
 +{
 +  // 서비스 요청시 받은 a와 b 값을 더하여 서비스 응답 값에 저장한다.
 +  res.result = req.a + req.b;
 +
 +  // 서비스 요청에 사용된 a, b 값의 표시 및 서비스 응답에 해당되는 result 값을 출력한다.
 +  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;
 +}
 +
 +int main(int argc, char **argv)  // 노드 메인 함수
 +{
 +  ros::init(argc, argv, "service_server");  // 노드명 초기화
 +  ros::NodeHandle nh;  // 노드 핸들 선언
 +
 +  // 서비스 서버 선언, ros_tutorials_service 패키지의 SrvTutorial 서비스 파일을 이용한 서비스 서버 ros_tutorials_service_server를 선언한다.
 +  // 서비스명은 ros_tutorial_srv이며 서비스 요청이 있을 때, calculation라는 함수를 실행하라는 설정이다.
 +  ros::ServiceServer ros_tutorials_service_server = nh.advertiseService("ros_tutorial_srv", calculation);
 +
 +  ROS_INFO("ready srv server!");
 +
 +  ros::spin(); // 서비스 요청을 대기한다.
 +
 +  return 0;
 +}
 +</sxh>
 +\\
 +====3.2. 클라이언트(client)====
 +위에서처럼 service_client.cpp 파일을 새로 만들고 내용을 수정하자.
 +<sxh bash>
 +gedit service_client.cpp
 +</sxh>
 +
 +<sxh cpp title:src/service_client.cpp>
 +#include "ros/ros.h"  // ROS 기본 헤더 파일
 +#include "ros_tutorials_service/SrvTutorial.h"  // SrvTutorial 서비스 파일 헤더 (빌드후 자동 생성됨)
 +#include <cstdlib>  // atoll 함수 사용을 위한 라이브러리
 +
 +int main(int argc, char **argv)  // 노드 메인 함수
 +{
 +  ros::init(argc, argv, "service_client");  // 노드명 초기화
 +
 +  if (argc != 3)  // 입력값 오류 처리
 +  {
 +    ROS_INFO("cmd : rosrun ros_tutorials_service service_client arg0 arg1");
 +    ROS_INFO("arg0: double number, arg1: double number");
 +
 +    return 1;
 +  }
 +
 +  ros::NodeHandle nh;  // ROS 시스템과 통신을 위한 노드 핸들 선언
 +
 +  // 서비스 클라이언트 선언, ros_tutorials_service 패키지의 SrvTutorial 서비스 파일을 이용한 서비스 클라이언트 ros_tutorials_service_client를 선언한다.
 +  // 서비스명은 "ros_tutorial_srv"이다.
 +  ros::ServiceClient ros_tutorials_service_client = nh.serviceClient<ros_tutorials_service::SrvTutorial>("ros_tutorial_srv");
 +
 +  // srv라는 이름으로 SrvTutorial 서비스 파일을 이용하는 서비스를 선언한다.
 +  ros_tutorials_service::SrvTutorial srv;
 +
 +  // 서비스 요청 값으로 노드가 실행될 때 입력으로 사용된 매개변수를 각각의 a, b에 저장한다.
 +  srv.request.a = atoll(argv[1]);
 +  srv.request.b = atoll(argv[2]);
 +
 +  // 서비스를 요청하고, 요청이 받아들여졌을 경우, 응답 값을 표시한다.
 +  if (ros_tutorials_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("receive srv, srv.Response.result: %ld", (long int)srv.response.result);
 +  }
 +  else
 +  {
 +    ROS_ERROR("Failed to call service ros_tutorial_srv");
 +
 +    return 1;
 +  }
 +
 +  return 0;
 +}
 +</sxh>
 +\\
 +=====4. ROS 노드 빌드=====
 +다음 명령어로 ros_tutorials_service 패키지의 서비스 파일, 서비스 서버 노드와 클라이언트 노드를 빌드한다.
 +<sxh bash>
 +cd ~/catkin_ws && catkin_make
 +</sxh>
 +\\
 +=====5. 서비스 노드 실행=====
 +====5.1. 서비스 서버 실행====
 +roscore을 실행한 뒤 다음 코드로 서비스 서버를 실행한다.
 +<sxh bash>
 +rosrun ros_tutorials_service service_server
 +</sxh>
 +
 +  [INFO] [1495726541.268629564]: ready srv server!
 +\\
 +====5.2. 서비스 클라이언트 실행====
 +마찬가지로 서비스 클라이언트를 실행하자.
 +<sxh bash>
 +rosrun ros_tutorials_service service_client 2 3
 +</sxh>
 +
 +  [INFO] [1495726543.277216401]: send srv, srv.Request.a and b: 2, 3
 +  [INFO] [1495726543.277258018]: receive srv, srv.Response.result: 5
 +