ROS初学 Acemyzoe

ROS

wiki

wiki_cn

提供了操作系统应有的服务,包括硬件抽象,底层设备控制,常用函数的实现,进程间消息传递,以及包管理。

提供用于获取、编译、编写、和跨计算机运行代码所需的工具和库函数。

ROS是围绕着基于驱动传感器(倾斜式激光,盘式/斜试头部传感器,机械臂传感器)的复杂移动处理平台设计的

“graph”:图概念,基于ROS通信基础结构的松耦合点对点进程网络

  • nodes:节点是使用ROS与其他节点通信的可执行文件。
  • msg:订阅或发布主题时使用的ROS数据类型。
  • topics:节点可以将消息发布到主题,也可以订阅主题以接收消息。
  • master:ROS的名称服务(即帮助节点相互查找)
  • rosout:该节点等效于stdout / stderr,收集并记录节点的调试输出
  • roscore:Master + rosout +参数服务器(参数服务器将在以后介绍)

通信方式

ROS Client Libraries

rospy

rospy是ROS的纯Python客户端库,旨在为ROS提供面向对象的脚本语言的优点。rospy的设计优先于实现速度(即开发人员时间)而不是运行时性能,以便可以在ROS中快速对算法进行原型设计和测试。对于非关键路径代码(例如配置和初始化代码),它也是理想的选择。许多ROS工具都是用rospy编写的,以利用类型自省功能。ROS Master,roslaunch和其他ros工具是用rospy开发的,因此Python是ROS的核心依赖项。

ROS 2 developer guide

ROS-Tutorials

Thew new build system for ROS is “catkin”

浏览ros文件系统

sudo apt-get install ros-noetic-ros-tutorials # 轻量级模拟器,ros版本Noetic
# packages : 每个软件包可以包含库,可执行文件,脚本或其他工件
# package.xml : 清单用于定义软件包之间的依赖关系并捕获有关软件包的元信息

# rospack获取有关软件包的信息
rospack find [package_name]
rospack find roscpp # > /opt/ros/kinetic/share/roscpp
# roscd
roscd [locationname[/subdir]]
roscd log # 日志
echo $ ROS_PACKAGE_PATH  # >环境变量 /opt/ros/kinetic/base/install/share
# rosls
rosls roscpp_tutorials # cmake launch package.xml srv

创建ros包

# package结构
my_package /
  CMakeLists.txt
  package.xml #软件包清单
# catkin workspace
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
sudo apt-get install ros-noetic-catkin
source /opt/ros/noetic/setup.bash
# 创建工作区
mkdir -p〜/catkin_ws/src
# Creating a catkin Package
cd〜/ catkin_ws/src
# 创建名为“ beginner_tutorials”的新程序包,取决于std_msgs,roscpp和rospy:
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
# 构建软件包
cd〜/catkin_ws
catkin_make # 生成CMakeLists.txt
. ~/catkin_ws/devel/setup.bash # 将工作空间添加到您的ROS环境

# 查看一阶依赖,依赖同样保存在package.xml
rospack depends1 beginner_tutorials 
roscd beginner_tutorials
cat package.xml
# 递归确定所有嵌套的依赖项
rospack depends beginner_tutorials
<!-- package.xml -->
<!-- 注释 -->
<?xml version="1.0"?>
<package format="2">
  <name>beginner_tutorials</name>
  <version>0.1.0</version>
  <description>描述标签</description>

  <maintainer email="you@yourdomain.tld">Your Name</maintainer>
  <license>BSD</license>
  <url type="website">http://wiki.ros.org/beginner_tutorials</url>
  <author email="you@yourdomain.tld">Jane Doe</author>

  <buildtool_depend>catkin</buildtool_depend>

  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
    
<!-- 添加一个exec_depend标记,构建和运行时都可用 -->
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

</package>

构建ros包

# 设置环境变量
source /opt/ros/noetic/setup.bash

