ROS基础学习—话题、服务、动作编程

ROS基础学习---话题、服务、动作编程

引言:

​ 通过本实验,我们将进行ROS基础学习内容主要包括:话题、服务、动作编程。掌握ROS的这些基础概念,进一步深入ROS的学习。

希望你在本次学习过后,能够有一定的收获!!!

推荐歌曲---白月光与朱砂痣-大籽

​ 冲啊!!!! ٩(͡๏̯͡๏)۶ ٩(͡๏̯͡๏)۶ ٩(͡๏̯͡๏)۶

文章目录

一、工作空间

定义

在ROS(Robot Operating System)中,工作空间(Workspace)是一个用户可以用来组织并构建自定义ROS软件包的文件夹结构。通常,这个工作空间被称为 catkin workspace ,得名于ROS的构建系统 catkin

一个典型的catkin工作空间包含以下几个部分:

  1. src (source)目录:这是工作空间的核心目录,包含所有的ROS软件包源代码。当你创建一个新的ROS工作空间时,会从创建这个目录开始。任何你下载或创建的自定义ROS软件包都应该放在这个目录下。
  2. build目录 :当你编译你的工作空间时(使用catkin_makecatkin build命令),catkin构建系统会在这个目录下创建中间文件。这些文件帮助catkin跟踪构建过程中的依赖关系,以确保软件包以正确的顺序构建。
  3. devel目录 :一旦软件包被构建,所有的可执行文件、库文件和其他必要的文件都会被放置在这个目录下。通过 sourcing 这个目录下的setup.sh文件(即运行source devel/setup.sh),你可以让ROS找到你的工作空间中的包和程序。
  4. install目录 (可选):如果你选择 make install 安装你的软件包,制品(可执行文件、配置文件等)会被放到这个目录下,类似于本地安装。这个目录通常用于为其他机器准备软件包,或者当你想要使软件包在系统中变得全局可用时。

实现过程

  1. 创建工作空间

    mkdir -p ~/catkin_ws/src #创建文件夹

    cd ~/catkin_ws/src #进入目录

    catkin_init_workspace #初始化,使其成为ROS的工作空间

  1. 编译工作空间

    cd ..
    catkin_make

  1. 设置环境变量

    #该环境变量设置只对当前终端有效,lx567是用户名
    source /home/lx567/catkin_ws/devel/setup.bash
    #将上面命令放置到~/.bashrc文件中,让其对所有终端都有效
    sudo nano ~/.bashrc

  1. 检查环境变量

    echo $ROS_PACKAGE_PATH

二、功能包

定义

在ROS(Robot Operating System)中,功能包(Package)是ROS应用程序的基本组织单元,它包含了实现一系列相关功能所需的一组编程代码和数据。功能包的目的是促进代码的模块化和复用,使得机器人的软件设计更为易于管理和扩展。

每个ROS包通常包含以下内容:

  1. CMakeLists.txt:这是一个用于构建ROS包的CMake项目文件。它告诉catkin构建系统如何编译和链接程序和库。
  2. package.xml:它提供了关于ROS包的元数据,包括包的名称、版本、维护者、依赖关系以及许可证信息等。
  3. 源代码:包括C++、Python或其他支持的编程语言编写的代码文件。
  4. 消息定义(msg文件):如果包定义了自定义ROS消息,它们将被包含在这里。
  5. 服务定义(srv文件):如果包定义了自定义ROS服务,这些服务定义同样存放于此。
  6. 动作定义(action文件):用于定义ROS动作,如果包包含动作服务器或客户端。
  7. 配置文件 :这些可能包括启动文件(.launch ),这些文件用于启动一组ROS节点;参数文件(.yaml),定义节点运行时使用的参数;以及其他用于配置特定节点或应用程序的文件。
  8. README和其他文档:提供了关于包用途、安装和运行方式的信息。

实现过程

  1. 创建功能包

    cd ~/catkin_ws/src
    catkin_create_pkg learning_communication std_msgs rospy roscpp
    #catkin_create_pkg 功能包名字 依赖
    #std_msgs:定义的标准的数据结构
    #rospy:提供python编程接口
    #roscpp:提供c++编程接口

2.编译功能包

bash 复制代码
cd ~/catkin_ws
catkin_make

三、ROS通信编程

在ROS中,通信编程是指创建能够在不同的ROS节点之间传递信息的程序。ROS提供了几种不同的通信机制,以适应不同类型的数据交换和各种交互模式的需要。

主要的通信机制包括:

1. 话题(Topics)

这是ROS中最常用的通信方式。节点可以发布(publish)消息到一个话题,或订阅(subscribe)一个话题以接收消息。话题适用于无状态的、流式的通信,如传感器数据流。它使用发布/订阅模型,可以有多个发布者和多个订阅者。

2. 服务(Services)

服务是一种双向的通信方式,允许一个节点发送请求(request)给另一个节点,并等待响应(response)。服务通信是同步的,并且在请求处理完成之前,调用节点会阻塞。服务适合那些不需要连续数据流的应答模式交互,如客户端查询信息或发送特定的命令。

