ROS基础配置
准备工作
创建工作空间并初始化
mkdir -p 自定义空间名称/src
cd 自定义空间名称
catkin_make
首先会创建一个工作空间以及一个 src 子目录,然后再进入工作空间调用 catkin_make 命令编译
进入src创建ros包并添加依赖
cd src
catkin_create_pkg 自定义ROS包名 roscpp rospy std_msgs
在工作空间下生成一个功能包,该功能包依赖于 roscpp、rospy 与 std_msgs,其中roscpp是使用C++实现的库,而rospy则是使用python实现的库,std_msgs是标准消息库,创建ROS功能包时,一般都会依赖这三个库实现
HelloWorld(C++版)
进入 ros 包的 src 目录编辑源文件
cd 自定义的包
C++源码实现(文件名自定义)
#include "ros/ros.h"
int main(int argc, char *argv[])
{
//执行 ros 节点初始化
ros::init(argc,argv,"hello");
//创建 ros 节点句柄(非必须)
ros::NodeHandle n;
//控制台输出 hello world
ROS_INFO("Hello World!");
return 0;
}
编辑 ros 包下的 Cmakelist.txt文件
add_executable(源文件名
src/源文件名.cpp
)
target_link_libraries(源文件名
${catkin_LIBRARIES}
)
进入工作空间目录并编译
cd 自定义工作空间名称
catkin_make
生成 build devel ....
执行
先启动命令行1: roscore
再启动命令行2: cd 工作空间 source ./devel/setup.bash rosrun 包名 C++节点 命令行输出: Hello World!
PS:source ~/工作空间/devel/setup.bash可以添加进.bashrc文件,使用上更方便
添加方式1: 直接使用 gedit 或 vi 编辑 .bashrc 文件,最后添加该内容
添加方式2:echo "source ~/工作空间/devel/setup.bash" >> ~/.bashrc
HelloWorld(Python版)
进入 ros 包添加 scripts 目录并编辑 python 文件
cd ros包
mkdir scripts
新建 python 文件: (文件名自定义)
#! /usr/bin/env python
#指定解释器
#1. 导包
import rospy
#2. 编写主入口
if __name__ == "__main__":
#3. 初始化 ROS 节点
rospy.init_node("hello_p")
#4. 输出日志
rospy.loginfo("HelloWorld!")
为 python 文件添加可执行权限
chmod +x 自定义文件名.py
编辑 ros 包下的 CamkeList.txt 文件
catkin_install_python(PROGRAMS scripts/自定义文件名.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
进入工作空间目录并编译
cd 自定义空间名称
catkin_make
进入工作空间目录并执行
先启动命令行1: roscore
再启动命令行2: cd 工作空间 source ./devel/setup.bash rosrun 包名 自定义文件名.py 输出结果:HelloWorld!
ROS集成开发环境搭建
在 ROS 中,需要频繁的使用到终端,且可能需要同时开启多个窗口,推荐一款较为好用的终端Terminator
sudo apt install terminator
vscode 中编译 ros
快捷键 ctrl + shift + B 调用编译,选择:catkin_make:build
可以点击配置设置为默认,修改.vscode/tasks.json 文件
{
// 有关 tasks.json 格式的文档,请参见
// https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"label": "catkin_make:debug", //代表提示的描述性信息
"type": "shell", //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
"command": "catkin_make",//这个是我们需要运行的命令
"args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
"group": {"kind":"build","isDefault":true},
"presentation": {
"reveal": "always"//可选always或者silence,代表是否输出信息
},
"problemMatcher": "$msCompile"
}
]
}
创建 ROS 功能包
选定 src 右击 ---> create catkin package
- 设置包名xxx
- 添加依赖roscpp rospy std_msgs
PS1: 如果没有代码提示
修改 .vscode/c_cpp_properties.json
设置 "cppStandard": "c++17"
PS2: main 函数的参数不可以被 const 修饰
PS3: 当ROS__INFO 终端输出有中文时,会出现乱码
INFO: ????????????????????????
解决办法:在函数开头加入下面代码的任意一句
setlocale(LC_ALL, "");
// 或者
setlocale(LC_CTYPE, "zh_CN.utf8");
Python的scripts代码需要可执行权限:*chmod +x .p
PS:
如果不编译直接执行 python 文件,会抛出异常。
-
第一行解释器声明,可以使用绝对路径定位到 python3 的安装路径 #! /usr/bin/python3,但是不建议
-
建议使用 #!/usr/bin/env python 但是会抛出异常 : /usr/bin/env: “python”: 没有那个文件或目录
解决1: #!/usr/bin/env python3 直接使用 python3 但存在问题: 不兼容之前的 ROS 相关 python 实现
解决2: 创建一个链接符号到 python 命令:sudo ln -s /usr/bin/python3 /usr/bin/python
launch文件演示
- 需求
一个程序中可能需要启动多个节点,比如:ROS内置的小乌龟案例,如果要控制乌龟运动,要启动多个窗口,分别启动roscore、乌龟界面节点、键盘控制节点。如果每次都调用 rosrun 逐一启动,显然效率低下,如何优化?
官方给出的优化策略是使用 launch 文件,可以一次性启动多个 ROS 节点。
- 实现
选定功能包右击 ---> 添加 launch 文件夹
选定 launch 文件夹右击 ---> 添加 launch 文件
编辑 launch 文件内容
<launch>
<!-- 添加被执行的节点 -->
<!-- <node pkg="" type="" name=""/> -->
<node pkg="turtlesim" type="turtlesim_node" name="t1"/>
<node pkg="turtlesim" type="turtle_teleop_key" name="key1" />
<node pkg="helloworld" type="hello_vscode_c" name="hello" output="screen" />
</launch>
node ---> 包含的某个节点 pkg -----> 功能包 type ----> 被运行的节点文件 name --> 为节点命名 output-> 设置日志的输出目标
运行 launch 文件
roslaunch 包名 launch文件名
运行结果: 一次性启动了多个节点
ROS架构
立足不同的角度,对ROS架构的描述也是不同的,一般我们可以从设计者、维护者、系统结构与自身结构4个角度来描述ROS结构:
- 设计者
ROS设计者将ROS表述为“ROS = Plumbing + Tools + Capabilities + Ecosystem”
Plumbing: 通讯机制(实现ROS不同节点之间的交互)
Tools:工具软件包(ROS中的开发和调试工具)
Capabilities:机器人高层技能(ROS中某些功能的集合,比如:导航)
Ecosystem:机器人生态系统(跨地域、跨软件与硬件的ROS联盟)
- 维护者
立足维护者的角度: ROS 架构可划分为两大部分
main:核心部分,主要由 Willow Garage 和一些开发者设计、提供以及维护。它提供了一些分布式计算的基本工具,以及整个ROS的核心部分的程序编写。
universe:全球范围的代码,有不同国家的ROS社区组织开发和维护。一种是库的代码,如OpenCV、PCL等;库的上一层是从功能角度提供的代码,如人脸识别,他们调用下层的库;最上层的代码是应用级的代码,让机器人完成某一确定的功能。
- 系统架构
立足系统架构: ROS 可以划分为三层
OS 层,也即经典意义的操作系统
ROS 只是元操作系统,需要依托真正意义的操作系统,目前兼容性最好的是 Linux 的 Ubuntu,Mac、Windows 也支持 ROS 的较新版本
中间层
是 ROS 封装的关于机器人开发的中间件,比如: 基于 TCP/UDP 继续封装的 TCPROS/UDPROS 通信系统, 用于进程间通信 Nodelet,为数据的实时性传输提供支持, 另外,还提供了大量的机器人开发实现库,如:数据类型定义、坐标变换、运动控制....
应用层
功能包,以及功能包内的节点,比如: master、turtlesim的控制与运动节点...
- 自身结构
就 ROS 自身实现而言: 也可以划分为三层
文件系统
ROS文件系统级指的是在硬盘上面查看的ROS源代码的组织形式
计算图
ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程,计算图中的重要概念: 节点(Node)、消息(message)、通信机制_主题(topic)、通信机制_服务(service)
开源社区
ROS的社区级概念是ROS网络上进行代码发布的一种表现形式
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: 编译的基本配置
- package.xml
该文件定义有关软件包的属性,例如软件包名称,版本号,作者,维护者以及对其他catkin软件包的依赖性。请注意,该概念类似于旧版 rosbuild 构建系统中使用的manifest.xml文件。
<?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="jane.doe@example.com">Jane Doe</maintainer> -->
<!-- 维护人员 -->
<maintainer email="xuzuo@todo.todo">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="jane.doe@example.com">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_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>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>
- CMakelists.txt
文件CMakeLists.txt是CMake构建系统的输入,用于构建软件包。任何兼容CMake的软件包都包含一个或多个CMakeLists.txt文件,这些文件描述了如何构建代码以及将代码安装到何处。
cmake_minimum_required(VERSION 3.0.2) #所需 cmake 版本
project(demo01_hello_vscode) #包名称,会被 ${PROJECT_NAME} 的方式调用
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
#设置构建所需要的软件包
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
)
## System dependencies are found with CMake's conventions
#默认添加系统依赖
# find_package(Boost REQUIRED COMPONENTS system)
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# 启动 python 模块支持
# catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
## 声明 ROS 消息、服务、动作... ##
################################################
## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend tag for "message_generation"
## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
## but can be declared for certainty nonetheless:
## * add a exec_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )
## Generate added messages and services with any dependencies listed here
# 生成消息、服务时的依赖包
# generate_messages(
# DEPENDENCIES
# std_msgs
# )
################################################
## Declare ROS dynamic reconfigure parameters ##
## 声明 ROS 动态参数配置 ##
################################################
## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
## * add "dynamic_reconfigure" to
## find_package(catkin REQUIRED COMPONENTS ...)
## * uncomment the "generate_dynamic_reconfigure_options" section below
## and list every .cfg file to be processed
## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
# cfg/DynReconf1.cfg
# cfg/DynReconf2.cfg
# )
###################################
## catkin specific configuration ##
## catkin 特定配置##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
# 运行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo01_hello_vscode
# CATKIN_DEPENDS roscpp rospy std_msgs
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
# 添加头文件路径,当前程序包的头文件路径位于其他文件路径之前
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# 声明 C++ 库
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/demo01_hello_vscode.cpp
# )
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# 添加库的 cmake 目标依赖
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# 声明 C++ 可执行文件
add_executable(Hello_VSCode src/Hello_VSCode.cpp)
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
#重命名c++可执行文件
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
## Add cmake target dependencies of the executable
## same as for the library above
#添加可执行文件的 cmake 目标依赖
add_dependencies(Hello_VSCode ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
#指定库、可执行文件的链接库
target_link_libraries(Hello_VSCode
${catkin_LIBRARIES}
)
#############
## Install ##
## 安装 ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
#设置用于安装的可执行脚本
catkin_install_python(PROGRAMS
scripts/Hi.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
## Mark executables for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
# install(TARGETS ${PROJECT_NAME}_node
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark libraries for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
# install(TARGETS ${PROJECT_NAME}
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
# )
## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
# FILES_MATCHING PATTERN "*.h"
# PATTERN ".svn" EXCLUDE
# )
## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
# # myfile1
# # myfile2
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_demo01_hello_vscode.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
ROS文件系统相关命令
- 增
catkin_create_pkg 自定义包名 依赖包 === 创建新的ROS功能包
sudo apt install xxx === 安装 ROS功能包
- 删
sudo apt purge xxx ==== 删除某个功能包
- 查
rospack list === 列出所有功能包
rospack find 包名 === 查找某个功能包是否存在,如果存在返回安装路径
roscd 包名 === 进入某个功能包
rosls 包名 === 列出某个包下的文件
apt search xxx === 搜索某个功能包
- 改
rosed 包名 文件名 === 修改功能包文件
需要安装 vim
比如:rosed turtlesim Color.msg
- 执行
roscore
roscore === 是 ROS 的系统先决条件节点和程序的集合, 必须运行 roscore 才能使 ROS 节点进行通信。
roscore 将启动: ros master ros 参数服务器 rosout 日志节点
用法:
roscore
或(指定端口号)
roscore -p xxxx
rosrun
rosrun 包名 可执行文件名 === 运行指定的ROS节点
比如:rosrun turtlesim turtlesim_node
roslaunch
roslaunch 包名 launch文件名 === 执行某个包下的 launch 文件
ROS计算图
- 计算图简介
ROS文件结构是磁盘上 ROS 程序的存储结构,是静态的,而 ros 程序运行之后,不同的节点之间是错综复杂的,ROS 中提供了一个实用的工具: rqt_graph。
rqt_graph能够创建一个显示当前系统运行情况的动态图形。ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程。rqt_graph是rqt程序包中的一部分。
- 计算图安装
如果前期把所有的功能包(package)都已经安装完成,则直接在终端窗口中输入
rosrun rqt_graph rqt_graph
如果未安装则在终端(terminal)中输入
$ sudo apt install ros-<distro>-rqt
$ sudo apt install ros-<distro>-rqt-common-plugins
请使用你的ROS版本名称(比如:kinetic、melodic、Noetic等)来替换掉<distro>。
例如当前版本是 Noetic,就在终端窗口中输入
$ sudo apt install ros-noetic-rqt
$ sudo apt install ros-noetic-rqt-common-plugins
ROS通信机制
机器人是一种高度复杂的系统性实现,在机器人上可能集成各种传感器(雷达、摄像头、GPS...)以及运动控制实现,为了解耦合,在ROS中每一个功能点都是一个单独的进程,每一个进程都是独立运行的。更确切的讲,ROS是进程(也称为Nodes)的分布式框架。 因为这些进程甚至还可分布于不同主机,不同主机协同工作,从而分散计算压力。
ROS 中的基本通信机制主要有如下三种实现策略:
-
话题通信(发布订阅模式)
-
服务通信(请求响应模式)
-
参数服务器(参数共享模式)
话题通信
话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景也极其广泛,比如下面一个常见场景:
机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。
概念:以发布订阅的方式实现不同节点之间数据交互的通信模式。
作用:用于不断更新的、少逻辑处理的数据传输场景。
理论模型
话题通信实现模型是比较复杂的,该模型如下图所示,该模型中涉及到三个角色:
- ROS Master (管理者)
- Talker (发布者)
- Listener (订阅者)
ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。
-
Talker注册 Talker启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含所发布消息的话题名称。ROS Master 会将节点的注册信息加入到注册表中。
-
Listener注册 Listener启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要订阅消息的话题名。ROS Master 会将节点的注册信息加入到注册表中。
-
ROS Master实现信息匹配 ROS Master 会根据注册表中的信息匹配Talker 和 Listener,并通过 RPC 向 Listener 发送 Talker 的 RPC 地址信息。
-
Listener向Talker发送请求 Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。
-
Talker确认请求 Talker 接收到 Listener 的请求后,也是通过 RPC 向 Listener 确认连接信息,并发送自身的 TCP 地址信息。
-
Listener与Talker件里连接 Listener 根据步骤4 返回的消息使用 TCP 与 Talker 建立网络连接。
-
Talker向Listener发送消息 连接建立后,Talker 开始向 Listener 发布消息。
注意1:上述实现流程中,前五步使用的 RPC协议,最后两步使用的是 TCP 协议 注意2: Talker 与 Listener 的启动无先后顺序要求 注意3: Talker 与 Listener 都可以有多个 注意4: Talker 与 Listener 连接建立后,不再需要 ROS Master。也即,即便关闭ROS Master,Talker 与 Listern 照常通信。
话题通信基本操作A(C++)
需求:编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。
- 发布方
// 1.包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h" //普通文本类型的消息
#include <sstream>
int main(int argc, char *argv[])
{
//设置编码
setlocale(LC_ALL,"");
//2.初始化 ROS 节点:命名(唯一)
// 参数1和参数2 后期为节点传值会使用
// 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
ros::init(argc,argv,"talker");
//3.实例化 ROS 句柄
ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能
//4.实例化 发布者 对象
//泛型: 发布的消息类型
//参数1: 要发布到的话题
//参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);
//5.组织被发布的数据,并编写逻辑发布数据
//数据(动态组织)
std_msgs::String msg;
// msg.data = "你好啊!!!";
std::string msg_front = "Hello 你好!"; //消息前缀
int count = 0; //消息计数器
//逻辑(一秒10次)
ros::Rate r(1);
//节点不死
while (ros::ok())
{
//使用 stringstream 拼接字符串与编号
std::stringstream ss;
ss << msg_front << count;
msg.data = ss.str();
//发布消息
pub.publish(msg);
//加入调试,打印发送的消息
ROS_INFO("发送的消息:%s",msg.data.c_str());
//根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率;
r.sleep();
count++;//循环结束前,让 count 自增
//暂无应用
ros::spinOnce();
}
return 0;
}
- 订阅方
// 1.包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h"
void doMsg(const std_msgs::String::ConstPtr& msg_p){
ROS_INFO("我听见:%s",msg_p->data.c_str());
// ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化 ROS 节点:命名(唯一)
ros::init(argc,argv,"listener");
//3.实例化 ROS 句柄
ros::NodeHandle nh;
//4.实例化 订阅者 对象
ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
//5.处理订阅的消息(回调函数)
// 6.设置循环调用回调函数
ros::spin();//循环读取接收的数据,并调用回调函数处理
return 0;
}
- 配置 CMakeLists.txt
add_executable(Hello_pub
src/Hello_pub.cpp
)
add_executable(Hello_sub
src/Hello_sub.cpp
)
target_link_libraries(Hello_pub
${catkin_LIBRARIES}
)
target_link_libraries(Hello_sub
${catkin_LIBRARIES}
)
- 执行
1.启动 roscore;
2.启动发布节点;
3.启动订阅节点。
运行结果与引言部分的演示案例1类似。
- 注意
补充0:
- vscode 中的 main 函数 声明 int main(int argc, char const *argv[]){},默认生成 argv 被 const 修饰,需要去除该修饰符
补充1:
ros/ros.h No such file or directory .....
检查 CMakeList.txt find_package 出现重复,删除内容少的即可
参考资料:https://answers.ros.org/question/237494/fatal-error-rosrosh-no-such-file-or-directory/
补充2:
订阅时,第一条数据丢失
原因: 发送第一条数据时, publisher 还未在 roscore 注册完毕
解决: 注册后,加入休眠 ros::Duration(3.0).sleep(); 延迟第一条数据的发送
PS:可以使用 rqt_graph 查看节点关系。
话题通信基本操作B(Python)
- 发布方
#! /usr/bin/env python
"""
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)
PS: 二者需要设置相同的话题
消息发布方:
循环发布信息:HelloWorld 后缀数字编号
实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3.实例化 发布者 对象
4.组织被发布的数据,并编写逻辑发布数据
"""
#1.导包
import rospy
from std_msgs.msg import String
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node("talker_p")
#3.实例化 发布者 对象
pub = rospy.Publisher("chatter",String,queue_size=10)
#4.组织被发布的数据,并编写逻辑发布数据
msg = String() #创建 msg 对象
msg_front = "hello 你好"
count = 0 #计数器
# 设置循环频率
rate = rospy.Rate(1)
while not rospy.is_shutdown():
#拼接字符串
msg.data = msg_front + str(count)
pub.publish(msg)
rate.sleep()
rospy.loginfo("写出的数据:%s",msg.data)
count += 1
- 订阅方
#! /usr/bin/env python
"""
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)
消息订阅方:
订阅话题并打印接收到的消息
实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3.实例化 订阅者 对象
4.处理订阅的消息(回调函数)
5.设置循环调用回调函数
"""
#1.导包
import rospy
from std_msgs.msg import String
def doMsg(msg):
rospy.loginfo("I heard:%s",msg.data)
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node("listener_p")
#3.实例化 订阅者 对象
sub = rospy.Subscriber("chatter",String,doMsg,queue_size=10)
#4.处理订阅的消息(回调函数)
#5.设置循环调用回调函数
rospy.spin()
-
添加可执行权限 终端下进入 scripts 执行:chmod +x *.py
-
配置 CMakeLists.txt
catkin_install_python(PROGRAMS
scripts/talker_p.py
scripts/listener_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
- 执行
1.启动 roscore;
2.启动发布节点;
3.启动订阅节点。
运行结果与引言部分的演示案例1类似。
PS:可以使用 rqt_graph 查看节点关系。
话题通信自定义msg
在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty....
ROS中还有一种特殊类型:Header,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header标头。
- 定义msg文件
功能包下新建 msg 目录,添加文件 Person.msg
string name
uint16 age
float64 height
- 编辑配置文件
package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
<!--
exce_depend 以前对应的是 run_depend 现在非法
-->
CMakeLists.txt编辑 msg 相关配置
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs
## 配置 msg 源文件
add_message_files(
FILES
Person.msg
)
# 生成消息时依赖于 std_msgs
generate_messages(
DEPENDENCIES
std_msgs
)
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
- 编译
后续说说
-
因为之前学过ros2,这里为了兼容ros1才学习的,具体在博客中就不详解了,详细内容查看官网文档
