Jetson nano之ROS入门- -ROS集成开发搭建与ROS通信学习笔记


一、ROS集成开发环境搭建

在这里插入图片描述

VSCode 全称 Visual Studio Code,是微软出的一款轻量级代码编辑器,免费、开源而且功能强大。它支持几乎所有主流的程序语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比 Diff、GIT 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。

vscode 下载 https://code.visualstudio.com/docs?start=true

cd到vscode的deb安装包目录下

sudo dpkg -i xxxx.deb

安装好后打开vscode,需要下载一些插件,比如Python拓展,C/C++拓展,ROS插件,简体中文插件,CMake插件等,下载好后创建一个工作空间,工作空间下创建一个src文件包

sudo mkdir -p /home/nvidia/xxx/src
cd /home/nvidia/xxx

给刚刚创建的工作空间和src文件包添加权限

sudo chmod +777 /home/nvidia/xxx 
sudo chmod +777 /home/nvidia/xxx/src

接着在工作空间目录下执行catkin_make编译命令

catkin_make

其中CMake是对make工具的生成器,是更高层的工具,它简化了编译构建过程,能够管理大型项目,具有良好的扩展性。对于ROS这样大体量的平台来说,就采用的是CMake,并且ROS对CMake进行了扩展,于是便有了Catkin编译系统。下面是整个ROS工作空间的文件架构。
在这里插入图片描述

WorkSpace --- 自定义的工作空间

    |--- build:编译空间,用于存放CMake和catkin的缓存信息、配置信息和其他中间文件。

    |--- devel:开发空间,用于存放编译后生成的目标文件,包括头文件、动态&静态链接库、可执行文件等。

    |--- src: 源码

        |-- package:功能包(ROS基本单元)包含多个节点、库与配置文件,包名所有字母小写,只能由字母、数字与下划线组成

            |-- CMakeLists.txt 配置编译规则,比如源文件、依赖项、目标文件

            |-- package.xml 包信息,比如:包名、版本、作者、依赖项...(以前版本是 manifest.xml)

            |-- scripts 存储python文件

            |-- src 存储C++源文件

            |-- include 头文件

            |-- msg 消息通信格式文件

            |-- srv 服务通信格式文件

            |-- action 动作格式文件

            |-- launch 可一次性运行多个节点 

            |-- config 配置信息

        |-- CMakeLists.txt: 编译的基本配置

在工作空间下执行终端命令打开vscode

code .

二、ROS通信机制和命令

在这里插入图片描述

ROS的通信机制基本上依赖于RPC协议框架,RPC(远程过程调用协议)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议,其调用的流程主要分为几步:

1、服务消费方(client)调用以本地调用方式调用服务;
2、client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
3、client stub找到服务地址,并将消息发送到服务端;
4、server stub收到消息后进行解码;
5、server stub根据解码结果调用本地的服务;
6、本地服务执行并将结果返回给server stub;
7、server stub将返回结果打包成消息并发送至消费方;
8、client stub接收到消息,并进行解码;
9、服务消费方得到最终结果。

在这里插入图片描述

ROS通信层是ros_comm栈的一部分,遵循 publish/subscribe 模型。在topic通信中,一个节点可以发布一些话题,其他的节点可以订阅这个话题;services 的机制也类似,话题和服务被设计成为一个固定的类型,通过ROS封装之后发布。

1. 话题通信

话题通信实现模型是比较容易理解的,其过程与MQTT的通信方式类似,该模型中涉及到三个角色:

ROS Master (管理者)

Talker (发布者)

Listener (订阅者)

首先客户端要向ROS Master注册信息,注册信息包括话题(topic) 、消息的数据类型、消息队列大小等,ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅

在这里插入图片描述

2. 服务通信

服务通信较之于话题通信实现起来差不多,该模型中也涉及到三个角色:

ROS master(管理者)

Server(服务端)

Client(客户端)

