Slam学习笔记——ROS踩坑记录

Slam学习笔记——ROS踩坑记录

  • 1. 安装
  • 2. ROS文件系统
    • 2.1 工作区
    • 2.2 包package
      • 2.2.1 包的操作
      • 2.2.2 描述文件package.xml
    • 2.3 节点node
    • 2.4 主题topic
    • 2.5 消息Message
    • 2.6 服务service
    • 2.7 参数param
  • 3. 管理多个节点
  • 4. C++编程
    • 4.1 用C++编写发布者节点(Publisher) talker
    • 4.2 用C++编写订阅者节点(Subscriber) listener
  • 5. 用sh脚本启动ros项目

ROS系统,即机器人操作系统(Robot Operating System),学习slam的过程中需要掌握的一个库。
官方网站:http://wiki.ros.org
大量内容转自官方wiki教程,使用的操作系统为:Ubuntu18.04

1. 安装

1、进入官方网站,点击Install进入安装页面。
2、选择安装ROS的版本1,点击网页上的Noetic Ninjemys进入对应版本页面。
3、选择安装Ubuntu系统的版本,获取具体安装步骤。
4、点击Mirrors获取镜像下载源,选一个地理位置比较近的下载源,比如说选择USTC的版本,复制下面的命令,在本地终端运行。
5、回到上一个网页,按照说明继续安装。
6、执行

curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

出现报错

gpg: 找不到有效的 OpenPGP 数据。

搜索网上解决攻略,执行以下命令代替官方指令:

wget http://packages.ros.org/ros.key
sudo apt-key add ros.key
sudo apt-get update --fix-missing

然后输入

sudo apt install ros-noetic-desktop-full

出现错误

正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
E: 无法定位软件包 ros-noetic-desktop-full

参考网上资料得知由于ubuntu版本不同,ros安装版本也不同
ubuntu18.04 应该安装Melodic版本的ROS
于是改为执行命令

sudo apt-get install ros-melodic-desktop-full

结果……

正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
有一些软件包无法被安装。如果您用的是 unstable 发行版,这也许是
因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件
包尚未被创建或是它们已被从新到(Incoming)目录移出。
下列信息可能会对解决问题有所帮助:

下列软件包有未满足的依赖关系:
 ros-melodic-desktop-full : 依赖: ros-melodic-perception 但是它将不会被安装
E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

好吧,看起来得先安装ros-melodic-perception
运行

sudo apt-get install ros-melodic-perception

得到

下列软件包有未满足的依赖关系:
 ros-melodic-perception : 依赖: ros-melodic-perception-pcl 但是它将不会被安装
E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

血压up……那就安装ros-melodic-perception-pcl,试着运行

sudo apt-get install ros-melodic-perception-pcl

得到

下列软件包有未满足的依赖关系:
 ros-melodic-perception-pcl : 依赖: ros-melodic-pcl-conversions 但是它将不会被安装
                              依赖: ros-melodic-pcl-ros 但是它将不会被安装
E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

你她喵的到底有完没完?!
试图寻找解决方法,网上很多文章里面是这么写这个问题的:

解决方法
就是不要关闭【软件和更新】里面的更新设置,全部通知。因为取消自动更新通知导致一直报错。

喵喵喵?!这什么鬼?!
然后在右上角系统设置里面找了好长时间的【软件和更新】在哪里……
最后发现相关设置需要打开左下角的程序列表,找到一个可视化的图标打开,【软件与更新】或者【软件更新器】……总之是个类似这样的玩意。
然后发现我的更新通知压根没关啊?这玩意一点用都没有,还是回去继续套娃吧。
最后把所有套娃的库都按照依赖顺序整理了出来,放在一个命令【仅适用于Ubuntu18.04 的Melodic版本】里面,希望可以帮助到后来人【如果好用就点个赞吧~】:

sudo apt-get install libvtk6-jni=6.3.0+dfsg1-11build1 libvtk6-java=6.3.0+dfsg1-11build1 libvtk6-dev=6.3.0+dfsg1-11build1 libvtk6-dev libvtk6-qt-dev libpcl-dev ros-melodic-pcl-conversions ros-melodic-pcl-ros ros-melodic-perception-pcl ros-melodic-perception ros-melodic-desktop-full

运行得到:

...
E: 有几个软件包无法下载,要不运行 apt-get update 或者加上 --fix-missing 的选项再试试?

