1 ROS的安装

本节参考

2 ROS的文件系统命令rosls、roscd、rospack find的快速使用

首先说明(本节参考),rosls、roscd、rospack find命令和我们平时使用的ls、cd、find功能几乎是一样的,唯一的区别就是能够快速定位到ros系统文件的位置,下面来快速学习一下吧!

2.1 rosls:快速列举ros文件目录下的文件

1、rosls <要查看的目录名>

(base) shl@zhihui-mint:~$ rosls roscpp_tutorials/
cmake  launch  package.xml  srv
(base) shl@zhihui-mint:~

注意:

目录名如果记不太清楚,可以通过按tab键进行补全

2.2 roscd:快速切换到ros文件系统的指定目录

roscd有两种用法:

1、roscd不加参数:不带参数时roscd直接进入环境变量 $ROS_ROOT定义的目录.

(base) shl@zhihui-mint:~$ roscd
(base) shl@zhihui-mint:/opt/ros/melodic$

2、roscd <目录名>:切换到指定的目录下

(base) shl@zhihui-mint:/opt/ros/melodic$ roscd roscpp_tutorials/
(base) shl@zhihui-mint:/opt/ros/melodic/share/roscpp_tutorials$

注意:

目录名如果记不太清楚,可以通过按tab键进行补全

2.3 rospack find <文件名/目录名>查找指定文件或目录的路径

(base) shl@zhihui-mint:~$ rospack find roscpp_tutorials
/opt/ros/melodic/share/roscpp_tutorials
(base) shl@zhihui-mint:~$

rospack find命令和rosstack find命令的使用是差不多的,也是快速查找ros文件系统中的文件或目录的路径:

(base) shl@zhihui-mint:~$ rosstack find roscpp_tutorials
/opt/ros/melodic/share/roscpp_tutorials
(base) shl@zhihui-mint:~$

注意:

目录名如果记不太清楚,可以通过按tab键进行补全

3 创建ROS程序包

本教程介绍如何使用roscreate-pkgcatkin创建一个新程序包,并使用rospack查看程序包的依赖关系

3.1 一个catkin程序包有哪些文件组成?

一个程序包要想称为catkin程序包必须符合以下要求:

  • 1)该程序包必须包含catkin compliant package.xml文件,这个package.xml文件提供有关程序包的元信息

  • 2)程序包必须包含一个catkin 版本CMakeLists.txt文件,而Catkin metapackages中必须包含一个对CMakeList.txt文件的引用。

  • 3)每个目录下只能有一个程序包。这意味着在同一个目录下不能有嵌套的或者多个程序包存在。

my_package/
├── CMakeLists.txt
└── package.xml

3.2 在catkin工作空间中的程序包

开发catkin程序包的一个推荐方法是使用catkin工作空间,一个简单的工作空间也许看起来像这样:

(base) shl@zhihui-mint:~$ tree catkin_ws/     
catkin_ws/   # 工作空间
└── src     # 源码目录
    ├── package_1
    │   ├── CMakeLists.txt
    │   └── package.xml
    ├── package_2
    │   ├── CMakeLists.txt
    │   └── package.xml
    └── package_n
        ├── CMakeLists.txt
        └── package.xml

4 directories, 6 files
(base) shl@zhihui-mint:~$ 

3.3 创建一个catkin程序包

本部分教程将演示如何使用catkin_create_pkg命令来创建一个新的catkin程序包以及创建之后都能做些什么。

1、首先把路径切换到源码目录下


cd ~/catkin_ws/src

2、现在使用catkin_create_pkg命令来创建一个名为beginner_tutorials新程序包,这个程序包依赖于std_msgsroscpprospy这三个package:


catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

其中:

  • rospy:rospy是Python的客户端库
  • roscpp:roscpp是C++的客户端库

执行上面的命令:

  • 会创建一个名为beginner_tutorials的文件夹
  • 这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件
  • 这两个文件都已经自动包含了部分你在执行catkin_create_pkg命令时提供的信息。
  • 如果你还需要其他的程序包依赖,可以在后面继续添加

创建新的程序包后,生成的文件目录结果如下:

(base) shl@zhihui-mint:~$ tree catkin_ws/
catkin_ws/
└── src

1 directory, 0 files
(base) shl@zhihui-mint:~$ cd ~/catkin_ws/src/
(base) shl@zhihui-mint:~/catkin_ws/src$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
Created file beginner_tutorials/package.xml
Created file beginner_tutorials/CMakeLists.txt
Created folder beginner_tutorials/include/beginner_tutorials
Created folder beginner_tutorials/src
Successfully created files in /home/shl/catkin_ws/src/beginner_tutorials. Please adjust the values in package.xml.
(base) shl@zhihui-mint:~/catkin_ws/src$ tree ~/catkin_ws/
/home/shl/catkin_ws/
└── src
    └── beginner_tutorials
        ├── CMakeLists.txt
        ├── include
        │   └── beginner_tutorials
        ├── package.xml
        └── src

5 directories, 2 files
(base) shl@zhihui-mint:~/catkin_ws/src$ 

可以看到生成了程序包beginner_tutorials,下面我们来看一下CMakeLists.txtpackage.xml文件中有哪些内容:

  • 1)CMakeLists.txt文件中的内容:
(base) shl@zhihui-mint:~/catkin_ws/src$ cat beginner_tutorials/CMakeLists.txt 
cmake_minimum_required(VERSION 3.0.2)
project(beginner_tutorials)

## 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
# catkin_python_setup()

################################################
## 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 beginner_tutorials
#  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
# add_library(${PROJECT_NAME}
#   src/${PROJECT_NAME}/beginner_tutorials.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/beginner_tutorials_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
# catkin_install_python(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_beginner_tutorials.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)
(base) shl@zhihui-mint:~/catkin_ws/src$ 

  • 2)package.xml文件中的内容:
(base) shl@zhihui-mint:~/catkin_ws/src$ cat beginner_tutorials/package.xml 
<?xml version="1.0"?>
<package format="2">
  <name>beginner_tutorials</name>
  <version>0.0.0</version>
  <description>The beginner_tutorials package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="shl@todo.todo">shl</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 -->
  <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/beginner_tutorials</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>
