ROS复习笔记之——系统框架及其编程规范

之前的学习笔记已经介绍过ROS的一些基本架构了

《ROS复习笔记之——ROS术语》

《 ROS复习笔记之——消息通信》

《 ROS复习笔记之——消息》

《ROS复习笔记之——名称》

《ROS复习笔记之——文件系统》

本博文意在重温ros的架构及其编程规范。这是ROS开发的基础也是重中之重。

 

目录

ROS系统架构

主节点和节点

功能包(package)

消息通信(messages communication)

名称(name)

ROS关键指令

catkin

roscore

rosrun

roslaunch

ROS编程规范

创建功能包

功能包配置文件(package.xml)

构建配置文件(CMakeLists.txt)

编写源代码(节点的源代码)

构建功能包

运行节点

ROS编程的一些规范

ROS编程中使用的标准单位

坐标的表示方式(右手定则)

ROS编程

发布者节点和订阅者节点的创建和运行

其他

ROS功能包的安装

安装目录

工作目录

ROS shell命令

roscd:移动ROS目录

roscore:运行master节点

rosrun:运行ROS节点

roslaunch:运行多个ROS节点

rosnode list:列出正在运行中的所有节点

rosnode kill [节点名称]:终止指定节点的运行

rostopic list:列出活动话题

rosservice list:显示活动的服务信息

rosparam list:查看参数列表

rosparam get [参数名称]:获取参数值

rosparam set [参数名称]:设置参数值

rosmsg list:显示所有消息

catkin_create_pkg:自动生成功能包

catkin_make:基于catkin 构建系统的构建

catkin_init_workspace:初始化catkin构建系统的工作目录

消息(msg、srv、action)功能包的独立化

参考资料


 

本博文是在之前的基础上,再次详细一点复习ROS的系统框架及其编程规范

ROS系统架构

在ROS中,组成软件的基本单位是功能包(package),因此ROS应用程序是以功能包为单位开发的。功能包包含一个以上的节点(node,ROS中最小的执行处理器)或包含用于运行其他节点的配置文件。节点之间通过消息进行通信。

主节点和节点

主节点(master)负责节点到节点的连接和消息通信,类似于名称服务器(Name Server)。roscore是它的运行命令,当运行主节点时,可以注册每个节点的名字,并根 据需要获取信息。没有主节点,就不能在节点之间建立访问和消息交流(如话题和服务)。

主节点使用XML远程过程调用(XMLRPC,XML-Remote Procedure Call)与节点进行通信。XMLRPC是一种基于HTTP的协议,主节点不与连接到主节点的节点保持连接。换句话说,节点只有在需要注册自己的信息或向其他节点发送请求信息时才能访问主节点并获取信息。通常情况下,不检查彼此的连接状态。

当启动ROS时,主节点将获取用户设置的ROS_MASTER_URI变量中列出的URI地址和端口。除非另外设置,默认情况下,URI地址使用当前的本地IP,端口使用11311。

节点(node)是指在ROS中运行的最小处理器单元。可以把它看作一个可执行程序。在ROS中,建议为一个目的创建一个节点,建议设计时注重可重用性。例如,在移动机器人的情况下,为了驱动机器人,将每个程序细分化。也就是说,使用传感器驱动、传感器数据转换、障碍物判断、电机驱动、编码器输入和导航等多个细分节点。

节点在运行的同时,向主节点注册节点的名称,并且还注册发布者(publisher)、订阅者(subscriber)、服务服务器(service server)、服务客户端(service client)的名称,且注册消息形式、URI地址和端口。基于这些信息,每个节点可以使用话题和
服务与其他节点交换消息。

节点使用XMLRPC与主站进行通信,并使用TCP/IP通信系列的XMLRPC或TCPROS进行节点之间的通信。节点之间的连接请求和响应使用XMLRPC,而消息通信使用TCPROS,因为它是节点和节点之间的直接通信,与主节点无关。URI地址和端口则使用
存储于运行当前节点的计算机上的名为ROS_HOSTNAME的环境变量作为URI地址,并将端口设置为任意的固有值。