ROS Master 负责保管 Server 和 Client 注册的信息,并匹配话题相同的 Server 与 Client ,帮助 Server 与 Client 建立连接,连接建立后,Client 发送请求信息,Server 返回响应信息。

在这里插入图片描述

Client 启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要请求的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。ROS Master 会根据注册表中的信息匹配Server和 Client,并通过 RPC 向 Client 发送 Server 的 TCP 地址信息。Client 根据步骤2 响应的信息,使用 TCP 与 Server 建立网络连接,并发送请求数据。Server 接收、解析请求的数据,并产生响应结果返回给 Client。

3. 参数服务

参数服务器实现是最为简单的,该模型中涉及到三个主要角色:

ROS Master (管理者)

Talker (参数设置者)

Listener (参数调用者)

ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。

在这里插入图片描述
Talker 通过 RPC 向参数服务器发送参数(包括参数名与参数值),ROS Master 将参数保存到参数列表中。Listener 通过 RPC 向参数服务器发送参数查找请求,请求中包含要查找的参数名。ROS Master 根据步骤2请求提供的参数名查找参数值,并将查询结果通过 RPC 发送给 Listener。

4. ROS常用命令

rosnode

rosnode ping    测试到节点的连接状态
rosnode list    列出活动节点
rosnode info    打印节点信息
rosnode machine    列出指定设备上节点
rosnode kill    杀死某个节点
rosnode cleanup    清除不可连接的节点

rostopic

rostopic bw     显示主题使用的带宽
rostopic delay  显示带有 header 的主题延迟
rostopic echo   打印消息到屏幕
rostopic find   根据类型查找主题
rostopic hz     显示主题的发布频率
rostopic info   显示主题相关信息
rostopic list   显示所有活动状态下的主题
rostopic pub    将数据发布到主题
rostopic type   打印主题类型

rosmsg

rosmsg show    显示消息描述
rosmsg info    显示消息信息
rosmsg list    列出所有消息
rosmsg md5    显示 md5 加密后的消息
rosmsg package    显示某个功能包下的所有消息
rosmsg packages    列出包含消息的功能包

rosservice

rosservice args 打印服务参数
rosservice call    使用提供的参数调用服务
rosservice find    按照服务类型查找服务
rosservice info    打印有关服务的信息
rosservice list    列出所有活动的服务
rosservice type    打印服务类型
rosservice uri    打印服务的 ROSRPC uri

三、Python实现ROS通信- - 控制和读取小乌龟状态

切换到vscode界面,首先在工作空间下的右键点击src文件夹,选择Create Catkin Package选项,随便给新文件夹取个名,添加下面依赖包

roscpp rospy std_msgs

在该新文件夹目录下的src文件夹用于存放c++文件,创建一个scripts文件夹存放python文件

1. 配置package.xml文件

首先配置package.xml文件,该文件主要声明编译和执行所依赖的包名,这里可以根据自己的需求添加,比如你自定义了一种消息文件,你就要添加编译依赖 <build_depend>message_generation</build_depend>和运行依赖<exec_depend>message_runtime</exec_depend>