(base) shl@zhihui-mint:~/catkin_ws/src$ 

3.4 查看程序包的直接依赖关系(一级依赖)

1、上面我们已经创建了一个新的程序包beginner_tutorials,然后我们开始编译这个程序包

先把目录切换到程序的工作目录下,然后使用catkin_make进行程序的编译:

(base) shl@zhihui-mint:~/catkin_ws$ source /opt/ros/melodic/setup.bash 
(base) shl@zhihui-mint:~/catkin_ws$ catkin_make
Base path: /home/shl/catkin_ws
Source space: /home/shl/catkin_ws/src
Build space: /home/shl/catkin_ws/build
Devel space: /home/shl/catkin_ws/devel
Install space: /home/shl/catkin_ws/install
Creating symlink "/home/shl/catkin_ws/src/CMakeLists.txt" pointing to "/opt/ros/melodic/share/catkin/cmake/toplevel.cmake"
####
#### Running command: "cmake /home/shl/catkin_ws/src -DCATKIN_DEVEL_PREFIX=/home/shl/catkin_ws/devel -DCMAKE_INSTALL_PREFIX=/home/shl/catkin_ws/install -G Unix Makefiles" in "/home/shl/catkin_ws/build"
####
-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Using CATKIN_DEVEL_PREFIX: /home/shl/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /opt/ros/melodic
-- This workspace overlays: /opt/ros/melodic
-- Found PythonInterp: /usr/bin/python2 (found suitable version "2.7.17", minimum required is "2") 
-- Using PYTHON_EXECUTABLE: /usr/bin/python2
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/shl/catkin_ws/build/test_results
-- Found gtest sources under '/usr/src/googletest': gtests will be built
-- Found gmock sources under '/usr/src/googletest': gmock will be built
-- Found PythonInterp: /usr/bin/python2 (found version "2.7.17") 
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE  
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.29
-- BUILD_SHARED_LIBS is on
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 1 packages in topological order:
-- ~~  - beginner_tutorials
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'beginner_tutorials'
-- ==> add_subdirectory(beginner_tutorials)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/shl/catkin_ws/build
####
#### Running command: "make -j12 -l12" in "/home/shl/catkin_ws/build"
####
(base) shl@zhihui-mint:~/catkin_ws$ ls

2、编译好之后,可以在工作目录下看到生成两个新的目录:

  • build目录
  • devel目录
(base) shl@zhihui-mint:~/catkin_ws$ 
build  devel  src
(base) shl@zhihui-mint:~/catkin_ws$ 

3、把编译后的环境添加到系统中


source devel/setup.bash

(base) shl@zhihui-mint:~/catkin_ws$ source devel/setup.bash 

注意:


如果要切换到新的终端下,还要再次source添加一次!!!

4、 使用rospack查看创建的程序包中有哪些依赖

之前在使用catkin_create_pkg命令时提供了几个程序包作为依赖包,下面是查看程序包中的一级依赖


rospack depends1 beginner_tutorials

(base) shl@zhihui-mint:~/catkin_ws$ rospack 
cflags-only-I            depends1                          depends-msgsrv        depends-why        help                   libs-only-L             list-duplicates    profile              vcs                
cflags-only-other  depends-indent             depends-on                  export                      langs                 libs-only-other     list-names            rosdep             vcs0               
depends                    depends-manifests      depends-on1               find                           libs-only-l        list                             plugins                   rosdep0            
(base) shl@zhihui-mint:~/catkin_ws$ rospack depends1 beginner_tutorials 
roscpp
rospy
std_msgs
(base) shl@zhihui-mint:~/catkin_ws$ 

从上面可以知道创建的程序包依赖的一级依赖有:

  • roscpp
  • rospy
  • std_msgs

这些依赖都被保存到了:package.xml文件中

<package>
...
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
...
</package>

注意:


可以先输入rospack,然后tab补全查看rospack有哪些参数,也可以使用:rospack -h查看

3.5 查看程序包的间接依赖关系

我们知道一级依赖有rospy,然后通过rospack depends1 rospy就可以查看rospy依赖的包有哪些,就相当与是间接依赖:

(base) shl@zhihui-mint:~/catkin_ws$ rospack depends1 rospy
genpy
roscpp
rosgraph
rosgraph_msgs
roslib
std_msgs
(base) shl@zhihui-mint:~/catkin_ws$ 

3.6 查看所有的依赖

一个程序包可能有多个间接的依赖,rospack可以递归的检测出所有的依赖


rospack depends 程序包名

(base) shl@zhihui-mint:~/catkin_ws$ rospack depends beginner_tutorials 
cpp_common
rostime
roscpp_traits
roscpp_serialization
catkin
genmsg
genpy
message_runtime
gencpp
geneus
gennodejs
genlisp
message_generation
rosbuild
rosconsole
std_msgs
rosgraph_msgs
xmlrpcpp
roscpp
rosgraph
ros_environment
rospack
roslib
rospy
(base) shl@zhihui-mint:~/catkin_ws$ 

##3.7 自定义自己的程序包

本部分教程将剖析catkin_create_pkg命令生成的每个文件并详细描述这些文件的组成部分以及如何自定义这些文件。这里自定义主要是包括:

  • 自定义 CMakeLists.txt
  • 自定义 package.xml

##3.8 自定义:package.xml

在自定义之前,我们再来看一下:package.xml文件中的内容以及每一个需要你注意的标签元素

(base) shl@zhihui-mint:~/catkin_ws$ cat src/beginner_tutorials/package.xml 
<?xml version="1.0"?>
<package format="2">
  <name>beginner_tutorials</name>
  <version>0.0.0</version>
  <description>The beginner_tutorials package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="shl@todo.todo">shl</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 -->
  <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/beginner_tutorials</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>
(base) shl@zhihui-mint:~/catkin_ws$ 

3.8.1 修改描述标签

用一句话简单介绍一下package.xml文件,如果一行不够,可以换行

<description>The beginner_tutorials package</description>

3.8.2 修改维护者标签

