• ROS 消息订阅 状态同步 action 行为通讯方式


    理解行为:

    在执行一些耗时短的任务时没有问题,

    在执行一些耗时长的任务如让机器人从大厅的A点移动至B点时,服务会造成线程的阻塞,

    为了解决这一问题,ROS提供了行为执行耗时长的异步行为。

    行为的组织:

    ROS的行为由后缀为action的资源文件定义,放置在action目录下

    行为文件包含: 

    goal、result、feedback三部分的内容。三者之间通过“---”隔开。一个action文件的示例如下:

    1. #goal
    2. int32 total
    3. ---
    4. #result
    5. int32 sum
    6. ---
    7. #feedback

    goal:任务目标

    cancel:请求取消任务

    status:通知client当前的状态

    feedback:周期反馈任务运行的监控数据

    result:向client发送任务的执行结果,这个只会发布一次

    Action行为的实现:

    当执行行为时,首先ActionClient发送“goal”请求给ActionServer,

    一旦ActionServer收到“goal”请求,

    ActionServer就为该“goal”请求创建一个状态机来跟踪其状态转换。

    然后ActionServer发送“feedback”消息给ActionClient反馈行为进度,

    当任务完成或ActionClient发送取消请求后,

    ActionServer发送“result”消息给ActionClient,

    需注意的是,“result”消息只能发送一次。

    Action行为的实现:

    在实现行为时,要考虑连接的时延和状态的可用性。

    客户端方法:

    1. void sendGoal(const Goal & goal,
    2. SimpleDoneCallback done_cb = SimpleDoneCallback(),
    3. SimpleActiveCallback active_cb = SimpleActiveCallback(),
    4. SimpleFeedbackCallback feedback_cb = SimpleFeedbackCallback());
    5. bool waitForServer(const ros::Duration & timeout = ros::Duration(0, 0) )
    6. # 发送目标
    7. # 等待反馈
    8. # 等待激活
    9. # 结果发送给客户端

    服务端方法:

    1. void publishFeedback(const Feedback & feedback)
    2. bool isPreemptRequested();
    3. void setSucceeded(const Result & result = Result(), const std::string & text std::string(""));

    行为的实现:

    Action行为本质上是基于消息的发布/订阅实现的一种通信机制

    //ActionServer的实现

    1. class ActionServer : public ActionServerBase
    2. { ......
    3. ros::NodeHandle node_;
    4. ros::Subscriber goal_sub_, cancel_sub_;
    5. ros::Publisher status_pub_, result_pub_, feedback_pub_;
    6. ros::Timer status_timer_;
    7. }

    //结果和反馈的发布

    1. result_pub_ = node_.advertise("result", static_cast(pub_queue_size));
    2. feedback_pub_ =node_.advertise("feedback", static_cast(pub_queue_size));
    3. # 形成队列

    自定义行为步骤:    

    编译执行 action依赖于actionlib、actionlib_msgs程序包。

    跑步例子实例:

    步骤1 创建自定义行为.action

    1. #goal
    2. int32 total
    3. ---
    4. #result
    5. int32 sum
    6. ---
    7. #feedback
    8. int32 number
    9. # 总目标
    10. # 最终跑了多少
    11. # 正在跑多少

    步骤2 编写客户端文件 .client

    1. #include
    2. #include
    3. #include
    4. #include "example_5/RunningAction.h"
    5. void doneCb(const actionlib::SimpleClientGoalState& state,
    6. const example_5::RunningResultConstPtr& result){
    7. ROS_INFO("the runing are now finished! the sum is %d",result->sum);
    8. }
    9. void activeCb()
    10. {
    11. ROS_INFO("Goal just went active");
    12. }
    13. void feedbackCb(const example_5::RunningFeedbackConstPtr& feedback){
    14. ROS_INFO("running number is :%d",feedback->number);
    15. }
    16. int main (int argc, char **argv)
    17. {
    18. ros::init(argc, argv, "running_client");
    19. actionlib::SimpleActionClient actionClient("running", true);
    20. //SimpleActionClient 实例子选择
    21. ROS_INFO("Waiting for action server to start.");
    22. actionClient.waitForServer(); //will wait for infinite time等待响应
    23. ROS_INFO("Action server started, sending goal.");
    24. example_5::RunningGoal goal;
    25. goal.total = 20; //跑了20步
    26. actionClient.sendGoal(goal,&doneCb,&activeCb,&feedbackCb);
    27. //wait 50s
    28. bool finished_before_timeout = actionClient.waitForResult(ros::Duration(50.0));
    29. if (finished_before_timeout) //如果超时
    30. {
    31. actionlib::SimpleClientGoalState state = actionClient.getState();
    32. ROS_INFO("Action finished: %s",state.toString().c_str());
    33. } //如果没超时
    34. else{
    35. actionClient.cancelGoal();
    36. ROS_INFO("Action did not finish before the time out.");
    37. }
    38. return 0;
    39. }

    步骤3 编写服务文件  .service

    1. #include
    2. #include
    3. #include
    4. class RunningAction
    5. {
    6. protected:
    7. ros::NodeHandle nh_;
    8. // NodeHandle instance must be created before this line. Otherwise strange error occurs.
    9. actionlib::SimpleActionServer actionServer;
    10. std::string action_name_;
    11. // create messages that are used to published feedback/result
    12. example_5::RunningFeedback actionFeedback;
    13. example_5::RunningResult actionResult;
    14. public:
    15. RunningAction(std::string name): // 绑定回调目标和循环
    16. actionServer(nh_, name, boost::bind(&RunningAction::executeCB, this, _1), false),
    17. action_name_(name)
    18. {
    19. actionServer.start();
    20. }
    21. ~RunningAction(void)
    22. {
    23. }
    24. void executeCB(const example_5::RunningGoalConstPtr &goal)
    25. {
    26. // helper variables
    27. ros::Rate r(1);
    28. bool success = true;
    29. // start executing the action
    30. for(int i=1; i<=goal->total; i++) // 判断是否被抢占了
    31. {
    32. // check that preempt has not been requested by the client
    33. if (actionServer.isPreemptRequested() || !ros::ok())
    34. {
    35. ROS_INFO("%s: Preempted", action_name_.c_str());
    36. // set the action state to preempted
    37. actionServer.setPreempted();
    38. success = false;
    39. break;
    40. }
    41. actionFeedback.number++;
    42. // publish the feedback
    43. actionServer.publishFeedback(actionFeedback);
    44. ROS_INFO("Executing, creating %i of total %i",actionFeedback.number,goal->total);
    45. r.sleep();
    46. }
    47. if(success)
    48. {
    49. actionResult.sum = actionFeedback.number;
    50. ROS_INFO("%s: Succeeded", action_name_.c_str());
    51. // set the action state to succeeded
    52. actionServer.setSucceeded(actionResult);
    53. }
    54. }
    55. };
    56. int main(int argc, char** argv)
    57. {
    58. ros::init(argc, argv, "running_server");
    59. RunningAction running("running");
    60. ros::spin();
    61. return 0;
    62. }

    步骤4 package.xml、CMakeLists.txt配置

    1. cmake_minimum_required(VERSION 3.0.2)
    2. project(example_5)
    3. ## Compile as C++11, supported in ROS Kinetic and newer
    4. # add_compile_options(-std=c++11)
    5. ## Find catkin macros and libraries
    6. ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
    7. ## is used, also find other catkin packages
    8. find_package(catkin REQUIRED COMPONENTS
    9. roscpp
    10. rospy
    11. std_msgs
    12. actionlib
    13. actionlib_msgs
    14. )
    15. ## System dependencies are found with CMake's conventions
    16. # find_package(Boost REQUIRED COMPONENTS system)
    17. ## Uncomment this if the package has a setup.py. This macro ensures
    18. ## modules and global scripts declared therein get installed
    19. ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
    20. # catkin_python_setup()
    21. ################################################
    22. ## Declare ROS messages, services and actions ##
    23. ################################################
    24. ## To declare and build messages, services or actions from within this
    25. ## package, follow these steps:
    26. ## * Let MSG_DEP_SET be the set of packages whose message types you use in
    27. ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
    28. ## * In the file package.xml:
    29. ## * add a build_depend tag for "message_generation"
    30. ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
    31. ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
    32. ## but can be declared for certainty nonetheless:
    33. ## * add a exec_depend tag for "message_runtime"
    34. ## * In this file (CMakeLists.txt):
    35. ## * add "message_generation" and every package in MSG_DEP_SET to
    36. ## find_package(catkin REQUIRED COMPONENTS ...)
    37. ## * add "message_runtime" and every package in MSG_DEP_SET to
    38. ## catkin_package(CATKIN_DEPENDS ...)
    39. ## * uncomment the add_*_files sections below as needed
    40. ## and list every .msg/.srv/.action file to be processed
    41. ## * uncomment the generate_messages entry below
    42. ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
    43. ## Generate messages in the 'msg' folder
    44. # add_message_files(
    45. # FILES
    46. # Message1.msg
    47. # Message2.msg
    48. # )
    49. ## Generate services in the 'srv' folder
    50. # add_service_files(
    51. # FILES
    52. # Service1.srv
    53. # Service2.srv
    54. # )
    55. ## Generate actions in the 'action' folder
    56. add_action_files(
    57. FILES
    58. Running.action
    59. )
    60. ## Generate added messages and services with any dependencies listed here
    61. generate_messages(
    62. DEPENDENCIES
    63. std_msgs
    64. actionlib_msgs
    65. )
    66. ################################################
    67. ## Declare ROS dynamic reconfigure parameters ##
    68. ################################################
    69. ## To declare and build dynamic reconfigure parameters within this
    70. ## package, follow these steps:
    71. ## * In the file package.xml:
    72. ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
    73. ## * In this file (CMakeLists.txt):
    74. ## * add "dynamic_reconfigure" to
    75. ## find_package(catkin REQUIRED COMPONENTS ...)
    76. ## * uncomment the "generate_dynamic_reconfigure_options" section below
    77. ## and list every .cfg file to be processed
    78. ## Generate dynamic reconfigure parameters in the 'cfg' folder
    79. # generate_dynamic_reconfigure_options(
    80. # cfg/DynReconf1.cfg
    81. # cfg/DynReconf2.cfg
    82. # )
    83. ###################################
    84. ## catkin specific configuration ##
    85. ###################################
    86. ## The catkin_package macro generates cmake config files for your package
    87. ## Declare things to be passed to dependent projects
    88. ## INCLUDE_DIRS: uncomment this if your package contains header files
    89. ## LIBRARIES: libraries you create in this project that dependent projects also need
    90. ## CATKIN_DEPENDS: catkin_packages dependent projects also need
    91. ## DEPENDS: system dependencies of this project that dependent projects also need
    92. catkin_package(
    93. # INCLUDE_DIRS include
    94. # LIBRARIES example_5
    95. CATKIN_DEPENDS roscpp rospy std_msgs actionlib_msgs
    96. # DEPENDS system_lib
    97. )
    98. ###########
    99. ## Build ##
    100. ###########
    101. ## Specify additional locations of header files
    102. ## Your package locations should be listed before other locations
    103. include_directories(
    104. # include
    105. ${catkin_INCLUDE_DIRS}
    106. )
    107. ## Declare a C++ library
    108. # add_library(${PROJECT_NAME}
    109. # src/${PROJECT_NAME}/example_5.cpp
    110. # )
    111. ## Add cmake target dependencies of the library
    112. ## as an example, code may need to be generated before libraries
    113. ## either from message generation or dynamic reconfigure
    114. # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
    115. ## Declare a C++ executable
    116. ## With catkin_make all packages are built within a single CMake context
    117. ## The recommended prefix ensures that target names across packages don't collide
    118. # add_executable(${PROJECT_NAME}_node src/example_5_node.cpp)
    119. ## Rename C++ executable without prefix
    120. ## The above recommended prefix causes long target names, the following renames the
    121. ## target back to the shorter version for ease of user use
    122. ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
    123. # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
    124. ## Add cmake target dependencies of the executable
    125. ## same as for the library above
    126. # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
    127. ## Specify libraries to link a library or executable target against
    128. # target_link_libraries(${PROJECT_NAME}_node
    129. # ${catkin_LIBRARIES}
    130. # )
    131. if(CMAKE_BUILD_TYPE STREQUAL DEBUG)
    132. add_executable(action_service src/service.cpp)
    133. add_executable(action_client src/client.cpp)
    134. target_link_libraries(action_service
    135. ${catkin_LIBRARIES}
    136. )
    137. target_link_libraries(action_client
    138. ${catkin_LIBRARIES}
    139. )
    140. endif()
    141. #############
    142. ## Install ##
    143. #############
    144. # all install targets should use catkin DESTINATION variables
    145. # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
    146. ## Mark executable scripts (Python etc.) for installation
    147. ## in contrast to setup.py, you can choose the destination
    148. # catkin_install_python(PROGRAMS
    149. # scripts/my_python_script
    150. # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    151. # )
    152. ## Mark executables for installation
    153. ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
    154. # install(TARGETS ${PROJECT_NAME}_node
    155. # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    156. # )
    157. ## Mark libraries for installation
    158. ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
    159. # install(TARGETS ${PROJECT_NAME}
    160. # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
    161. # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
    162. # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
    163. # )
    164. ## Mark cpp header files for installation
    165. # install(DIRECTORY include/${PROJECT_NAME}/
    166. # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
    167. # FILES_MATCHING PATTERN "*.h"
    168. # PATTERN ".svn" EXCLUDE
    169. # )
    170. ## Mark other files for installation (e.g. launch and bag files, etc.)
    171. # install(FILES
    172. # # myfile1
    173. # # myfile2
    174. # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
    175. # )
    176. #############
    177. ## Testing ##
    178. #############
    179. ## Add gtest based cpp test target and link libraries
    180. # catkin_add_gtest(${PROJECT_NAME}-test test/test_example_5.cpp)
    181. # if(TARGET ${PROJECT_NAME}-test)
    182. # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
    183. # endif()
    184. ## Add folders to be run by python nosetests
    185. # catkin_add_nosetests(test)

    PS:需要注意的亮点

     

    package.xml

    1. "1.0"?>
    2. "2">
    3. example_5
    4. 0.0.0
    5. The example_5 package
    6. "miaozl@todo.todo">miaozl
    7. D
    8. O
    9. O
    10. T
    11. catkin
    12. roscpp
    13. rospy
    14. std_msgs
    15. actionlib_msgs
    16. roscpp
    17. rospy
    18. std_msgs
    19. actionlib_msgs
    20. roscpp
    21. rospy
    22. std_msgs
    23. message_generation

    步骤5 生成行为头文件,编译

  • 相关阅读:
    深度学习——几种学习类型
    Monkey压力测试
    【linux】coredump问题排查
    Java学习笔记3.9.3 Lambda表达式 - 方法引用
    python基于Echarts的城科就业数据可视化系统毕业设计源码150915
    JVM-HotSpot虚拟机对象探秘
    通过STM32Cube配置完成基于I2C协议的AHT20温湿度传感器的数据采集
    Vue elementui组件分页
    桌面云架构讲解(VDI、IDV、VOI/TCI、RDS)
    【LeetCode】No.75. Sort Colors -- Java Version
  • 原文地址:https://blog.csdn.net/weixin_44025389/article/details/126470251