ROS学习记录
ROS笔记(官方Wiki)
一、ROS安装:
ros版本:
- ROS Kinetic Kame:此版本不推荐用于新安装
- ROS Melodic Morenia:推荐用于 Ubuntu 18.04
- ROS Noetic Ninjemys:推荐用于 Ubuntu 20.04
ros安装:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt install curl # if you haven't already installed curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
sudo apt update
sudo apt install ros-melodic-desktop-full
一步步执行即可
这里发现虽然开着VPN,但是有一些国外源还是访问不到,因此还是换源下,这些是软件包:
sudo cp /etc/apt/sources.list /etc/apt/sources.list_backup /
sudo gedit /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
Terminator安装:
sudo apt-get install terminator
https://blog.csdn.net/zhangkzz/article/details/90524066
https://blog.csdn.net/clksjx/article/details/87350037
二、ROS基础
2.1 文件系统
(若出现“No such package/stack 'beginner_tutorials”,运行source devel/setup.bash)
如果要避免每次都输入,则在~下,通过编辑.bashrc文件,末尾加上:
source ~/xxxx_ws/devel/setup.bash --extend
即可
#获取有关软件包的信息
rospack find [package_name]
#允许您将目录 (cd) 直接更改为包或堆栈
roscd <package-or-stack>[/subdir]
#带您到 ROS 存储日志文件的文件夹
roscd log
#允许您通过名称而不是绝对路径直接在包中 ls
rosls <package-or-stack>[/subdir]
2.2 Catkin功能包
条件:
- 包含一个package.xml文件(介绍包信息)
- 包含使用catkin的CMakeLists.txt(元包也必须有)
- 每一个包得有文件夹(包不可嵌套,也不可多包在一个文件夹下)
PS:位置在工作空间src文件夹下
#基本结构
my_package/
CMakeLists.txt
package.xml
创建工作空间:
#建立文件夹,然后make
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make
创建功能包:
#在工作空间下的src中,创建功能包,在外面编译
cd ~/catkin_ws/src
catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
cd ~/catkin_ws
catkin_make
查看包依赖:
#直接(一级)依赖,就是没有再包含
rospack depends1 <package_name>
#全部依赖
rospack depends <package_name>
工作空间目录:
build
devel
src
2.3 节点 (Node)
#启动服务器
roscore
#新窗口中
rosnode list #列出当前节点
rosnode info [node_name] #查看当前节点信息
#启动节点
rosrun [package_name] [node_name]
#ping节点
rosnode ping [package_name]
2.4 话题 (Topic)
#显示在某个主题上发布的数据
rostopic list [/topic] 打印所有活动主题的信息(包括发布者和订阅者)
-h 帮助
-b ,-b BAGFILE, --bag=BAGFILE 列出 .bag 文件中的主题
参数: -v ,--verbose 列出每个主题的完整详细信息
-p 只显示发布者
-s 只显示订阅者
rostopic pub [/topic] [msg_type] [args] 将数据发布到主题
参数: -1 只发送一次
-r 一直循环发送
rostopic echo [/topic] 将消息打印到屏幕(可以直接查看当前话题信息)
rostopic hz [/topic] 显示主题发布率(单位HZ)
rostopic bw [/topic] 显示主题使用的带宽
rostopic type [/topic] 打印主题类型
#显示消息
rosmsg show [msg]
2.5 服务(Services)和 参数(Parameters)
服务是节点可以相互通信的另一种方式,服务允许节点发送请求并接收响应。
# 展示了节点提供的服务
rosservice list
# 展示了节点提供服务的类型
rosservice type [/service]
#通过服务名和参数调用服务
rosservice call [service] [args]
#按服务类型查找服务
rosservice find
#打印服务ROSRPC的uri
rosservice uri
参数是在ROS参数服务器上存储和操作的数据,将其存储在文件中,以便下次重新加载:
#列出参数名称
rosparam list
#设置参数
rosparam set [param_name]
#获取参数(用\参数可以获取全部参数信息)
rosparam get [param_name
#转储当前参数到文件,可以在一个新的工作空间中
rosparam dump [file_name] [namespace]
#从文件中加载之前保存的参数,可以在一个新的工作空间中
rosparam load [file_name] [namespace]
#删除参数
rosparam delete
2.6 RQT工具箱
#万能方法(弹出后通过上方菜单栏选择对应功能)
rqt
#用图表显示当前运行的节点和主题
rosrun rqt_graph rqt_graph
#用图标显示曲线图(弹出界面上方可以设置监视信息)
rosrun rqt_plot rqt_plot
#附加到 ROS 的日志框架以显示节点的输出
rosrun rqt_console rqt_console
#允许我们在节点运行时更改节点的详细级别(DEBUG、WARN、INFO 和 ERROR)选中就是切换,无需确认
rosrun rqt_logger_level rqt_logger_level
优先级由高到底,设定的越高,显示的信息越少:
Fatal
Error
Warn
Info
Debug
2.7 启动文件 (Launch)
#存储启动文件的目录不一定要命名为launch。事实上,您甚至不需要将它们存储在目录中。 roslaunch 命令会自动查看传递的包并检测可用的启动文件
#启动启动文件中定义的节点(一般在功能包的根文件夹下)
roslaunch [package] [filename.launch]
#启动文件目录 /launch/xxx.launch
#启动文件内容例子:
#用launch标签启动launch文件,这样文件就被标识为launch文件了
<launch>
#使用命名空间标签turtlesim1和turtlesim2两个组turtlesim节点的名称为 sim。这允许我们启动两个模拟器而不会发生名称冲突
#组的作用就是在访问topic之前,加上一级文件前缀\group
<group ns="turtlesim1">
<node pkg="turtlesim" name="sim" type="turtlesim_node"/>
</group>
<group ns="turtlesim2">
<node pkg="turtlesim" name="sim" type="turtlesim_node"/>
</group>
#设定Topic输入和Topic输出为turtlesim1 和turtlesim2来启动mimic 节点。将使turtlesim2重命名为mimic turtlesim1
<node pkg="turtlesim" name="mimic" type="mimic">
<remap from="input" to="turtlesim1/turtle1"/>
<remap from="output" to="turtlesim2/turtle1"/>
</node>
#这将关闭启动文件的 xml 标记
</launch>
2.8 编辑文件(Rosed)
# rosed 是 rosbash 套件的一部分。它允许您通过使用包名称直接编辑包中的文件,而不必键入包的整个路径(可使用TAB补全)
rosed [package_name] [filename]
#切换编辑器(默认编辑器是Vim)切换成nano/gedit
export EDITOR='nano -w'
export EDITOR='gedit -w'
2.9 建立msg文件和srv文件
msg 文件是描述 ROS 消息字段的简单文本文件。它们用于为不同语言的消息生成源代码:
#存储位置/msg
rosmsg -h #查看命令帮助
#可以使用的字段类型
int8, int16, int32, int64 (plus uint*)
float32, float64
string
time, duration
other msg files
variable-length array[] and fixed-length array[C]
header中包含了ROS中常用的时间戳和坐标系信息
srv 文件描述了一项服务。它由两部分组成:请求和响应
#存储位置/srv
eg:
int64 A #request
int64 B
---
int64 Sum #response
建立msg:
#建立msg文件夹和文件
roscd [package]
mkdir msg
echo "int64 num" > msg/Num.msg
#打开 package.xml,并确保这两行在其中并且取消注释,需要确保将 msg 文件转换为 C++、Python 和其他语言的源代码
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
#打开 CMakeLists.txt 编辑下面几个地方:
#将 message_generation 依赖项添加到 CMakeLists.txt 中已经存在的 find_package 调用中,以便您可以生成消息
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
#确保导出消息运行时依赖项
catkin_package(
...
CATKIN_DEPENDS message_runtime ...
...)
#删除 # 符号取消注释,然后将 Message*.msg 文件中的支架替换为您的 .msg 文件
add_message_files(
FILES
Num.msg
)
#保存后退出,使用下列命令可以验证:
rosmsg show [message type]
建立srv:
#建立srv文件夹和文件
roscd beginner_tutorials
mkdir srv
#这里可以直接拷贝一个模板
roscp [package_name] [file_to_copy_path] [copy_path]
roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv
#打开 package.xml,确保这两行在其中没被注释:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
#打开 CMakeLists.txt 编辑下面几个地方(message_generation 同时适用于 msg 和 sr):
#将 message_generation 依赖项添加到 CMakeLists.txt 中已经存在的 find_package 调用中,以便您可以生成消息
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
#确保导出消息运行时依赖项
catkin_package(
...
CATKIN_DEPENDS message_runtime ...
...)
#删除 # 符号取消注释,并为您的服务文件替换占位符 Service*.srv 文件
add_service_files(
FILES
AddTwoInts.srv
)
#保存后退出,使用下列命令可以验证:
rossrv show <service type>
编译:
#注释掉生成message,添加您依赖的任何包,这些包包含您的消息使用的 .msg 文件(在本例中为 std_msgs),如下所示:
generate_messages(
DEPENDENCIES
std_msgs
)
#编译
cd ~/catkin_ws
catkin_make
cd - #返回上一级设定目录
2.10 建立发布者订阅者(C++)
发布者(Publisher):
#存储位置/src/xxx.cpp
https://raw.github.com/ros/ros_tutorials/kinetic-devel/roscpp_tutorials/talker/talker.cpp
#解析
#include "ros/ros.h" 包括使用 ROS 系统最常见的公共部分所需的所有头文件
#include "std_msgs/String.h" 这包括位于 std_msgs 包中的 std_msgs/String 消息,自动生成的标头
ros::init(argc, argv, "talker"); 初始化 ROS,这也是我们指定节点名称的地方。节点名称在正在运行的系统中必须是唯一的
ros::NodeHandle n; 创建此进程节点的句柄
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
告诉主机将在Topic(ROS中名为chatter)上发布 std_msgs/String 类的消息 ,1000代表缓冲队列的大小
NodeHandle::advertise() 返回一个 ros::Publisher 对象,它有两个用途:1) 它包含一个 publish() 方法,允许您将消息发布 到创建它的主题上,以及 2) 当它超出范围时,它将自动取消发布
ros::Rate loop_rate(10); 指定要循环的频率,这里为10Hz
int count = 0;
while (ros::ok()) #提供 Ctrl-C、同名冲突、ros::shutdown()等处理,如果发生这种情况将导致 ros::ok() 返回 false
{
std_msgs::String msg; #建立一个字符串类型的消息(还可以用msg文件)
std::stringstream ss; #建立一个字符串流
ss << "hello world " << count;
msg.data = ss.str(); #赋值
chatter_pub.publish(msg); #将消息发布到任何连接的人
ROS_INFO("%s", msg.data.c_str()); #LOG显示发送数据
ros::spinOnce(); #订阅后回调函数,这里没用到,可拓展
loop_rate.sleep(); #sleep后,按照 ros::Rate 对象设定的频率,发布数据
}
订阅者(Subscriber):
#存储位置/src/xxx.cpp
https://raw.github.com/ros/ros_tutorials/kinetic-devel/roscpp_tutorials/listener/listener.cpp
#解析
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
} 当新消息发布到主题时,调用的回调函数
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); 设定ROS中订阅者节点名称,缓冲区大小,回调函数
ros::spin(); 进入一个循环,尽可能快地调用消息回调
编译节点:
#CMakeLists文件:
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv)
generate_messages(DEPENDENCIES std_msgs)
catkin_package()
#末尾增加
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)
2.11 建立发布者订阅者(Python)
发布者(Publisher):
#存储位置/scripts/xxx.py
mkdir scripts
gedit ./scripts/talker.py
chmod +x listener.py 添加可执行性
#代码及解析
#!/usr/bin/env python 这个是每个python的脚本的声明,每个python的ROS节点都要有
# license removed for brevity
import rospy 和C一样,导入ros.py库
from std_msgs.msg import String 和C一样,从std_msgs导入String库
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10) 声明使用String类型发布到Chatter主题,队列缓冲区
rospy.init_node('talker', anonymous=True) 指定节点的名字,anonymous可以自动在名字末尾加上随机数保证唯一性
rate = rospy.Rate(10) # 10hz 设定在sleep()下的循环速率
while not rospy.is_shutdown(): 判断rospy是否被退出
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str) 消息打印到屏幕,写入节点的日志文件,然后写入 rosout
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__': 传统的python的main函数检查
try:
talker()
except rospy.ROSInterruptException: 异常退出时
pass
订阅者(Subscriber):
#存储位置/scripts/xxx.py
gedit ./scripts/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():
rospy.init_node('listener', anonymous=True) 设定节点名字,使能自动命名
rospy.Subscriber("chatter", String, callback) 设定订阅主题,
rospy.spin() 使节点在节点关闭之前不会退出
if __name__ == '__main__':
listener()
编译节点:
#编辑CMakeLists.txt
catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
#编译
cd ~/catkin_ws
catkin_make
2.12 建立服务和客户端(C++)
服务者(Service ):
#存储位置 /src/xxx.cpp
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h" 我们之前创建的 srv 文件生成的头文件
提供一个两个数字相加的服务,其请求和相应类型在srv文件中定义,并返回状态
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); 建立服务并发布,设定服务回调函数add
ROS_INFO("Ready to add two ints.");
ros::spin();
return 0;
}
客户端(Client):
#存储位置 /src/xxx.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 != 3)
{
ROS_INFO("usage: add_two_ints_client X Y");
return 1;
}
ros::NodeHandle n;
实例化一个自动生成的服务类,并将值分配给它的请求成员。一个服务类包含两个成员,请求和响应
ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
beginner_tutorials::AddTwoInts srv;
将输入参数写入请求数组
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
发起请求
if (client.call(srv)) 服务为阻塞性,成功返回true
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_two_ints");
return 1;
}
return 0;
}
编译节点:
#编辑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)
#编译
cd ~/catkin_ws
catkin_make
2.14 建立服务和客户端(Python)
服务者(Service ):
#存储位置/scripts/xxx.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') 初始化服务
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()
客户端(Client):
#存储位置/scripts/xxx.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') 在调用服务可用之前阻塞
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)))
编译节点:
#编译
catkin_install_python(PROGRAMS scripts/add_two_ints_server.py scripts/add_two_ints_client.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
cd ~/catkin_ws
catkin_make
2.15 记录数据
从正在运行的ROS中记录数据,并存在一个包中:
#运行小乌龟鼠标例程
roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
#查看发布的主题列表,这个是唯一可以记录在数据日志文件中的消息类型,因为只记录已经发布的消息:
rostopic list -v
#创建备份文件夹
mkdir ~/bagfiles
cd ~/bagfiles
rosbag record -a
运行完备份文件夹下应该会生成一个名称以年份、日期和时间以及后缀 .bag 开头的文件
#查看包信息
rosbag info <your bagfile>
#重放数据
rosbag play <your bagfile>
参数 -r 2 设定回放发布每条消息后等待的时间0.2秒,才真正发布包文件内容。
-d 2 设定等待时间
-O [输出文件名] [话题信息1] [话题信息2] ...
#指定主题/名称
rosbag record -O subset /turtle1/cmd_vel /turtle1/pose
rosbag在消息被rosbag记录和处理的时间方面无法准确复制正在运行的系统的行为。记录,以及使用 rosbag play 时产生和处理消息的时间。对于像turtlesim这样的节点,在处理命令消息时的微小时间变化会微妙地改变行为,用户不应该期望完全模仿行为。
2.16 检查错误
roswtf
三、ROS进阶实践
以下记录为实验记录,主要记录经验以及错误解决方法:
-
GAZEBO出错:[Err] [REST.cc:205] Error in REST request
libcurl: (51) SSL: no alternative certificate subject name matches target host name 'api.ignitionfuel.org'
gedit ~/.ignition/fuel/config.yaml
替换url为:
原来:https://api.ignitionfuel.org
新:https://api.ignitionrobotics.org
- GAZEBO闪退:
在VM虚拟机选项中禁用3D加速即可
但是这样挺卡的
法2:export SVGA_VGPU10=0(暂时)
echo "export SVGA_VGPU10=0" >> ~/.profile(永久)
- 更新Gazebo到11,出错:
先运行:
sudo apt install libgazebo11
再更新
sudo apt install gazebo11
- Gazebo编译tianbot出错:
https://its301.com/article/u012197995/85009861
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了