在package.xml中定义维护者标签,方便维护和联系到程序包的相关人员:

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="shl@todo.todo">shl</maintainer>

3.8.3 修改许可标签

选择许可协议:

你应该选择一种许可协议并将它填写到这里。一些常见的开源许可协议有BSD、MIT、Boost Software License、GPLv2、GPLv3、LGPLv2.1和LGPLv3。

  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <license>TODO</license>

本教程使用的许可协议为:BSD

 <license>BSD</license>

3.8.4 修改依赖项标签

接下来的标签用来描述程序包的各种依赖项,这些标签分别为:

  • build_depend
  • buildtool_depend
  • run_depend
  • test_depend

关于这些标签的更详细介绍请参考Catkin Dependencies相关的文档

在之前的操作中,因为我们将std_msgs、roscpp、rospy作为catkin_create_pkg命令的参数,所以生成的依赖项看起来如下:

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

1、buildtool_depend标签,指定编译的工具为:catkin_make

2、build_depend标签,这些标签中添加的是程序的一级依赖包

3、run_depend标签,在编译运行时我们需要用到所有指定的依赖包,因此还需要将每一个依赖包分别添加到run_depend标签

<run_depend>roscpp</run_depend>
<run_depend>rospy</run_depend>
<run_depend>std_msgs</run_depend>

从上面的标签元素中可以看到:除了catkin中默认提供的buildtool_depend,所有我们列出的依赖包都已经被添加到build_depend标签

3.9 自定义:CMakeLists.txt

catkin_create_pkg命令生成的CMakeLists.txt文件将在后续关于编译ROS程序代码的教程中讲述。

4 编译ROS程序包

在介绍编译ROS程序包之前,我们先来说一下CMake的标准编译流程

# 在一个CMake项目里
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install  # (可选)

编译ROS的程序包有两种方式:

  • rosmake
  • catkin_make

4.1 rosmake编译ROS程序包

4.2 catkin_make编译程序包

catkin_make 是一个命令行工具,它简化了catkin的标准工作流程。你可以认为catkin_make是在CMake标准工作流程中依次调用了cmake和 make。

使用方法 :在catkin工作空间下

$ catkin_make [make_targets] [-DCMAKE_VARIABLES=…]

1、进入到工作空间下

cd ~/catkin_ws/src

2、开始编译(源码在默认的工作空间下)

catkin_make

如果编译的源码不在catkin_ws/src目录下,则可以通过加上—source参数,比如源码放在my_src目录下,此时的编译命令为:

catkin_make —source my_srccatkin_make install —source my_src # (optionally)

3、编译好之后会查看到三个目录:

(base) shl@zhihui-mint:~/catkin_ws$ ls
build  devel  src
(base) shl@zhihui-mint:~/catkin_ws$ 
  • build目录:是build space的默认所在位置,同时cmake和make也是在这里被调用来配置并编译你的程序包。
  • devel目录:是devel space的默认所在位置, 同时也是在你安装程序包之前存放可执行文件库文件的地方。

4、编译好后,添加到当前终端环境

source devel/setup.bash

5 理解ROS节点(Node)

本教程主要介绍 ROS 图(graph)概念 并讨论roscorerosnoderosrun 命令行工具的使用。

5.1 先决条件

在本教程中我们将使用到一个轻量级的模拟器,请使用以下命令来安装:

$ sudo apt-get install ros-<distro>-ros-tutorials

用你使用的ROS发行版本名称(例如electric、fuerte、groovy、hydro等)替换掉。

我的系统是:Ubuntu18.04,对应的ROS的发行版本号为:melodic,因此安装命令为:

$ sudo apt-get install ros-melodic-ros-tutorials

5.2 ros图(graph)概念描述

  • Nodes:节点一个节点即为一个可执行文件,它可以通过ROS与其它节点进行通信
  • Messages:消息消息是一种ROS数据类型,用于订阅发布到一个话题
  • Topics:话题节点可以发布消息话题,也可以订阅话题以接收消息
  • Master:节点管理器,ROS名称服务 (比如帮助节点找到彼此)。
  • rosout:ROS中相当于stdout/stderr
  • roscore主机+rosout+ 参数服务器 (参数服务器会在后面介绍)。

1、如下,我在的机器上连接了单线激光雷达网络摄像头之后,通过rostopic list查看有话题topic

rostopic list

(base) shl@zhihui-mint:~$ rostopic list
/LiDAR/LD06
/clicked_point
/image_view/output
/image_view/parameter_descriptions
/image_view/parameter_updates
/initialpose
/move_base_simple/goal
/reprojection
/rosout
/rosout_agg
/tf
/tf_static
/usb_cam/camera_info
/usb_cam/image_raw
/usb_cam/image_raw/compressed
/usb_cam/image_raw/compressed/parameter_descriptions
/usb_cam/image_raw/compressed/parameter_updates
/usb_cam/image_raw/compressedDepth
/usb_cam/image_raw/compressedDepth/parameter_descriptions
/usb_cam/image_raw/compressedDepth/parameter_updates
/usb_cam/image_raw/theora
/usb_cam/image_raw/theora/parameter_descriptions
/usb_cam/image_raw/theora/parameter_updates
(base) shl@zhihui-mint:~$ 

2、然后可以通过rqt_graph查看ros的图是什么样的

$rqt_graph

5.3 节点 Node

  • 一个节点其实只不过是ROS程序包中的一个可执行文件
  • ROS节点可以使用ROS客户库与其他节点通信
  • 节点可以发布或接收一个话题
  • 节点也可以提供或使用某种服务。

5.4 ROS客户端库

ROS客户端库允许使用不同编程语言编写的节点之间互相通信:

-rospy = python 客户端库
-roscpp = c++ 客户端库

  • rosjs= javascripts客户端库
  • rosjava = java客户端库

5.5 roscore

roscore是你在运行所有ROS程序前首先要运行的命令

$roscore

运行roscore命令会看到如下输出:

(base) shl@zhihui-mint:~$ roscore
... logging to /home/shl/.ros/log/1018130a-9bff-11eb-902e-e0d55e449b44/roslaunch-zhihui-mint-18822.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://zhihui-mint:39045/
ros_comm version 1.14.9