3. 动作(Actions)

动作是一种用于长期运行的任务,并且需要周期性反馈的通信方式。动作客户端发送一个目标,并且动作服务器在执行长时任务过程中提供反馈,最后发送最终结果。动作是有状态的,并且可以被抢占。这适用于需要长时间完成的任务,如移动机器人到指定位置。

4. 参数服务器(Parameter Server)

参数服务器是多个节点共享配置参数的地方。它不是交互式通信的主要形式,而是一种节点可以存储和检索配置信息的手段。它通常被用来在启动时设置系统参数。

1.话题编程

步骤:

  1. 创建发布者
    • 初始化ROS节点
    • 向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型
    • 按照一定频率循环发布消息
  2. 创建订阅者
    • 初始化ROS节点
    • 订阅需要的话题
    • 循环等待话题消息,接受到消息后进行回调函数
    • 回调函数中完成消息处理
  3. 添加编译选项
    • 设置需要编译的代码和生成的可执行文件
    • 设置链接库
    • 设置依赖
  4. 运行可执行程序

编写代码

talker.cpp

c++ 复制代码
#include<sstream>
#include"ros/ros.h"
#include"std_msgs/String.h"
int main(int argc,char **argv)
{
	//ROS节点初始化
	ros::init(argc,argv,"talker");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
	ros::Publisher chatter_pub=n.advertise<std_msgs::String>("chatter",1000);
	//设置循环的频率
	ros::Rate loop_rate(10);
	int count=0;
	while(ros::ok())
	{
		//初始化std_msgs::String类型的消息
		std_msgs::String msg;
		std::stringstream ss;
		ss<<"hello world"<<count;
		msg.data=ss.str();
		//发布消息
		ROS_INFO("%s",msg.data.c_str());
		chatter_pub.publish(msg);
		//循环等待回调函数
		ros::spinOnce();
		//接受循环频率延时
		loop_rate.sleep();
		++count;
	}
	return 0;
}

listener.cpp

c++ 复制代码
#include"ros/ros.h"
#include"std_msgs/String.h"
//接收到订阅的消息,会进入消息的回调函数
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
	//将接收到的消息打印处理
	ROS_INFO("I heard:{%s}",msg->data.c_str());
}
int main(int argc,char **argv)
{
	//初始化ROS节点
	ros::init(argc,argv,"listener");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
	ros::Subscriber sub=n.subscribe("chatter",1000,chatterCallback);
	//循环等待回调函数
	ros::spin();
	return 0;
}

设置CMakeLists.txt文件

编译

运行可执行文件

roscore
rosrun learning_communication talker
rosrun learning_communication listener

2.自定义话题消息

  • 定义msg文件

    mkdir ~/catkin_ws/src/learning_communication/msg
    sudo nano Person.msg

Person.msg

string name
uint8 sex
uint8 age

uint8 unknown=0
uint8 male=1
uint8 female=2

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

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

在CMakeLists.txt添加编译选项

编译成功后,查看自定义消息

3.服务编程

定义srv文件

mkdir ~/catkin_ws/src/learning_communication/srv
sudo nano AddTwoInts.srv

AddTwoInts.srv

int64 a
int64 b
---
int64 sum

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

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

在CMakeLists.txt添加编译选项

步骤:

  • 创建服务器
    • 初始化ROS节点
    • 创建Serve实例
    • 循环等待服务请求,进入回调函数
    • 在回调函数中完成服务功能的处理,并反馈应答数据
  • 创建客户端
    • 初始化ROS节点
    • 创建一个Client实例
    • 发布服务请求数据
    • 等待Serve处理之后的应答结果
  • 添加编译选项
    • 设置需要编译的代码和生成的可执行文件
    • 设置链接库
    • 设置依赖
  • 运行可执行程序

server.cpp

c++ 复制代码
#include<ros/ros.h>
#include"learning_communication/AddTwoInts.h"
//service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwoInts::Request &req,learning_communication::AddTwoInts::Response &res)
{
	//将输入的参数中的请求数据相加,结果放到应答变量中
	res.sum=req.a+req.b;
	ROS_INFO("request: x=%1d,y=%1d",(long int)req.a,(long int)req.b);
	ROS_INFO("sending back response:[%1d]",(long int)res.sum);
	return true;
}
int main(int argc,char **argv)
{
	//ROS节点初始化
	ros::init(argc,argv,"add_two_ints_server");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个名为add_two_ints的server,注册回调函数add()
	ros::ServiceServer service=n.advertiseService("add_two_ints",add);
	//循环等待回调函数
	ROS_INFO("Ready to add two ints.");
	ros::spin();
	return 0;
}

client.cpp

