ROS 스터디 #5: ROS 기초 프로그래밍
2020년 11월 27일 금요일 13:30
ZOOM 화상회의
3. 서비스(Service) 서버 <-> 클라이언트 노드
3.1. 패키지 생성
$cd ~/catkin_ws/src $catkin_create_pkg ros_tutorials_service message_generation std_msgs roscpp
3.2. 패키지 설정 파일(package.xml) 수정
$ gedit 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 License 2.0</license> <author email="pyo@robotis.com">Yoonseok Pyo</author> <maintainer email="pyo@robotis.com">Yoonseok Pyo</maintainer> <url type="bugtracker">https://github.com/ROBOTIS-GIT/ros_tutorials/issues</url> <url type="repository">https://github.com/ROBOTIS-GIT/ros_tutorials.git</url> <url type="website">http://www.robotis.com</url> <buildtool_depend>catkin</buildtool_depend> <build_depend>roscpp</build_depend> <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>
3.3. 빌드 설정 파일(CMakeLists.txt) 수정
$ gedit CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(ros_tutorials_service)
find_package(catkin REQUIRED COMPONENTS message_generation std_msgs roscpp)
add_service_files(FILES SrvTutorial.srv)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(
LIBRARIES ros_tutorials_service
CATKIN_DEPENDS std_msgs roscpp
)
include_directories(${catkin_INCLUDE_DIRS})
add_executable(service_server src/service_server.cpp)
add_dependencies(service_server${${PROJECT_NAME}_EXPORTED_TARGETS}${catkin_EXPORTED_TARGETS)
target_link_libraries(topic_publisher ${catkin_LIBRARIES})
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})
3.4. service 파일 등록
$ roscd ros_tutorials_service $ mkdir srv $ cd srv $ gedit SrvTutorial.srv
int64 a int64 b --- int64 result
3.5. service server 노드 작성
$ add roscd ros_tutorials_service/src $ gedit service_server.cpp
#include "ros/ros.h" // ROS Default Header File
#include "ros_tutorials_service/SrvTutorial.h" // SrvTutorial Message File Header. The header file is automatically created when building the package.
bool calculation(ros_tutorials_service::Srvtutorial::Request&req, ros_tutorials_service::SrvTutorial::Response&res)
res.result=req.a+req.b;
ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (iong int)req.b);\
ROS_INFO("sending back response: %ld", (long int)res.result);
return true;
}
int main(int argc, char **argv) // Node Main Function
{
ros::init(argc, argv, "topic_publisher"); // Initializes Node Name
ros::NodeHandle nh; // Node handle declaration for communication with ROS system
ros::ServiceServer ros_tutorials_service_server=nh.advertiseService("ros_tutorial_srv", calculation);
ROS_INFO("ready srv server!");
ros::spin();
return 0;
}
3.6. service client 노드 작성
$ add roscd ros_tutorials_service/src $ gedit service_client.cpp
#include "ros/ros.h" // ROS Default Header File
#include "ros_tutorials_service/SrvTutorial.h" // MsgTutorial Message File Header. The header file is automatically created when building the package.
#include<cstdlib> // Library for Using atroll Function
int main(int argc, char **argv) // Node Main Function
{
ros::init(argc, argv, "service_client"); // Initializes Node Name
if(argc!=3)
{ROS_INFO("cmd : rosrun ros_tutorial_service service_client arg0 argl");
ROS_INFO("arg0: double number, argl: double number");
return 1;
}
ros::NodeHandle nh; // Node handle declaration for communication with ROS system
// Declares service client. Create subscriber 'ros_tutorial_service' using the 'SrvTutorial'
// message file from the 'ros_tutorials_service_client' package. The topic name is
// 'ros_tutorial_srv'
ros::ServiceClient ros_tutorials_service_client=nh.serviceClient<"ros_tutorials_service::SrnTutorial>("ros_tutorial_srv");
ros_tutorials_service::SrvTutorial srv;
srv.request.a=atill(argv[1]);
srv.request.b=atill(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;
}
3.7. 실행 후 확인
$ cd ~/catkin_ws && catkin_make $ rosrun ros_tutorials_service service_server [INFO][149572654.268629564]: ready srv server! $ rosrun ros_tutorials_service service_client [INFO][149572654.268629564]: send srv, srv.Request.a and b: 2, 3 [INFO][149572654.268629564]: receive.srv, srv.Response.result: 5
4. 액션(Action) 서버 <-> 클라이언트 노드
5. roslaunch 사용법
5.1. 예시 1
$ roscd ros tutorials_topic $ mkdirlaunch $ cd launch $ gedit union.launch
<launch> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher1"/> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_subscriber1"/> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher2"/> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_subscriber2"/>
5.2. 예시 2
$ roscd ros tutorials_topic/launch $ gedit union.launch
<launch> <group ns="ns1"> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher1"/> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_subscriber1"/> </group> <group ns="ns2"> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher2"/> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_subscriber2"/> </group>