拳头硬了,主机你吃我一拳!
打开【软件与更新】,在【Ubuntu软件】里面把下载自【中国服务器】换成【主服务器】,重新更新,再执行命令。
在因为网络问题导致多次Hash检验错误后,终于成功安装了所有的库,之前的错误的确是因为中国服务器上找不到对应的软件源可以下载,在主服务器上都能找到。

2000 years later…
终于完成了安装后,开始绑定环境,此处需要把官网文档上的路径改成自己具体的版本名(如果你已经打错了,就用vi ~/.bashrc进入文件,在文件末尾把刚才加错的那行手动删掉。):

echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc

运行完毕,没有报错,安装完成。

2. ROS文件系统

转自官方wiki的教程

包:包是ROS代码的软件组织单元。
每个包都可以包含库、可执行文件、脚本或其他组件。

清单 ( package.xml ):清单是对包的描述。
它用于定义包之间的依赖关系并捕获有关包的元信息,如版本、维护者​​、许可证等...

Nodes: 节点是使用 ROS 与其他节点通信的可执行文件。
Messages: 订阅或发布主题时使用的 ROS 数据类型。
Topics: 节点可以向主题发布消息,也可以订阅主题以接收消息。
Master: ROS的名称服务(即帮助节点找到彼此)
rosout: ROS 等价于 stdout/stderr
roscore: Master + rosout + 参数服务器

查看日志

roscd log

2.1 工作区

在ubuntu上安装catkin

sudo apt-get install cmake python-catkin-pkg python-empy python-nose python-setuptools libgtest-dev build-essential

在路径下新catkin建工作区catkin_ws:

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make

catkin工作区结构:

|-catkin_ws
    |-src
        |-CMakeLists.txt
        |-包1
            |-CMakeLists.txt
            |-package.xml 
        ...
        |-包N
            |-CMakeLists.txt
            |-package.xml 

为确保安装脚本正确覆盖您的工作区,请确保ROS_PACKAGE_PATH环境变量包含您所在的目录。
将当前工作区添加到ROS_PACKAGE_PATH环境变量:

source devel/setup.bash

验证是否添加成功:

echo $ROS_PACKAGE_PATH

2.2 包package

2.2.1 包的操作

包的名称支持tab自动补全。
查找包

rospack find [package_name]

将当前路径修改为包

roscd <包名>

进入包的子路径

roscd roscpp/cmake

用名称直接访问包

rosls <包名>

只能列出ROS_PACKAGE_PATH中的包,访问ROS_PACKAGE_PATH方式:

echo $ROS_PACKAGE_PATH

ROS_PACKAGE_PATH应该包含一个目录列表,其中拥有以冒号分隔的 ROS 包

构建包(需要先拥有已经完成的catkin工作区与包代码):

cd ~/catkin工作区/
ls src操作
包名/  CMakeLists.txt@  

查看包的一阶依赖项,也可以用于查看依赖项的依赖项:

rospack depends1 包名

递归查看所有依赖项

rospack depends 包名

2.2.2 描述文件package.xml

描述标签

<description>The beginner_tutorials package</description>

维护者标签

<!-- 至少一个维护者标签,可以有多个,每人一个 --> 
<maintainer email="[email protected]">Jane Doe</maintainer>

许可证标签

<!-- 至少一个许可证标签,可以有多个,每个许可证一个 --> 
<!-- 常用许可证: -->
<!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>BSD</license>

依赖标签

<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>

2.3 节点node

节点初始化【每次都要先进行初始化】:

roscore

查看正在运行的节点的信息【在一个独立终端中运行】:

rosnode list
rosnode info /rosout(节点信息,在执行上一条命令后可以看到节点列表)

运行指定包中的指定节点【在一个独立终端中运行】:

rosrun [package_name] [node_name]

运行海龟样例:

roscore
rosrun turtlesim turtlesim_node

在运行时指定节点的名称

rosrun turtlesim turtlesim_node __name:=节点名字

2.4 主题topic

在已经运行海龟样例的基础上,在新终端中启用键盘控制海龟移动【需要在这个新终端中使用键盘控制】:

rosrun turtlesim turtle_teleop_key

两个终端之间通过主题topic进行通讯,一个终端接收了键盘参数后,通过通信发给了另一个终端。

可以使用rqt_graph显示当前正在运行的节点和主题。
安装rqt_graph :

sudo apt-get install ros-melodic-rqt
sudo apt-get install ros-melodic-rqt-common-plugins

在一个新终端里面运行:

rosrun rqt_graph rqt_graph

它能以可视化方式展现出节点当前通讯状态。