功能包(package)

package是构成ROS的基本单元。ROS应用程序是以功能包为单位开发的。功能包包括至少一个以上的节点或拥有用于运行其他功能包的节点的配置文件。它还包含功能包所需的所有文件,如用于运行各种进程的ROS依赖库、数据集和配置文件等。

元功能包(metapackage)是一个具有共同目的的功能包的集合。例如,导航元功 能包包含AMCL、DWA、EKF和map_server等10余个功能包

消息通信(messages communication)

为了最大化用户的可重用性,ROS是以节点的形式开发的,而节点是根据其目的细分的可执行程序的最小单位。节点则通过消息(message)与其他的节点交换数据,最终成为一个大型的程序。这里的关键概念是节点之间的消息通信,它包括:

  • 话题——发布者(发布)与订阅者(订阅)
  • 服务——服务服务器与服务客户端
  • 动作——动作服务器与动作客户端
  • 参数——参数服务器

关于消息通信参考之前的博客《 ROS复习笔记之——消息通信》已经介绍得比较详细了

ROS复习笔记之——系统框架及其编程规范_第1张图片

名称(name)

ROS有一个称为图(graph)的抽象数据类型作为其基本概念。这显示了每个节点的连接关系以及通过箭头表达发送和接收消息(数据)的关系。为此,服务中使用的节点、话题、消息以及ROS中使用的参数都具有唯一的名称(name)

 

ROS关键指令

在本博文的后面还会介绍ros的shell命令

catkin

catkin是指ROS的构建系统。ROS的构建系统基本上使用CMake(Cross Platform Make),并在功能包目录中的CMakeLists.txt文件中描述构建环境。在ROS中,我们将CMake修改成专为ROS定制的catkin构建系统。

roscore

roscore是运行ROS主节点的命令。也可以在另一台位于同一个网络内的计算机上运行它。但是,除了支持多roscore的某些特殊情况,roscore在一个网络中只能运行一个。运行ROS时,将使用您在ROS_MASTER_URI变量中列出的URI地址和端口。如果用
户没有设置,会使用当前本地IP作为URI地址并使用端口11311。

rosrun

rosrun是ROS的基本运行命令。它用于在功能包中运行一个节点。节点使用的URI地址将存储在当前运行节点的计算机上的ROS_HOSTNAME环境变量作为URI地址,端口被设置为任意的固有值。

roslaunch

roslaunch是运行多个节点的概念。该命令允许运行多个确定的节点。其他功能还包括一些专为执行具有诸多选项的节点的ROS命令,比如包括更改功能包参数或节点名称、配置节点命名空间、设置ROS_ROOT和ROS_PACKAGE_PATH以及更改环境变量等。

roslaunch使用*.launch文件来设置可执行节点,它基于可扩展标记语言(XML),并提供XML标记形式的多种选项。

 

 

ROS编程规范

ROS的构建系统默认使用CMake(Cross Platform Make),其构建环境在功能包目录中的CMakeLists.txt文件中描述。在ROS中,CMake被修改为适合于ROS的“catkin” 构建系统。

创建功能包

首先进入到工作空间的src

cd ~/catkin_ws/src

创建功能包

catkin_create_pkg [功能包名称] [依赖功能包1] [依赖功能包n]
catkin_create_pkg my_first_ros_pkg std_msgs roscpp

##########################################################################
用“std_msgs”和“roscpp”作为前面命令格式中的依赖功能包的选项。
这意味着为了使用ROS的标准消息包std_msgs和客户端库roscpp(为了在ROS中使用C/C++),
在创建功能包之前先进行这些选项安装。
这些相关的功能包的设置可以在创建功能包时指定,但也可以在创建之后直接在package.xml中输入。

然后如下图所示

ROS复习笔记之——系统框架及其编程规范_第2张图片

“catkin_create_pkg”命令在创建用户功能包时会生成catkin 构建系统所需的CMakeLists.txt和package.xml文件的包目录。

要注意:ROS中的功能包名称全部是小写字母,不能包含空格。格式规则是将每个单词用下划线(_)而不是短划线( - )连接起
来。