<?xml version="1.0"?>
<!-- 格式: 以前是 1,推荐使用格式 2 -->
<package format="2">
  <!-- 包名 -->
  <name>demo01_hello_vscode</name>
  <!-- 版本 -->
  <version>0.0.0</version>
  <!-- 描述信息 -->
  <description>The demo01_hello_vscode package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
  <!-- 维护人员 -->
  <maintainer email="[email protected]">xuzuo</maintainer>


  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <!-- 许可证信息,ROS核心组件默认 BSD -->
  <license>TODO</license>


  <!-- Url tags are optional, but multiple are allowed, one per tag -->
  <!-- Optional attribute type can be: website, bugtracker, or repository -->
  <!-- Example: -->
  <!-- <url type="website">http://wiki.ros.org/demo01_hello_vscode</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="[email protected]">Jane Doe</author> -->


  <!-- The *depend tags are used to specify dependencies -->
  <!-- Dependencies can be catkin packages or system dependencies -->
  <!-- Examples: -->
  <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
  <!--   <depend>roscpp</depend> -->
  <!--   Note that this is equivalent to the following: -->
  <!--   <build_depend>roscpp</build_depend> -->
  <!--   <exec_depend>roscpp</exec_depend> -->
  <!-- Use build_depend for packages you need at compile time: -->
  <!--   <build_depend>message_generation</build_depend> -->
  <!-- Use build_export_depend for packages you need in order to build against this package: -->
  <!--   <build_export_depend>message_generation</build_export_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use exec_depend for packages you need at runtime: -->
  <!--   <exec_depend>message_runtime</exec_depend> -->
  <!-- Use test_depend for packages you need only for testing: -->
  <!--   <test_depend>gtest</test_depend> -->
  <!-- Use doc_depend for packages you need only for building documentation: -->
  <!--   <doc_depend>doxygen</doc_depend> -->
  <!-- 依赖的构建工具,这是必须的 -->
  <buildtool_depend>catkin</buildtool_depend>

  <!-- 指定构建此软件包所需的软件包 -->
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>message_generation</build_depend>

  <!-- 指定根据这个包构建库所需要的包 -->
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>

  <!-- 运行该程序包中的代码所需的程序包 -->  
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>message_runtime</exec_depend>

  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

2. 配置CMakeLists.txt文件

接着配置CMakeLists.txt文件,CMakeList.txt文件是CMake编译系统编译软件包过程的输入文件,cmake指令依据CMakeLists.txt 文件生成makefiles文件,make命令再依据makefiles文件编译链接生成可执行文件。

find_package里面主要填写查找构建所需的其他CMake / Catkin软件包

find_package(catkin REQUIRED COMPONENTS 
  roscpp
  rospy
  std_msgs
  message_generation
)

add_message_files(),add_service_files(),add_action_files()主要是消息/服务/动作生成器,里面需要填写自己编写的相关消息/服务/动作文件名

add_message_files(
  FILES
  person.msg
)

generate_messages()主要用于生成消息/服务/动作等自定义消息,只需要填写消息/服务/动作生成的依赖包

generate_messages(
  DEPENDENCIES
  std_msgs
)

catkin_package()作用是指定包的构建信息输出,我们只需要填写编译时依赖的包即可

catkin_package( 
#  INCLUDE_DIRS include  
#  LIBRARIES ${PROJECT_NAME}   
   CATKIN_DEPENDS roscpp rospy std_msgs message_runtime   
#   DEPENDS eigen opencv
)

对于Python代码,安装规则看起来是不同的,因为没有使用add_library()和add_executable()函数,catkin_install_python()用于告诉catkin编译哪些python文件。 如果你只安装Python脚本并且不提供任何模块,则不需要创建setup.py文件,也不需要配置catkin_python_setup()。

catkin_install_python(PROGRAMS 
#  scripts/myscript  
   scripts/turtle_circle.py
   scripts/turtle_pose.py
   scripts/turtle_create.py
   DESTINATION ${
    
    CATKIN_PACKAGE_BIN_DESTINATION}
)

3. 编写Python代码

下面我们编写一个话题发布节点来发布小乌龟的运动消息,使小乌龟的运动轨迹成圆形,在scripts目录下新建.py文件命名为turtle_circle.py

#! /usr/bin/python

#1.导包
import rospy
from geometry_msgs.msg import Twist

if __name__ == "__main__":
    # 2.初始化 ROS 节点
    rospy.init_node("turtle_circle")
    # 3.创建发布者对象
    pub = rospy.Publisher("/turtle1/cmd_vel",Twist,queue_size=1000)
    # 4.循环发布运动控制消息
    rate = rospy.Rate(10)
    msg = Twist()
    msg.linear.x = 1.0
    msg.linear.y = 0.0
    msg.linear.z = 0.0
    msg.angular.x = 0.0
    msg.angular.y = 0.0
    msg.angular.z = 0.6

    while not rospy.is_shutdown():
        pub.publish(msg)
        rate.sleep()