查看topic相关子命令:

rostopic -h

运行得到子命令说明:

rostopic is a command-line tool for printing information about ROS Topics.

Commands:
	rostopic bw	display bandwidth used by topic
	rostopic delay	display delay of topic from timestamp in header
	rostopic echo	print messages to screen
	rostopic find	find topics by type
	rostopic hz	display publishing rate of topic    
	rostopic info	print information about active topic
	rostopic list	list active topics
	rostopic pub	publish data to topic
	rostopic type	print topic or field type

Type rostopic <command> -h for more detailed usage, e.g. 'rostopic echo -h'

查看当前所有主题:

rostopic list

查看当前所有主题的详细信息:

rostopic list -v

显示发布在某个主题上的数据:

rostopic echo [topic]

海龟样例中为:

rostopic echo /turtle1/cmd_vel

能够看到每一次按键对线性移动和旋转的具体参数。

2.5 消息Message

rostopic type返回正在发布的任何主题的消息类型

rostopic type [topic]

rostopic pub向主题发布消息数据。

rostopic pub [topic] [msg_type] [args]

直接向海龟样例发布消息让它移动:

rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'

-1:只发布一条消息然后退出
geometry_msgs/Twist:消息的类型
–:告诉编译器后续参数都不是选项,避免选项参数-与负数-的混淆。

使用-r 1发布1Hz的稳定命令流让海龟不断转圈:

rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'

查看数据发布的速度:

rostopic hz [topic]

绘制滚动时间图

rosrun rqt_plot rqt_plot

2.6 服务service

服务是节点相互通信的另一种方式。服务允许节点发送请求并接收响应。

rosservice list         print information about active services
rosservice call         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 call /clear

在给定的位置和方向生成一个海龟,并且不取名字,让名字自动生成

rosservice call /spawn 2 2 0.2 ""

现在有两只海龟了。

2.7 参数param

rosparam允许您在 ROS参数服务器上存储和操作数据。参数服务器可以存储整数、浮点数、布尔值、字典和列表。

rosparam set 设置参数
rosparam get 获取参数
rosparam load 从文件加载参数
rosparam dump 转储参数到文件
rosparam delete 删除参数
rosparam list 列出参数名称

将海龟背景改成紫色,需要用clear清空后才能实际生效:

rosparam set /turtlesim/background_r 150
rosservice call /clear

获取绿色背景通道的值

rosparam get /turtlesim/background_g 

将所有参数写入params.yaml文件:

rosparam dump params.yaml

从文件中加载参数:

rosparam load params.yaml copy_turtle

3. 管理多个节点

安装rqt和turtlesim

sudo apt-get install ros-<distro>-rqt ros-<distro>-rqt-common-plugins ros-<distro>-turtlesim

在两个终端中分别启动可视化ui

 rosrun rqt_console rqt_console
rosrun rqt_logger_level rqt_logger_level

进入自己的包

cd ~/catkin_ws
source devel/setup.bash
roscd 包名

创建启动路径

mkdir launch
cd launch

创建启动脚本turtlemimic.launch

<launch>

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

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

<node pkg="turtlesim" name="mimic" type="mimic">
<remap from="input" to="turtlesim1/turtle1"/>
<remap from="output" to="turtlesim2/turtle1"/>
</node>

</launch>

运行启动脚本

roslaunch beginner_tutorials turtlemimic.launch

在新终端中发送命令

rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'

虽然命令只发给了海龟1,但是海龟2也同步开始运动了。

4. C++编程

转自:http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29

4.1 用C++编写发布者节点(Publisher) talker

#include "ros/ros.h"
#include "std_msgs/String.h"

#include 

/**
 * 本教程演示了通过ROS系统发送消息的简单方法。
 */