SUMMARY
========

PARAMETERS
 * /rosdistro: melodic
 * /rosversion: 1.14.9

NODES

auto-starting new master
process[master]: started with pid [18832]
ROS_MASTER_URI=http://zhihui-mint:11311/

setting /run_id to 1018130a-9bff-11eb-902e-e0d55e449b44
process[rosout-1]: started with pid [18873]
started core service [/rosout]

注意:

如果不能够正确初始化roscore,可能原因如下:

  • 很有可能是存在网络配置问题。
  • 如果roscore不能初始化并提示缺少权限,这可能是因为~/.ros文件夹归属于root用户(只有root用户才能访问)

$ sudo chown -R <your_username> ~/.ros

5.6 rosnode的使用

先查看一下rosnode有哪些命令参数:

(base) shl@zhihui-mint:~$ rosnode -h
rosnode is a command-line tool for printing information about ROS Nodes.

Commands:
	rosnode ping	test connectivity to node
	rosnode list	list active nodes
	rosnode info	print information about node
	rosnode machine	list nodes running on a particular machine or list machines
	rosnode kill	kill a running node
	rosnode cleanup	purge registration information of unreachable nodes

Type rosnode <command> -h for more detailed usage, e.g. 'rosnode ping -h'

(base) shl@zhihui-mint:~$ 

1、rosnode节点介绍

  • 打开一个新的终端, 可以使用 rosnode 像运行roscore一样看看在 运行什么…
  • 注意: 当打开一个新的终端时,你的运行环境会复位,同时你的~/.bashrc文件会复原。
  • 如果你在运行类似于rosnode的指令时出现一些问题
  • 也许你需要添加一些环境设置文件到你的~/.bashrc或者手动重新配置他们。
    -rosnode显示当前运行ROS节点信息
  • rosnode list指令列出活跃的节点

2、rosnode节点有哪些命令参数

(base) shl@zhihui-mint:~$ rosnode -h
rosnode is a command-line tool for printing information about ROS Nodes.

Commands:
	rosnode ping	test connectivity to node
	rosnode list	list active nodes
	rosnode info	print information about node
	rosnode machine	list nodes running on a particular machine or list machines
	rosnode kill	kill a running node
	rosnode cleanup	purge registration information of unreachable nodes

Type rosnode <command> -h for more detailed usage, e.g. 'rosnode ping -h'

(base) shl@zhihui-mint:~$ 

3、使用rosnode list查看当前正在运行的节点

(base) shl@zhihui-mint:~$ rosnode list
/LD06
/image_view
/reprojection
/rosout
/rviz
/usb_cam
(base) shl@zhihui-mint:~$ 

因此,我连接了激光雷达网络摄像头,因此能看到的激活节点比较多,你自己能看到的节点可能只有rosout

  • 因为rosout这个节点用于收集记录节点调试输出信息,所以它总是在运行的

4、rosnode info命令返回的是关于一个特定节点的信息。

$ rosnode info /rosout

这给了我们更多的一些有关于rosout的信息,

(base) shl@zhihui-mint:~$ rosnode info /rosout
--------------------------------------------------------------------------------
Node [/rosout]
Publications: 
 * /rosout_agg [rosgraph_msgs/Log]

Subscriptions: 
 * /rosout [rosgraph_msgs/Log]

Services: 
 * /rosout/get_loggers
 * /rosout/set_logger_level


