ROS1重温:Action通信

文章详细介绍了ROS中Action通信与服务通信的区别,包括应答机制、可取消性以及反馈次数。接着,通过累加器的例子展示了Action通信的实际应用,包括创建ROS程序包、自定义action文件、服务端和客户端代码的编写,以及如何在执行过程中进行反馈和接收结果。
摘要由CSDN通过智能技术生成


Action 通信与服务通信的区别

相同点

  • 二者均采用应答机制,有服务端与客户端
  • 二者均值发送一次请求,并在任务最后收到最终结果

不同点

  • 服务通信服务端任务一旦启动,该执行过程中不可取消;
    Action 通信客户端可以在服务端执行过程中发送取消(cancel)指令
  • 服务通信过程中只给出一次最终反馈;
    Action 通信在执行过程中可以进行多次反馈
  • 服务通信始终只发送一次执行结果;
    Action 通信在执行过程中可以多次发送反馈结果

Action 通信实际应用方向

  • 需要在通信过程中,处理中间产物的应用。例如,导航过程中的局部路径规划

Action 通信例程 —— 累加器

需求

  • 客户端发送累加次数,服务端给出累加结果,并在累加过程中反馈累加进度

涉及到的文件名

  • 程序包名:action_demo
  • 服务端文件名:action_server_demo.cpp
  • 客户端文件名:action_client_demo.cpp
  • 自定义 action 文件名:AddInts.action

实现过程

创建 ROS 程序包 action_demo

  • 需要的依赖:std_msgs roscpp actionlib actionlib_msgs

创建自定义 action 文件

  • 在 src/ 目录下创建目录 action/ ,在该目录下创建 AddInts.action 文件,内容如下:
# 目标数据变量
int32 num
---
# 最终响应变量
int32 result
---
# 连续反馈变量
float64 progress_bar

注:三个 “-” 是用来做分隔符,自上而下分别为:目标数据变量、最终响应结果变量、过程中的反馈变量

  • 修改 CMakeLists.txt 文件,主要修改后的内容如下:
## Generate actions in the 'action' folder
add_action_files(
  FILES
  AddInts.action
)

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

catkin_package(
 CATKIN_DEPENDS actionlib actionlib_msgs roscpp rospy std_msgs
)

创建服务端 action_server_demo.cpp

  • 核心函数:
actionlib::SimpleActionServer(std::string name, 
					ExecuteCallback execute_callback, 
					bool auto_start);
  • 程序代码:
#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "action_demo/AddIntsAction.h"

// 变量类型名过长,之后多次用到,此处进行重新定义为简短变量名
typedef actionlib::SimpleActionServer<action_demo::AddIntsAction> ActionServer;

// 请求处理
void addIntsCallBack(const action_demo::AddIntsGoalConstPtr &goal, ActionServer *server)
{
    // 解析提交的目标值
    int goal_num = goal->num;
    ROS_INFO("客户端提交的目标值是:%d", goal_num);

    // 设置频率 10 Hz
    ros::Rate r(10);
    // 声明累加结果变量
    int add_result = 0;
    ROS_INFO("开始持续反馈...");
    for (int i = 1; i <= goal_num; i++)
    {
        // 累加
        add_result += i;
        // 休眠
        r.sleep();
        // 声明持续反馈结果变量,本例程是用于存储累加进度
        action_demo::AddIntsFeedback fb;
        // 计算累计进度
        fb.progress_bar = i / (double)goal_num;
        // 反馈累加进度
        server->publishFeedback(fb);
    }
    ROS_INFO("最终结果:%d\n", add_result);
    // 声明服务最终结果变量
    action_demo::AddIntsResult action_result;
    // 存储累加结果
    action_result.result = add_result;
    // 反馈最终结果
    server->setSucceeded(action_result);
}

int main(int argc, char *argv[])
{
    // 设置中文编码
    setlocale(LC_ALL, "");
    // ROS 初始化
    ros::init(argc, argv, "action_server_demo_node");
    // 句柄初始化
    ros::NodeHandle nh;

    // 创建 action 服务对象
    ActionServer action_server(nh, "addInts", boost::bind(&addIntsCallBack, _1, &action_server), false);
    action_server.start(); // 创建服务对象时,最后一个参数 auto_start 设置为 false,则需手动启动
    ROS_INFO("服务已启动...\n");
    // 调用调用回调函数
    ros::spin();

    return 0;
}
  • CMakeLists.txt 修改:
add_executable(action_server_demo_node src/action_server_demo.cpp)

add_dependencies(action_server_demo_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

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

创建客户端 action_client_demo.cpp

  • 核心函数:
void SimpleActionClient<ActionSpec>::sendGoal(const Goal & goal,
  SimpleDoneCallback done_cb,
  SimpleActiveCallback active_cb,
  SimpleFeedbackCallback feedback_cb)
  • 参数中的三个回调函数意义:
// 官方注释
done_cb – Callback that gets called on transitions to Done
active_cb – Callback that gets called on transitions to Active
feedback_cb – Callback that gets called whenever feedback for this goal is received

// 中文翻译
done_cb – 在转换到“完成”时调用的回调,即响应成功时的回调函数

active_cb – 在转换到“激活”时调用的回调,即客户端与服务端通信激活时的回调函数

feedback_cb – 每当收到此目标的反馈时调用的回调,即连续反馈的回调函数
  • 程序代码:
#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"
#include "action_demo/AddIntsAction.h"

// 参数2:响应成功时的回调函数
void done_cb(const actionlib::SimpleClientGoalState &state, const action_demo::AddIntsResultConstPtr &result)
{
    // 响应状态是否成功
    if (state.state_ == state.SUCCEEDED)
    {
        ROS_INFO("响应成功!最终结果为:%d", result->result);
    }
    else
    {
        ROS_WARN("请求失败!");
    }
}

// 参数设置3:客户端与服务端通信激活时的回调函数
void active_cb()
{
    ROS_INFO("客户端与服务端已建立连接...");
}

// 参数设置4:连续反馈的回调函数
void feedback_cb(const action_demo::AddIntsFeedbackConstPtr &feedback)
{
    ROS_INFO("当前进度:%.2f", feedback->progress_bar);
}

int main(int argc, char *argv[])
{
    // 设置中文编码
    setlocale(LC_ALL, "");
    // ROS 初始化
    ros::init(argc, argv, "action_client_demo_node");
    // 句柄创建
    ros::NodeHandle nh;
    // 创建 action 客户端对象
    actionlib::SimpleActionClient<action_demo::AddIntsAction> action_client(nh, "addInts");

    // 等待服务端启动
    action_client.waitForServer();

    // 参数1:设置目标值
    action_demo::AddIntsGoal goal;
    goal.num = 100;

    // 发送目标数据
    action_client.sendGoal(goal, done_cb, active_cb, feedback_cb);

    // 持续调用回调函数
    ros::spin();
    return 0;
}
  • CMakeLists.txt 文件:
add_executable(action_client_demo_node src/action_client_demo.cpp)

add_dependencies(action_client_demo_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(action_client_demo_node
  ${catkin_LIBRARIES}
)
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值