int main(int argc, char **argv)
{
  /**
   * ros::init()函数需要看到argc和argv,这样它就可以执行命令行提供的任何ros参数和名称重映射。
   * 对于编程式重标记,你可以使用不同版本的init(),它直接接受重标记,
   * 但对于大多数命令行程序,传递argc和argv是最简单的方法。
   * init()的第三个参数是节点的名称。
   *
   * 在使用ros系统的任何其他部分之前,必须调用其中一个版本的ros::init()。
   */
  ros::init(argc, argv, "talker");

  /**
   * NodeHandle是与ROS系统通信的主要接入点。
   * 第一个被构造的NodeHandle将完全初始化该节点,
   * 最后一个被破坏的NodeHandle将关闭该节点。
   */
  ros::NodeHandle n;

  /**
   * advertise()函数是告诉ROS您想要发布给定主题名称的方法。
   * 这将调用对ROS主节点的调用,后者将保存谁在发布和谁在订阅的注册表。
   * 在这个advertise()调用完成后,主节点将通知任何试图订阅这个主题名的人,
   * 然后他们将与这个节点协商一个点对点连接。
   * advertise()返回一个Publisher对象,该对象允许您通过调用publish()来发布主题上的消息。
   * 一旦返回的Publisher对象的所有副本被销毁,主题将自动取消通告。
   * 
   * advertise()的第二个参数是用于发布消息的消息队列的大小。
   * 如果消息发布的速度比发送的速度快,
   * 这里的数字指定了在丢弃一些消息之前需要缓冲多少条消息。
   */
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  /**
   * 我们已经发送了多少消息的计数。
   * 这用于为每个消息创建一个惟一的字符串。
   */
  int count = 0;
  while (ros::ok())
  {
    /**
     * 这是一个消息对象。你用数据填充,然后发布。
     */
    std_msgs::String msg;

    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    /**
     * publish()函数是发送消息的方式。参数是消息对象。
     * 这个对象的类型必须与作为advertise<>()调用的模板形参给出的类型一致,
     * 就像在上面的构造函数中所做的那样。
     */
    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;
  }


  return 0;
}

4.2 用C++编写订阅者节点(Subscriber) listener

#include "ros/ros.h"
#include "std_msgs/String.h"

/**
 * 本教程演示了通过ROS系统简单地接收消息。
 */
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  /**
   * ros::init()函数需要看到argc和argv,这样它就可以执行命令行提供的任何ros参数和名称重映射。
   * 对于编程式重标记,你可以使用不同版本的init(),它直接接受重标记,
   * 但对于大多数命令行程序,传递argc和argv是最简单的方法。
   * init()的第三个参数是节点的名称。
   *
   * 在使用ros系统的任何其他部分之前,必须调用其中一个版本的ros::init()。
   */
  ros::init(argc, argv, "listener");

  /**
   * NodeHandle是与ROS系统通信的主要接入点。
   * 第一个被构造的NodeHandle将完全初始化该节点,
   * 最后一个被破坏的NodeHandle将关闭该节点。
   */
  ros::NodeHandle n;

  /**
   * 使用subscribe()调用可以告诉ROS您希望接收关于给定主题的消息。
   * 这将调用对ROS主节点的调用,后者将保存谁在发布和谁在订阅的注册表。
   * 消息被传递给一个回调函数,这里称为chatterCallback。
   * subscribe()返回一个Subscriber对象,您必须持有该对象,直到您想取消订阅为止。
   * 当订阅服务器对象的所有副本超出范围时,将自动从该主题取消订阅此回调。
   *
   * subscribe()函数的第二个参数是消息队列的大小。
   * 如果消息到达的速度比处理的速度快,这就是在开始丢弃最旧的消息之前将被缓冲的消息数。
   */
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  /**
   * ros::spin()将进入一个循环,泵送回调函数。在这个版本中,所有的回调都将在这个线程(主线程)中被调用。
   * ros::spin()将在按Ctrl-C时退出,或者被主节点关闭。
   */
  ros::spin();

  return 0;
}

5. 用sh脚本启动ros项目

参考:Ubuntu16.04系统运行vins mono(完整版环境配置及编译)

用VINS-Mono启动EUROC数据集中的V1_01_easy.bag数据集。
下载与编译的sh脚本:

#!/bin/bash

mkdir -p ~/catkin_ws/src

cd ~/catkin_ws/src

catkin_init_workspace

git clone https://github.com/HKUST-Aerial-Robotics/VINS-Mono.git

cd ..

catkin_make

运行的sh脚本【会打开三个新的终端执行命令】
如果不加sleep可能会因为几乎同时启动而连接失败。

#!/bin/bash

gnome-terminal -- bash -c "source ~/catkin_ws/devel/setup.bash; roslaunch vins_estimator euroc.launch; exec bash"
sleep 2
gnome-terminal -- bash -c "source ~/catkin_ws/devel/setup.bash; roslaunch vins_estimator vins_rviz.launch; exec bash"
sleep 2
gnome-terminal -- bash -c "source ~/catkin_ws/devel/setup.bash; rosbag play ~/catkin_ws/V1_01_easy.bag; exec bash"

启动时只需要运行sh脚本文件即可。

你可能感兴趣的:(C++/slam学习笔记,ubuntu,ROS)