接着我们编写一个话题订阅节点来实时获取小乌龟的运动状态,包括线速度、角速度和位姿,在scripts目录下新建.py文件命名为turtle_pose.py

#! /usr/bin/python

#1.导包
import rospy
from turtlesim.msg import Pose

def doPose(data):
    rospy.loginfo("乌龟坐标:x=%.2f, y=%.2f,theta=%.2f",data.x,data.y,data.theta)

if __name__ == "__main__":

    # 2.初始化 ROS 节点
    rospy.init_node("sub_pose_p")

    # 3.创建订阅者对象
    sub = rospy.Subscriber("/turtle1/pose",Pose,doPose,queue_size=1000)
    #     4.回调函数处理订阅的数据
    #     5.spin循环
    rospy.spin()

接着我们编写一个服务请求节点来生成新的小乌龟,在scripts目录下新建.py文件命名为turtle_create.py

#! /usr/bin/python

#1.导包
import rospy
from turtlesim.srv import Spawn,SpawnRequest,SpawnResponse

if __name__ == "__main__":
    # 2.初始化 ros 节点
    rospy.init_node("set_turtle_p")
    # 3.创建 service 客户端
    client = rospy.ServiceProxy("/spawn",Spawn)
    # 4.等待服务启动
    client.wait_for_service()
    # 5.发送请求
    req = SpawnRequest()
    req.x = 2.5
    req.y = 2.5
    req.theta = 0
    req.name = "turtle2"
    try:
        response = client.call(req)
        # 6.处理响应
        rospy.loginfo("乌龟创建成功!,叫:%s",response.name)
    except expression as identifier:
        rospy.loginfo("服务调用失败")

记得在终端里给python文件添加可执行权限

chmod +777 *.py

然后快捷键 ctrl + shift + B 调用编译,选择:catkin_make:build,查看终端有没有报错,没报错基本没问题

4. 配置launch文件

一个程序中可能需要启动多个节点,比如:ROS 内置的小乌龟案例,如果要控制乌龟运动并读取运动状态,要启动多个窗口,分别启动 roscore、乌龟界面节点、运动话题发布节点、运动话题订阅节点。如果每次都调用 rosrun 逐一启动,显然效率低下, ROS官方给出的优化策略是使用 launch 文件,可以一次性启动多个 ROS 节点。

node --> 包含的某个节点
pkg -----> 功能包
type ----> 被运行的节点文件
name --> 为节点命名
output --> 设置日志的输出目标

在xxx功能包下面新建一个launch文件夹,文件夹下新建一个xxx.launch文件,配置.launch文件内容

<launch>
    <node pkg="xxx" type="turtle_circle.py" name="run_circle" output="screen" />
    <node pkg="xxx" type="turtle_pose.py" name="run_pose" output="screen" />
    <node pkg="xxx" type="turtle_create.py" name="run_create" output="screen" />
    <node pkg="turtlesim" type="turtlesim_node" name="t1"/>
</launch>

最后在vscode终端里面执行roslaunch的命令运行launch脚本

roslaunch xxx(功能包名) xxx.launch(launch文件名)

总结

以上就是ROS集成开发搭建与ROS通信学习笔记的全部内容,本篇笔记简单地介绍了ROS开发环境基础搭建过程和ROS通信的原理学习及测试部署。ROS采用分布式框架,主要是因为一个机器人通常包含多个部件,每个部件都有配套的控制程序,以实现机器人的运动与感知功能等。那么要协调一个机器人中的这些部件,或者协调由多个机器人组成的机器人集群,这时就需要让分散的部件能够互相通信,解决这种分布式通信问题正是ROS的设计初衷。

猜你喜欢

转载自blog.csdn.net/m0_55202222/article/details/130415912
今日推荐