contacting node http://zhihui-mint:35585/ ...
Pid: 18873
Connections:
 * topic: /rosout
    * to: /LD06 (http://zhihui-mint:42629/)
    * direction: inbound (52012 - zhihui-mint:46679) [13]
    * transport: TCPROS
 * topic: /rosout
    * to: /image_view (http://zhihui-mint:45923/)
    * direction: inbound (45082 - zhihui-mint:35753) [17]
    * transport: TCPROS
 * topic: /rosout
    * to: /usb_cam (http://zhihui-mint:39995/)
    * direction: inbound (44188 - zhihui-mint:35259) [16]
    * transport: TCPROS
 * topic: /rosout
    * to: /rviz (http://zhihui-mint:38439/)
    * direction: inbound (39514 - zhihui-mint:54301) [18]
    * transport: TCPROS
 * topic: /rosout
    * to: /reprojection (http://zhihui-mint:42737/)
    * direction: inbound (48372 - zhihui-mint:40099) [19]
    * transport: TCPROS

(base) shl@zhihui-mint:~$ 

单线激光雷达的节点/LD06的更多信息:

(base) shl@zhihui-mint:~$ rosnode info /LD06
--------------------------------------------------------------------------------
Node [/LD06]
Publications: 
 * /LiDAR/LD06 [sensor_msgs/LaserScan]
 * /rosout [rosgraph_msgs/Log]

Subscriptions: None

Services: 
 * /LD06/get_loggers
 * /LD06/set_logger_level


contacting node http://zhihui-mint:42629/ ...
Pid: 20354
Connections:
 * topic: /rosout
    * to: /rosout
    * direction: outbound (46679 - 127.0.0.1:52012) [12]
    * transport: TCPROS
 * topic: /LiDAR/LD06
    * to: /reprojection
    * direction: outbound (46679 - 127.0.0.1:60506) [11]
    * transport: TCPROS
 * topic: /LiDAR/LD06
    * to: /rviz
    * direction: outbound (46679 - 127.0.0.1:60516) [14]
    * transport: TCPROS

(base) shl@zhihui-mint:~$ 

5.7 rosrun的使用

rosrun允许你使用包名直接运行一个包内的节点(而不需要知道这个包的路径)。

用法:

$ rosrun [package_name] [node_name]

现在我们可以运行turtlesim包中的 turtlesim_node。

1、下面我们启动一个turtlesim包中的turtlesim_node节点来说明

rosrun turtlesim turtlesim_node

2、此时再使用rosnode list查看一下正在运行的节点有哪些

(base) shl@zhihui-mint:~$ rosnode list
/LD06
/image_view
/reprojection
/rosout
/rviz
/turtlesim
/usb_cam
(base) shl@zhihui-mint:~$ 

3、改变发布节点的名称

首先停止之前发布的/turtlesim节点,在更改节点之前,先停止我们之前运行的turtlesim节点

  • 关闭 turtlesim 窗口停止运行节点 (或者回到rosrun turtlesim终端并使用ctrl -C)。
  • 现在让我们重新运行它,但是这一次使用Remapping Argument改变节点名称:

$ rosrun turtlesim turtlesim_node __name:=my_turtle

然后我们在使用rosnode list查看一下发布的节点名称有没有变化:

(base) shl@zhihui-mint:~$ rosnode list
/LD06
/image_view
/my_turtle
/reprojection
/rosout
/rviz
/usb_cam
(base) shl@zhihui-mint:~$ 

4、如果你不能够关掉之前发布的/turtlesim节点,需要

1)先杀死之前的发布的节点

rosnode kill /turtlesim

2)然后再清楚杀掉的节点即可

rosnode cleanup

5、使用rosnode ping进行测试

(base) shl@zhihui-mint:~$ rosnode ping /my_turtle 
rosnode: node is [/my_turtle]
pinging /my_turtle with a timeout of 3.0s
xmlrpc reply from http://zhihui-mint:37485/	time=0.388861ms
xmlrpc reply from http://zhihui-mint:37485/	time=0.316858ms
xmlrpc reply from http://zhihui-mint:37485/	time=0.284195ms
xmlrpc reply from http://zhihui-mint:37485/	time=0.282049ms

6 理解ROS话题(Topic)

本教程介绍ROS话题(topics)以及如何使用rostopicrxplot等 命令行工具。

6.1 通过键盘远程控制turtle

1、先启动roscore

roscore

2、启动turtlesim节点

rosrun turtlesim turtlesim_node

3、启动turtle鼠标控制节点

rosrun turtlesim turtle_teleop_key

  • 现在你可以使用键盘上的方向键来控制turtle运动了。
  • 如果不能控制,请选中turtle_teleop_key所在的终端窗口以确保你的按键输入能够被捕获。

下面让我们来看看小乌龟移动的过程的背后都发生了什么

6.2 ROS Topics

  • turtlesim_node节点turtle_teleop_key节点之间是通过一个ROS话题互相通信的。
  • turtle_teleop_key在一个话题上发布按键输入消息,而turtlesim订阅该话题接收该消息
  • 下面让我们使用rqt_graph来显示当前运行的节点和话题。
  • 注意:如果你使用的是electric或更早期的版本,那么rqt是不可用的,请使用rxgraph代替。

6.3 rqt_graph的使用

  • rqt_graph能够创建一个显示当前系统运行情况的动态图形
  • rqt_graphrqt程序包中的一部分。
  • 通过鼠标滚轮图结构进行放大和缩小

如果你没有安装,请通过以下命令来安装:

$ sudo apt-get install ros-<distro>-rqt
$ sudo apt-get install ros-<distro>-rqt-common-plugins

更具你需要的版本,替换ros的发行版本号!

1、在一个新的终端中运行

rosrun rqt_graph rqt_graph

或者

rqt_graph

2、你会看到如下的图形

只显示节点Nodes

  • 如果你将鼠标放在/turtle1/command_velocity上方,相应的ROS节点(蓝色和绿色)话题(红色)就会高亮显示。
  • 正如你所看到的turtlesim_node节点turtle_teleop_key节点正通过一个名为/turtle1/cmd_vel的话题来互相通信。

蓝色节点绿色节点就相当与是两部手机,必须通过红色的话题就相当于是基站,然后进行信息交互通信!

6.4 rostopic的使用

1、rostopic命令参数有哪些:

(base) shl@zhihui-mint:~$ rostopic -h
rostopic is a command-line tool for printing information about ROS Topics.

Commands:
	rostopic bw	display bandwidth used by topic
	rostopic delay	display delay of topic from timestamp in header
	rostopic echo	print messages to screen
	rostopic find	find topics by type
	rostopic hz	display publishing rate of topic    
	rostopic info	print information about active topic
	rostopic list	list active topics
	rostopic pub	publish data to topic
	rostopic type	print topic or field type

Type rostopic <command> -h for more detailed usage, e.g. 'rostopic echo -h'

(base) shl@zhihui-mint:~$ 

2、rostopic echo显示某个话题上发布的数据

rostopic echo [topic]

我们打印/turtle1/cmd_vel话题的数据

$ rostopic echo /turtle1/cmd_vel

  • 你可能看不到任何东西因为现在还没有数据发布到该话题上。

  • 接下来我们通过按下方向键使turtle_teleop_key节点发布数据。

  • 记住如果turtle没有动起来的话就需要你重新选中turtle_teleop_key节点运行时所在的终端窗口。

  • 现在当你按下向上方向键时应该会看到下面的信息:

(base) shl@zhihui-mint:~$ rostopic echo /turtle1/cmd_vel 
linear: 
  x: 0.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: -2.0
---
linear: 
  x: 2.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---

现在让我们再看一下rqt_graph(你可能需要刷新一下ROS graph)。

正如你所看到的rostopic echo(红色显示部分)现在也订阅turtle1/cmd_vel话题

蓝色节点发布小乌龟移动的信息到topic,然后一个绿色的节点从tipic订阅接受消息!

3、rostopic list能够列出所有当前订阅发布话题

(base) shl@zhihui-mint:~$ rostopic list
/LiDAR/LD06
/clicked_point
/image_view/output
/image_view/parameter_descriptions
/image_view/parameter_updates
/initialpose
/move_base_simple/goal
/reprojection
/rosout
/rosout_agg
/tf
/tf_static
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
/usb_cam/camera_info
/usb_cam/image_raw
/usb_cam/image_raw/compressed
/usb_cam/image_raw/compressed/parameter_descriptions
/usb_cam/image_raw/compressed/parameter_updates
/usb_cam/image_raw/compressedDepth
/usb_cam/image_raw/compressedDepth/parameter_descriptions
/usb_cam/image_raw/compressedDepth/parameter_updates
/usb_cam/image_raw/theora
/usb_cam/image_raw/theora/parameter_descriptions
/usb_cam/image_raw/theora/parameter_updates
(base) shl@zhihui-mint:~$ 

4、查看rostopic list -h的参数

(base) shl@zhihui-mint:~$ rostopic list -h
Usage: rostopic list [/namespace]

Options:
  -h, --help            show this help message and exit
  -b BAGFILE, --bag=BAGFILE
                        list topics in .bag file
  -v, --verbose         list full details about each topic
  -p                    list only publishers
  -s                    list only subscribers
  --host                group by host name
(base) shl@zhihui-mint:~

在rostopic list中使用verbose选项,可以显示出有关所发布订阅话题及其类型的详细信息

(base) shl@zhihui-mint:~$ rostopic list -v

Published topics:
 * /image_view/parameter_updates [dynamic_reconfigure/Config] 1 publisher
 * /usb_cam/camera_info [sensor_msgs/CameraInfo] 1 publisher
 * /usb_cam/image_raw/compressedDepth/parameter_updates [dynamic_reconfigure/Config] 1 publisher
 * /clicked_point [geometry_msgs/PointStamped] 1 publisher
 * /usb_cam/image_raw/compressed [sensor_msgs/CompressedImage] 1 publisher
 * /turtle1/cmd_vel [geometry_msgs/Twist] 1 publisher
 * /move_base_simple/goal [geometry_msgs/PoseStamped] 1 publisher
 * /usb_cam/image_raw/compressedDepth/parameter_descriptions [dynamic_reconfigure/ConfigDescription] 1 publisher
 * /usb_cam/image_raw/compressed/parameter_descriptions [dynamic_reconfigure/ConfigDescription] 1 publisher
 * /LiDAR/LD06 [sensor_msgs/LaserScan] 1 publisher
 * /usb_cam/image_raw/theora/parameter_descriptions [dynamic_reconfigure/ConfigDescription] 1 publisher
 * /usb_cam/image_raw/compressedDepth [sensor_msgs/CompressedImage] 1 publisher
 * /usb_cam/image_raw/compressed/parameter_updates [dynamic_reconfigure/Config] 1 publisher
 * /rosout [rosgraph_msgs/Log] 8 publishers
 * /usb_cam/image_raw/theora/parameter_updates [dynamic_reconfigure/Config] 1 publisher
 * /initialpose [geometry_msgs/PoseWithCovarianceStamped] 1 publisher
 * /rosout_agg [rosgraph_msgs/Log] 1 publisher
 * /reprojection [sensor_msgs/Image] 1 publisher
 * /usb_cam/image_raw [sensor_msgs/Image] 1 publisher
 * /turtle1/color_sensor [turtlesim/Color] 1 publisher
 * /usb_cam/image_raw/theora [theora_image_transport/Packet] 1 publisher
 * /image_view/output [sensor_msgs/Image] 1 publisher
 * /image_view/parameter_descriptions [dynamic_reconfigure/ConfigDescription] 1 publisher
 * /turtle1/pose [turtlesim/Pose] 1 publisher

Subscribed topics:
 * /usb_cam/image_raw [sensor_msgs/Image] 2 subscribers
 * /rosout [rosgraph_msgs/Log] 1 subscriber
 * /tf [tf2_msgs/TFMessage] 1 subscriber
 * /tf_static [tf2_msgs/TFMessage] 1 subscriber
 * /LiDAR/LD06 [sensor_msgs/LaserScan] 2 subscribers
 * /turtle1/cmd_vel [geometry_msgs/Twist] 2 subscribers

(base) shl@zhihui-mint:~$ 

6.5 ROS Messages

  • 话题之间的通信是通过在节点之间发送ROS消息实现的。
  • 对于发布器(turtle_teleop_key)订阅器(turtulesim_node)之间的通信,发布器和订阅器之间必须发送和接收相同类型的消息。
  • 这意味着话题的类型是由发布在它上面的消息类型决定的。
  • 使用rostopic type命令可以查看发布在某个话题上的消息类型

6.6 rostopic type命令用来查看所发布话题消息类型

rostopic type命令用来查看所发布话题消息类型

rostopic type [topic]

(base) shl@zhihui-mint:~$ rostopic type /turtle1/cmd_vel 
geometry_msgs/Twist
(base) shl@zhihui-mint:~$ 

下面是我的激光雷达和相机发布消息类型

rostopic type [topic]

(base) shl@zhihui-mint:~$ rostopic type /LiDAR/LD06 
sensor_msgs/LaserScan
(base) shl@zhihui-mint:~$ rostopic type /usb_cam/image_raw
sensor_msgs/Image
(base) shl@zhihui-mint:~$ 

也可以使用rosmsg show查看发布消息的详细类型情况:

(base) shl@zhihui-mint:~$ rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z

(base) shl@zhihui-mint:~$ 

可以看出,这个是和我们上面打印出消息的类型是对应的:

(base) shl@zhihui-mint:~$ rostopic echo /turtle1/cmd_vel 
linear: 
  x: 0.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: -2.0

6.7 rostopic pub可以把数据发布到当前某个正在广播的话题上

先来看一下rostopic pub有哪些参数

(base) shl@zhihui-mint:~$ rostopic pub -h
Usage: rostopic pub /topic type [args...]

Options:
  -h, --help            show this help message and exit
  -v                    print verbose output
  -r RATE, --rate=RATE  publishing rate (hz).  For -f and stdin input, this
                        defaults to 10.  Otherwise it is not set.
  -1, --once            publish one message and exit
  -f FILE, --file=FILE  read args from YAML file (Bagy)
  -l, --latch           enable latching for -f, -r and piped input.  This
                        latches the first message.
  -s, --substitute-keywords
                        When publishing with a rate, performs keyword ('now'
                        or 'auto') substitution for each message
  --use-rostime         use rostime for time stamps, else walltime is used
(base) shl@zhihui-mint:~$ 

1、rostopic pub可以把数据发布到当前某个正在广播的话题

rostopic pub [topic] [msg_type] [args]

2、示例:

$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, 1.8]’

以上命令会发送一条消息给turtlesim,告诉它以2.0大小的线速度和1.8大小的角速度开始移动。

3、下面我们来深入说明一下上面的那条命令含义

$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, 1.8]’

  • rostopic pub 将会发布消息到某个话题
  • -1:发布完一条消息之后马上就退出
  • /turtle1/cmd_vel :消息发布到的话题名称
  • geometry_msgs/Twist:发布消息的类型
  • :(双破折号)这会告诉命令选项解析器接下来的参数部分都不是命令选项

正如之前提到的,在一个geometry_msgs/Twist消息里面包含有两个浮点型元素:linear和angular。在本例中2.0是linear的值,1.8是angula的值。

4、可以使用-r设置一个稳定的频率,保持一直移动的状态

这条命令以1Hz的频率发布速度命令到速度话题上

$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, 1.8]’

