ROS话题、服务、动作(自定义)

一.话题消息自定义和使用

以一个例题为例演示

使用 ROS 话题(Topic) 机制实现消息发布与订阅

要求:编写代码实现 ROS 中消息的发布与订阅: 创建一个发布者,每隔 100ms 依次发送斐波拉契数列的数字到话题/fibonacci 中;创建一个订阅者,订阅该话题,输出订阅结果。如,订阅者依次输出: 1 1 2 3 5 8 ··

1.如何自定义话题消息

·定义msg文件

#发送到话题内的数字
int32 number

在工作空间homeworkws/src内的homeworkpkg功能包内创建文件夹msg,并在msg内创建文件number.msg文件,在把上面的文件内容复制进文件。

·在package.xml中添加动态生成message的功能包依赖

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

·在CMakeLists.txt添加编译选项

1.在findpacksge(…..)结尾添加messagegeneration

2.在写有关于message内容下面添加

add_message_files(
  FILES
  number1.msg
)
generate_messages(
  DEPENDENCIES
  std_msgs
)

·在catkinpackage(….)结尾添加messageruntime

·回到工作空间的根目录下编译生成相应的头文件

cd homework_ws
catkin_make

2.创建发布者和订阅者代码实现(C++)

在工作空间homeworkws/src内的homeworkpkg功能包src内创建文件编写代码

发布者

cd homework_ws/src/homework_pkg/src
touch number_publisher.cpp
vim number_publisher.cpp
i(进入编辑模式)
写代码
esc键
:wq!(强制保存退出)

具体代码

#include<ros/ros.h>
#include"homework_pkg/number1.h"
int f(int count) {
    if (count == 1 || count == 2) {
        return 1;
    }
    else {
        return f(count - 2) + f(count - 1);
    }
}
int main(int argc, char** argv) {
     setlocale(LC_ALL,"");
    //ROS节点初始化
    ros::init(argc, argv, "number_publisher");
    //创建节点句柄
    ros::NodeHandle n;
    //创建一个publisher,发布名为/fibonacci的topic,消息类型为std_msgs::Int32,队>列长度为10
    ros::Publisher fibonacci_pub = n.advertise<homework_pkg::number1>("/fibonacci", 100);
    //设置循环频率
    ros::Rate loop_rate(10);
    int count = 1;
  while (ros::ok()) {
        //初始化geometry_sgs::Twist类型消息
        homework_pkg::number1 msg;
        msg.number = f(count);
        //发布消息
        fibonacci_pub.publish(msg);
        ROS_INFO("%d",msg.number);
        //按循环频率延时
        loop_rate.sleep();
        count++;
    }
    return 0;
}

订阅者

touch number_subscriber.cpp
vim number_subscriber.cpp
i(进入编辑模式)
写代码
esc键
:wq!(强制保存退出)

具体代码

#include<ros/ros.h>
#include"homework_pkg/number1.h"
void poseCallback(const homework_pkg::number1::ConstPtr& msg)
{
    //将接受到的消息打印出来
    ROS_INFO("%d", msg->number);
}
int main(int argc, char** argv)
{

    //初始化ROS节点
    ros::init(argc, argv, "number_subscriber");
    //创建节点句柄
    ros::NodeHandle n;
    //创建一个Subscriber,订阅名为/fibonacci的topic,注册回调函数poseCallback
    ros::Subscriber number_sub = n.subscribe("/fibonacci", 1000, poseCallback);
    //循环等待回调函数
    ros::spin();
    return 0;
}

3.编译并运行

编译规则设置

编译前先要在功能包homework_pkg内的CMakeList.txt内配置编译规则

·设置需要编译的代码和生成的可执行文件

·设置链接库

add_executable(number_publisher src/number_publisher.cpp)
target_link_libraries(number_publisher ${catkin_LIBRARIES})
  
add_executable(number_subscriber src/number_subscriber.cpp)
target_link_libraries(number_subscriber ${catkin_LIBRARIES})

addexecutable(numberpublisher src/numberpublisher.cpp),src/numberpublisher.cpp是指的前面编写代码的文件,numberpublisher是设置src/numberpublisher.cpp编译后形成的可执行文件的名字

targetlinklibraries(numberpublisher ${catkinLIBRARIES})是将可执行文件与对应的链接库链接。

将这两句话写在homework_pkg功能包内的CMakeList.txt内的有关build的内容的最下面

回到homework_ws工作空间根目录下编译

cd homework_ws
catkin_make

运行

开三个终端,分别执行命令
roscore
rosrun homework_pkg number_publisher
rosrun homework_pkg number_subscriber

效果

二.服务数据自定义与使用

以一个例题为例演示

使用 ROS 服务(Service)机制实现同步请求与答复

