< >
Home » ROS与C++入门教程 » ROS与C++入门教程-actionlib-编写简单的action服务器(Execute Callback)

ROS与C++入门教程-actionlib-编写简单的action服务器(Execute Callback)

ROS与C++入门教程-actionlib-编写简单的action服务器(Execute Callback)

说明:

  • 介绍如何编写简单带Execute Callback的action服务器
  • 介绍如何使用simple_action_server库来实现action服务器
  • 介绍实现生成Fibonacci数列,goal是数列序,feedback是计算中数列,result是计算完成的数列。

参考:

  • http://wiki.ros.org/actionlib
  • http://wiki.ros.org/actionlib/DetailedDescription
  • https://github.com/ros/common_tutorials/tree/indigo-devel/actionlib_tutorials

创建包

cd ~/catkin_ws/src
catkin_create_pkg actionlib_tutorials roscpp actionlib message_generation std_msgs actionlib_msgs

创建Action消息

  • action有三种消息:goal, result, and feedback
  • 他们通过.action文件自动生成的。想了解更多查阅actionlib wiki
  • 创建Fibonacci.action:参考代码
cd ~/catkin_ws/src/actionlib_tutorials/src
mkdir action
touch Fibonacci.action
vim Fibonacci.action
  • 代码如下:
#goal definition
int32 order
---
#result definition
int32[] sequence
---
#feedback
int32[] sequence

编译:

  • 更改CMakeLists.txt文件
  • 增加actionlib_msgs支持,需要有如下行,没有则增加:
find_package(catkin REQUIRED COMPONENTS actionlib_msgs)
  • 增加add_action_files:
add_action_files(
  DIRECTORY action
  FILES Fibonacci.action
)
  • 调用generate_messages
generate_messages(
  DEPENDENCIES actionlib_msgs std_msgs  # Or other packages containing msgs
)
  • 增加actionlib_msgs到catkin_package
catkin_package(
  CATKIN_DEPENDS actionlib_msgs
)
  • 编译并查看结果:
$ cd ~/catkin_ws
$ catkin_make
$ ls devel/share/actionlib_tutorials/msg/
FibonacciActionFeedback.msg  FibonacciAction.msg        FibonacciFeedback.msg
FibonacciResult.msg          FibonacciActionGoal.msg    FibonacciActionResult.msg  FibonacciGoal.msg
$ ls devel/include/actionlib_tutorials/
FibonacciActionFeedback.h  FibonacciAction.h        FibonacciFeedback.h  FibonacciResult.h
FibonacciActionGoal.h      FibonacciActionResult.h  FibonacciGoal.h
  • 也可以通过actionlib_msgs包下的genaction.py文件来手工生成上面的文件。

编写action服务器端

cd ~/catkin_ws/actionlib_tutorials/src/
touch fibonacci_server.cpp
vim fibonacci_server.cpp
  • 代码如下:
#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include <actionlib_tutorials/FibonacciAction.h>

class FibonacciAction
{
protected:

  ros::NodeHandle nh_;
  actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs.
  std::string action_name_;
  // create messages that are used to published feedback/result
  actionlib_tutorials::FibonacciFeedback feedback_;
  actionlib_tutorials::FibonacciResult result_;

public:

  FibonacciAction(std::string name) :
    as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false),
    action_name_(name)
  {
    as_.start();
  }

  ~FibonacciAction(void)
  {
  }

  void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal)
  {
    // helper variables
    ros::Rate r(1);
    bool success = true;

    // push_back the seeds for the fibonacci sequence
    feedback_.sequence.clear();
    feedback_.sequence.push_back(0);
    feedback_.sequence.push_back(1);

    // publish info to the console for the user
    ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);

    // start executing the action
    for(int i=1; i<=goal->order; i++)
    {
      // check that preempt has not been requested by the client
      if (as_.isPreemptRequested() || !ros::ok())
      {
        ROS_INFO("%s: Preempted", action_name_.c_str());
        // set the action state to preempted
        as_.setPreempted();
        success = false;
        break;
      }
      feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
      // publish the feedback
      as_.publishFeedback(feedback_);
      // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes
      r.sleep();
    }

    if(success)
    {
      result_.sequence = feedback_.sequence;
      ROS_INFO("%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;
}

代码解释:

  • 代码:
#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
  • 解释:

    • actionlib/server/simple_action_server.h 是action库,用来执行简单的actions
  • 代码:

#include <actionlib_tutorials/FibonacciAction.h>
  • 解释:这个头文件是由Fibonacci.action自动生成。
  • 代码:
protected:

  ros::NodeHandle nh_;
  // NodeHandle instance must be created before this line. Otherwise strange error occurs.
  actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; 
  std::string action_name_;
  // create messages that are used to published feedback/result
  actionlib_tutorials::FibonacciFeedback feedback_;
  actionlib_tutorials::FibonacciResult result_;
  • 解释:创建多个私有变量,节点实例化变量,actionlib实例化变量,保存反馈的feedback_变量,保存结果的result_变量

  • 代码:

  FibonacciAction(std::string name) :
    as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false),
    action_name_(name)
  {
    as_.start();
  }
  • 解释:

    • 构造函数,并初始化函数,创建action服务器。需要提供action名称,节点实例变量,可选的executeCB变量。
  • 代码:

