ros_actionlib_tutorial 入门

本文详细介绍ROS中的Actionlib机制,用于解决长时间任务处理及任务取消的需求。通过实例演示如何创建Action Server与Client,包括消息类型的定义及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

actionlib 是ros中又一种通信机制,为了解决大型程序中服务机制响应阻塞时间过长的问题。
相比服务疑问一答的形式,多了一个反馈,不断反馈项目的进度。但有时候呢,如果这个service需要稍长一些的时间来运算之后才能反馈所需的结果,但在运行过程中,用户sonictl也许要根据运行的不同情况来决定是否取消request或者是需要周期性地获知运行状态。The actionlib 包就是提供这些工具,使得可以创建一些servers, 这些servers是用来执行需要长时间的任务的,并且是可以被preempted(预先制止)的。同时,actionlib包还提供了一个client接口,用来给server发请求。
官方wiki tutorial website:http://wiki.ros.org/actionlib_tutorials
本文内容记录与教程一致。
mkdir -p action_ws/src
cd action_ws
catkin_make && . devel/setup.bash
cd src
catkin_create_pkg actionlib_tutorial actionlib message_generation roscpp std_msgs actionlib_msgs
和话题/服务类似,actionlib需要建立自己的消息格式。后缀为.action
mkdir action && cd action
vim Fibonaccia.action(类似自定义的话题消息类型开头要大写)

#goal definition
int32 order
---
#result definition
int32[] sequence
---
#feedback
int32[] sequence

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(actionlib_tutorials)

find_package(catkin REQUIRED COMPONENTS  actionlib  message_generation  roscpp)
#利用add_action_files宏,声明 你想要生成的action
add_action_files(DIRECTORY action   FILES Fibonacci.action)#这句要在下句前面

generate_messages(DEPENDENCIES actionlib_msgs std_msgs)

#define catkin exports
catkin_package(
  INCLUDE_DIRS include 
  LIBRARIES actionlib_tutorials
  CATKIN_DEPENDS  actionlib  message_generation roscpp 
  DEPENDS system_lib 
)

 #add_executable(${PROJECT_NAME}_node src/actionlib_tutorials_node.cpp)

 #target_link_libraries(${PROJECT_NAME}_node   ${catkin_LIBRARIES} )

package.xml

<?xml version="1.0"?>
<package>
  <name>actionlib_tutorials</name>
  <version>0.0.0</version>
  <description>The actionlib_tutorials package</description>
  <maintainer email="robot@todo.todo">robot</maintainer>
  <license>BSD</license>
  <buildtool_depend>catkin</buildtool_depend>

  <build_depend>action_msgs</build_depend>
  <build_depend>actionlib</build_depend>
  <build_depend>message_generation</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>action_msgs</run_depend>
  <run_depend>actionlib</run_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>rospy</run_depend>
  <run_depend>std_msgs</run_depend>
  <run_depend>message_generation</run_depend> #这个是后续加上的,必须


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

在工作空间编译catkin_make

$ ls devel/share/actionlib_tutorials/msg/    #生成的消息文件格式为.msg
FibonacciActionFeedback.msg  FibonacciAction.msg        FibonacciFeedback.msg
FibonacciResult.msg          FibonacciActionGoal.msg    FibonacciActionResult.msg  FibonacciGoal.msg
$ ls devel/include/actionlib_tutorials/ #src/include 里面没有头文件,在devel/下
FibonacciActionFeedback.h  FibonacciAction.h        FibonacciFeedback.h  FibonacciResult.h
FibonacciActionGoal.h      FibonacciActionResult.h  FibonacciGoal.h

现在在devel下居然还有一个share文件夹
一共生成6个头文件,三个为acition文件同名+goal/result/feedback
其他三个为aciton文件同名后+Action+goal/result/feedback(Action is apended)
These messages are then used internally by actionlib to communicate between the ActionClient and ActionServer;are generated by genaction.py:

头文件会用到的是FibonacciAction.h
不带Action的Goal Result Feedback 定义了基本的数据类型
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_;
std::string action_name_;
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){}
//ConstPtr 写法是boost的共享指针
void executeCB(const actionlib_tutorials::FibonacciGoal::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);

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
for(int i=1;i<=goal->order;i++)
{
// check that preempt has not been requested by the client
//if代表了action可以被中途取消的功能
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
//没有结束前,周期提供feedback,最后执行成功再向客户端提供result(由feedback赋值)
as_.publishFeedback(feedback_);
//this sleeep is not necessary, the sequence is computed at 1hz for demonstration purpose
r.sleep();
}
if(success)
{
result_.sequence = feedback_.sequence;
ROS_INFO("%s: Succeeded", action_name_.c_str());
//set the action states to succeeded
as_.setSucceeded(result_);
}
}

};

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

    return 0;
}