# catkin_make在标准CMake工作流程中结合了对cmake和make的调用。
# In a CMake project # 标准CMake工作流程
mkdir build
cd build
cmake ..
make
make install  # (optionally)
# In a catkin workspace
catkin_make # 构建在src文件夹中找到的所有catkin项目
catkin_make --source my_src # 自定src位置
catkin_make install  # (optionally)

ls # >build,devel,src

ros node

# 使用ros运行第一步
roscore
# ros未初始化,修改网络配置
# 修改权限
sudo chown -R <your_username> ~/.ros

# new terminal
rosnode list # > /rosout
rosnode info /rosout
# new node
rosrun [软件包名称] [节点名称]
rosrun turtlesim turtlesim_node
rosnode cleanup # 清理node
rosrun turtlesim turtlesim_node __name:= my_turtle # 自定名称
rosnode ping my_turtle # ping来测试它是否启动

ros topics

roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key # 键盘操纵小乌龟
# turtlesim_node和turtle_teleop_key节点彼此通过topics通信。
# turtle_teleop_key正在发布(publish)主题的按键,而turtlesim订阅(subscribes)同一主题以接收这些按键

# rqt_graph创建有关系统中发生的情况的动态图
rosrun rqt_graph rqt_graph 
# turtlesim_node和turtle_teleop_key节点在名为/turtle1/command_velocity的主题上进行通信

rostopic -h
rostopic bw     # display bandwidth used by topic 带宽
rostopic echo   # print messages to screen 
rostopic hz     # display publishing rate of topic 显示主题的发布率    
rostopic list   # print information about active topics
rostopic pub    # publish data to topic 将数据发布到主题
rostopic type   # print topic type
rostopic echo /turtle1/cmd_vel # 显示turtle_teleop_key节点发布的命令速度数据

rostopic list -h
# ros messages : 通过在节点之间发送ROS消息来进行主题交流
rostopic type [topic] # 返回主题的消息类型
rostopic type /turtle1/cmd_vel # > geometry_msgs/Twist
rosmsg show geometry_msgs/Twist
rostopic type /turtle1/cmd_vel | rosmsg show # 一起使用
# rostopic pub
rostopic pub [topic] [msg_type] [args]
# 让小乌龟以线速度2.0和角速度1.8移动
rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
# 参数是YAML语法:[YAML command line documentation](http://wiki.ros.org/ROS/YAMLCommandLine).
# 乌龟需要1 Hz的稳定命令流才能继续移动
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
# new terminal
rostopic echo /turtle1/pose
rostopic hz /turtle1/pose
# rqt_plot显示有关主题发布的数据的滚动时间图
rosrun rqt_plot rqt_plot
#  /turtle1/pose/x; /turtle1/pose/y; /turtle1/pose/theta 

ros services & parameters

# 服务允许节点发送请求并接收响应
rosservice list         # print information about active services
rosservice call [service] [args] # call the service with the provided args 使用提供的参数调用服务
rosservice type         # print service type
rosservice find         # find services by service type
rosservice uri          # print service ROSRPC uri

rosservice list
# turtlesim提供的服务:
/clear
/kill
/reset
/spawn
...

rosservice type /clear # > std_srvs/Empty 服务调用时不接受任何参数
rosservice call /clear # 调用该服务

rosservice type /spawn | rossrv show # 通过查看服务产生的信息来查看服务具有参数
'''
float32 x
float32 y
float32 theta
string name
---
string name
'''
rosservice call /spawn 2 2 0.2 ""    # > name: turtle2

# rosparam允许您在ROS参数服务器上存储和处理数据
# 参数服务器可以存储整数,浮点数,布尔值,字典和列表
# YAML标记语言用于语法
# YAML: 1是整数,1.0是浮点数,一个是字符串,true是布尔值,[1、2、3]是整数列表,并且{a:b,c: d}是字典。
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