功能包配置文件(package.xml)

必要的ROS配置文件之一的package.xml是一个包含功能包信息的XML文件,包括功能包名称、作者、许可证和依赖功能包。最初生成的如下所示



  my_first_ros_pkg
  0.0.0
  The my_first_ros_pkg package

  
  
  
  kwanwaipang


  
  
  
  TODO


  
  
  
  


  
  
  
  


  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  catkin
  roscpp
  std_msgs
  roscpp
  std_msgs
  roscpp
  std_msgs


  
  
    

  

每个语句的说明如下图所示

ROS复习笔记之——系统框架及其编程规范_第3张图片

ROS复习笔记之——系统框架及其编程规范_第4张图片

关于exec_depend而不是run_depend(参考https://www.jianshu.com/p/d18aca8468d5)

构建配置文件(CMakeLists.txt)

ROS的构建系统catkin基本上使用CMake,并在功能包目录中的CMakeLists.txt文件中描述构建环境。在这个文件中设置可执行文件的创建、依赖包优先构建、连接器(linker)的创建等等。最初没有做任何修改的原始文件如下:

cmake_minimum_required(VERSION 2.8.3)
###***上面一条是指是操作系统中安装的cmake的最低版本。
###***由于它目前被指定为版本2.8.3,所以如果使用低于此版本的cmake,则必须更新版本。
project(my_first_ros_pkg)########project项是功能包的名称

## 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
  std_msgs
)
###***find_package项是进行构建所需的组件包。目前,roscpp和std_msgs被添加为依赖包

## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)  ###***使用ROS以外的功能包时使用的方法。例如,使用Boost时,必须安装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
# catkin_python_setup()###catkin_python_setup( )选项是在使用Python,也就是使用rospy时的配置选项。其功能是调用Python安装过程setup.py。

################################################
## Declare ROS messages, services and actions ##
################################################

## 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 ##
################################################

## 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 ##
###################################
## 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 my_first_ros_pkg
#  CATKIN_DEPENDS roscpp 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
# add_library(${PROJECT_NAME}
#   src/${PROJECT_NAME}/my_first_ros_pkg.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
# 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
# add_executable(${PROJECT_NAME}_node src/my_first_ros_pkg_node.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"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${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
# install(PROGRAMS
#   scripts/my_python_script
#   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_my_first_ros_pkg.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)

由于上面文件太大了,部分的描述看下面

## Generate messages in the 'msg' folder
###***add_message_files是添加消息文件的选项。
add_message_files(
   FILES###***FILES将引用当前功能包目录的msg目录中的*.msg文件,自动生成一个头文件(*.h)
   Message1.msg
   Message2.msg
 )

## Generate services in the 'srv' folder
###***添加要使用的服务文件的选项
 add_service_files(
   FILES###***FILES会引用功能包目录中的srv目录中的*.srv文件
   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
###***此处是将DEPENDENCIES选项设置为使用std_msgs消息包。
 )
catkin_package(#是catkin 构建选项
  INCLUDE_DIRS include#将使用INCLUDE_DIRS后面的内部目录include的头文件
  LIBRARIES my_first_ros_pkg#表示将使用随后而来的功能包的库
  CATKIN_DEPENDS roscpp std_msgs #目前的设置是表示依赖于roscpp和std_msgs。
  DEPENDS system_lib#是一个描述系统依赖包的设置
)
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(##可以指定包含目录的选项
# include
  ${catkin_INCLUDE_DIRS}
###这意味着将引用每个功能包中的include目录中的头文件。当用户想指定一个额外的include目录时,写在${catkin_INCLUDE_DIRS}的下一行即可。
)
## Declare a C++ library
 add_library(${PROJECT_NAME}#声明构建之后需要创建的库
   src/${PROJECT_NAME}/my_first_ros_pkg.cpp
##上面是:引用位于my_first_ros_pkg功能包的src目录中的my_first_ros_pkg.cpp文件来创建my_first_ros_pkg库的命令。
 )

