ROS学习(二)——ROS基础命令

1.创建工作空间和功能包

1.1 工作空间

工作空间是一个存在工程开发相关文件的文件夹,典型的工作空间中一般包括以下目录:

  • src: 代码空间,存储所有ROS功能包的源码
  • build: 编译空间,存储工作空间编译过程中产生的缓存信息和中间文件
  • devel: 开发空间,放置放置编译生成的可执行文件
  • install: 安装空间,非必须,编译成功后,可以使用make install命令将可执行文件安装到该空间中,运行该空间中的环境变量脚本。

1.2 创建工作空间

  • 创建工作空间目录并初始化
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
  • 编译工作空间
$ cd ~/catkin_ws/
$ catkin_make
  • 编译过程中,在工作空间的根目录里会自动产生build和devel两个文件夹及其中的文件。编译完成后,devel文件中已经产生了一个setup.*sh形式的环境变量设置脚本。使用source使其生效:
$ source devel/setup.bash
  • 可以使用echo命令检查环境变量是否生效
$ echo $ROS_PACKAGE_PATH

注,在终端中使用source命令设置的环境变量只能在当前终端中生效,如果希望环境变量在所有终端中有效,需要在终端配置文件中加入环境变量的设置:

$ echo "source/WORLSPACE/devel/setup.bash">>~/.bashrc

WORKSPACE为自己的工作空间路径

1.3创建功能包

ROS创建功能呢瑰宝的命令为catkin_create_pkg,使用方法如下:

$ catkin_create_pkg  <package_name> [depend1] [depend2] [depend3]

depend1、depend2、depend3表示所以来的其他功能包的名称。

1.4 覆盖工作空间

ROS允许多个工作空间共存,每个工作空间的创建、编译和运行方法均相同。存在一种情况,即不同工作空间中存在相同命名的功能包 ,这时涉及到ROS中工作空间的覆盖问题。ROS中所有工作空间的路径会在ROS_PACKAGE_PATH环境变量中记录,当设置多个工作空间的环境变量后,新设置的路径在环境变量中会自动放置在最前端,运行时,ROS会优先查找最前端的工作空间中是否存在指定的功能包,若不存在就会按顺序向后查找。

2.话题中的Publisher和Subscriber

以"Hello World"为例,创建Publisher和Subscriber,具体步骤可以参考Writing a Simple Publisher and Subscriber (C++),该链接下的创建步骤比较老旧,根据其中内容进行适当调整

首先根据步骤1建立工作空间,然后再工作空间catkin_ws/src目录下创建包,本例创建包的命令如下:

catkin_create_pkg wk_tutorials std_msgs roscpp rospy

此时catkin_ws/src目录下多了wk_tutorials的文件夹,打开catkin_ws/src/wk_tutorials/src,在该文件夹下创建Publisher和Subscriber

2.1创建Publisher

流程如下:

  • 初始化ROS节点
  • 向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型
  • 按照一定的频率循环发送消息

在catkin_ws/src/wk_tutorials/src路径下创建talker.cpp,写入内容如下:

//头文件
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, argv, char **argv)
{
	//初始化ROS节点,第三个参数为ROS节点的名称
	ros::init(argc,arcgv,"tarker");
	//创建节点句柄,方便对节点资源的使用和管理;
	ros::NodeHandle n;
	//在ROS Master注册Publisher,告诉系统该节点会发布以chatter为话题的sting信息
	ros::Publisher chatter_pub=n.advertise<std_msgs::String>("chatter",1000);
	//设置循环频率。大小为10Hz
	ros::Rate loop_rate(10);
	int count=0;
	while  (ros::ok())
	{
		std_msgs::String msg;
		srd::stringstream ss;
		ss<<"Hello World"<<count;
		msg.data=ss.str();
		//ROS_INFO类似于print
		ROS_INFO("%s",msg.data.c_str());
		//发布封装完毕的消息msg
		chatter_pub_publish(msg);
		//处理节点订阅话题的所有回调函数
		ros::spinOnce();
		++count;
	}
	return 0;	
}

2.2创建Subscriber

流程如下:

  • 初始化ROS节点
  • 订阅需要的话题
  • 循环等待话题消息,接受到消息后进入回调函数
  • 在回调函数中完成消息处理

在catkin_ws/src/wk_tutorials/src路径下创建listener.cpp,写入内容如下:

//头文件
#include <sstream>
#include "ros/ros.h"
//接受到订阅的消息,进入消息回调函数
void chatterCallback(const std_msgs::String::Const Ptr& msg)
{
	ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, argv, char **argv)
{
	//初始化ROS节点,第三个参数为ROS节点的名称
	ros::init(argc,arcgv,"tarker");
	//创建节点句柄,方便对节点资源的使用和管理;
	ros::NodeHandle n;
	//创建一个Subscriber,订阅名为chatter的话题,注册回调函数chatterCallback
	ros::Subscriber chatter_pub=n.subscribe("chatter",1000,chatterCallback);
	//循环等待回调函数
	ros:;spin();
	return 0;	
}

2.3编译功能包

打开catkin_ws/src/wk_tutorials/src路径下的CMakeLists.txt文件,修改文件build对应部分的内容,如图:
在这里插入图片描述

//设置头文件的相对路径,全局路径默认是功能包所在目录
include_directories(include ${catkin_INCLUDE_DIRS})