rosparam get /  # 展示整个Parameter Server的内容
rosparam set /turtlesim/background_r 150 # 改变背景颜色RGB
rosservice call /clear # 调用清除服务以使参数更改生效
rosparam dump params.yaml
rosparam load params.yaml copy_turtle

rqt_console & roslaunch

sudo apt-get install ros-noetic-rqt ros-noetic-rqt-common-plugins ros-noetic-turtlesim
# rqt_console附加到ROS的日志记录框架以显示节点的输出
rosrun rqt_console rqt_console
# rqt_logger_level允许我们在节点运行时更改日志记录级别(Fatal、Error、Warn、Info、Debug)
rosrun rqt_logger_level rqt_logger_level
rosrun turtlesim turtlesim_node
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.0}}'

# roslaunch 按照启动文件中的定义启动节点
# roslaunch [package] [filename.launch]
roscd beginner_tutorials
mkdir launch
cd launch

turtlemimic.launch

<launch>

  <group ns="turtlesim1">	<!-- 命名空间标签 -->
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>	<!--名为sim的turtlesim节点-->
  </group>

  <group ns="turtlesim2">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <node pkg="turtlesim" name="mimic" type="mimic">  <!--mimic 模仿-->
    <remap from="input" to="turtlesim1/turtle1"/>	<!--重映射使turtlesim2模仿turtlesim1-->
    <remap from="output" to="turtlesim2/turtle1"/>
  </node>

</launch>
# 启动两个turtlesim
roslaunch beginner_tutorials turtlemimic.launch
# 发布命令发送到turtlesim1,turtlesims2也移动
rostopic pub / turtlesim1 / turtle1 / cmd_vel geometry_msgs / Twist -r 1-'[2.0,0.0,0.0]''[0.0,0.0,-1.8]'
rqt_graph

rosed

# 通过使用包名称直接编辑包中的文件
rosed [package_name] [filename]
rosed roscpp Logger.msg # 使用vim
export EDITOR='nano -w' # 修改编辑器
rosed roscpp <tab><tab> # 查看和选择编辑程序包中的所有文件

rosmsg & rossrv

  • msg:msg文件是描述ROS消息字段的简单文本文件。它们用于为不同语言的消息生成源代码。
  • srv:srv文件描述服务。它由两部分组成:请求和响应。
  • Header:标头包含时间戳和ROS中常用的坐标帧信息。
# msg示例
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist

# srv示例
int64 A
int64 B
---
int64 Sum

rosmsg

roscd beginner_tutorials
mkdir msg
echo "int64 num" > msg/Num.msg

package.xml:在构建时,我们需要“ message_generation”,而在运行时,我们仅需要“ message_runtime”。

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

CMakeLists.txt:将message_generation依赖项添加到CMakeLists.txt中已经存在的find_package调用中,以便可以生成消息。

# Do not just add this to your CMakeLists.txt, modify the existing text to add message_generation before the closing parenthesis
find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)
#确保导出消息运行时依赖项
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...)
# 通过手动添加.msg文件,我们确保在添加其他.msg文件之后CMake知道何时需要重新配置项目。  
add_message_files(
  FILES
  Num.msg
)
generate_messages(
  DEPENDENCIES
  std_msgs
)
 rosmsg show beginner_tutorials/Num # > int64 num
 rosmsg show Num # > [beginner_tutorials/Num]:int64 num

rossrc

roscd beginner_tutorials
mkdir srv
# roscp用于将文件从一个软件包复制到另一个软件包
roscp [package_name] [file_to_copy_path] [copy_path]
roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv

修改CMakeLists.txt

find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
) 
add_service_files(
  FILES
  AddTwoInts.srv
)

rossrv show beginner_tutorials/AddTwoInts
rossrv show AddTwoInts
# 再次制作软件包,msg目录中的任何.msg文件都将生成用于所有受支持语言的代码。
# In your catkin workspace
roscd beginner_tutorials
cd ../..
catkin_make
cd -

编写简单的发布者和订阅者(Python)