fibonacci_client.cpp

#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <actionlib_tutorials/FibonacciAction.h>

int main(int argc,char** argv)
{
    ros::init(argc,argv,"test_fibonacci");
    //create action client
    //true casuses the client to spin its own thread
    //不需要nodehandle?
    actionlib::SimpleActionClient<actionlib_tutorials::FibonacciAction> ac("fibonacci",true);
//ac初始化的字符串名字不可以改,与之前对应
    ROS_INFO("Waiting for action server to start");
    //wait for action server to start
    ac.waitForServer();

    ROS_INFO("Action server started");

    //sent a goal to the action
    //自定义的消息格式不含action~!
    actionlib_tutorials::FibonacciGoal goal;
    goal.order = 30;
    ac.sendGoal(goal);

    //wait for the action to return

    bool finished_before_timeout = ac.waitForResult(ros::Duration(30.0));
    if(finished_before_timeout)
    {
    actionlib::SimpleClientGoalState state = ac.getState();
    ROS_INFO("Action finished:%s",state.toString().c_str());
    }
    else
        ROS_INFO("Action didnot finish before the time out");

    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(actionlib_tutorials)


find_package(catkin REQUIRED COMPONENTS
  actionlib
  actionlib_msgs
  message_generation
  roscpp
  rospy
  std_msgs
)


 add_action_files(
   FILES
   Fibonacci.action
 )
generate_messages(
  DEPENDENCIES actionlib_msgs std_msgs  # Or other packages containing msgs
)
catkin_package(
  INCLUDE_DIRS include
  LIBRARIES actionlib_tutorials
  CATKIN_DEPENDS actionlib actionlib_msgs message_generation roscpp rospy std_msgs
  DEPENDS system_lib
)


include_directories( include  ${catkin_INCLUDE_DIRS})



add_executable(fibonacci_server src/fibonacci_server.cpp)
target_link_libraries(fibonacci_server  ${catkin_LIBRARIES})
#add_dependencies可省,如下为默认写法
add_dependencies(fibonacci_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

add_executable(fibonacci_client src/fibonacci_client.cpp)
target_link_libraries(fibonacci_client  ${catkin_LIBRARIES})
add_dependencies(fibonacci_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

python version:
server.py

#!/usr/bin/env python
import rospy
import actionlib
import actionlib_tutorials.msg
#from actionlib_tutorials import *

class FibonacciAction(object):
    '''
    new tyle of class
    python2.4-3.0
    '''
    # # create messages that are used to publish feedback/result
    _feedback = actionlib_tutorials.msg.FibonacciFeedback()
    _result = actionlib_tutorials.msg.FibonacciResult()

    def __init__(self,name):
        self._action_name = name
        self._as = actionlib.SimpleActionServer(self._action_name,actionlib_tutorials.msg.FibonacciAction,execute_cb = self.execute_cb,auto_start = False)
        self._as.start()

    def execute_cb(self,goal):
        r = rospy.Rate(1)
        success = True

        self._feedback.sequence = []
        self._feedback.sequence.append(0)
        self._feedback.sequence.append(1)

        rospy.loginfo('%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i' % (self._action_name, goal.order, self._feedback.sequence[0], self._feedback.sequence[1]))

        for i in range(1,goal.order):
            if self._as.is_preempt_requested():
                rospy.loginfo('%s: Preempted' % self._action_name)
                self._as.set_preempted()
                success = False
                break
            self._feedback.sequence.append(self._feedback.sequence[i] + self._feedback.sequence[i-1])
            self._as.publish_feedback(self._feedback)

            r.sleep()

        if success:
            self._result.sequence = self._feedback.sequence
            rospy.loginfo('%s: Succeeded' % self._action_name)
            self._as.set_succeeded(self._result)

if __name__ == '__main__':
    rospy.init_node('fibonacci')
    server = FibonacciAction(rospy.get_name())
    rospy.spin()

client.py

#!/usr/bin/env python
from __future__ import print_function
import rospy
import actionlib
import actionlib_tutorials.msg

def fibonacci_client():
    client = actionlib.SimpleActionClient('fibonacci',actionlib_tutorials.msg.FibonacciAction)
    client.wait_for_server()

    goal = actionlib_tutorials.msg.FibonacciGoal(order = 20)

    client.send_goal(goal)

    client.wait_for_result()

    return client.get_result()

if __name__ == '__main__':
    try:
        rospy.init_node('fibonacci_client_py')
        result = fibonacci_client()

        print("Result:", ', '.join([str(n) for n in result.sequence]))
    except rospy.ROSInterruptException:
        print("program interrupted before completion", file = sys.stderr)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值