//设置需要编译的得吗和生成的可执行文件,第一个参数为文件名称,后边的参数为源码文件
//需要多个代码文件,可以在后面一次列出,中间使用空格进行分隔
add_executable(talker src/talker.cpp)
//设置链接库,第一个参数为文件名称,后边的参数为链接库
target_link_libraries(talker ${catkin_LIBRARIES})
//设置依赖,一些应用中需要定义与语言无关的消息类型,这些消息类型在编译过程中产生相应的语言的代码
//若编译的可执行文件依赖这些动态生成的代码,需要添加如下配置
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)

2.4 运行

  • 首先启动roscore
  • 然后启动Publisher,即talker文件,运行结果如下:
cd catkin_ws
rosrun wk_tutorials talker

在这里插入图片描述

  • 新打开终端,运行Subscriber,即listener,运行结果如下:
cd catkin_ws
rosrun wk_tutorials listener

在这里插入图片描述

3.自定义话题消息

3.1创建消息文件夹并自定义消息

ROS中提供了一系列不同消息类型的功能包,如std_msgs、geometry_msgs等,很多情况下需,要针对自己的机器人应用设计特定的消息类型,以下列msg文件为例,定义了描述一个个人信息的消息类型

string name
uint8 sex 
uint8 age
uint8 unknown=0
uint8 male=1
unit8 female=2

承接第2部分,在catkin_ws/src/wk_tutorials路径下新建msg文件夹,在msg文件夹下新建Person.msg文件写入上述内容。

3.2 修改package.xml

添加如下依赖:

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

3.3 修改CMakeLists.txt

  • 在find_package添加message_generation
find_package(catkin REQUIRED COMPONENTS
  message_generation
  roscpp)
  • 在add_message_files中添加Person.msg
add_message_files(FILES
Person.msg)
  • 取消generate_messages部分的注释
generate_messages(DEPENDENCIES
  std_msgs)
  • 在catkin_package内添加依赖message_runtime
catkin_package(
  CATKIN_DEPENDS
  roscpp
  rospy
  std_msgs
  message_runtime)

上述配置完成后,回到根目录即catkin_ws下使用catkin_make命令编译文件,然后输入如下命令可查看Person消息类型

rosmsg show Person

在这里插入图片描述

4.服务中的Server和Client

服务(Service)是节点之间同步通信的一种方式,允许客户端(Client)节点发布请求,由服务端(Server)节点处理后反馈应答。以一个简单的加法为例,研究ROS中的服务应用。

4.1 自定义服务数据

ROS服务数据通过通过srv文件进行语言无关的接口定义。文件内包含请求与应答两个数据域,请求与应答的描述之间需要使用’—'进行分割。在catkin_ws/src/wk_tutorials下建立srv文件夹,在srv文件夹下建立AddTwoInts.srv文件:

int64 a
int 64 b
---
int64 sum

打开package.xml文件,添加一下依赖配置(3.2中已经添加)

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

打开CMakeLists.txt问价,添加如下(3.3中已经添加了message_generation):

find_package(catkin REQUIRED COMPONENTS
  message_generation
  roscpp)
add_service_files(
	FILES
	AddTwoInts.srv
)

其中,message_generation包不仅可以根据话题消息产生相应代码,也可以根据服务消息产生相应代码

4.2 创建server

在catkin_ws/src/wk_tutorials/src下建立server.cpp文件,Server实现流程和代码如下:

  • 初始化ROS节点
  • 创建Server实例
  • 循环等待服务请求,进入回调函数
  • 在回调函数中完成服务功能的处理并反馈应答数据
//头文件
#include "ros/ros.h"
#include "wk_tutorials/AddTwoInts.h"
//回调函数。输入参数req,输入参数res
bool add(wk_tutorials::AddTwoInts::Request  &req,
         wk_tutorials::AddTwoInts::Response &res)
{
//将输入参数中的请求数据相加,结果放到应答变量中
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  //ROS节点初始化
  ros::init(argc, argv, "server");
  //创建节点句柄
  ros::NodeHandle n;
  //创建server,注册回调函数add()
  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  //循环等待回调函数
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}

4.3 创建Client

创建client.cpp文件,流程和代码如下:

  • 初始化ROS节点
  • 创建Server实例
  • 循环等待服务请求,进入回调函数
  • 在回调函数中完成服务功能的处理并反馈应答数据
#include "ros/ros.h"
#include "wk_tutorials/AddTwoInts.h"
#include <cstdlib>

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_int的service消息
  ros::ServiceClient client = n.serviceClient<wk_tutorials::AddTwoInts>("add_two_ints");
  //创建wk_tutorials类型的sevice消息
  wk_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  //发布service请求,等待加法运算答疑结果
  if (client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

4.4 编译功能包

类似于2.3,编译功能包

add_executable(server src/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server wk_tutorials_gencpp)

add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client wk_tutorials_gencpp)

然后再catkin_ws目录下使用catkin_make编译功能包

4.5运行

  • 运行roscore
  • 运行server节点
    在这里插入图片描述
rosrun wk_tutorials server
  • 运行client节点
rosrun wk_tutorials client 3 5

在这里插入图片描述
此时服务端显示为:
在这里插入图片描述

参考:
[1] https://blog.csdn.net/weixin_42075471/article/details/85988995

猜你喜欢

转载自blog.csdn.net/space_dandy/article/details/114965023
今日推荐