由于有太多的相关命令了。本博文就不一一详述了,后面开发的过程中涉及到,再写博客说明吧,不然现在抄下来了也很快忘掉hhh

下面这个比较重要。是对于构建之后要创建的可执行文件的选项。就是说你要运行某个节点,需要在这里声明一下

## 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
add_executable(${PROJECT_NAME}_node src/my_first_ros_pkg_node.cpp)

是在创建特定的可执行文件之前将库和可执行文件进行链接的选项

## Specify libraries to link a library or executable target against
 target_link_libraries(${PROJECT_NAME}_node
   ${catkin_LIBRARIES}
 )

接下来现在原来的CMakeLists.txt添加下面两项

add_executable(hello_world_node src/hello_world_node.cpp)

 target_link_libraries(hello_world_node 
   ${catkin_LIBRARIES}
 )

(其实有一点很傻的就是,很多教程都是先讲了配置再讲源代码的编写。正常的思路不是应该是写完源代码了,要编译了再向package和camakelists中添加依赖才对吗。。。。。。)

编写源代码(节点的源代码)

上面在CMakeLists.txt添加的两项中的

add_executable(hello_world_node src/hello_world_node.cpp)

其实是引用功能包的src目录中的hello_world_node.cpp源代码来生成hello_world_node可执行文件。

首先进入到目录

cd ~/catkin_ws/src/my_first_ros_pkg/src/

然后通过运行下面命令再保存就可以生成一个cpp文件了

gedit hello_world_node.cpp

文件内容如下所示

//头文件的定义
#include 
#include 
#include 


int main(int argc, char **argv)
{
	ros::init(argc, argv, "hello_world_node"); // 初始化节点
	ros::NodeHandle nh; // 声明一个节点
	ros::Publisher chatter_pub = nh.advertise("say_hello_world", 1000);//声明发布者,发布话题say_hello_world
	ros::Rate loop_rate(10);
	int count = 0;
	while (ros::ok())
	{
		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;
}

(下面会对这个文件作进一步的介绍)

 

构建功能包

所有构建功能包的准备工作都已完成。在构建之前,使用以下命令更新ROS功能包的配置文件。这是一个将之前创建的功能包反映在ROS功能包列表的命令,这并不是必选操作,但在创建新功能包后更新的话使用时会比较方便。

rospack profile

下面是catkin构建。移动到catkin工作目录后进行catkin构建。

cd ~/catkin_ws && catkin_make

运行节点

如果构建无误,那么将在“~/catkin_ws/devel/lib/my_first_ros_pkg”中生成“hello_world_node”文件。如下图所示

ROS复习笔记之——系统框架及其编程规范_第5张图片

下面运行节点

roscore
rosrun my_first_ros_pkg hello_world_node

结果如下图所示

ROS复习笔记之——系统框架及其编程规范_第6张图片

ROS编程的一些规范

上面简单的介绍了所设计的第一个节点。本节对该消息和节点的源代码进行更详细的讨论。

ROS编程中使用的标准单位

这部分虽然不是很重要,确实规范编程的关键。消息用到的单位却必须要遵守使用SI单位,这是为了让其他用户使用这种消息的时候不需要转换单位。

对ROS中所使用的消息(message),推荐使用世界上最广泛运用的标准单位SI。如下图所示。

ROS复习笔记之——系统框架及其编程规范_第7张图片

坐标的表示方式(右手定则)

ROS复习笔记之——系统框架及其编程规范_第8张图片

除此以外还有命名方式等,这里就不一一介绍了。

ROS编程

发布者节点和订阅者节点的创建和运行

前面已经介绍过通过下面命令来创建功能包了

catkin_create_pkg [功能包名称] [依赖功能包1] [依赖功能包n]

ROS复习笔记之——系统框架及其编程规范_第9张图片

在此新增加一个依赖message_generation(直接在已有的my_first_ros_pkg功能包中的package.xml中修改)。如下所示

  roscpp
  std_msgs
  message_generation
  roscpp
  std_msgs
  message_generation
  roscpp
  std_msgs
  message_generation

对应的cmakelist修改如下。

首先是组件包

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
## catkin构建时需要的组件包。
## 是依赖包,是message_generation、 std_msgs和roscpp。
## 如果这些功能包不存在,在构建过程中会发生错误。

find_package(catkin REQUIRED COMPONENTS
  message_generation
  roscpp
  std_msgs
)

然后是消息声明

## Generate messages in the 'msg' folder
# add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# )
## 消息声明:MsgTutorial.msg
add_message_files(FILES MsgTutorial.msg)

这意味着在构建时要包含消息MsgTutorial.msg,该消息将在此节点中被使用。现在我们还没有创建MsgTutorial.msg,因此按以下顺序创建它:

#移动到功能包目录
roscd my_first_ros_pkg
#功能包中创建新的msg消息目录
mkdir msg
#转到创建的msg目录
cd msg
#创建新的MsgTutorial.msg文件并修改内容
gedit MsgTutorial.msg

内容很简单。如下所示,创建一个time消息类型的stamp消息和一个int32消息类型的data消息, 除了这些消息类型之外,还有一些如bool、int8、int16、float32、string、time、duration和common_msgs等基本消息类型7,以及在ROS中收集常用消息的common_msgs。这里我们只是为了创建一个简单的例子,因此用了time和int32。

time stamp
int32 data

然后继续回到cmakelist。设置依赖性消息的选项


## Generate added messages and services with any dependencies listed here
# generate_messages(
#   DEPENDENCIES
#   std_msgs
# )
## 这是设置依赖性消息的选项。
## 如果未安装std_msgs,则在构建过程中会发生错误。
generate_messages(
   DEPENDENCIES 
   std_msgs
)

接着是

###################################
## catkin specific configuration ##
###################################
## 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功能包选项,描述了库、catkin构建依赖项和系统依赖的功能包。
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES my_first_ros_pkg
#  CATKIN_DEPENDS roscpp std_msgs
#  DEPENDS system_lib
   LIBRARIES my_first_ros_pkg#表示将使用随后而来的功能包的库
   CATKIN_DEPENDS std_msgs roscpp
)