要求:编写代码实现 ROS 中的服务请求与答复: 创建服务端,注册 Service,当服务端收到客户端 Service 请求(携带整型参数 a.b) 后,服务端返回 a.b 的和给客户端,客户端输出结果。如,客户端给服务端 Service 发送参数 3,9,服务端返回 12,客户端输出: 12。

1.如何自定义服务数据

·定义srv文件

#客户端请求时发送的两个数据
int32 num1
int32 num2
---
#服务端响应时发送的两数据
int32 sum

在工作空间homeworkws/src内的homeworkpkg功能包内创建文件夹srv,并在srv内创建文件number.srv文件,在把上面的文件内容复制进文件。

·在package.xml中添加动态生成message的功能包依赖

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

·在CMakeLists.txt添加编译选项

1.在findpacksge(…..)结尾添加messagegeneration

2.在写有关于service内容下面添加

add_service_files(
  FILES
  number.srv
)
generate_messages(
  DEPENDENCIES
  std_msgs
)

·在catkinpackage(….)结尾添加messageruntime

·回到工作空间的根目录下编译生成相应的头文件

cd homework_ws
catkin_make

2.创建服务端和客户端代码实现(C++)

在工作空间homeworkws/src内的homeworkpkg功能包src内创建文件编写代码

客户端

cd homework_ws/src/homework_pkg/src
touch number_client.cpp
vim number_client.cpp
i(进入编辑模式)
写代码
esc键
:wq!(强制保存退出)

具体代码

