ROS官网新手级教程总结
第 1 关卡:安装和配置 ROS 环境
目标:在计算机上安装和配置 ROS 环境。
安装 ROS
按照 ROS 安装说明进行安装。
管理环境
确定环境变量 ROS_ROOT 和 ROS_PACKAGE_PATH 已经设置好了。以我的为例:
- printenv | grep ROS
输出为:
- ROS_ETC_DIR=/opt/ros/melodic/etc/ros
- ROS_ROOT=/opt/ros/melodic/share/ros
- ROS_MASTER_URI=http://localhost:11311
- ROS_VERSION=1
- ROS_PYTHON_VERSION=2
- ROS_PACKAGE_PATH=/opt/ros/melodic/share
- ROSLISP_PACKAGE_DIRECTORIES=
- ROS_DISTRO=melodic
每次会话进入的时候都需要执行一次(注意 melodic 根据版本不同而更换):
- source /opt/ros/melodic/setup.bash
为了方便,可以把这条语句放在 .bashrc 脚本中。
创建 ROS 工作空间
相对于 rosbuild 而言,catkin 是目前官方推荐的用于管理代码的方法。
创建一个 catkin 工作空间:
- mkdir -p ~/catkin_ws/src
- cd ~/catkin_ws/
- catkin_make
这会创建出类似这样的目录结构:
- .
- ├── build
- │ ├── CATKIN_IGNORE
- │ ├── CMakeCache.txt
- │ ├── CMakeFiles
- │ │ ├── 3.10.2
- │ │ │ ├── CMakeCCompiler.cmake
- │ │ │ ├── CMakeCXXCompiler.cmake
- │ │ │ ├── CMakeDetermineCompilerABI_C.bin
- │ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
- │ │ │ ├── CMakeSystem.cmake
- │ │ │ ├── CompilerIdC
- │ │ │ │ ├── CMakeCCompilerId.c
- │ │ │ │ ├── a.out
- │ │ │ │ └── tmp
- │ │ │ └── CompilerIdCXX
- │ │ │ ├── CMakeCXXCompilerId.cpp
- │ │ │ ├── a.out
- │ │ │ └── tmp
- │ │ ├── CMakeDirectoryInformation.cmake
- │ │ ├── CMakeError.log
- │ │ ├── CMakeOutput.log
- │ │ ├── CMakeRuleHashes.txt
- │ │ ├── CMakeTmp
- │ │ ├── Makefile.cmake
- │ │ ├── Makefile2
- │ │ ├── TargetDirectories.txt
- │ │ ├── clean_test_results.dir
- │ │ │ ├── DependInfo.cmake
- │ │ │ ├── build.make
- │ │ │ ├── cmake_clean.cmake
- │ │ │ └── progress.make
- │ │ ├── cmake.check_cache
- │ │ ├── download_extra_data.dir
- │ │ │ ├── DependInfo.cmake
- │ │ │ ├── build.make
- │ │ │ ├── cmake_clean.cmake
- │ │ │ └── progress.make
- │ │ ├── doxygen.dir
- │ │ │ ├── DependInfo.cmake
- │ │ │ ├── build.make
- │ │ │ ├── cmake_clean.cmake
- │ │ │ └── progress.make
- │ │ ├── feature_tests.bin
- │ │ ├── feature_tests.c
- │ │ ├── feature_tests.cxx
- │ │ ├── progress.marks
- │ │ ├── run_tests.dir
- │ │ │ ├── DependInfo.cmake
- │ │ │ ├── build.make
- │ │ │ ├── cmake_clean.cmake
- │ │ │ └── progress.make
- │ │ └── tests.dir
- │ │ ├── DependInfo.cmake
- │ │ ├── build.make
- │ │ ├── cmake_clean.cmake
- │ │ └── progress.make
- │ ├── CTestConfiguration.ini
- │ ├── CTestCustom.cmake
- │ ├── CTestTestfile.cmake
- │ ├── Makefile
- │ ├── atomic_configure
- │ │ ├── _setup_util.py
- │ │ ├── env.sh
- │ │ ├── local_setup.bash
- │ │ ├── local_setup.sh
- │ │ ├── local_setup.zsh
- │ │ ├── setup.bash
- │ │ ├── setup.sh
- │ │ └── setup.zsh
- │ ├── catkin
- │ │ └── catkin_generated
- │ │ └── version
- │ │ └── package.cmake
- │ ├── catkin_generated
- │ │ ├── env_cached.sh
- │ │ ├── generate_cached_setup.py
- │ │ ├── installspace
- │ │ │ ├── _setup_util.py
- │ │ │ ├── env.sh
- │ │ │ ├── local_setup.bash
- │ │ │ ├── local_setup.sh
- │ │ │ ├── local_setup.zsh
- │ │ │ ├── setup.bash
- │ │ │ ├── setup.sh
- │ │ │ └── setup.zsh
- │ │ ├── order_packages.cmake
- │ │ ├── order_packages.py
- │ │ ├── setup_cached.sh
- │ │ └── stamps
- │ │ └── Project
- │ │ ├── _setup_util.py.stamp
- │ │ ├── interrogate_setup_dot_py.py.stamp
- │ │ ├── order_packages.cmake.em.stamp
- │ │ └── package.xml.stamp
- │ ├── catkin_make.cache
- │ ├── cmake_install.cmake
- │ ├── gtest
- │ │ ├── CMakeFiles
- │ │ │ ├── CMakeDirectoryInformation.cmake
- │ │ │ └── progress.marks
- │ │ ├── CTestTestfile.cmake
- │ │ ├── Makefile
- │ │ ├── cmake_install.cmake
- │ │ └── googlemock
- │ │ ├── CMakeFiles
- │ │ │ ├── CMakeDirectoryInformation.cmake
- │ │ │ ├── gmock.dir
- │ │ │ │ ├── DependInfo.cmake
- │ │ │ │ ├── __
- │ │ │ │ │ └── googletest
- │ │ │ │ │ └── src
- │ │ │ │ ├── build.make
- │ │ │ │ ├── cmake_clean.cmake
- │ │ │ │ ├── depend.make
- │ │ │ │ ├── flags.make
- │ │ │ │ ├── link.txt
- │ │ │ │ ├── progress.make
- │ │ │ │ └── src
- │ │ │ ├── gmock_main.dir
- │ │ │ │ ├── DependInfo.cmake
- │ │ │ │ ├── __
- │ │ │ │ │ └── googletest
- │ │ │ │ │ └── src
- │ │ │ │ ├── build.make
- │ │ │ │ ├── cmake_clean.cmake
- │ │ │ │ ├── depend.make
- │ │ │ │ ├── flags.make
- │ │ │ │ ├── link.txt
- │ │ │ │ ├── progress.make
- │ │ │ │ └── src
- │ │ │ └── progress.marks
- │ │ ├── CTestTestfile.cmake
- │ │ ├── Makefile
- │ │ ├── cmake_install.cmake
- │ │ └── gtest
- │ │ ├── CMakeFiles
- │ │ │ ├── CMakeDirectoryInformation.cmake
- │ │ │ ├── gtest.dir
- │ │ │ │ ├── DependInfo.cmake
- │ │ │ │ ├── build.make
- │ │ │ │ ├── cmake_clean.cmake
- │ │ │ │ ├── depend.make
- │ │ │ │ ├── flags.make
- │ │ │ │ ├── link.txt
- │ │ │ │ ├── progress.make
- │ │ │ │ └── src
- │ │ │ ├── gtest_main.dir
- │ │ │ │ ├── DependInfo.cmake
- │ │ │ │ ├── build.make
- │ │ │ │ ├── cmake_clean.cmake
- │ │ │ │ ├── depend.make
- │ │ │ │ ├── flags.make
- │ │ │ │ ├── link.txt
- │ │ │ │ ├── progress.make
- │ │ │ │ └── src
- │ │ │ └── progress.marks
- │ │ ├── CTestTestfile.cmake
- │ │ ├── Makefile
- │ │ └── cmake_install.cmake
- │ └── test_results
- ├── devel
- │ ├── _setup_util.py
- │ ├── cmake.lock
- │ ├── env.sh
- │ ├── lib
- │ ├── local_setup.bash
- │ ├── local_setup.sh
- │ ├── local_setup.zsh
- │ ├── setup.bash
- │ ├── setup.sh
- │ └── setup.zsh
- └── src
- └── CMakeLists.txt -> /opt/ros/melodic/share/catkin/cmake/toplevel.cmake
运行以下命令可以让该工作空间添加到 ROS 环境变量中,使得 ROS 可以识别:
- source devel/setup.bash
查看 ROS 环境变量确认这个目录已经添加进来了:
- echo $ROS_PACKAGE_PATH
我的环境变量如下:
- /workspace/catkin_ws/src:/opt/ros/melodic/share
其中 /workspace/catkin_ws/src 是我新创建的工作空间。
第 2 关卡:浏览 ROS 文件系统
目标:介绍 ROS 文件系统概念,用到了 roscd,rosls,rospack 命令。
准备工作
下载:
- sudo apt-get install ros-<distro>-ros-tutorials
<distro> 对应相应的版本。
ROS 文件系统概念
- 包(package):ROS 代码的软件组织单元。
- Manifests(package.xml):包的描述性文件。
文件系统工具
rospack
获取包信息:
- rospack find roscpp
输出:
- /opt/ros/melodic/share/roscpp
roscd
改变当前目录:
- roscd roscpp
pwd
输出:
- /opt/ros/melodic/share/roscpp
注意,这几个识别 ROS 包的命令都是根据 ROS 环境变量(ROS_PACKAGE_PATH)去找包的。
进入包内的子目录:
- roscd roscpp/cmake/
- pwd
输出:
- /opt/ros/melodic/share/roscpp/cmake
进入 ROS 应用的日志目录:
- roscd log
注意:如果还没有运行 ROS 输出日志的话,会显示:
- No active roscore
之类的信息。
rosls
显示包内的文件:
- rosls roscpp_tutorials
输出:
- cmake launch package.xml srv
第 3 关卡:包的创建
目标:使用 roscreate-pkg 和 catkin 创建包,rospack 列出包的依赖。
catkin 包必须满足的条件:
- 包含描述性文件 package.xml
- 包含使用了 catkin 的 CMakeLists.txt 文件
- 每个包都有独立的目录,没有嵌套
最简单的包结构如下:
- my_package/
- CMakeLists.txt
- package.xml
典型的工作区中包结构的样子:
- workspace_folder/ -- WORKSPACE
- src/ -- SOURCE SPACE
- CMakeLists.txt -- 'Toplevel' CMake file, provided by catkin
- package_1/
- CMakeLists.txt -- CMakeLists.txt file for package_1
- package.xml -- Package manifest for package_1
- ...
- package_n/
- CMakeLists.txt -- CMakeLists.txt file for package_n
- package.xml -- Package manifest for package_n
创建 catkin 包
进入 src 目录并创建 catkin 包:
- cd ~/catkin_ws/src
- catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
catkin_create_pkg 会指定包名及其依赖:
- # This is an example, do not try to run this
- # catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
工作区中包的编译
- cd ~/catkin_ws
- catkin_make
- source devel/setup.bash
包依赖
查看一阶依赖:
- rospack depends1 beginner_tutorials
输出:
- roscpp
- rospy
- std_msgs
这些依赖可以在包描述性文件中查看:
- roscd beginner_tutorials
- cat 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="root@todo.todo">root</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>
依赖也会有自己的依赖,比如:
- rospack depends1 roscpp
输出:
- cpp_common
- message_runtime
- rosconsole
- roscpp_serialization
- roscpp_traits
- rosgraph_msgs
- rostime
- std_msgs
- xmlrpcpp
要查看包的所有依赖(区别于一阶依赖):
- 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
包的定制化
修改 package.xml:
- roscd beginner_tutorials
- vim 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="root@todo.todo">root</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>
更新第 5 行的 description:The very good beginner-tutorials package
更新第 10 行的维护者标签。
更新第 16 行的证书。
最终修改后的文件如下:
- <?xml version="1.0"?>
- <package format="2">
- <name>beginner_tutorials</name>
- <version>0.0.0</version>
- <description>The very good 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="1183851628@qq.com">heyulong</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>BSD</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>
第 4 关卡:包的编译
目标:介绍编译包的工具链。
首先记得确认激活环境配置,在工作区下输入:
- source devel/setup.bash
前面已经用过,使用 catkin_make 可以同时编译多个包:
- # In a catkin workspace
- $ catkin_make [make_targets] [-DCMAKE_VARIABLES=...]
这会自动编译 src 目录下的包。如果包名是自定义的,比如说 my_src,那么应该这样做:
- # In a catkin workspace
- catkin_make --source my_src
上一关卡修改了 package.xml,这里在工作区内输入:
- catkin_make
输出:
- Base path: /workspace/catkin_ws
- Source space: /workspace/catkin_ws/src
- Build space: /workspace/catkin_ws/build
- Devel space: /workspace/catkin_ws/devel
- Install space: /workspace/catkin_ws/install
- ####
- #### Running command: "make cmake_check_build_system" in "/workspace/catkin_ws/build"
- ####
- -- Using CATKIN_DEVEL_PREFIX: /workspace/catkin_ws/devel
- -- Using CMAKE_PREFIX_PATH: /workspace/catkin_ws/devel;/opt/ros/melodic
- -- This workspace overlays: /workspace/catkin_ws/devel;/opt/ros/melodic
- -- Found PythonInterp: /usr/bin/python2 (found suitable version "2.7.15", 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: /workspace/catkin_ws/build/test_results
- -- Found gmock sources under '/usr/src/googletest': gmock will be built
- -- Found PythonInterp: /usr/bin/python2 (found version "2.7.15")
- -- Found gtest sources under '/usr/src/googletest': gtests will be built
- -- Using Python nosetests: /usr/bin/nosetests-2.7
- -- catkin 0.7.17
- -- 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: /workspace/catkin_ws/build
- ####
- #### Running command: "make -j2 -l2" in "/workspace/catkin_ws/build"
- ####
第 5 关卡:认识 ROS 节点
目标:介绍 ROS 图的概念,使用 roscore、rosnode、rosrun 命令。
准备条件
- apt-get install ros-<distro>-ros-tutorials
图概念介绍
- 节点(node):使用 ROS 与其他节点通信的可执行文件。
- 消息(message):当订阅或者发布主题时使用的 ROS 数据类型。
- 主题(topic):节点可以向主题发布消息,也可以向主题订阅消息。
- 主节点(master):ROS 的命名服务(name service),帮助各节点找到对方。
- rosout:ROS 中的 stdout/stderr。
- roscore:master、rosout、parameter 服务器。
节点
节点(node)就是 ROS 包中的可执行文件。ROS 节点使用 ROS 客户端库来与各节点进行通信。
节点可以发布或者订阅主题。
节点也可以提供或者消费服务。
客户端库
ROS 客户端可以允许用不同的语言编写的节点进行通信。
- rospy:Python 客户端库
- roscpp:C++ 客户端库
roscore
运行 roscore 开启 ROS 主服务:
- roscore
输出:
- ... logging to /root/.ros/log/c10afc7a-da7e-11e9-bbfa-0242ac110004/roslaunch-57c67ed2b135-886.log
- Checking log directory for disk usage. This may take awhile.
- Press Ctrl-C to interrupt
- Done checking log file disk usage. Usage is <1GB.
- started roslaunch server http://57c67ed2b135:38567/
- ros_comm version 1.14.3
- SUMMARY
- ========
- PARAMETERS
- * /rosdistro: melodic
- * /rosversion: 1.14.3
- NODES
- auto-starting new master
- process[master]: started with pid [896]
- ROS_MASTER_URI=http://57c67ed2b135:11311/
- setting /run_id to c10afc7a-da7e-11e9-bbfa-0242ac110004
- process[rosout-1]: started with pid [907]
- started core service [/rosout]
使用 rosnode
在运行 roscore 后,另外打开一个终端,输入:
- rosnode list
输出:
- /rosout
这说明当前只有一个 rosout 节点在运行,该节点总是在运行,为了收集记录节点的输出日志。
查看某节点的信息:
- rosnode info /rosout
输出:
- --------------------------------------------------------------------------------
- Node [/rosout]
- Publications:
- * /rosout_agg [rosgraph_msgs/Log]
- Subscriptions:
- * /rosout [unknown type]
- Services:
- * /rosout/get_loggers
- * /rosout/set_logger_level
- contacting node http://57c67ed2b135:34783/ ...
- Pid: 907
使用 rosrun
rosrun 用于直接运行包中的节点:
- rosrun [package_name] [node_name]
打开一个新的终端,输入:
- rosrun turtlesim turtlesim_node
打开一个新的终端,输入:
- rosnode list
输出:
- /rosout
- /turtlesim
关闭 turtlesim 窗口,重新打开该节点,并且指定节点名:
- rosrun turtlesim turtlesim_node __name:=my_turtle
在那个窗口输入 rosnode list 后显示:
- /my_turtle
- /rosout
查看与某节点之间的通信:
- rosnode ping my_turtle
输出:
- rosnode: node is [/my_turtle]
- pinging /my_turtle with a timeout of 3.0s
- xmlrpc reply from http://57c67ed2b135:37817/ time=29.969931ms
- xmlrpc reply from http://57c67ed2b135:37817/ time=1.099825ms
- xmlrpc reply from http://57c67ed2b135:37817/ time=1.539230ms
- xmlrpc reply from http://57c67ed2b135:37817/ time=2.717018ms
- ......
第 6 关卡:认识 ROS 主题
目标:介绍 ROS 主题以及 rostopic 和 rqt_plot 命令的使用。
配置
接着上一关卡做的东西。
确保 roscore 以及运行起来了:
- roscore
确保 turtlesim_node 运行起来了:
- rosrun turtlesim turtlesim_node __name:=my_turtle
然后,在一个新的终端运行一个新节点:
- rosrun turtlesim turtle_teleop_key
输出:
- Reading from keyboard
- ---------------------------
- Use arrow keys to move the turtle.
在这个节点里动一动箭头键:
ROS 主题
my_turtle 节点和 turtle_teleop_key 节点通过 ROS 主题(topic)进行通信。
turtle_teleop_key 以主题的方式发布按键,而 my_turtle 订阅该主题接收按键。
rqt_graph
使用 rqt_graph 创建 ROS 系统动态图结构。
安装:
- apt-get install ros-<distro>-rqt
- apt-get install ros-<distro>-rqt-common-plugins
输入:
- rosrun rqt_graph rqt_graph
得到:
rostopic
rostopic 用于获取 ROS 主题的信息。
- 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'
显示主题的发布数据:
- rostopic echo /turtle1/cmd_vel
在发布按键主题的节点中活动箭头键后,这边的 rostopic 会显示出:
- linear:
- x: 0.0
- y: 0.0
- z: 0.0
- angular:
- x: 0.0
- y: 0.0
- z: 2.0
- ---
- linear:
- x: 0.0
- y: 0.0
- z: 0.0
- angular:
- x: 0.0
- y: 0.0
- z: 2.0
- ---
- linear:
- x: 0.0
- y: 0.0
- z: 0.0
- angular:
- x: 0.0
- y: 0.0
- z: 2.0
- ---
- linear:
- x: 0.0
- y: 0.0
- z: 0.0
- angular:
- x: 0.0
- y: 0.0
- z: 2.0
- ---
- linear:
- x: 0.0
- y: 0.0
- z: 0.0
- angular:
- x: 0.0
- y: 0.0
- z: 2.0
- ---
- 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 出的图(刷新或者重启),可以看到 rostopic 也订阅了 /turtle1/cmd_vel 主题了。
查看当前发布和订阅的主题:
- rostopic list -v
输出:
- Published topics:
- * /turtle1/color_sensor [turtlesim/Color] 1 publisher
- * /turtle1/cmd_vel [geometry_msgs/Twist] 1 publisher
- * /rosout [rosgraph_msgs/Log] 5 publishers
- * /rosout_agg [rosgraph_msgs/Log] 1 publisher
- * /turtle1/pose [turtlesim/Pose] 1 publisher
- Subscribed topics:
- * /turtle1/cmd_vel [geometry_msgs/Twist] 2 subscribers
- * /rosout [rosgraph_msgs/Log] 1 subscriber
- * /statistics [rosgraph_msgs/TopicStatistics] 2 subscribers
主题间的通信通过节点间发送的 ROS 消息(message)来实现。发布者和订阅者之间要通信,必须发送和接收相同的消息类型。
消息类型定义了主题的类型。
查看发布主题的消息类型:
- # rostopic type [topic]
- rostopic type /turtle1/cmd_vel
输出:
- geometry_msgs/Twist
使用 rostopic pub 发送某一主题的数据:
- # rostopic pub [topic] [msg_type] [args]
- rostopic pub - /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
效果如下:
发布稳定的数据流:
- rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
此时乌龟会不断地转圈移动:
查看目前的 ROS 图:
订阅查看 /turtle1/pose 主题:
- rostopic echo /turtle1/pose
输出:
- ......
- x: 5.10276937485
- y: 5.45978927612
- theta: 0.407544314861
- linear_velocity: 2.0
- angular_velocity: -1.79999995232
- ---
- x: 5.13250160217
- y: 5.47162103653
- theta: 0.37874430418
- linear_velocity: 2.0
- angular_velocity: -1.79999995232
- ---
- x: 5.16256189346
- y: 5.48259210587
- theta: 0.349944293499
- linear_velocity: 2.0
- angular_velocity: -1.79999995232
- ---
- ......
查看目前的图结构:
使用 rostopic hz 查看主题发布的频率:
- # rostopic hz [topic]
- rostopic hz /turtle1/pose
输出:
- subscribed to [/turtle1/pose]
- average rate: 30.777
- min: 0.030s max: 0.036s std dev: 0.00128s window: 29
- average rate: 30.489
- min: 0.030s max: 0.042s std dev: 0.00181s window: 60
- average rate: 30.510
- min: 0.029s max: 0.042s std dev: 0.00211s window: 90
- average rate: 30.517
- min: 0.029s max: 0.042s std dev: 0.00208s window: 121
- average rate: 30.354
- min: 0.029s max: 0.042s std dev: 0.00207s window: 151
- average rate: 30.378
- min: 0.029s max: 0.062s std dev: 0.00296s window: 181
- average rate: 30.380
- min: 0.029s max: 0.062s std dev: 0.00287s window: 212
- average rate: 29.823
- min: 0.029s max: 0.062s std dev: 0.00439s window: 237
...
可以看到 my_turtle 以 30Hz 的速率不断发数据。
查看消息的更多细节:
- rostopic type /turtle1/cmd_vel | rosmsg show
输出:
- geometry_msgs/Vector3 linear
- float64 x
- float64 y
- float64 z
- geometry_msgs/Vector3 angular
- float64 x
- float64 y
- float64 z
输入:
- rostopic type /turtle1/pose | rosmsg show
输出:
- float32 x
- float32 y
- float32 theta
- float32 linear_velocity
- float32 angular_velocity
rqt_plot
rqt_plot 可以显示主题上发布的数据滚动式时间图。
- rosrun rqt_plot rqt_plot
第 7 关卡:ROS 服务和参数
目标:熟悉 ROS 服务和参数,使用 rosservice 和 rosparam。
服务(servece)节点相互通信的另一种方式。服务使得节点可以发送请求和接收响应。
rosservice
rosservice 可以很容易用上 ROS 的客户端/服务端框架。
- 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'
rosservece list 显示当前服务的列表:
- rosservice list
输出:
- /clear
- /kill
- /my_turtle/get_loggers
- /my_turtle/set_logger_level
- /reset
- /rosout/get_loggers
- /rosout/set_logger_level
- /rostopic_4219_1568863406310/get_loggers
- /rostopic_4219_1568863406310/set_logger_level
- /rqt_gui_py_node_3673/get_loggers
- /rqt_gui_py_node_3673/set_logger_level
- /rqt_gui_py_node_4098/get_loggers
- /rqt_gui_py_node_4098/set_logger_level
- /rqt_gui_py_node_4237/get_loggers
- /rqt_gui_py_node_4237/set_logger_level
- /spawn
- /teleop_turtle/get_loggers
- /teleop_turtle/set_logger_level
- /turtle1/set_pen
- /turtle1/teleport_absolute
- /turtle1/teleport_relative
rosservice type 查询服务类型:
- rosservice type /clear
输出:
- std_srvs/Empty
Empty 表示该服务既没有参数也没有返回值。
rosservice call 调用服务:
- # rosservice call [service] [args]
- rosservice call /clear
输入之后 my_turtle 节点的背景轨迹清空了:
rossrv show 查询 /spawn 的参数和返回值信息。
- rosservice type /spawn | rossrv show
输出:
- float32 x
- float32 y
- float32 theta
- string name
- ---
- string name
调用 /spawn 创建另一只乌龟:
- rosservice call /spawn 0.2 "good turtle"
效果如下:
- name: "good_turtle"
rosparam
rosparam 可以存储和操作 ROS 参数服务器(parameter server)上的数据。
参数服务器可以存储整型、浮点数、布尔型、字典和列表。
rosparame 使用 YAML 标记语言的语法。
- rosparam -h
输出:
- rosparam is a command-line tool for getting, setting, and deleting parameters from the ROS Parameter Server.
- Commands:
- rosparam set set parameter
- rosparam get get parameter
- rosparam load load parameters from file
- rosparam dump dump parameters to file
- rosparam delete delete parameter
- rosparam list list parameter names
set 和 get:
设置参数:
- # rosparam set [param_name]
- rosparam set /background_r 150
- # refresh
- rosservice call /clear
效果如下:
获取参数:
- # rosparam get [param_name]
- rosparam get /background_g
输出:
- 86
显示参数服务器中所有的参数:
- rosparam get /
输出:
- background_b: 255
- background_g: 86
- background_r: 150
- rosdistro: 'melodic
- '
- roslaunch:
- uris: {host_57c67ed2b135__39317: 'http://57c67ed2b135:39317/'}
- rosversion: '1.14.3
- '
- run_id: 9a92ffb2-da87-11e9-9b98-0242ac110004
rosparam 进行参数的持久化和加载
- # usage
- # rosparam dump [file_name] [namespace]
- # rosparam load [file_name] [namespace]
rosparam dump 进行持久化:
- rosparam dump params.yaml
会在当前目录生成一个 params.yaml 文件。
rosparam dump 加载参数到一个新的命名空间(如 version2):
- rosparam load params.yaml version2
- rosparam get /version2/background_b
返回:
- 255
第 8 关卡:使用 rqt_console 和 roslaunch
目标:使用 rqt_console 和 rqt_logger_level 进行调试;roslaunch 一次性启动多个节点。
准备条件
- apt-get install ros-melodic-rqt ros-melodic-rqt-common-plugins ros-melodic-turtlesim
使用 rqt_console 和 rqt_logger_level
rqt_console 利用了 ROS 的日志框架,用于显示节点的输出。
rqt_logger_level 可以用于调节日志的 verbosity 级别。
在两个终端分别运行两个命令,首先打开 console:
- rosrun rqt_console rqt_console
然后打开 logger level:
- rosrun rqt_logger_level rqt_logger_level
重启乌龟应用:
- rosrun turtlesim turtlesim_node __name:=my_turtle
显示出来一条日志:
使用 roslaunch
- # Usage
- # roslaunch [package] [filename.launch]
进入 beginner_tutorials 目录:
- source devel/setup.bash
roscd beginner_tutorials
创建 launch 目录:
- mkdir launch
- cd launch
创建 Launch 文件:
- vim turtlemimic.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>
注解:
- 第 1 行:表示这是个 launch 文件。
- 第 2-8 行:创建两个 turtlesim 节点,其命名空间不冲突。
- 第 10-13 行:创建一个 mimic 节点,其中 turtlesim2 会模仿 turtlesim1。
启动 launch 文件:
- roslaunch beginner_tutorials turtlemimic.launch
再开一个终端向 turtlesim1 发送数据流:
- rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
查看图结构:
- rqt_graph
第 9 关卡:使用 rosed 修改 ROS 文件
目标:使用 rosed 进行编辑。
- # Usage
- # rosed [package_name] [filename]
修改 roscpp 包中的 Logger.msg 文件(默认使用 vim 打开)。
第 10 关卡:创建 ROS msg 和 srv
目标:创建和构建 msg 和 srv 文件;使用 rosmsg、rossrv、roscp 命令。
msg 和 srv 的介绍
- msg:msg 文件是描述 ROS 消息字段的文本文件。它用于生成不同编程语言的消息源代码。
- srv:srv 用于描述服务。它包含两部分:请求和响应。
msg 文件存储于包中的 msg 目录,而 srv 文件存储于 srv 目录。
在 msg 文件中,每行都是一个字段类型和对应的字段名称。
字段类型种类有:
- int8, int16, int32, int64 (plus uint*)
- float32, float64
- string
- time, duration
- 其他 msg 文件
- 变长数组 array[] 和固定长度数组 array[C]
ROS 中还有特殊的类型:Header,header 包含了时间戳和坐标系信息。
一个 msg 文件的例子:
- Header header
- string child_frame_id
- geometry_msgs/PoseWithCovariance pose
- geometry_msgs/TwistWithCovariance twist
srv 文件与 msg 文件类似,只不过通过 --- 分割了请求和响应两部分。
- int64 A
- int64 B
- ---
- int64 Sum
创建 msg 及其配置
创建一个 Num.msg 文件:
- roscd beginner_tutorials
- mkdir msg
- echo "int64 num" > msg/Num.msg
为了保证该文件转换为其他语言的源代码,打开 package.xml,确保添加了以下两行:
- <build_depend>message_generation</build_depend>
- <exec_depend>message_runtime</exec_depend>
message_generation 在编译时有用,message_runtime 用在运行时。
打开 CMakeLists.txt 添加 message_generation 的依赖,这样才能生成消息。
- ## 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
- message_generation
- )
并且确保道出了 message_runtime 依赖:
- catkin_package(
- ...
- CATKIN_DEPENDS message_runtime ...
- ...)
还要添加 msg 文件:
- add_message_files(
- FILES
- Num.msg
- )
确保 generate_messages 函数的调用:
- generate_messages(
- DEPENDENCIES
- std_msgs
- )
使用 rosmsg
- # Usage
- # rosmsg show [message type]
生成一个消息:
- catkin_make
- rosmsg show beginner_tutorials/Num
输出:
- int64 num
使用 srv
创建 srv 目录:
- roscd beginner_tutorials
- mkdir srv
复制一个 srv 文件过去:
- roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv
文件的内容如下:
- int64 a
- int64 b
- ---
- int64 sum
同样,配置 package.xml 文件,确保 srv 文件会转换为源代码(前面已经完成)。
- <build_depend>message_generation</build_depend>
- <exec_depend>message_runtime</exec_depend>
配置 CMakeLists.txt 文件,处理依赖(前面已经完成):
- # Do not just add this line to your CMakeLists.txt, modify the existing line
- find_package(catkin REQUIRED COMPONENTS
- roscpp
- rospy
- std_msgs
- message_generation
- )
注册服务文件:
- add_service_files(
- FILES
- AddTwoInts.srv
- )
使用 rossrv
- # Usage
- # rossrv show <service type>
编译后运行例子:
- catkin_make
- rossrv show beginner_tutorials/AddTwoInts
输出:
- int64 a
- int64 b
- ---
- int64 sum
第 11 关卡:编写简单的发布者和订阅者(C++)
目标:用 C++ 编写发布者和订阅者。
编写发布者节点
进入目录:
- roscd beginner_tutorials
- mkdir src
创建 src/talker.cpp 文件:
- #include "ros/ros.h"
- #include "std_msgs/String.h"
- #include <sstream>
- /**
- * This tutorial demonstrates simple sending of messages over the ROS system.
- */
- int main(int argc, char **argv)
- {
- /**
- * The ros::init() function needs to see argc and argv so that it can perform
- * any ROS arguments and name remapping that were provided at the command line.
- * For programmatic remappings you can use a different version of init() which takes
- * remappings directly, but for most command-line programs, passing argc and argv is
- * the easiest way to do it. The third argument to init() is the name of the node.
- *
- * You must call one of the versions of ros::init() before using any other
- * part of the ROS system.
- */
- ros::init(argc, argv, "talker");
- /**
- * NodeHandle is the main access point to communications with the ROS system.
- * The first NodeHandle constructed will fully initialize this node, and the last
- * NodeHandle destructed will close down the node.
- */
- ros::NodeHandle n;
- /**
- * The advertise() function is how you tell ROS that you want to
- * publish on a given topic name. This invokes a call to the ROS
- * master node, which keeps a registry of who is publishing and who
- * is subscribing. After this advertise() call is made, the master
- * node will notify anyone who is trying to subscribe to this topic name,
- * and they will in turn negotiate a peer-to-peer connection with this
- * node. advertise() returns a Publisher object which allows you to
- * publish messages on that topic through a call to publish(). Once
- * all copies of the returned Publisher object are destroyed, the topic
- * will be automatically unadvertised.
- *
- * The second parameter to advertise() is the size of the message queue
- * used for publishing messages. If messages are published more quickly
- * than we can send them, the number here specifies how many messages to
- * buffer up before throwing some away.
- */
- ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", );
- ros::Rate loop_rate();
- /**
- * A count of how many messages we have sent. This is used to create
- * a unique string for each message.
- */
- int count = ;
- while (ros::ok())
- {
- /**
- * This is a message object. You stuff it with data, and then publish it.
- */
- std_msgs::String msg;
- std::stringstream ss;
- ss << "hello world " << count;
- msg.data = ss.str();
- ROS_INFO("%s", msg.data.c_str());
- /**
- * The publish() function is how you send messages. The parameter
- * is the message object. The type of this object must agree with the type
- * given as a template parameter to the advertise<>() call, as was done
- * in the constructor above.
- */
- chatter_pub.publish(msg);
- ros::spinOnce();
- loop_rate.sleep();
- ++count;
- }
- return ;
- }
该代码流程:
- 初始化 ROS 系统。
- 向 master 通知:以主题 chatter 发布 std_msgs/String 消息。
- 以 10 Hz 的频率进行消息发布。
编写订阅者节点
创建 listener.cpp 文件:
- #include "ros/ros.h"
- #include "std_msgs/String.h"
- /**
- * This tutorial demonstrates simple receipt of messages over the ROS system.
- */
- void chatterCallback(const std_msgs::String::ConstPtr& msg)
- {
- ROS_INFO("I heard: [%s]", msg->data.c_str());
- }
- int main(int argc, char **argv)
- {
- /**
- * The ros::init() function needs to see argc and argv so that it can perform
- * any ROS arguments and name remapping that were provided at the command line.
- * For programmatic remappings you can use a different version of init() which takes
- * remappings directly, but for most command-line programs, passing argc and argv is
- * the easiest way to do it. The third argument to init() is the name of the node.
- *
- * You must call one of the versions of ros::init() before using any other
- * part of the ROS system.
- */
- ros::init(argc, argv, "listener");
- /**
- * NodeHandle is the main access point to communications with the ROS system.
- * The first NodeHandle constructed will fully initialize this node, and the last
- * NodeHandle destructed will close down the node.
- */
- ros::NodeHandle n;
- /**
- * The subscribe() call is how you tell ROS that you want to receive messages
- * on a given topic. This invokes a call to the ROS
- * master node, which keeps a registry of who is publishing and who
- * is subscribing. Messages are passed to a callback function, here
- * called chatterCallback. subscribe() returns a Subscriber object that you
- * must hold on to until you want to unsubscribe. When all copies of the Subscriber
- * object go out of scope, this callback will automatically be unsubscribed from
- * this topic.
- *
- * The second parameter to the subscribe() function is the size of the message
- * queue. If messages are arriving faster than they are being processed, this
- * is the number of messages that will be buffered up before beginning to throw
- * away the oldest ones.
- */
- ros::Subscriber sub = n.subscribe("chatter", , chatterCallback);
- /**
- * ros::spin() will enter a loop, pumping callbacks. With this version, all
- * callbacks will be called from within this thread (the main one). ros::spin()
- * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
- */
- ros::spin();
- return ;
- }
该代码的流程:
- 初始化 ROS 系统。
- 订阅 chatter 主题。
- spin:等待消息到达。
- 当消息到达时,调用 chatterCallback()。
编译节点
确保 CMakeLists.txt 的配置:
- cmake_minimum_required(VERSION 2.8.3)
- project(beginner_tutorials)
- ## Find catkin and any catkin packages
- find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
- ## Declare ROS messages and services
- add_message_files(FILES Num.msg)
- add_service_files(FILES AddTwoInts.srv)
- ## Generate added messages and services
- generate_messages(DEPENDENCIES std_msgs)
- ## Declare a catkin package
- catkin_package()
- ## Build talker and listener
- include_directories(include ${catkin_INCLUDE_DIRS})
- add_executable(talker src/talker.cpp)
- target_link_libraries(talker ${catkin_LIBRARIES})
- add_dependencies(talker beginner_tutorials_generate_messages_cpp)
- add_executable(listener src/listener.cpp)
- target_link_libraries(listener ${catkin_LIBRARIES})
- add_dependencies(listener beginner_tutorials_generate_messages_cpp)
构建后会创建两个可执行文件 talker 和 listener,放在 ~/catkin_ws/devel/lib/<package name> 中。
在工作区上运行:
- catkin_make
第 12 关卡:编写简单的发布者和订阅者(Python)
目标:用 Python 编写发布者和订阅者。
编写发布者节点
进入目录:
- roscd beginner_tutorials
- mkdir scripts
- cd scripts
创建 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
编写订阅者节点
在 scripts 下面创建 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()
编译节点
注意需要运行的 Python 脚本必须修改成可执行文件,scripts 目录下:
- chmod +x talker.py
- chmod +x listener.py
工作区下面输入:
- catkin_make
第 13 关卡:运行检查简单的发布者和订阅者
目标:运行检查编写好的发布者和订阅者。
运行发布者
工作区下面,启动主节点:
- roscore
另开启一个终端激活环境:
- source devel/setup.bash
运行发布者:
- # C++
- rosrun beginner_tutorials talker
- # Python
- rosrun beginner_tutorials talker.py
不断输出:
- [INFO] [WallTime: 1314931831.774057] hello world 1314931831.77
- [INFO] [WallTime: 1314931832.775497] hello world 1314931832.77
- [INFO] [WallTime: 1314931833.778937] hello world 1314931833.78
- [INFO] [WallTime: 1314931834.782059] hello world 1314931834.78
- [INFO] [WallTime: 1314931835.784853] hello world 1314931835.78
- [INFO] [WallTime: 1314931836.788106] hello world 1314931836.79
在另一个终端用同样的方式运行订阅者:
- # C++
- rosrun beginner_tutorials listener
- # Python
- rosrun beginner_tutorials listener.py
不断输出:
- [INFO] [WallTime: 1314931969.258941] /listener_17657_1314931968795I heard hello world 1314931969.26
- [INFO] [WallTime: 1314931970.262246] /listener_17657_1314931968795I heard hello world 1314931970.26
- [INFO] [WallTime: 1314931971.266348] /listener_17657_1314931968795I heard hello world 1314931971.26
- [INFO] [WallTime: 1314931972.270429] /listener_17657_1314931968795I heard hello world 1314931972.27
- [INFO] [WallTime: 1314931973.274382] /listener_17657_1314931968795I heard hello world 1314931973.27
- [INFO] [WallTime: 1314931974.277694] /listener_17657_1314931968795I heard hello world 1314931974.28
- [INFO] [WallTime: 1314931975.283708] /listener_17657_1314931968795I heard hello world 1314931975.28
第 14 关卡:编写简单的服务器和客户端(C++)
目标:用 C++ 编写服务器和客户端节点。
编写服务器节点
在 beginner_tutorials/src 里编写 add_two_ints_server.cpp:
- #include "ros/ros.h"
- #include "beginner_tutorials/AddTwoInts.h"
- bool add(beginner_tutorials::AddTwoInts::Request &req,
- beginner_tutorials::AddTwoInts::Response &res)
- {
- res.sum = req.a + req.b;
- ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
- ROS_INFO("sending back response: [%ld]", (long int)res.sum);
- return true;
- }
- int main(int argc, char **argv)
- {
- ros::init(argc, argv, "add_two_ints_server");
- ros::NodeHandle n;
- ros::ServiceServer service = n.advertiseService("add_two_ints", add);
- ROS_INFO("Ready to add two ints.");
- ros::spin();
- return ;
- }
编写客户端节点
再创建 add_two_ints_client.cpp 文件:
- #include "ros/ros.h"
- #include "beginner_tutorials/AddTwoInts.h"
- #include <cstdlib>
- int main(int argc, char **argv)
- {
- ros::init(argc, argv, "add_two_ints_client");
- if (argc != )
- {
- ROS_INFO("usage: add_two_ints_client X Y");
- return ;
- }
- ros::NodeHandle n;
- ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
- beginner_tutorials::AddTwoInts srv;
- srv.request.a = atoll(argv[]);
- srv.request.b = atoll(argv[]);
- if (client.call(srv))
- {
- ROS_INFO("Sum: %ld", (long int)srv.response.sum);
- }
- else
- {
- ROS_ERROR("Failed to call service add_two_ints");
- return ;
- }
- return ;
- }
编译节点
在 beginner_tutorials 包中的 CMakeLists.txt 添加配置:
- add_executable(add_two_ints_server src/add_two_ints_server.cpp)
- target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
- add_dependencies(add_two_ints_server beginner_tutorials_gencpp)
- add_executable(add_two_ints_client src/add_two_ints_client.cpp)
- target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
- add_dependencies(add_two_ints_client beginner_tutorials_gencpp)
最后在工作区进行编译:
- # In your catkin workspace
- cd ~/catkin_ws
- catkin_make
第 15 关卡:编写简单的服务器和客户端(Python)
目标:用 Python 编写服务器和客户端节点。
编写服务器节点
在 beginner_tutorials/scripts 里编写 add_two_ints_server.py:
- #!/usr/bin/env python
- from beginner_tutorials.srv import AddTwoInts,AddTwoIntsResponse
- import rospy
- def handle_add_two_ints(req):
- print "Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))
- return AddTwoIntsResponse(req.a + req.b)
- def add_two_ints_server():
- rospy.init_node('add_two_ints_server')
- s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
- print "Ready to add two ints."
- rospy.spin()
- if __name__ == "__main__":
- add_two_ints_server()
使脚本可执行:
- chmod +x add_two_ints_server.py
编写客户端节点
再创建 add_two_ints_client.py 文件:
- #!/usr/bin/env python
- import sys
- import rospy
- from beginner_tutorials.srv import *
- def add_two_ints_client(x, y):
- rospy.wait_for_service('add_two_ints')
- try:
- add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
- resp1 = add_two_ints(x, y)
- return resp1.sum
- except rospy.ServiceException, e:
- print "Service call failed: %s"%e
- def usage():
- return "%s [x y]"%sys.argv[0]
- if __name__ == "__main__":
- if len(sys.argv) == 3:
- x = int(sys.argv[1])
- y = int(sys.argv[2])
- else:
- print usage()
- sys.exit(1)
- print "Requesting %s+%s"%(x, y)
- print "%s + %s = %s"%(x, y, add_two_ints_client(x, y))
使脚本可执行:
- chmod +x add_two_ints_client.py
最后编译一下即可。
第 16 关卡:运行检查简单的服务器和客户端
目标:运行检查编写好的服务器和客户端。
运行服务器
工作区下面,启动主节点:
- roscore
另开启一个终端激活环境:
- source devel/setup.bash
运行服务器:
- # C++
- rosrun beginner_tutorials add_two_ints_server
- # Python
- rosrun beginner_tutorials add_two_ints_server.py
输出:
- [ INFO] [1568949373.838082500]: Ready to add two ints.
运行客户端
运行客户端:
- # C++
- rosrun beginner_tutorials add_two_ints_client 1 3
- # Python
- rosrun beginner_tutorials add_two_ints_client.py 1 3
输出:
- [ INFO] [1568949401.094979600]: Sum: 4
第 17 关卡:录制和播放数据
目标:从运行的 ROS 系统上将数据录制为 .bag 文件;重新播放 .bag 文件上的数据。
录制数据
这里解决如何从运行的 ROS 系统中录制主题数据,主题数据最终会汇聚为一个 bag 文件。
下面执行我们前面已经熟悉了几个操作。
终端 1:
- roscore
终端 2:
- rosrun turtlesim turtlesim_node
终端 3:
- rosrun turtlesim turtle_teleop_key
查看当前运行系统中发布的主题列表:
- rostopic list -v
输出:
- Published topics:
- * /turtle1/color_sensor [turtlesim/Color] 1 publisher
- * /rosout [rosgraph_msgs/Log] 2 publishers
- * /rosout_agg [rosgraph_msgs/Log] 1 publisher
- * /turtle1/cmd_vel [geometry_msgs/Twist] 1 publisher
- * /turtle1/pose [turtlesim/Pose] 1 publisher
- Subscribed topics:
- * /turtle1/cmd_vel [geometry_msgs/Twist] 1 subscriber
- * /rosout [rosgraph_msgs/Log] 1 subscriber
其中,/turtle1/cmd_vel 是 teleop_turtle 发布的主题数据。
打开新终端,运行命令录制所有正在发布的主题数据(rosbag record):
- mkdir ~/bagfiles
- cd ~/bagfiles
- rosbag record -a
然后在 turtle_teleop 终端里面滑动方向键,移动乌龟十来秒,接着在最新的 rosbag record 命令的终端窗口下面终止进程。查看当前目录,可以发现已经生成了一个新的 bag 文件。
- 2019-09-19-17-55-44.bag
这个 bag 文件现在包含了所有 rosbag record 期间的所有节点发布的主题数据。
检查并播放 bag 文件
使用 rosbag info 检查 bag 文件信息:
- rosbag info -----.bag
输出:
- path: 2019-09-19-17-55-44.bag
- version: 2.0
- duration: 57.9s
- start: Sep 19 2019 17:55:44.60 (1568886944.60)
- end: Sep 19 2019 17:56:42.50 (1568887002.50)
- size: 413.4 KB
- messages: 5842
- compression: none [1/1 chunks]
- types: geometry_msgs/Twist [9f195f881246fdfa2798d1d3eebca84a]
- rosgraph_msgs/Log [acffd30cd6b6de30f120938c17c593fb]
- turtlesim/Color [353891e354491c51aabe32df673fb446]
- turtlesim/Pose [863b248d5016ca62ea2e895ae5265cf9]
- topics: /rosout 5 msgs : rosgraph_msgs/Log (2 connections)
- /turtle1/cmd_vel 105 msgs : geometry_msgs/Twist
- /turtle1/color_sensor 2869 msgs : turtlesim/Color
- /turtle1/pose 2863 msgs : turtlesim/Pose
接下来重播 bag 文件以生成 ROS 当时运行时的行为。
首先中断 teleop 程序,免得它一直发数据。而 turtlesim 继续运行。
接着运行命令:
- rosbag play <your bagfile>
进行播放,最后输出:
- [ INFO] [1568887897.273155900]: Opening 2019-09-19-17-55-44.bag
- Waiting 0.2 seconds after advertising topics... done.
- Hit space to toggle paused, or 's' to step.
- [RUNNING] Bag Time: 1568887002.474074 Duration: 57.874504 / 57.904033
- Done.
这个时候乌龟会继续按照之前记录好的套路动起来。
记录数据的子集
rosbag record 支持录制特定主题的数据。
- rosbag record -O subset /turtle1/cmd_vel /turtle1/pose
故技重施,生成了文件 subset.bag 文件。-O 指定了文件名,后面跟的两个参数制定了特定的主题。
- rosbag info subset.bag
输出:
- path: subset.bag
- version: 2.0
- duration: 38.1s
- start: Sep 19 2019 18:22:02.74 (1568888522.74)
- end: Sep 19 2019 18:22:40.83 (1568888560.83)
- size: 144.5 KB
- messages: 1787
- compression: none [1/1 chunks]
- types: geometry_msgs/Twist [9f195f881246fdfa2798d1d3eebca84a]
- turtlesim/Pose [863b248d5016ca62ea2e895ae5265cf9]
- topics: /turtle1/cmd_vel 72 msgs : geometry_msgs/Twist
- /turtle1/pose 1715 msgs : turtlesim/Pose
参考:
ROS官网新手级教程总结的更多相关文章
- Docker的官网在线--中文教程
1.官网界面:https://www.docker.com/tryit/ In this 10-minute tutorial, see how Docker works first-hand: Yo ...
- 官网下载CentOS教程(各版本)
1.进入官网,并点击下图所示的红框(alternative downloads) 官网网址:https://www.centos.org/download/ 2.在往下翻,可以看到如下图的历史版本, ...
- UiPath官网认证中文教程
RPA之家公众号:RPA之家 RPA之家官网:http://rpazj.com 斗鱼直播:http://www.douyu.com/rpazj UiPath中文社区QQ群:465630324 RPA& ...
- 翻译BonoboService官网的安装教程
This page covers simple Bonobo Git Server installation. Be sure to check prerequisites page before i ...
- [pytorch学习]2. 官网60分钟教程摘要
https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html 1. Pytorch的基本单元,tensor,本质上和num ...
- 从谷歌官网下载android 6.0源码、编译并刷入nexus 6p手机
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/fuchaosz/article/details/52473660 1 前言 经过一周的奋战,终于从谷 ...
- React 系列教程 1:实现 Animate.css 官网效果
前言 这是 React 系列教程的第一篇,我们将用 React 实现 Animate.css 官网的效果.对于 Animate.css 官网效果是一个非常简单的例子,原代码使用 jQuery 编写,就 ...
- 从CentOS官网下载系统镜像详细教程
很多新手小白鼠想学习CentOS系统,但是不知道镜像去哪里搞,随便去个第三方发现要么要注册,要么各种广告病毒,或者好不容易找到官网,点进去一看却一脸懵逼,不仅全英文,有些专业术语也不懂啊,不要担心 ...
- 超详细教程2021新版oracle官网下载Windows JAVA-jdk11并安装配置(其他版本流程相同)
异想之旅:本人博客完全手敲,绝对非搬运,全网不可能有重复:本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告.本人所有文章发布平台为CSDN.博客园.简书和开源中国,后期可能会有个人博客,除此之外 ...
随机推荐
- 数据结构——链队列(linked queue)
/* linkedQueue.c */ /* 链队列 */ #include <stdio.h> #include <stdlib.h> #include <stdboo ...
- __str__与__repr__的触发顺序总结
1.__str__是个内置的方法,无需使用者去调用,其会在满足某一条件时自动触发.那么要触发它运行都有哪些条件呢? 有三种条件,分别为:print , str , %s 2.__repr__同样是个内 ...
- Linux基于FPM制作RPM包(以Nginx为例)
1.搭建Epel Yum源 安装在线yum源 [root@localhost ~]# rpm -ivh epel-release-latest-.noarch.rpm //安装扩展源 [root@ ...
- Educational Codeforces Round 57 (Rated for Div. 2) D dp
https://codeforces.com/contest/1096/problem/D 题意 给一个串s,删掉一个字符的代价为a[i],问使得s的子串不含"hard"的最小代价 ...
- python脚本生成exe程序
去年十一月换了新公司后,一直没闲着,马不停蹄地接不同的需求,一个版本一个版本的迭代,也没时间研究python了.十一休假归来,某日,老婆问金融量化需要学python吗?并分享了一个公众号文章,内容是吹 ...
- 第五次实验报告:使用Packet Tracer理解OSPF路由协议
目录 1 实验目的 2 实验内容 3. 实验报告 3.1 建立网络拓扑结构 4. 配置 4.1 配置并激活串行地址和以太网地址 4.1.1 R1 4.1.2 R2 4.1.3 R3 4.1.4 PC ...
- FontForge 汉化教程
引用 :http://www.sucaijishi.com/2018/articles_0815/258.html FontForge是一款免费字库编辑工具,官方暂不提供简体中文,本文汉化方法在201 ...
- xcode打包签名访问失败errSecInternalComponent
错误信息 /Users/xxxx/Library/Developer/Xcode/DerivedData/Unity-iPhone-bzwyypshqjwshtbpohwldjmqkstx/Build ...
- SpringBoot第七篇:整合Mybatis-Plus
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10881666.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 一看这个名 ...
- IOS手机 html5页面 数字变成蓝色链接的原因
IOS手机 html5页面 数字变成蓝色链接的原因 这个是ios手机自动识别 写如下代码 即可<pre> <meta name="format-detection" ...