然后

## 设置包含目录。
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)

然后。设置生成以下可执行文件的选项

## 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
# add_executable(${PROJECT_NAME}_node src/my_first_ros_pkg_node.cpp)
add_executable(hello_world_node src/hello_world_node.cpp)
## topic_publisher节点的构建选项。
add_executable(topic_publisher src/topic_publisher.cpp)
## topic_subscriber节点的构建选项。
add_executable(topic_subscriber src/topic_subscriber.cpp)

这里就包括了发布者和订阅者节点。

先在src目录中构建topic_publisher.cpp文件以创建发布者topic_publisher可执行文件。

如下所示

roscd my_first_ros_pkg/src
gedit topic_publisher.cpp

代码如下所示

#include "ros/ros.h" // ROS默认头文件
#include "my_first_ros_pkg/MsgTutorial.h" // MsgTutorial消息头文件( 构建后自动生成)
//千米已经定义了这个消息,相当于引用这个消息



int main(int argc, char **argv) // 节点主函数
{
    ros::init(argc, argv, "topic_publisher"); // 初始化节点名称

    ros::NodeHandle nh; // 声明一个节点句柄来与ROS系统进行通信


    // 声明发布者,创建一个使用my_first_ros_pkg功能包的MsgTutorial 消息文件的
    // 发布者ros_tutorial_pub。话题名称是"ros_tutorial_msg",
    // 消息文件发布者队列(queue)的大小设置为100
    ros::Publisher ros_tutorial_pub =nh.advertise("ros_tutorial_msg", 100);//话题名称将在订阅者中重现

    // 设定循环周期。"10"是指10Hz,是以0.1秒间隔重复
    ros::Rate loop_rate(10);


    my_first_ros_pkg::MsgTutorial msg; // 以MsgTutorial消息文件格式声明一个 叫做msg的消息
    int count = 0; // 声明要在消息中使用的变量
    while (ros::ok())
    {
        //消息文件中的两个元素
        msg.stamp = ros::Time::now(); // 把当前时间传给msg的下级消息stamp
        msg.data = count; // 将变量count的值传给下级消息data
        
//屏幕上显示的内容仅仅是使用ROS专用的ROS_INFO()函数将信息显示在屏幕上,这个函数与常见编程语言中使用的printf()函数类似。
        ROS_INFO("send msg = %d", msg.stamp.sec); // 显示stamp.sec消息
        ROS_INFO("send msg = %d", msg.stamp.nsec); // 显示stamp.nsec消息
        ROS_INFO("send msg = %d", msg.data); // 显示data消息
        ros_tutorial_pub.publish(msg); // 发布消息。
        loop_rate.sleep(); // 按照上面定义的循环周期进行暂歇
        ++count; // 变量count增加1
    }
    return 0;
}