c++ 复制代码
#include<cstdlib>
#include<ros/ros.h>
#include"learning_communication/AddTwoInts.h"
int main(int argc,char **argv)
{
	//ROS节点初始化
	ros::init(argc,argv,"add_two_ints_client");
	//从终端命令行获取两个加数
	if(argc!=3)
	{
		ROS_INFO("usage:add_two_ints_client X Y");
		return 1;
	}
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个client,请求add_two_ints_service
	//service消息类型是learning_communication::AddTwoInts
	ros::ServiceClient client=n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
	//创建learning_communication::AddTwoInts类型的service消息
	learning_communication::AddTwoInts srv;
	srv.request.a=atoll(argv[1]);
	srv.request.b=atoll(argv[2]);
	//发布service请求,等待加法运算的应答请求
	if(client.call(srv))
	{
		ROS_INFO("sum: %1d",(long int)srv.response.sum);
	}
	else
	{
		ROS_INFO("Failed to call service add_two_ints");
		return 1;
	}
	return 0;
}

设置CMakeLists.txt文件

编译产生最后文件

运行可执行文件

roscore
rosrun learning_communication server
rosrun learning_communication client 56 123

4. 动作编程

动作是一种基于ROS消息实现的问答通信机制,它包含连续反馈,可以在任务过程中止运行。

动作(Action)的接口

接口名称 接口含义
goal 发布任务目标
cancel 请求取消任务
status 通知客户端当前的状态
feedback 周期反馈任务运行的监控数据
result 向客户端发送任务的执行结果,只发布一次

自定义动作消息

  • 定义action文件

    mkdir ~/catkin_ws/src/learning_communication/action
    sudo nano DoDishes.action

DoDishes.action

#定义目标信息
uint32 dishwasher_id
---
#定义结果信息
uint32 total_dishes_cleaned
---
#定义周期反馈的消息
float32 percent_complete

在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添加编译选项

步骤:

  • 创建动作服务器
    • 初始化ROS节点
    • 创建动作服务器实例
    • 启动服务器,等待动作请求
    • 在回调函数中完成动作服务功能的处理,并反馈进度信息
    • 动作完成,发送结束信息
  • 创建动作客户端
    • 初始化ROS节点
    • 创建动作客户端实例
    • 连接动作服务器
    • 发送动作目标
    • 根据不同类型的服务器端反馈处理回调函数
  • 添加编译选项
    • 设置需要编译的代码和生成的可执行文件
    • 设置链接库
    • 设置依赖
  • 运行可执行程序

DoDishes_server.cpp

c++ 复制代码
#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server;
// 收到action的goal后调用该回调函数
void execute(const learning_communication::DoDishesGoalConstPtr &goal, Server *as)
{
	ros::Rate r(1);
	learning_communication::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);
		r.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 hNode;
	// 定义一个服务器
	Server server(hNode, "do_dishes", boost::bind(&execute, _1, &server), false);
	// 服务器开始运行
	server.start();
	ros::spin();
	return 0;
}

DoDishes_client.cpp

c++ 复制代码
#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client;
// 当action完成后会调用该回调函数一次
void doneCallback(const actionlib::SimpleClientGoalState &state
	, const learning_communication::DoDishesResultConstPtr &result)
{
	ROS_INFO("Yay! The dishes are now clean");
	ros::shutdown();
}
// 当action激活后会调用该回调函数一次
void activeCallback()
{
	ROS_INFO("Goal just went active");
}
// 收到feedback后调用该回调函数
void feedbackCallback(const learning_communication::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
	learning_communication::DoDishesGoal goal;
	goal.dishwasher_id = 1;
	// 发送action的goal给服务端,并且设置回调函数
	client.sendGoal(goal, &doneCallback, &activeCallback, &feedbackCallback);
	ros::spin();
	return 0;
}

设置CMakeLists.txt文件

编译-运行可执行文件

roscore
rosrun learning_communication DoDishes_client
rosrun learning_communication DoDishes_server

参考资料

https://blog.csdn.net/qq_43279579/article/details/114764633

相关推荐
十年一梦实验室4 小时前
波士顿动力ATLAS 3.0展示6项新AI升级(SPACEO机器人)
人工智能·机器人
电气_空空4 小时前
基于单片机及传感器的机器人设计与实现
单片机·嵌入式硬件·机器人·毕业设计·毕设
boss-dog4 小时前
视觉在协作机器人上的场景应用
机器人·视觉
flashier5 小时前
C语言 进阶指针学习笔记
c语言·笔记·学习
大白的编程日记.6 小时前
【Linux学习笔记】Linux基本指令分析和权限的概念
linux·笔记·学习
螺旋式上升abc6 小时前
GO语言学习笔记
笔记·学习·golang
W起名有点难6 小时前
前端学习——CSS
前端·css·学习
Moonnnn.7 小时前
51单片机——汇编工程建立、仿真、调试全过程
汇编·笔记·嵌入式硬件·学习·51单片机
EnigmaCoder7 小时前
蓝桥杯刷题周计划(第二周)
学习·算法·蓝桥杯
IT猿手8 小时前
2025最新群智能优化算法:云漂移优化(Cloud Drift Optimization,CDO)算法求解23个经典函数测试集,MATLAB
开发语言·数据库·算法·数学建模·matlab·机器人