然后就可以看到小王八一直在哪里转圈圈!

6.8 rostopic hz查看数据发布的频率

rostopic hz [topic]

rostopic hz /turtle1/pose

(base) shl@zhihui-mint:~$ rostopic hz /turtle1/pose 
subscribed to [/turtle1/pose]
average rate: 62.502
	min: 0.015s max: 0.017s std dev: 0.00048s window: 62
average rate: 62.515
	min: 0.015s max: 0.017s std dev: 0.00049s window: 125
average rate: 62.503
	min: 0.015s max: 0.017s std dev: 0.00049s window: 187
average rate: 62.506
	min: 0.015s max: 0.017s std dev: 0.00049s window: 250
average rate: 62.500
	min: 0.015s max: 0.017s std dev: 0.00049s window: 312

现在我们可以知道了turtlesim正以大约60Hz的频率发布数据给turtle

6.9 ros_plot实时显示一个发布到某个话题上的数据变化图形

这里我们将使用rqt_plot命令来绘制正在发布到/turtle1/pose话题上的数据变化图形。

首先,在一个新终端中运行rqt_plot命令:

$ rosrun rqt_plot rqt_plotrqt_plot

这会弹出一个新窗口,在窗口左上角的一个文本框里面你可以添加需要绘制的话题。

  • 在里面输入/turtle1/pose/x后之前处于禁用状态的加号按钮将会被使能变亮。
  • 按一下该按钮,并对/turtle1/pose/y重复相同的过程。
  • 现在你会在图形中看到turtle的x-y位置坐标图。