至于订阅者(类似于发布者的创新方式)

roscd my_first_ros_pkg/src
gedit topic_subscriber.cpp

代码如下所示

#include "ros/ros.h" // ROS默认头文件
#include "my_first_ros_pkg/MsgTutorial.h" // MsgTutorial消息头文件( 构建后自动生成)
//千米已经定义了这个消息,相当于引用这个消息


// 这是一个消息后台函数,
// 此函数在收到一个下面设置的名为ros_tutorial_msg的话题时候被调用。(在发布者中定义了))
// 输入的消息是从my_first_ros_pkg功能包接收MsgTutorial消息。
void msgCallback(const my_first_ros_pkg::MsgTutorial::ConstPtr& msg)
{
    ROS_INFO("recieve msg = %d", msg->stamp.sec); // 显示stamp.sec消息
    ROS_INFO("recieve msg = %d", msg->stamp.nsec); // 显示stamp.nsec消息
    ROS_INFO("recieve msg = %d", msg->data); // 显示data消息
}


int main(int argc, char **argv) // 节点主函数
{
    ros::init(argc, argv, "topic_subscriber"); // 初始化节点名称
    ros::NodeHandle nh; // 声明用于ROS系统和通信的节点句柄

    // 声明订阅者,创建一个订阅者ros_tutorial_sub,
    // 它利用my_first_ros_pkg功能包的的MsgTutorial消息文件。
    // 话题名称是"ros_tutorial_msg",订阅者队列(queue)的大小设为100。
    ros::Subscriber ros_tutorial_sub = nh.subscribe("ros_tutorial_msg", 100, msgCallback);

    // 用于调用后台函数,等待接收消息。在接收到消息时执行后台函数。
    ros::spin();
    return 0;
}

然后继续回到cmakelist。配置订阅者与发布者