#include "ros/ros.h"
#include "homework_pkg/number.h"
int main(int argc, char **argv)
{
    // 初始化 ROS 节点
    ros::init(argc, argv, "xiaomei");
    // 创建 ROS 句柄
    ros::NodeHandle n;
    // 创建 客户端 对象
    ros::ServiceClient client = n.serviceClient<homework_pkg::number>("number");
    // 提交请求并处理响应
    homework_pkg::number a;
    //提交请求
    a.request.num1 = 3;
    a.request.num2 = 9;
    //处理响应
    bool flag = client.call(a);
    if (flag)
    {
        ROS_INFO(" 响应成功!两个数的和为:%d", a.response.sum);
    }
    else
    {
        ROS_INFO("响应失败");
    }

    // ros::spin()循环等待回调函数
    ros::spin();
    ret

服务端

touch number_server.cpp
vim number_server.cpp
i(进入编辑模式)
写代码
esc键
:wq!(强制保存退出)

具体代码

#include "ros/ros.h"
#include "homework_pkg/number.h"

// 回调函数:bool 返回值由于标志是否处理成功
bool Callback(homework_pkg::number::Request& req,
    homework_pkg::number::Response& resp)
{
    //1处理请求
    int num1 = req.num1;
    int num2 = req.num2;
    ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d", num1, num2);
    //2组织响应
    int sum = num1 + num2;
    resp.sum = sum;
    ROS_INFO("两个数的和:sum = %d", sum);
    return true;
}

int main(int argc, char **argv)
{
 
    // 初始化 ROS 节点
    ros::init(argc, argv, "number_Server");
    // 创建 ROS 句柄
    ros::NodeHandle n;
    // 创建 服务 对象
    ros::ServiceServer server = n.advertiseService("number", Callback);
    ROS_INFO("服务启动....");
    //     回调函数处理请求并产生响应
    //     由于请求有多个,需要调用 ros::spin()
   

3.编译并运行

编译规则设置

编译前先要在功能包homework_pkg内的CMakeList.txt内配置编译规则

·设置需要编译的代码和生成的可执行文件

·设置链接库

add_executable(number_client src/number_client.cpp)
target_link_libraries(number_client ${catkin_LIBRARIES})
  
add_executable(number_server src/number_server.cpp)
target_link_libraries(number_server ${catkin_LIBRARIES})

addexecutable(numberclient src/numberclient.cpp),src/numberclient.cpp是指的前面编写代码的文件,numberclient是设置src/numberclient.cpp编译后形成的可执行文件的名字

targetlinklibraries(numberclient ${catkinLIBRARIES})是将可执行文件与对应的链接库链接。

将这两句话写在homework_pkg功能包内的CMakeList.txt内的有关build的内容的最下面

回到homework_ws工作空间根目录下编译

cd homework_ws
catkin_make

运行

开三个终端,分别执行命令
roscore
rosrun homework_pkg number_client
rosrun homework_pkg number_server

效果

三.动作编程自定义

以一个例题演示

使用 ROS 动作(Action)机制实现目标请求、进度与完成结果的反馈。

要求: 编写代码实现 ROS 中动作请求与进度反馈,创建服务端,注册 Action,客户端发送action 请求检测 40 个零件, 服务端接收后,每隔 1s 测一个零件 (每检测一个打印一次),:实时给客户端返回检测进度

(客户端打印进度百分比),并在检测完毕时告知客户端目标完成。如,服务端实时打印: 检测 1个零件 检测2 个零件 …检测 40 个零件 检测完成客户端实时打印: 2.5% 5% … 100% 检测完成

1.自定义动作消息

·定义action文件

cd homework_ws/src/homework_pkg
mkdir action
cd action
touch checkaction.action
int32 requestnumber
---
int32 resultnumber
---
int32 feedbacknumber

·在package.xml中添加功能包依赖

  <build_depend>actionlib</build_depend>
  <build_depend>actionlib_msgs</build_depend>
  <exec_depend>actionlib</exec_depend>
  <exec_depend>actionlib_msgs</exec_depend>

·在CMakeLists.txt中添加编译选项

findpackage(catkin REQUIRED actionlibmsgs actionlib)

addactionfiles(DIRECTORY action FILES checkaction.action)

generatemessages(DEPENDENCIES actionlibmsgs)(这最后一句是把内容追加到之前话题服务部分已经添加了的语句后面。)之后再回到工作空间根目录下编译。

2.实现动作服务器(C++)

  • 初始化ROS节点

  • 创建动作服务器实例

  • 启动服务器,等待动作请求

  • 在回调函数中完成动作服务功能的处理,并反馈进度信息

  • 动作完成,发送结束信息

在src下创建代码文件checkactionserver.cpp和checkactionclient.cpp

具体代码

checkaction_server.cpp

#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "homework_pkg/checkactionAction.h"
typedef actionlib::SimpleActionServer<homework_pkg::checkactionAction> Server;
// 收到action的goal后调用该回调函数
void execute(const homework_pkg::checkactionGoalConstPtr &goal, Server *as)
{
        ros::Rate r(1);
        homework_pkg::checkactionFeedback feedback;
        ROS_INFO("开始检测 %d 个零件.", goal->requestnumber);
        // 假设检测的进度,并且按照1Hz的频率发布进度feedback 
        for (int i = 1; i <= 40; i++)
        {
                feedback.feedbacknumber = i;
                as->publishFeedback(feedback);
                r.sleep();
        }
        // 当action完成后,向客户端返回结果
        ROS_INFO("已经检测完 %d 个零件", goal->requestnumber);
        as->setSucceeded();
}
int main(int argc, char** argv)
{
 setlocale(LC_ALL, "");
        ros::init(argc, argv, "check_server");
        ros::NodeHandle hNode;
        // 定义一个服务器
        Server server(hNode, "check", boost::bind(&execute, _1, &server), false);
        // 服务器开始运行
        server.start();
        ros::spin();
        return 0;
}

checkaction_client.cpp

#include <actionlib/client/simple_action_client.h>
#include "homework_pkg/checkactionAction.h"

typedef actionlib::SimpleActionClient<homework_pkg::checkactionAction> Client;

// 当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,
        const homework_pkg::checkactionResultConstPtr& result)
{
        ROS_INFO("检测完成!");
        ros::shutdown();
}

// 当action激活后会调用该回调函数一次
void activeCb()
{
        ROS_INFO("开始检测了");
}

// 收到feedback后调用该回调函数
void feedbackCb(const homework_pkg::checkactionFeedbackConstPtr& feedback)
{
        double t = feedback->feedbacknumber;
    double n = t / 40;
        ROS_INFO(" 检测进度 : %.2f%% ", n*100);
}

int main(int argc, char** argv)
{
        setlocale(LC_ALL, "");
        ros::init(argc, argv, "check_client");

        // 定义一个客户端
        Client client("check", true);

        // 等待服务器端
        ROS_INFO("等待服务器响应.");
        client.waitForServer();
        ROS_INFO("服务启动, 发送目标");

        // 创建一个action的goal
        homework_pkg::checkactionGoal goal;
        goal.requestnumber = 40;

        // 发送action的goal给服务器端,并且设置回调函数
        client.sendGoal(goal, &doneCb, &activeCb, &feedbackCb);

        ros::spin();

        return 0;
}

3.编译并运行

编译规则设置

add_executable(checkaction_server src / checkaction_server.cpp)
target_link_libraries(checkaction_server ${ catkin_LIBRARIES })
add_dependencies(checkaction_server ${ ${PROJECT_NAME}_EXPORTED_TARGETS })

add_executable(checkaction_client src / checkaction_client.cpp)
target_link_libraries(checkaction_client ${ catkin_LIBRARIES })
add_dependencies(checkaction_client ${ ${PROJECT_NAME}_EXPORTED_TARGETS })

编译

cd homework_ws
catkin_make

运行

roscore
rosrun homework_pkg checkaction_server
rosrun homework_pkg checkaction_client

效果

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值