文章目录
一、动作编程概念
动作(action):
- 一种问答通信机制
- 带有连续反馈
- 可以在任务过程中中止运行
- 基于ROS的消息机制实现
Action的接口
goal
:发布任务目标cancel
:请求取消任务status
:通知客户端当前服务器的状态feedback
:周期反馈任务运行的监控数据result
:向客户端发送任务的执行结果,只发布一次
二、自定义action文件
1.定义action文件
这个文件存储在功能包my_package
下新建的一个action
文件夹。
mkdir -p ~/catkin_ws/src/my_package/action
创建DoDishes.action
文件
gedit ~/catkin_ws/src/my_package/action/DoDishes.action
# Define the goal
uint32 dishwasher_id # specify which dishwasher we want to use
---
# Define the result
uint32 toatl_disher_cleaned
---
# Define a feedback message
float32 percent_complete
2.依赖
动作编程要用到自定义的动作数据结构,所以我们
- 添加build的依赖
actionlib
、actionlib_msgs
和exec的依赖actionlib
、actionlib_msgs
(话题编程messages
和服务编程serviecs
都是消息message
,依赖build的message_generation
和exec的message_runtime
)
(动作编程actions
是动作action
,依赖build和exec都是actionlib
、actionlib_msgs
) - 添加我们的
actions
文件DoDishes.action
- 添加动作编程
actions
使用的消息类型actionlib_msgs
消息类型(messages
(对应std_msgs
)/services
(对应std_msgs
)/actions
(对应actionlib_msgs
))
则对应CMakeLists.txt
新增修改内容:
-
find_package
:添加build的依赖,即找到catkin
包中需要的组件。
除了那三项( roscpp、rospy和std_msgs)后,还要有actionlib
和actionlib_msgs
。 -
add_action_files
:Generate services in the ‘srv’ folder(添加在’srv’ 文件夹中的消息文件。)
添加我们自定义文件的DoDishes.action
到FILES
中 -
generate_messages
:Generate added messages and services with any dependencies listed here(使用此处添加的任何依赖项来生成添加了的消息和服务)
添加消息类型actionlib_msgs
到DEPENDENCIES
中 -
catkin_package
:添加exec执行的依赖CATKIN_DEPENDS
除了添加那三项( roscpp、rospy和std_msgs)后,还要有actionlib
和actionlib_msgs
。
三、动作编程
1.DoDishes_server.cpp
#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include "my_package/DoDishesAction.h"
typedef actionlib::SimpleActionServer<my_package::DoDishesAction> Server;
// 收到action的goal后调用该回调函数
void execute(const my_package::DoDishesGoalConstPtr & goal, Server * as)
{
ros::Rate rate(1);
my_package::DoDishesFeedback feedback;
ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);
// 假设洗盘子的进度,并且按照1Hz的频率发布进度feedback
for(int i = 1 ; i <= 10 ; i++)
{
feedback.percent_complete = i * 10;
as->publishFeedback(feedback);
rate.sleep();
}
// 当action完成后,向客户端返回结果
ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id);
as->setSucceeded();
}
int main(int argc , char ** argv)
{
ros::init(argc, argv, "do_dishes_server");
ros::NodeHandle nodeHandle;
// 定义一个服务器
Server server(nodeHandle, "do_dishes", boost::bind(&execute, _1, &server), false);
// 服务器开始运行
server.start();
ros::spin();
return 0;
}
2.DoDisher_client.cpp
#include <actionlib/client/simple_action_client.h>
#include "my_package/DoDishesAction.h"
typedef actionlib::SimpleActionClient<my_package::DoDishesAction> Client;
// 当action完成后会调用该回调函数一次
void doneCallback(const actionlib::SimpleClientGoalState & state,
const my_package::DoDishesResultConstPtr & result)
{
ROS_INFO("The dishes are now clean");
ros::shutdown();
}
// 当action激活后会调用该回调函数一次
void activeCallback()
{
ROS_INFO("Goal just went active");
}
// 收到feedback后调用该回调函数
void feedbackCallback(const my_package::DoDishesFeedbackConstPtr & feedback)
{
ROS_INFO("percent_complete: [%f]", feedback->percent_complete);
}
int main(int argc, char ** argv)
{
ros::init(argc, argv, "do_dishes_client");
// 定义一个客户端
Client client("do_dishes", true);
// 等待服务器端
ROS_INFO("waiting for action server to start.");
client.waitForServer();
ROS_INFO("Action server started, sending goal.");
//创建一个action的goal
my_package::DoDishesGoal goal;
goal.dishwasher_id = 1;
// 发送aciton的goal给服务器端
client.sendGoal(goal, &doneCallback, &activeCallback, &feedbackCallback);
ros::spin();
return 0;
}
3.修改CMakeLists.txt
# project name
project(my_package)
# using C++11
set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -std=c++11 ")
# cmake version
cmake_minimum_required(VERSION 2.8.3)
# find catkin package需要的组件
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
actionlib_msgs
actionlib
)
# 添加动作文件
add_action_files(FILES DoDishes.action)
# 生成添加了的消息和服务
generate_messages(DEPENDENCIES actionlib_msgs)
# 添加exec执行的依赖
catkin_package(
CATKIN_DEPENDS roscpp rospy std_msgs actionlib_msgs actionlib
)
# link headers
include_directories(
${catkin_INCLUDE_DIRS}
)
# 生成可执行文件
add_executable(DoDishes_client src/DoDishes_client.cpp)
add_executable(DoDishes_server src/DoDishes_server.cpp)
# after ADD_EXECUTABLE,为生成文件target添加库
target_link_libraries( DoDishes_client ${catkin_LIBRARIES})
target_link_libraries( DoDishes_server ${catkin_LIBRARIES})
4.运行
catkin_make
roscore
rosrun my_package DoDishes_client
rosrun my_package DoDishes_server