注意:

你可能看不到曲线,这是由于总坐标的值太大,我们检测的值太小,导致只能看到一条直线几乎与横轴重合,因此可以通过设置纵轴的最大值范围,如下图,修改Top值即可(当然横、纵轴的左右和上下都是可以改的,快去试试吧)!

7 理解ROS服务和参数

本教程介绍了ROS 服务参数的知识,以及命令行工具rosservicerosparam的使用方法

7.1 ROS Services

  • 服务(services)节点之间通讯另一种方式
  • 服务允许节点发送请求(request) 并获得一个响应(response)

7.2 rosservice的使用

先查看rosservice有哪些参数

(base) shl@zhihui-mint:~$ rosservice -h
Commands:
	rosservice args	print service arguments
	rosservice call	call the service with the provided args
	rosservice find	find services by service type
	rosservice info	print information about service
	rosservice list	list active services
	rosservice type	print service type
	rosservice uri	print service ROSRPC uri

Type rosservice <command> -h for more detailed usage, e.g. 'rosservice call -h'

(base) shl@zhihui-mint:~$ 

  • rosservice可以很轻松的使用ROS 客户端/服务器框架提供的服务。

  • rosservice提供了很多可以在topic上使用的命令,如下所示:


    • rosservice list 输出可用服务的信息
    • rosservice call 调用带参数的服务
    • rosservice type 输出服务类型
    • rosservice find 依据类型寻找服务find services by service type
    • rosservice uri 输出服务的ROSRPC uri

(未完待续)

8 使用 rqt_console 和 roslaunch

##8.1 rqt_console

(未完待续)

8.2 roslaunch的使用

roslaunch可以用来启动定义在launch文件中的多个节点

8.2.1 创建launch文件

1、roslaunch的使用法

$ roslaunch [package] [filename.launch]

2、先切换到beginner_tutorials程序包目录下:

$ roscd beginner_tutorials

(base) shl@zhihui-mint:~/catkin_ws$ ls
build  devel  src
(base) shl@zhihui-mint:~/catkin_ws$ roscd beginner_tutorials/
(base) shl@zhihui-mint:~/catkin_ws/src/beginner_tutorials$ ls
CMakeLists.txt  include  package.xml  src
(base) shl@zhihui-mint:~/catkin_ws/src/beginner_tutorials$ 

3、创建一个名为turtlemimic.launch的launch文件并复制粘贴以下内容到该文件里面

 <launch>

   <group ns="turtlesim1">
     <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
   </group>
 
   <group ns="turtlesim2">
     <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
   </group>
 
   <node pkg="turtlesim" name="mimic" type="mimic">
     <remap from="input" to="turtlesim1/turtle1"/>
     <remap from="output" to="turtlesim2/turtle1"/>
   </node>
 
</launch>

8.2.2 Launch 文件解析

下面对上面turtlemimic.launch文件中内容逐句解析l

1、标签开头,表明是一个launch文件

<launch>

2、创建两个节点分组

   <group ns="turtlesim1">
     <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
   </group>
 
   <group ns="turtlesim2">
     <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
   </group>
  • 在这里我们创建了两个节点分组并以命名空间(namespace)标签来区分,其中一个名为turtulesim1,另一个名为turtlesim2,两个组里面都使用相同的turtlesim节点并命名为sim
  • 这样可以让我们同时启动两个turtlesim模拟器而不会产生命名冲突。

3、启动模仿节点

   <node pkg="turtlesim" name="mimic" type="mimic">
     <remap from="input" to="turtlesim1/turtle1"/>
     <remap from="output" to="turtlesim2/turtle1"/>
   </node>

在这里我们启动模仿节点,并将所有话题的输入和输出分别重命名为turtlesim1turtlesim2,这样就会使turtlesim2模仿turtlesim1。

4、 结束标签

</launch>

8.2.3 启动launch文件

