action文件:
# Define the goal
uint32 dishwasher_id # Specify which dishwasher we want to use
---
# Define the result
uint32 total_dishes_cleaned
---
# Define a feedback message
float32 percent_complete
action_server.cpp文件
#include <ros/ros.h>
/*用于实现简单操作的操作库*/
#include <actionlib/server/simple_action_server.h>
/*这是从FibonacciAction.msg文件自动生成的标头*/
#include <eai_tutorials/FibonacciAction.h>
class FibonacciAction
{
protected:
ros::NodeHandle nh_; //构造节点句柄并在构造动作期间将其传递到动作服务端
/*定义动作库服务器变量*/
actionlib::SimpleActionServer<eai_tutorials::FibonacciAction> as_;
/*定义动作服务名*/
std::string action_name_;
/*定义动作服务器反馈变量*/
eai_tutorials::FibonacciFeedback feedback_;
/*定义动作服务器执行结果变量*/
eai_tutorials::FibonacciResult result_;
public:
/*类的构造函数,创建了一个操作服务端,并指定操作函数为executeCB,回调函数传递一个指向目标消息的指针。注意:这是一个boost共享指针,通过将“ConstPtr”附加到目标消息类型的末尾来给出*/
FibonacciAction(std::string name):
as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false),
action_name_(name){
as_.start();
}
/*类的析构函数*/
~FibonacciAction(void){}
/*操作函数为executeCB,回调函数传递一个指向目标消息的指针。注意:这是一个boost共享指针,通过将“ConstPtr”附加到目标消息类型的末尾来给出*/
void executeCB(const eai_tutorials::FibonacciGoalConstPtr &goal)
{
// helper variables
ros::Rate r(1);
bool success = true;
// 初始化fibonacci 队列
feedback_.sequence.clear();
feedback_.sequence.push_back(0);
feedback_.sequence.push_back(1);
// publish info to the console for the user
ROS_WARN("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);
/*动作服务端的一个重要组件是允许动作客户端请求取消当前目标执行的能力。当客户端请求抢占当前目标时,操作服务端应取消目标,执行必要的清理,并调用函数setPreempted(),该函数表示操作已被用户请求抢占。设置操作服务端检查抢占请求的速率由服务端的实现者决定。
*/
for(int i=1; i<=goal->order; i++)
{
// check that preempt has not been requested by the client
if (as_.isPreemptRequested() || !ros::ok())
{
ROS_WARN("%s: Preempted", action_name_.c_str());
// set the action state to preempted
as_.setPreempted();
success = false;
break;
}
//这里将Fibonacci序列放入反馈变量中
feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
// 在动作服务端提供的反馈通道上发布反馈
as_.publishFeedback(feedback_);
r.sleep();
}
/*一旦动作完成计算Fibonacci序列,该动作通过设置成功通知动作客户端动作完成*/
if(success)
{
result_.sequence = feedback_.sequence;
ROS_WARN("%s: Succeeded", action_name_.c_str());
// set the action state to succeeded
as_.setSucceeded(result_);
}
}
};
int main(int argc, char** argv)
{
ros::init(argc, argv, "fibonacci");
FibonacciAction fibonacci("fibonacci");
ros::spin();
return 0;
}
action_client.cpp文件:
#include <ros/ros.h>
/*用于实现简单操作的操作库*/
#include <actionlib/client/simple_action_client.h>
/*定义了可能的目标状态*/
#include <actionlib/client/terminal_state.h>
/*这是从FibonacciAction.msg文件自动生成的标头*/
#include <eai_tutorials/FibonacciAction.h>
int main (int argc, char **argv)
{
ros::init(argc, argv, "test_fibonacci");
/*指定要与动作服务端通信的消息类型。动作客户端构造函数还接受两个参数,即要连接的服务端名称和用于自动旋转线程的布尔选项*/
actionlib::SimpleActionClient<eai_tutorials::FibonacciAction> ac("fibonacci", true);
/*由于动作服务端可能未启动并运行,因此客户端将在继续之前等待操作服务端启动*/
ROS_WARN("Waiting for action server to start.");
// wait for the action server to start
ac.waitForServer(); //will wait for infinite time
/*此处创建目标消息,设置目标值并将其发送到操作服务端*/
ROS_WARN("Action server started, sending goal.");
// send a goal to the action
eai_tutorials::FibonacciGoal goal;
goal.order = 20;
ac.sendGoal(goal);
/*动作客户端现在等待目标完成后再继续。等待超时设置为30秒,这意味着如果目标尚未完成,则30秒后函数将返回false*/
bool finished_before_timeout = ac.waitForResult(ros::Duration(30.0));
/*如果在超时之前完成目标,则报告目标状态,否则通知用户目标未在指定的时间内完成*/
if (finished_before_timeout) {
actionlib::SimpleClientGoalState state = ac.getState();
ROS_WARN("Action finished: %s",state.toString().c_str());
}
else
ROS_WARN("Action did not finish before the time out.");
return 0;
}