ROS node調用service: ros::service::call/client.call()

簡介:介紹如何在一個node裏調用現有的rosservice list查詢到的service。node

效果:經過talker publish須要調用服務的數據,listener接收到數據後調用服務進行三個整形數據相加,並返回相加和。ubuntu

環境:ubuntu 14.04 +indigo.api

備註:文中未詳細介紹的api或ros的基本函數請參看以前博文。bash

[正文]函數

建立過程相似wiki教程中msg和srv的測試過程。在beginner_turtorials包下面建立。oop

1,建立msg文件夾,srv文件夾。測試

msg 文件夾下建立Num.msg,內容是this

int32 A命令行

int32 B設計

int32 C

srv文件夾下AddTwoInts.srv,內容是

int32 A

int32 B

int32 C

---

int32 sum

該文件表面輸入是ABC,返回是 sum,二者經過「---」分割。

2,而後更改CMakeList.txt文件,修改成以下內容,主要設計msg,srv的其餘依賴關係及編譯運行的相關關係。

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
## Generate messages in the 'msg' folder
 add_message_files(
   FILES
   Num.msg
 )


## Generate services in the 'srv' folder
 add_service_files(
   FILES
   AddTwoInts.srv
 )
## Generate added messages and services with any dependencies listed here
 generate_messages(
   DEPENDENCIES
   std_msgs
 )
# include_directories(include)
include_directories(
  ${catkin_INCLUDE_DIRS}
)
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES beginner_tutorials
#  CATKIN_DEPENDS roscpp rospy std_msgs
#  DEPENDS system_lib
  CATKIN_DEPENDS message_runtime
)

也可參考,wiki中CreatingMsgAndSrv中過程,名稱都沒有改變,只是改變了文件中內容,改寫完成後能夠在catkin_ws目錄下catkin_make一次,並source devel/setup.bash下。

3,創建幾個cpp的源文件,位於src目錄下。

3.1 src/example_srv_request.cpp

做用:主要實現服務的定義,初始化,註釋因爲ubuntu沒裝漢語輸入,所以註釋爲英文...聊勝於無。

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

bool add(beginner_tutorials::AddTwoInts::Request &req,
         beginner_tutorials::AddTwoInts::Response &res)
{
    res.sum=req.A+req.B+req.C;
    ROS_INFO("request: A=%ld,B=%ld,C=%ld",(int)req.A,(int)req.B,(int)req.C);
    ROS_INFO("sending back response:[%ld]",(int)res.sum);

    return true;
}


int main(int argc,char **argv)
{
   ros::init(argc,argv,"add_3_ints_server");
   ros::NodeHandle n;
   //init service:
   //Name: add_3_ints,advertise the service. add: call back function
   ros::ServiceServer service=n.advertiseService("add_3_ints",add);
   ROS_INFO("Ready to add 3 ints.");
   ros::spin();// start to deal with the call back event

   return 0;
}
3.2 src/example_srv_response.cpp,該文件並不是必要,是典型的client調用服務的形式,並不是此文目的,不添加最終目的也可實現,調用示例是(如今還不能調用):

rosrun beginner_tutorials example_srv_response 1 2 3

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>


int main(int argc,char **argv)
{
    ros::init(argc,argv,"add_3_ints_client");
    if(argc != 4)
    {
        ROS_INFO("usage: add_3_ints_client A B C");
        return 1;
    }
    ros::NodeHandle n;
    ros::ServiceClient client=n.serviceClient<beginner_tutorials::AddTwoInts>("add_3_ints");

    beginner_tutorials::AddTwoInts srv;

    //atoll:convert a string to long long int variable
    srv.request.A=atoll(argv[1]);
    srv.request.B=atoll(argv[2]);
    srv.request.C=atoll(argv[3]);


    if(client.call(srv))
    {
        ROS_INFO("Sum:%ld",(long int)srv.response.sum);
    }
    else
    {
        ROS_ERROR("Failed to call service add_three_ints");
        return 1;

    }
    return 0;
}
3.3 src/example_talker_msg.cpp

該文件主要實現3個參數的發佈,此處發佈了A=1,B=2,C=3;

#include "ros/ros.h"
#include "beginner_tutorials/Num.h"
#include <sstream>
//Usage:publish a msg with topic named message


