(八)动作服务器和动作客户端

概述

之前提到的发布-订阅通信机制是端到端的通信,发布者不知道订阅者,订阅者也不知道发布者;服务-客户端通信机制是点到点的通信,服务器知道客户端,客户端也知道服务器,这样就对发布-订阅通信机制有了一种改进,但是这种方法也有一种限制,就是客户端在等待服务器响应的时候,不能做任何事情。因此就有了第三种通信机制:动作服务器-动作客户端,这种通信机制使得客户端在执行对服务器的请求的时候,还可以继续运行其他任务。

定义动作服务器消息

动作服务器消息也叫操作消息,和服务-客户端的服务消息类似。
注意三个区域分别是goal,result,feedback,顺序是固定的,不可以更改,各区域之间由三个短横线分割。

在这里插入图片描述

动作服务器

#include <ros/ros.h>
//这是导入了simple_action_server包中的头文件
#include <actionlib/server/simple_action_server.h>
//这是自己定义的操作消息的描述
#include <example_action_server/demoAction.h>
 
int g_count=0;
bool g_count_failure=false;
class ExampleActionServer{
private:
  ros::NodeHandle nh_;
  //定义了SimpleActionServer类的对象as_,相当于构建了一个动作服务器
  actionlib::SimpleActionServer<example_action_server::demoAction> as_;
  //动作服务器将使用这些消息来进行通信
  example_action_server::demoGoal goal_;
  example_action_server::demoResult result_;//将结果传回给动作客户端
  example_action_server::demoFeedback feedback_;
public:
  ExampleActionServer();//构造函数
  ~ExampleActionServer(void){}//析构函数
  //这是回调函数,参数是指向目标消息的指针
  void executeCB(const actionlib::SimpleActionServer<example_action_server::demoAction>::GoalConstPtr& goal);
};
//相当于初始化动作服务器,取名为“example_action”,并指定回调函数为executeCB(使得回调函数与动作服务器相关联)
ExampleActionServer::ExampleActionServer():as_(nh_,"example_action",boost::bind(&ExampleActionServer::executeCB,this,_1),false)
{
   ROS_INFO("in constructor of exampleActionServer...");
   as_.start();
}
//这是回调函数的实现,一旦执行了回调函数,必须通过setAborted或者setSucceeded来将result消息传回客户端
void ExampleActionServer::executeCB(const actionlib::SimpleActionServer<example_action_server::demoAction>::GoalConstPtr& goal){
    g_count++;
    result_.output=g_count;
    result_.goal_stamp=goal->input;
    if(g_count!=goal->input){
        ROS_WARN("hey--mismatch!");
        ROS_INFO("g_count=%d;goal_stamp=%d",g_count,result_.goal_stamp);
        g_count_failure=true;
        ROS_WARN("informing client of aborted goal");
        as_.setAborted(result_);
    }
    else{
        as_.setSucceeded(result_);
    }
}
 
int main(int argc,char** argv){
    ros::init(argc,argv,"demo_action_server_node");
    ROS_INFO("instantiating the demo action server:");
    ExampleActionServer as_object;
    ROS_INFO("going into spin");
    while(!g_count_failure){
    ros::spinOnce();
    }
return 0;
}

动作客户端

#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <example_action_server/demoAction.h>
//这是回调函数
void doneCb(const actionlib::SimpleClientGoalState& state,const example_action_server::demoResultConstPtr& result){
    ROS_INFO("doneCB:server responded with state [%s]",state.toString().c_str());
    int diff=result->output-result->goal_stamp;
    ROS_INFO("got result output=%d;goal_stamp=%d;diff=%d",result->output,result->goal_stamp,diff);
 
}
 
int main(int argc,char** argv){
    ros::init(argc,argv,"demo_action_client_node");
    int g_count=0;
    //这是目标消息,用来将目标传给动作服务器
    example_action_server::demoGoal goal;
    //这是在构建动作客户端action_client,指明要连接的动作服务器
    actionlib::SimpleActionClient<example_action_server::demoAction> action_client("example_action",true);
    //用来判断是否连接服务器成功
    ROS_INFO("waiting for server: ");
    bool server_exists=action_client.waitForServer(ros::Duration(5.0));
    if(!server_exists){
        ROS_INFO("could not connect to server;halting");
        return 0;
    }
    //到这儿说明连接成功了
    ROS_INFO("connected to action server");
    while(true){
        g_count++;
        goal.input=g_count;
        //发送目标消息
        action_client.sendGoal(goal,&doneCb);
        bool finished_before_timeout=action_client.waitForResult(ros::Duration(5.0));
        if(!finished_before_timeout){
            ROS_WARN("giving up waiting on result for goal number %d",g_count);
            return 0;
        }else
        {
            
        }
        
    }
return 0;
}

编写CMakeLists.txt文件

类似话题消息和服务消息,在添加了新文件以后也要修改下面三个地方。

在这里插入图片描述
在这里插入图片描述
这里是在添加了动作服务端和动作客户端以后需要修改的地方。

在这里插入图片描述

运行截图

在这里插入图片描述
这实现的其实就是一个简单的比较,如果客户端输入goal->input的与服务器期望g_count的不一样,那么服务器就异常退出;如果相同,那么服务器就成功完成。
为数不多的代码写了注释的文章,老是抱怨别人不写注释,原来写注释这么麻烦。嗯…看来以后还是不能写注释,让别人写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值