1、通过roslaunch命令来启动launch文件:

$ roslaunch beginner_tutorials turtlemimic.launch

现在将会有两个turtlesims被启动

2、然后我们在一个新终端中使用rostopic命令发送速度设定消息

$ rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, -1.8]’

你会看到两个turtlesims会同时开始移动,虽然发布命令只是给turtlesim1发送了速度设定消息。

3、可以通过rqt_graph来更好的理解在launch文件中所做的事情。

9 编写简单的消息发布器和订阅器 (Python catkin)

本教程将通过Python编写一个发布器节点订阅器节点

9.1 python编写发布器节点

  • 节点”是ROS术语,它连接到ROS网络的可执行文件。在这里,我们将创建发布器(“talker”)节点不断广播消息。
  • 进入之前创建的beginner_tutorials包

1、进入创建的beginner_tutorials包

(base) shl@zhihui-mint:~/catkin_ws$ source devel/setup.bash 
(base) shl@zhihui-mint:~/catkin_ws$ roscd beginner_tutorials/
(base) shl@zhihui-mint:~/catkin_ws/src/beginner_tutorials$ 

2、首先创建scripts目录存放Python代码:

$ mkdir scripts
$ cd scripts

3、下载例子脚本talker.py到scripts目录,并修改权限为可执行:

$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py

4、浏览和编辑:

$ rosed beginner_tutorials talker.py

内容如下:

#!/usr/bin/env python


import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

9.1.1 代码解释

下面开始对发布器节点的代码逐行分析:

1、使用python执行该脚本

#!/usr/bin/env python

每个Python的ROS节点会在顶部描述,第一行确保你的脚本是使用Python执行的脚本

2、导入python的依赖库包

import rospy
from std_msgs.msg import String
    • 需要导入rospy客户端库
    • 导入std_msgs.msg 重用std_msgs/String消息类型

    3、定义talker接口

    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    
    • 定义talker接口,pub = rospy.Publisher(“chatter”, String, queue_size=10)表示节点发布chatter话题,使用String字符类型,实际上就是类std_msgs.msg.Stringqueue_size表示队列的大小(适合hydro以后版本),如果队列消息处理不够快,就会丢弃旧的消息。
    • rospy.init_node(NAME)初始化节点,开始跟ROS master通讯
    • 注意:保持节点名称在网络中是唯一的,不能包含斜杠”/“

    4、控制话题消息发布的频率

    rate = rospy.Rate(10) # 10hz
    

    • 创建Rate对象,与sleep()函数结合使用,控制话题消息发布频率
    • 10hz表示每秒发布10次。

    5、发布消息

    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()
    

    • loopospy的标准结构,检查rospy.is_shutdown()标识没返回值就会一直运行。
    • rospy.is_shutdown()返回false就会退出(例如按下Ctrl-C)
    • 程序执行pub.publish(String(str)),在chatter话题发布String消息
    • rate.sleep()通过睡眠来,保持消息发送频率
    • 你可以运行 rospy.sleep(),类似time.sleep()
    • rospy.loginfo(str)函数在屏幕输出调试信息,同时写入到节点日志文件和rosout节点
    • rosout节点对于调式来说是便利的方式。
    • 可以通过rqt_console查看调式信息。
    • std_msgs.msg.string是一个非常简单的消息类型,所以你可能想知道它看起来像发布更复杂的类型。
    • 一般的规则是,构造函数的参数是在.msg文件有相同的顺序。
    • 你也可以传递没有参数和直接初始化字段,例如:
    msg = String()
    msg.data = str
    

    或者你能初始化某些字段,剩余保持默认值:

    String(data=str)
    

    6、开始运行发布器节点

    if __name__ == '__main__':
        try:
            talker()
        except rospy.ROSInterruptException:
            pass
    
    • 标准的Python main检查,这个会捕获rospy.ROSInterruptException异常,当按下Ctrl-C或节点关闭的话,即使在rospy.sleep()和rospy.Rate.sleep()函数里都会抛出异常。

    ##9.2 编写python订阅器节点

    1、同样切换到scripts目录,然后下载listener.py代码

    $ roscd beginner_tutorials/scripts/
    $ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py

    2、listener.py文件内容如下:

      #!/usr/bin/env python
      
      
      import rospy
      from std_msgs.msg import String
      
      def callback(data):
          rospy.loginfo(rospy.get_caller_id() + 'I heard %s', data.data)
      
      def listener():
      
          # In ROS, nodes are uniquely named. If two nodes with the same
          # name are launched, the previous one is kicked off. The
          # anonymous=True flag means that rospy will choose a unique
          # name for our 'listener' node so that multiple listeners can
          # run simultaneously.
          rospy.init_node('listener', anonymous=True)
      
          rospy.Subscriber('chatter', String, callback)
      
          # spin() simply keeps python from exiting until this node is stopped
          rospy.spin()
      
      if __name__ == '__main__':
          listener()
      

      9.2.1 代码解释

      • listener.py的代码类似talker.py,除了新增加的函数回调机制
          rospy.init_node('listener', anonymous=True)
      
          rospy.Subscriber('chatter', String, callback)
      
          # spin() simply keeps python from exiting until this node is stopped
          rospy.spin()

      • 这表示节点订阅话题chatter消息类型是 std_msgs.msgs.String

      • 接受到新消息回调函数触发处理这些信息,并把消息作为第一个参数传递函数里

      • 还改变了调用rospy.init_node(),增加anonymous=True关键词参数。

      • ROS要求每个节点要有唯一名称,如果相同的名称,就会中止之前同名的节点。

      • anonymous=True标识就会告诉rospy,要生成一个唯一的节点名称,因此你可以有多个listener.py同时运行。

      • 最后rospy.spin()简单保持你的节点一直运行,直到程序关闭。

      • 不像roscpp,rospy.spin()不影响到订阅的回调函数,因为他们有自己的独立线程。

      构建节点

      • 我们使用CMake作为构建系统,即使是Python节点也需要使用。
        这确保针对消息和服务能自动生成Python代码
      • 进入catkin工作空间,运行catkin_make:
      $ cd ~/catkin_ws
      $ catkin_make