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

http://wiki.ros.org/melodic/Installation/Ubuntu

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功能包

条件:

  1. 包含一个package.xml文件(介绍包信息)
  2. 包含使用catkin的CMakeLists.txt(元包也必须有)
  3. 每一个包得有文件夹(包不可嵌套,也不可多包在一个文件夹下)

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
posted @   伦敦烟云  阅读(89)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示