重要说明:本文从网上资料整理而来,仅记录博主学习相关知识点的过程,侵删。
一、参考资料
ROS相关技术介绍,可参考之前的文章:ROS相关技术(概念版)
Autolabor主站
ROS官网
ROS
ROS教程
ROS编程技术
ROS书籍整理:机器人操作系统 ROS 相关书籍整理合集 [古月居推荐]
二、ROS相关介绍
ROS与Apollo对比
Apollo可以看作是ROS的改进版,Apollo从通信功能优化、去中心化网络拓扑以及数据兼容性扩展三个方面做了定制化的改进。
单对多的传输场景下,ROS 在处理一对多的消息传输时,底层实现实际是多个点对点的连接,当把一份数据要发给三个节点时,相同的数据会传输三次,这会造成很大的资源浪费。而Apollo采用了共享内存的解决方案,减少传输过程中的数据拷贝,大幅度提升效率。
ROS系统非常依赖Master,一旦Master出现异常,将导致整个系统崩溃,且缺乏恢复自动机制。Apollo的整个网络拓扑不再以 master 为中心构建,当一个新的节点加入网络时,会通过 RTPS 协议向域内的所有其他节点发送广播信息,各个节点也会将自己的服务信息发送给新的节点,以代替 Master 的信息交换功能。
ROS 系统为了保证收发双方的消息格式一致,会对message定义做 MD5 校验,任何字段的增减或顺序调整都会使 MD5 变化。然而这种严格的限制也引起了兼容性的问题,OTA升级后可能出现兼容问题,在Apollo中,做了一整套对protobuf的支持, 在工程中可以不需要做格式转换,直接publish protobuf格式的消息,调试工具也能够非常正确的解析出来正确的protobuf消息。这样既能够很好解决兼容性问题,也不会产生额外的学习成本和使用成本。
三、常用指令
ROS笔记(2)——ROS的基本命令
roscore
功能描述:用于启动ROS系统的核心功能。
启动roscore是ROS系统的先决条件,必须运行roscore才能使ROS节点进行通信。
启动roscore将:
- 启动ROS Master节点;
- ros参数服务器;
- rosout日志节点;
ROS Master节点是ROS系统中的核心管理节点,负责管理所有节点之间的通信,包括节点的发现、消息的路由、参数服务器等。当执行 roscore
指令时,ROS Master节点将在计算机上启动,并将等待其他节点连接。只有在启动 roscore
之后,才能启动其他节点,并进行ROS操作。因此,通常在开始进行任何ROS项目之前,第一步是启动 roscore
。
rosrun
功能描述:启动ROS包中的节点。
# 启动小海龟节点用于演示机器人控制
rosrun turtlesim turtlesim_node
rosnode
rosnode
功能描述:用于获取节点信息。
# 测试节点的连接状态
rosnode ping
# 列出活动的节点
rosnode list
# 打印节点信息
rosnode info
# 列出指定设备上的节点
rosnode machine
# 杀死节点
rosnode kill
# 清除不可连接的节点
# ctrl+c并没有清除节点,需要用cleanup彻底清除
rosnode cleanup
roslaunch
功能描述:执行功能包的launch文件。
roslaunch <package_name> <launch文件名>
rostopic
功能描述:用于显示有关ROS 话题的调试信息,包括发布者,订阅者,发布频率和ROS消息。
# 显示话题使用的带框
rostopic bw
# 显示带有header的话题延迟
rostopic delay
# 打印话题的消息到屏幕
rostopic echo
# 根据消息类型查找话题
rostopic find
# 显示话题的发布频率
rostopic hz
# 显示话题的相关信息
rostopic info
# 显示所有活动状态下的话题
rostopic list -v
# 将数据发布到话题
rostopic pub </topic_name> <message_type> <message_content>
# 以10HZ的频率发送信息
rostopic pub -r 10 </topic_name> <message_type> <message_content>
# 打印话题的消息类型
rostopic type
rosmsg
rosmsg
功能描述:显示有关 ROS消息类型的信息。
# 显示消息描述
rosmsg show <message_type>
# 显示消息信息
rosmsg info
# 列出所有消息
rosmsg list
# 显示md5加密后的消息
rosmsg hd5
# 显示某个功能包下的所有消息
rosmsg package <package_name>
# 列出包含消息的所有包
rosmsg packages
rosservice
rosservice
功能描述:用于列出和查询ROS服务。
# 打印服务参数
rosservice args </service_name>
# 按照服务类型查找服务
rosservice find <servervice_name>
# 打印指定服务的信息
rosservice info
# 列出所有活动的服务
rosservice list
# 打印服务的类型
rosservice type
# 打印服务的ROSRPC uri
rosservice uri
# 调用指定服务
rosservice call </service_name>
rosparam
功能描述:用于管理ROS参数。
# 设置指定参数的值
rosparam set param_name value
rosbag指令
rosbag详解
rosbag是ROS中的一种数据记录工具,它可以记录和回放ROS的消息数据。我们可以使用rosbag来记录ROS系统中的消息流,包括传感器数据、机器人状态等信息,然后在之后的时间点上回放这些消息数据,以便我们进行离线分析和调试。
rosbag可以将消息数据存储在文件中,并使用一种高效的压缩算法来减少文件大小。这样,我们可以在之后的时间点上使用rosbag回放工具来重新播放这些消息,以便我们在没有实际硬件的情况下进行测试和调试。rosbag还支持多个包(bag)之间的合并和分割,以便我们更好地管理消息数据。
rosbag常用指令
record
:用指定的话题录制一个 bag 包;info
:显示一个 bag 包的基本信息,比如包含哪些话题;play
:回放一个或者多个 bag 包;reindex
:重新索引一个或多个损坏 bag 包。
记录bag
rosbag record 是一个用于记录 ROS 消息到 ROS Bag 文件中的命令行工具。它可以记录指定主题的消息,将消息保存到一个ROS Bag文件中。例如,以下命令将记录名为/scan
的激光雷达数据并将其保存到名为scan.bag
的文件中:
rosbag record /scan -O scan.bag
以下是 rosbag record 命令的常用参数:
-a, --all
:记录所有主题。-O, --output-name
:指定输出的 ROS Bag 文件名。-b, --buffer-size
:设置ROS Bag文件的缓冲区大小。-d, --duration
:设置记录时间长度,以秒为单位。-l, --limit
:设置记录的消息数量限制。-j, --bz2
:使用bzip2压缩来压缩ROS Bag文件。-z, --lz4
:使用LZ4压缩来压缩ROS Bag文件。-p, --split
:设置ROS Bag文件的分段大小。-t, --topics
:指定要记录的主题列表。-x, --exclude
:指定要排除的主题列表。
# 录制所有话题数据
rosbag record -a
# 录制指定话题数据
rosbag record <topic_name1> <topic_name2> <topic_name3> ...
# 指定数据包名称
rosbag record -O <bagname> <topic_name1> <topic_name2> <topic_name3> ...
查看bag信息
rosbag info指令可以数据包中包含的话题名称,话题数量,话题消息类型等信息。
rosbag info <bagname>
播放bag
使用 rosbag play
指令可以从指定的ROS包文件中回放消息数据。
# 回放指定bag
rosbag play <bagname>
# 回放当前目录下所有bag
rosbag play *
# 从指定时间(n = 指定时间s)开始回放bag
rosbag play -s n <bagname>
# 延时指定时间(n = 延时时间s)开始回放bag
rosbag play -d n <bagname>
# 播放指定时间(n = 指定秒数)的bag
rosbag play -u n <bagname>
# 从指定时间(n = 开始时间s)开始播放指定时间(m = 指定播放时间s)的bag
rosbag play -s n -u m <bagname>
# 按指定倍率(n = 倍率)回放bag
rosbag play -r n <bagname>
修复bag
回放不成功,提示 reindex ,修复bag。
rosbag reindex
rqt_graph
ROS计算图
ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程。rqt_graph能够创建一个显示当前系统运行情况的动态图形。
# 安装rqt_graph
# <distro>是ROS的版本,例如:kinetic、melodic、Noetic等
sudo apt install ros-<distro>-rqt
sudo apt install ros-<distro>-rqt-common-plugins
# 启动rqt_graph
rosrun rqt_graph rqt_graph
四、机器人系统建模与仿真
ROS学习笔记16:机器人系统建模与仿真
1. 机器人系统仿真
机器人系统仿真是通过计算机对实体机器人系统进行模拟的技术。在ROS中,仿真实现涉及的内容主要有三:对机器人建模(URDF)、创建仿真环境(Gazebo)以及感知环境(Rviz)等系统性实现。
2. 机器人系统仿真所需组件
2.1 创建机器人模型(URDF)
URDF (Unified Robot Description Format,统一(标准化)机器人描述格式),以XML的方式描述机器人的部分结构,比如地盘、摄像头、激光雷达、机械臂以及不同关节的自由度,该文件可以被C++内置的解释器转换成可视化的机器人模型,是ROS中实现机器人仿真的重要组件。
2.2 显示各种传感器信息(rviz)
rviz(ROS Visualization Tool,ROS的三维可视化工具),它的主要目的是以三维方式显示ROS信息,可以将数据进行可视化表达。例如,可以显示机器人模型,可以无需编程就能表达激光测距仪(LRF)传感器中的传感器到障碍物的距离,Kinect或Xtion等三维距离传感器的点云数据(PCD,Point Cloud Data),从相机获取的图象值等。
2.3 搭建仿真环境(Gazebo)
Gazebo是一款3D动态模拟器,用于显示机器人模型并创建仿真环境,能够在复杂的室内和室外环境中准确有效地模拟机器人。与游戏引擎提供高保真度的视觉模拟类似,Gazebo提供高保真度的物理模拟,其提供一整套传感器模型,以及用户和程序非常友好的交互方式。
五、ROS Bag
ROS笔记(5)——Bag包概述与解析
ROS Bag是一种文件格式,用于存储ROS系统中的消息。ROS Bag可以将ROS节点发布的消息记录下来,然后在需要的时候将这些消息再次播放回ROS系统中。
1. ROS Bag适用场景
- 离线数据处理:在无法连接实时ROS系统时,可以使用ROS Bag记录消息,然后在离线状态下进行数据处理和算法开发;
- 数据集手机:ROS Bag可以用于收集数据集,以用于机器学习和深度学习等应用;
- 调试和测试:ROS Bag可以用于调试和测试ROS节点和程序的行为。
2. 生成ROS Bag文件的方式
ROS Bag文件以 .bag
拓展名结尾,可以通过以下两种方式保存:
rosbag
方式。在终端中使用rosbag record
命令来记录指定主题的消息,将消息保存到ROS Bag文件中。- ROS API方式。在ROS程序中使用ROS API来记录消息,将消息保存到ROS Bag文件中。
2.1 rosbag
方式
rosbag
方式,参见rosbag指令。
2.2 ROS API方式
以下代码段将记录名为/scan
的激光雷达数据并将其保存到名为scan.bag
的文件中。
C++代码示例
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
#include <rosbag/bag.h>
void scanCallback(const sensor_msgs::LaserScan::ConstPtr& msg)
{
static rosbag::Bag bag;
if (!bag.isOpen()) {
bag.open("scan.bag", rosbag::bagmode::Write);
}
bag.write("/scan", ros::Time::now(), *msg);
/*
当程序退出时,ROS Bag 的析构函数会自动关闭文件。
如果您想手动关闭文件,可以在程序退出前显式地删除ROS Bag对象或调用rosbag::Bag::close()方法来关闭
文件。
*/
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "scan_logger");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe<sensor_msgs::LaserScan>("/scan", 1, scanCallback);
ros::spin();
return 0;
}
python代码示例
#!/usr/bin/env python
import rospy
import rosbag
from sensor_msgs.msg import LaserScan
def scanCallback(msg):
global bag
if bag is None:
bag = rosbag.Bag('scan.bag', 'w')
bag.write('/scan', msg)
if __name__ == '__main__':
rospy.init_node('scan_logger')
bag = None
sub = rospy.Subscriber('/scan', LaserScan, scanCallback)
rospy.spin()
bag.close()
3. 解析ROS Bag文件
rosbag::View
是ROS Bag文件中的一组消息的视图,它提供了一些方便的方法来遍历和访问这些消息。
rosbag::View
实际上是一个包含 rosbag::Connection
对象的集合,每个对象代表一个主题。rosbag::Connection
对象包含一组时间戳和消息,表示该主题的所有消息。您可以使用以下方法来访问这些消息:
begin()
:返回指向第一条消息的迭代器。end()
:返回指向最后一条消息后面的位置的迭代器。rbegin()
:返回指向最后一条消息的迭代器。rend()
:返回指向第一条消息前面的位置的迭代器。size()
:返回视图中消息的数量。
在使用 rosbag::View
遍历Bag文件中的所有消息时,每个迭代器会返回一个 rosbag::MessageInstance
对象。这个对象包含了消息的时间戳、消息类型和消息数据等信息。可以使用以下方法来访问这些信息:
getTime()
:返回消息的时间戳。getTopic()
:返回消息所属的主题名称。getDataType()
:返回消息的数据类型。instantiate()
:将消息实例化为指定的数据类型。如果无法实`例化,则返回空指针。
3.1 C++代码示例
#include <ros/ros.h>
#include <rosbag/bag.h>
#include <std_msgs/String.h>
int main(int argc, char** argv) {
// 初始化ROS节点
ros::init(argc, argv, "rosbag_parser");
ros::NodeHandle n;
// 打开bag文件
rosbag::Bag bag;
bag.open("/path/to/bagfile.bag", rosbag::bagmode::Read);
// 遍历bag文件中的所有消息
rosbag::View view(bag);
for (rosbag::MessageInstance const m : view) {
std_msgs::String::ConstPtr msg = m.instantiate<std_msgs::String>();
if (msg != nullptr && m.getTopic() == "/my_topic") {
// 打印消息内容
ROS_INFO("Message: %s", msg->data.c_str());
}
}
// 关闭bag文件
bag.close();
return 0;
}
3.2 python代码示例
import rosbag
import rospy
from std_msgs.msg import String
# 初始化ROS节点
rospy.init_node('rosbag_parser')
# 打开bag文件
bag = rosbag.Bag('/path/to/bagfile.bag')
# 遍历bag文件中的所有消息
for topic, msg, t in bag.read_messages():
# 检查消息类型和主题名称
if topic == '/my_topic' and isinstance(msg, String):
# 打印消息内容
rospy.loginfo("Message: %s", msg.data)
# 关闭bag文件
bag.close()
在这个示例中,我们使用了ROS提供的rospy.loginfo
函数来输出消息,它类似于Python的print
函数,但是它会将消息输出到ROS的日志系统,这有助于调试和记录机器人的运行情况。
python执行
rosrun <package_name> <filename.py>
3.3 C++与Python接口对比
C++与Python 解析ROS Bag文件两种方式的对比。
- Python 中使用
rosbag.Bag
读取 Bag 文件,C++ 中使用rosbag::Bag
。 - Python 中使用
bag.read_messages()
方法遍历 Bag 文件中的消息,C++ 中使用rosbag::View
类和 C++11 的范围 for 循环来遍历消息。 - Python 中的 t 变量表示消息的时间戳,C++ 中使用
rosbag::MessageInstance::getTime()
方法来获取消息的时间戳。 - Python 中使用 msg 变量来存储消息的内容,C++ 中使用
rosbag::MessageInstance::instantiate()
方法将消息实例化为指定的数据类型,如果无法实例化,则返回空指针。 - Python 中使用 topic 变量来表示消息所属的主题,C++ 中使用
rosbag::MessageInstance::getTopic()
方法来获取消息所属的主题名称。 - Python 中使用
rospy.loginfo()
函数来输出消息,C++ 中可以使用 ROS 的日志系统来输出消息,例如使用 ROS_INFO 宏来输出消息。
使用 C++ 代码来解析 ROS Bag 文件,大致流程如下:
- 打开 Bag 文件并创建
rosbag::Bag()
对象。 - 创建
rosbag::View()
对象并遍历 Bag 文件中的消息。 - 对于每条消息,使用
rosbag::MessageInstance::instantiate()
方法将消息实例化为指定的数据类型,并使用rosbag::MessageInstance::getTopic()
方法获取消息所属的主题名称和rosbag::MessageInstance::getTime()
方法获取消息的时间戳。 - 对于符合条件的消息,使用 ROS 的日志系统或其他方式输出消息内容。
- 关闭 Bag 文件。
六、ROS相关经验
1. ROS Melodic
待补充。
2. D435i相机标定
D435i相机标定(不同标定方法总结)
深度相机D435i
Realsense d435i内参、外参标定
Realsense d435i驱动安装、配置及校准
3. 古月居ROS入门21讲
古月居ROS入门21讲学习笔记
4. 雷达相机标定(ROS)
雷达相机标定(ROS)