ROS
提供了操作系统应有的服务,包括硬件抽象,底层设备控制,常用函数的实现,进程间消息传递,以及包管理。
提供用于获取、编译、编写、和跨计算机运行代码所需的工具和库函数。
ROS是围绕着基于驱动传感器(倾斜式激光,盘式/斜试头部传感器,机械臂传感器)的复杂移动处理平台设计的
“graph”:图概念,基于ROS通信基础结构的松耦合点对点进程网络
- nodes:节点是使用ROS与其他节点通信的可执行文件。
- msg:订阅或发布主题时使用的ROS数据类型。
- topics:节点可以将消息发布到主题,也可以订阅主题以接收消息。
- master:ROS的名称服务(即帮助节点相互查找)
- rosout:该节点等效于stdout / stderr,收集并记录节点的调试输出
- roscore:Master + rosout +参数服务器(参数服务器将在以后介绍)
通信方式:
- 基于同步RPC样式通信的服务(services)机制
- 基于异步流媒体数据的话题(topics)机制
- 用于数据存储的参数服务器(Parameter Server)
ROS Client Libraries
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 # 检查您的系统以尝试发现问题