# Writing the Publisher Node,该节点将不断广播消息
roscd beginner_tutorials
mkdir scripts
cd scripts
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
chmod + x talker.py
rosed beginner_tutorials talker.py # show the code
#!/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) # 告诉rospy节点的名称,之后它与Master进行通信
    rate = rospy.Rate(10) # 10hz,借助其方法sleep(),每秒10次循环
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str) # 将消息打印到屏幕上,将消息写入Node的日志文件,并将消息写入rosout。
        pub.publish(hello_str)
        rate.sleep()

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

CMakeLists.txt:确保正确安装了python脚本,并使用了正确的python解释器

catkin_install_python(PROGRAMS scripts/talker.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
# Writing the Subscriber Node
roscd beginner_tutorials/scripts/
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py
chmod +x 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()

CMakeLists.txt

catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
# use CMake building nodes
cd〜/ catkin_ws
catkin_make
# 运行检查
roscore
cd ~/catkin_ws
source ./devel/setup.bash
# Running the Publisher
rosrun beginner_tutorials talker.py
# Running the Subscriber
rosrun beginner_tutorials listener.py

编写简单的服务和客户端(Python)

#Create the scripts/add_two_ints_server.py
#!/usr/bin/env python

from __future__ import print_function

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') # 声明节点
    # 声明服务add_two_ints、服务类型AddTwoInts、请求传递给handle_add_two_ints
    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()
#Create the scripts/add_two_ints_client.py
#!/usr/bin/env python

from __future__ import print_function

import sys
import rospy
from beginner_tutorials.srv import *

def add_two_ints_client(x, y):
    rospy.wait_for_service('add_two_ints') # 阻塞直到名为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 as 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)))

# rosrun beginner_tutorials add_two_ints_server.py
# rosrun beginner_tutorials add_two_ints_client.py 1 3

记录&回放数据(.bag)

# 记录所有已发布的主题
mkdir ~/bagfiles
cd ~/bagfiles
rosbag record -a 
# 检查目录〜/ bagfiles的内容(.bag文件)
rosbag info <your bagfile> # 查看
rosbag play <your bagfile> # 运行
# 记录指定主题至subset.bag
rosbag record -O subset /turtle1/cmd_vel /turtle1/pose

# 从bag文件中读取消息
wget https://open-source-webviz-ui.s3.amazonaws.com/demo.bag
time rosbag info demo.bag # time记录命令时间
time rosbag info mybag.bag | grep -E "(topic1|topic2|topic3)" # 指定主题

roscore # In terminal 1
rostopic echo /obs1/gps/fix | tee topic1.yaml # In terminal 2
rostopic echo /diagnostics_agg | tee topic2.yaml # In terminal 3
# --immediate 即刻运行demo.bag
time rosbag play --immediate demo.bag --topics /obs1/gps/fix /diagnostics_agg	
# 使用ros_readbagfile脚本轻松提取感兴趣的主题
# rosbag仅在Python2中运行,而不在Python3中运行??
# Download the file
wget https://raw.githubusercontent.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/master/useful_scripts/ros_readbagfile.py
# Make it executable
chmod +x ros_readbagfile.py
# Ensure you have the ~/bin directory for personal binaries
mkdir -p ~/bin
# Move this executable script into that directory as `ros_readbagfile`, so that it will
# be available as that command
mv ros_readbagfile.py ~/bin/ros_readbagfile
# Re-source your ~/.bashrc file to ensure ~/bin is in your PATH, so you can use this
# new `ros_readbagfile` command you just installed
. ~/.bashrc
rosbag info demo.bag # 确定要从bag文件中读取的主题名称
time ros_readbagfile demo.bag /obs1/gps/fix /diagnostics_agg | tee topics.yaml

roswtf

# 检查roscore是否仍在运行
ps -ef | grep -i rosmaster
roscd rosmaster
roswtf # 检查您的系统以尝试发现问题