这两天学习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节点,得到最终结果:
若有不对的地方,希望大家加以指正,欢迎交流!