void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal) 
  • 解释:

    • executeCB函数引用在构造函数中创建,回调函数传递boost的共享指针类型ConstPtr的goal作为参数
  • 代码:

    ros::Rate r(1);
    bool success = true;

    // push_back the seeds for the fibonacci sequence
    feedback_.sequence.clear();
    feedback_.sequence.push_back(0);
    feedback_.sequence.push_back(1);

    // publish info to the console for the user
    ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);
  • 解释:

    • 内部执行开始,显示接收的值
  • 代码:

   // start executing the action
    for(int i=1; i<=goal->order; i++)
    {
      // check that preempt has not been requested by the client
      if (as_.isPreemptRequested() || !ros::ok())
      {
        ROS_INFO("%s: Preempted", action_name_.c_str());
        // set the action state to preempted
        as_.setPreempted();
        success = false;
        break;
      }
      feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
  • 解释:

    • action服务器重要功能是可以接受客户端段取消目前目标的执行。
    • 当客户端请求当前取消的目标优先处理,action服务器就会清除相关内容,并调用setPreempted()函数。
    • 也可以设置优先处理检查的频率,action服务器就自动根据这个频率实现检查并做对应处理。
  • 代码:

// publish the feedback
  as_.publishFeedback(feedback_);
  // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes
  r.sleep();
}
  • 解释:Fibonacci数列会存放在变量feedback里,并发布这个feedback,然后进入新一轮的循环。

  • 代码:

if(success)
{
  result_.sequence = feedback_.sequence;
  ROS_INFO("%s: Succeeded", action_name_.c_str());
  // set the action state to succeeded
  as_.setSucceeded(result_);
}   }
  • 解释:

    • 当计算完成,action服务器就会通知客户端已经完成,并发送最后的结果。
  • 代码:

int main(int argc, char** argv)
{
  ros::init(argc, argv, "fibonacci");

  FibonacciAction fibonacci("fibonacci");
  ros::spin();

  return 0;
}
  • 解释:
    • main函数实现开始action,并启动线程处理,运行和等待去接受goal值传入。

编译

  • 更改 CMakeLists.txt,增加:
cd ~/catkin_ws/actionlib_tutorials/
vim CMakeLists.txt
  • 代码:
 add_executable(fibonacci_server src/fibonacci_server.cpp)

target_link_libraries(
  fibonacci_server
  ${catkin_LIBRARIES}
)

add_dependencies(
  fibonacci_server
  ${actionlib_tutorials_EXPORTED_TARGETS}
)
  • 完整版本如下:
cmake_minimum_required(VERSION 2.8.3)
project(actionlib_tutorials)

find_package(catkin REQUIRED COMPONENTS roscpp actionlib actionlib_msgs)
find_package(Boost REQUIRED COMPONENTS system)

add_action_files(
  DIRECTORY action
  FILES Fibonacci.action
)

generate_messages(
  DEPENDENCIES actionlib_msgs std_msgs
)

catkin_package(
  CATKIN_DEPENDS actionlib_msgs
)

include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})

add_executable(fibonacci_server src/fibonacci_server.cpp)

target_link_libraries(
  fibonacci_server
  ${catkin_LIBRARIES}
)

add_dependencies(
  fibonacci_server
  ${actionlib_tutorials_EXPORTED_TARGETS}
)
  • 编译:
cd ~/catkin_ws
catkin_make

运行

  • 新终端,运行roscore
$ roscore
  • 新终端,执行action服务器
$ rosrun actionlib_tutorials fibonacci_server
  • 执行显示:
[ INFO] 1250790662.410962000: Started node [/fibonacci], pid [29267], bound on [aqy], xmlrpc port [39746], tcpros port [49573], logging to [~/ros/ros/log/fibonacci_29267.log], using [real] time
  • 新终端,检查是否运行:
$ rostopic list -v
  • 显示:
Published topics:
 * /fibonacci/feedback [actionlib_tutorials/FibonacciActionFeedback] 1 publisher
 * /fibonacci/status [actionlib_msgs/GoalStatusArray] 1 publisher
 * /rosout [rosgraph_msgs/Log] 1 publisher
 * /fibonacci/result [actionlib_tutorials/FibonacciActionResult] 1 publisher
 * /rosout_agg [rosgraph_msgs/Log] 1 publisher

Subscribed topics:
 * /fibonacci/goal [actionlib_tutorials/FibonacciActionGoal] 1 subscriber
 * /fibonacci/cancel [actionlib_msgs/GoalID] 1 subscriber
 * /rosout [rosgraph_msgs/Log] 1 subscriber
  • 新终端或执行:
$ rqt_graph
  • 效果:
    请输入图片描述

纠错,疑问,交流: 请进入讨论区点击加入Q群

获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号


标签: ROS与C++入门教程