ROS之actionlib学习笔记

这两天学习ROS的ationlib机制,弄了一个demo作为笔记。

在demo中,action的目标是读书。client向server发送要读多少页书(goal);server收到目标后开始执行任务,且向client反馈已经读到了第几页(feedback),并在完成读书任务后告知client;客户端得知server完成任务后,使用ros::shutdown()函数关闭自身节点。


参考了大神的博客:http://www.guyuehome.com/908


一、创建一个package

$ catkin_create_pkg actionlib_demoactionlib actionlib_msgs roscpp

$ cd actionlib_demo/

二、和msg、srv一样,actionlib需要创建action文件

$ mkdir action

$ cd action/

$ vim ReadBook.action

# Define the goal
uint32 total_pages
---
# Define the result
bool is_finish
---
# Define a feedback message 
uint32 reading_page

三、编辑CMakelist.txt文件,添加action的编译规则

如下地方:

## Generate actions in the 'action' folder
# add_action_files(
#   FILES
#   Action1.action
#   Action2.action
# )

## Generate added messages and services with any dependencies listed here
# generate_messages(
#   DEPENDENCIES
#   std_msgs
# )

修改为:

## Generate actions in the 'action' folder
 add_action_files(
   FILES
   ReadBook.action
 )

## Generate added messages and services with any dependencies listed here
 generate_messages(
   DEPENDENCIES
   actionlib_msgs
 )

编译后在devel文件夹下会得到以下这些文件:




四、编写actionlib的客户端和服务器

1、客户端

$ vim …/…/actionlib_demo/src/read_book_client.cpp

#include <actionlib/client/simple_action_client.h>
#include "actionlib_demo/ReadBookAction.h"

//action完成后调用此函数
void doneCb(const actionlib::SimpleClientGoalState& state,
            const actionlib_demo::ReadBookResultConstPtr& result)
{
    ROS_INFO("Finsh Reading!");
    //任务完成就关闭节点
    ros::shutdown();
}

//action的目标任务发送给server且开始执行时,调用此函数
void activeCb()
{
   ROS_INFO("Goal is active! Begin to Read.");
}

//action任务在执行过程中,server对过程有反馈则调用此函数
void feedbackCb(const actionlib_demo::ReadBookFeedbackConstPtr& feedback)
{
    //将服务器的反馈输出(读到第几页书)
    ROS_INFO("Reading page: %d", feedback->reading_page);
}

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

    //创建一个action的client,指定action名称为”read_book”
    actionlib::SimpleActionClient<actionlib_demo::ReadBookAction> client("read_book", true);

    ROS_INFO("Waiting for action server to start");
    //等待服务器响应
    client.waitForServer();
    ROS_INFO("Action server started");
    
    //创建一个目标:读10页书
    actionlib_demo::ReadBookGoal goal;
    goal.total_pages = 10;
    
    //把action的任务目标发送给服务器,绑定上面定义的各种回调函数
    client.sendGoal(goal, &doneCb, &activeCb, &feedbackCb);

    ros::spin();

    return 0;
}

2、服务器

$ vim …/…/actionlib_demo/src/read_book_server.cpp

#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include "actionlib_demo/ReadBookAction.h"

//服务器发送任务目标后,调用该函数执行任务
void execute(const actionlib_demo::ReadBookGoalConstPtr& goal,
            actionlib::SimpleActionServer<actionlib_demo::ReadBookAction>* as)
{
    ros::Rate r(1);
    
    actionlib_demo::ReadBookFeedback feedback;

    ROS_INFO("Begin to read %d pages.", goal->total_pages);

    for(int i=0; i<goal->total_pages; i++)
    {
        feedback.reading_page = i;
        //反馈任务执行的过程
        as->publishFeedback(feedback);
        r.sleep();
    }
    

    ROS_INFO("All pages is read.");

    as->setSucceeded();
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "read_book_server");
    
    ros::NodeHandle n;

    //创建一个aciton服务器,接受名称”read_book”的aciton任务
    actionlib::SimpleActionServer<actionlib_demo::ReadBookAction> server(n, "read_book", 
                                                            boost::bind(&execute, _1, &server), false);

    //服务器启动
    server.start();

    ros::spin();

    return 0;
}

五、编辑CMakelist.txt文件,添加节点的编译规则

如下地方:

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/actionlib_demo_node.cpp)

## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )

修改为:

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
add_executable(read_book_client src/read_book_client.cpp)
add_executable(read_book_server src/read_book_server.cpp)

## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
add_dependencies(read_book_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(read_book_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
target_link_libraries(read_book_client
  ${catkin_LIBRARIES}
)
target_link_libraries(read_book_server
  ${catkin_LIBRARIES}
)

六、在工程目录下执行catkin_make进行编译

七、运行

使用rosrun命令运行分别actionlib_demo包下的read_book_client和read_book_server节点,得到最终结果:




若有不对的地方,希望大家加以指正,欢迎交流!

猜你喜欢

转载自blog.csdn.net/u014695839/article/details/80384754