int main(int argc, char **argv)
{
  ros::init(argc, argv, "example_talker_msg");
  ros::NodeHandle n;
  //advertise a topic named "message"
  ros::Publisher pub=n.advertise<beginner_tutorials::Num>("message",1000);
  ros::Rate loop_rate(10);
  while (ros::ok())
  {
    beginner_tutorials::Num msg;
    msg.A=1;
    msg.B=2;
    msg.C=3;
    pub.publish(msg);

    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}
3.4 src/example_listener_msg.cpp

該文件主要實現對前文talker發佈的數據的監聽,監聽到Num類型定義數據後,經過service: ros::service::call / client.call()兩種方式進行add_3_ints服務的調用。

#include "ros/ros.h"
#include "beginner_tutorials/Num.h"
#include "beginner_tutorials/AddTwoInts.h"

//declaration of the Example class:construct function, member and so on.
class Example{
public:
    Example();
private:
    ros::NodeHandle nh;
    ros::ServiceClient client;
    ros::Subscriber listener;
    void messageCallback(const beginner_tutorials::Num::ConstPtr& msg);

};

//implementation of construct function.
Example::Example()
{
    client=nh.serviceClient<beginner_tutorials::AddTwoInts>("add_3_ints");
    //monitor a topic named "message",this -> current object,pointer
    listener=nh.subscribe("message",1000,&Example::messageCallback,this);

}

//implementation of one of the Example class memeber.
void Example::messageCallback( const beginner_tutorials::Num::ConstPtr& msg)
{
//    ROS_INFO("I heard:[%d] [%d] [%d]",msg->A,msg->B,msg->C);
    beginner_tutorials::AddTwoInts srv;
    srv.request.A=msg->A;
    srv.request.B=msg->B;
    srv.request.C=msg->C;
    if(ros::service::call("add_3_ints",srv))
        ROS_INFO("SUM: %ld",(long int)srv.response.sum);
    else
        ROS_ERROR("Failed to call service add_three_ints");
    /*
    if(client.call(srv))
    {
        ROS_INFO("SUM: %ld",(long int)srv.response.sum);
    }
    else
    {
        ROS_ERROR("Failed to call service add_three_ints");

    }
    */
}



int main(int argc, char **argv)
{
  ros::init(argc, argv, "example_listener_msg");
  Example exp;
  ros::spin();
  return 0;
}
4 再次修改CMakeList.txt文件
添加編譯連接的相關控制語句。

add_executable(example_srv_request src/example_srv_request.cpp)
target_link_libraries(example_srv_request ${catkin_LIBRARIES})

add_executable(example_srv_response src/example_srv_response.cpp)
target_link_libraries(example_srv_response ${catkin_LIBRARIES})

add_executable(example_talker_msg src/example_talker_msg.cpp)
target_link_libraries(example_talker_msg ${catkin_LIBRARIES})

add_executable(example_listener_msg src/example_listener_msg.cpp)
target_link_libraries(example_listener_msg ${catkin_LIBRARIES})
添加後在工做空間主目錄cd ~/catkin_ws下進行catkin_make編譯,理論上不會出現問題,如有問題檢查本身包和msg,srv的生成及cmakelist文件。
5 測試

一個終端運行命令:roscore,

一個終端運行命令(注意此時近乎全部命令和包的名稱及可執行文件名稱均可以<table>自動補全):rosrun beginner_tutorials example_srv_request;會返回:  [INFO][時間戳]:Ready to add 3 ints.  此時若經過roservice list查詢ros提供的服務則會返回add_3_ints等幾個服務。

一個終端運行命令:rosrun beginner_tutorials example_talker_msg

一個終端運行命令:rosrun beginner_tutorials example_listener_msg;此時會返回: [INFO][時間戳]:SUM: 6

在此文件中,咱們實現了在一個node中如下面兩種方式對add_3_ints的服務調用,而不是在命令行中經過rosrun beginner_tutorials example_srv_response 1 2 3調用。

if(ros::service::call("add_3_ints",srv))
        ROS_INFO("SUM: %ld",(long int)srv.response.sum);
    else
        ROS_ERROR("Failed to call service add_three_ints");
    /*
    if(client.call(srv))
    {
        ROS_INFO("SUM: %ld",(long int)srv.response.sum);
    }
    else
    {
        ROS_ERROR("Failed to call service add_three_ints");

    }
    */
相關文章
相關標籤/搜索