## 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"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## topic_publisher节点的构建选项。
add_dependencies(topic_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## topic_subscriber节点的构建选项。
add_dependencies(topic_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

然后

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )
 target_link_libraries(hello_world_node 
   ${catkin_LIBRARIES}
 )
## topic_publisher节点的构建选项。
target_link_libraries(topic_publisher 
   ${catkin_LIBRARIES}
)
## topic_subscriber节点的构建选项。
target_link_libraries(topic_subscriber 
   ${catkin_LIBRARIES}
)

然后后,保存。然后

cd ~/catkin_ws
catkin_make

接下来运行发布者

roscore
rosrun my_first_ros_pkg topic_publisher

ROS复习笔记之——系统框架及其编程规范_第10张图片

然后看一下ROS网络当前正在使用的话题列表

ROS复习笔记之——系统框架及其编程规范_第11张图片

使用rostopic命令获取topic_publisher发布的话题吧。

rostopic echo /ros_tutorial_msg

ROS复习笔记之——系统框架及其编程规范_第12张图片

接下来运行订阅者

rosrun my_first_ros_pkg topic_subscriber

ROS复习笔记之——系统框架及其编程规范_第13张图片

再采用rqt命令来查看运行中的节点的通信状态。

rqt

执行rqt时,在菜单中选择[Plugins]→[Introspection]→[Node Graph]。则如下图所示,可以确认当前在ROS上运行的节点和消息。

ROS复习笔记之——系统框架及其编程规范_第14张图片

由于篇幅太长了,本博文就只介绍到话题这一part。关于服务,请参考博文《 ROS复习笔记之——创建和运行服务服务器与客户端节点》而关于动作的,请参考博客《ROS复习笔记之——创建和运行动作服务器与客户端节点》

 

其他

ROS功能包的安装

ROS功能包的安装方式有二进制文件安装和源代码安装两种。二进制文件安装是使用二进制形式的文件,无需额外的构建,而源代码安装是下载该功能包的源代码之后由用户进行构建之后使用的方式。根据功能包使用的目的不同选择不同的方式。如果需要修改安装包或者要检查源代码的内容,可以使用后一种安装方法。下面用turtlebot3功能包的例子,介绍两种安装方法的不同之处。
1. 二进制文件安装

sudo apt-get install ros-kinetic-turtlebot3

2. 源代码安装(一般采用这种方式来安装)

 cd ~/catkin_ws/src
 git clone https://github.com/ROBOTIS-GIT/turtlebot3.git
 cd ~/catkin_ws/
 catkin_make

 

安装目录

ROS安装在“/opt/ros/[版本名称]”目录中。

 

工作目录

一般以下面的形式作为工作目录

~/catkin_ws/

如下图所示

ROS复习笔记之——系统框架及其编程规范_第15张图片

catkin_ws目录中由build、devel和src组成。请注意,build和devel目录是在catkin_make之后创建的。

他们的作用如下图所示

ROS复习笔记之——系统框架及其编程规范_第16张图片

目录“~/catkin_ws/src”是用户源代码的空间。在这个目录中,用户可以保存和建立自己的ROS功能包或其他开发者开发的功能包。

 

ROS shell命令

ROS可以通过在shell环境中输入命令来进行文件系统的使用、源代码编辑、构建、调试和功能包管理等。为了正确使用ROS,除了基本的Linux命令之外,还需要熟悉ROS专用命令。(本博文不把所有的命令都列出来,仅仅列出一些平时常用的)

roscd:移动ROS目录

如下图所示

roscore:运行master节点

这个相信不用多说了。所有的ROS节点运行前都必须先运行且运行一次这个主节点

rosrun:运行ROS节点

rosrun [功能包名称] [节点名称]

是执行指定的功能包中的一个节点的命令。以下例子运行turtlesim功能包的turtlesim_node节点。请注意,屏幕上出现的乌龟图标是随机选择并运行的。

ROS复习笔记之——系统框架及其编程规范_第17张图片

roslaunch:运行多个ROS节点

roslaunch [功能包名称] [launch文件名]

roslaunch是运行指定功能包中的一个或多个节点或设置执行选项的命令。

rosnode list:列出正在运行中的所有节点

rosnode kill [节点名称]:终止指定节点的运行

rostopic list:列出活动话题

rosservice list:显示活动的服务信息

rosparam list:查看参数列表

rosparam get [参数名称]:获取参数值

rosparam set [参数名称]:设置参数值

rosmsg list:显示所有消息

catkin_create_pkg:自动生成功能包

catkin_create_pkg是创建一个包含CMakeLists.txt和package.xml文件的空功能包的命令。

catkin_make:基于catkin 构建系统的构建

catkin_init_workspace:初始化catkin构建系统的工作目录

catkin_init_workspace是初始化用户工作目录(~/catkin_ws/src)的命令。除了特殊情况外,这个命令在ROS安装期间只执行一次。

消息(msg、srv、action)功能包的独立化

一般情况下,建议将消息文件msg和服务文件srv制作成一个只包含消息文件的单独的包,而不是将其包含在可执行节点中。其原因是,假设订阅者节点和发布者节点在不同的计算机上运行,存在的问题是必须安装不必要的节点,因为这两个节点只有在它们具有相互依赖性时才能使用。如果您独立创建消息功能包,则只需将独立于消息的功能包添加到依赖性选项,从而消除功能包之间不必要的依赖关系。

 

 

 

参考资料

http://wiki.ros.org/Books/ROS_Robot_Programming_English

 

你可能感兴趣的:(ROS,移动机器人)