最近想搭建一个机器人移动平台,但是设备还没完全到齐,在设备全部到齐之前,我们先在gazebo中做一个仿真,进行相关的算法和功能包的部署。在这个仿真中机器人在一个移动底盘上搭载了16线激光雷达、IMU、RGB-D相机,并在最后跑了一个LIO-SAM,建图效果还不错。整个过程遇到了一些问题,都一一解决了,对主要的问题做了一些记录,有其他问题的可以在讨论区回复。另外,本工程的源码放在在GitHub上,欢迎大家下载学习。
首先下载VLP的激光雷达的仿真开发包到自己的工作空间中
git clone https://bitbucket.org/DataspeedInc/velodyne_simulator/src/master/
下载之后 /src 的文件结构如下
下载好激光雷达的仿真包之后重新catkin_make一次,主要是为了生成激光雷达的点云产生库文件,不然后面仿真的时候会没有点云相关话题。编译一次之后就会在我们工作空间的的devel/lib文件夹下生成两个动态链接库如下:
在仿真中会调用这两个库生成点云信息。
给激光雷达添加一个支架,把激光雷达在车上立起来,在自己的机器人包里面的urdf文件夹里面新建一个 laser_support.xacro 文件写入如下内容
<robot name="laser_support" xmlns:xacro="http://wiki.ros.org/xacro">
<xacro:property name="support_length" value="0.30" />
<xacro:property name="support_radius" value="0.025" />
<xacro:property name="support_x_size" value="-0.2" />
<xacro:property name="support_y_size" value="0.0" />
<xacro:property name="support_z_size" value="${base_z_size}" />
<xacro:property name="support_m" value="0.02" />
<link name="support">
<visual>
<geometry>
<cylinder radius="${support_radius}" length="${support_length}" />
geometry>
<origin xyz="0 0 0" rpy="0.0 0.0 0.0" />
<material name="red">
<color rgba="0.8 0.2 0.0 0.8" />
material>
visual>
<collision>
<geometry>
<cylinder radius="${support_radius}" length="${support_length}" />
geometry>
<origin xyz="0 0 0" rpy="0.0 0.0 0.0" />
collision>
<xacro:cylinder_inertial_matrix m="${support_m}" r="${support_radius}" h="${support_length}" />
link>
<joint name="support2base_link" type="fixed">
<parent link="base_link" />
<child link="support" />
<origin xyz="${support_x_size} ${support_y_size} ${support_z_size}" />
joint>
<gazebo reference="support">
<material>Gazebo/Whitematerial>
gazebo>
robot>
在机器人的base.xacro描述文件中添加激光雷达的描述
首先,包含激光雷达的支架描述文件
然后,添加雷达的两个属性描述变量
最后,包含激光雷达的描述文件,这里会用到上面两个属性变量
编写launch文件,启动rviz看看我们的机器人
<launch>
<arg name = "model_xacro" default = "$(find scout_gazebo)/urdf/base.xacro" />
<param name="robot_description" command="$(find xacro)/xacro $(arg model_xacro)" />
<node name="joint_state_publisher" pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" >node>
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find scout_gazebo)/config/show_robot.rviz" />
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find scout_gazebo)/worlds/lab.world" />
include>
<node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model scout -param robot_description" />
launch>
roslaunch之后就可以打开gazebo和rviz,并在里面显示我们的机器人携带着激光雷达如下:
此时可以打开我们的话题,看看是否有点云输出
可以看到是有点云话题的,我们在rviz里面尝试把点云可视化出来看看
可以看到我们的点云是正常输出的。注意,我们我们为了在gazebo里面看到我们的机器人,所以没有在gazebo里面吧激光点云可视化出来,如果想要可视化可以通过修改 VLP-16.urdf.xacro 文件中这个地方
修改之后,我们就可以在gazebo里面看到激光点云了,如下:
把我们的车都给盖住了,16线激光雷达的点云还是比较稠密的。现在激光雷达已经加入到仿真中了,下一步我们跑一个经典的激光SLAM框架 LIO-SAM试试看。
因为我们需要跑的框架是LIO-SAM,需要用到IMU模块,所以我们在仿真中也添加进去。同样地,我们在工程中的urdf文件夹下面再增加一个 imu.xacro文件
<robot xmlns:xacro="http://wiki.ros.org/xacro">
<xacro:macro name="imu" params="sensor_name parent_link *origin">
<xacro:property name="imu_offset_x" value="0" />
<xacro:property name="imu_offset_y" value="0" />
<xacro:property name="imu_offset_z" value="0.2" />
<xacro:property name="imu_size" value="0.05" />
<xacro:property name="imu_m" value="0.01" />
<joint name="imutobase" type="fixed">
<xacro:insert_block name="origin" />
<parent link="${parent_link}"/>
<child link="imu_base"/>
joint>
<link name="imu_base">
<visual>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<box size="${imu_size} ${imu_size} ${imu_size}"/>
geometry>
<material name= "black" >
<color rgba="1.0 0.0 0.0 0.6" />
material>
visual>
<collision>
<geometry>
<box size="${imu_size} ${imu_size} ${imu_size}" />
geometry>
<origin xyz="0.0 0.0 0" rpy="0.0 0.0 0.0" />
collision>
<xacro:Box_inertial_matrix m = "${imu_m}" l = "${imu_size}" w = "${imu_size}" h = "${imu_size}"/>
link>
<gazebo reference="imu_base">
<material>Gazebo/Bulematerial>
<gravity>truegravity>
<sensor name="imu_sensor" type="imu">
<always_on>truealways_on>
<update_rate>100update_rate>
<visualize>truevisualize>
<topic>__default_topic__topic>
<plugin filename="libgazebo_ros_imu_sensor.so" name="imu_plugin">
<topicName>imu/datatopicName>
<bodyName>imu_basebodyName>
<updateRateHZ>100.0updateRateHZ>
<gaussianNoise>0.01gaussianNoise>
<xyzOffset>0 0 0xyzOffset>
<rpyOffset>0 0 0rpyOffset>
<frameName>imu_baseframeName>
plugin>
<pose>0 0 0 0 0 0pose>
sensor>
gazebo>
xacro:macro>
robot>
然后在我们主描述文件 base.xacro中包含这个文件
我们这里使用一个realsense系列的RGB-D相机,先去下载它的仿真SDK
$ git clone https://github.com/nilseuropa/realsense_ros_gazebo.git
这里是下载到工程的源码目录下
然后同样地,在主描述文件base.xarco中把相机也包含进去
添加完之后,我们这个仿真机器人已经配备了 IMU、RGB-D相机、16线激光雷达这些传感器,我们把环境启动起来,看看发布了多少话题
可以看到发布了很多话题,双目的、IMU的、点云的……都有,基本是机器人配置已经完成,下面准备跑一个SLAM框架试试
$ sudo apt-get install -y ros-noetic-navigation
$ sudo apt-get install -y ros-noetic-robot-localization
$ sudo apt-get install -y ros-noetic-robot-state-publisher
$ git clone https://github.com/borglab/gtsam
$ cd gtsam
$ mkdir build && cd build
# 注意这里要加-DGTSAM_BUILD_WITH_MARCH_NATIVE=OFF这个选项,不然后面运行会报错
$ cmake -DGTSAM_BUILD_WITH_MARCH_NATIVE=OFF ..
$ sudo make install -j8
$ sudo ln -s /usr/local/lib/libmetis-gtsam.so /usr/lib/libmetis-gtsam.so
$ cd ~/robot_ws/src
$ git clone https://github.com/TixiaoShan/LIO-SAM
$ cd ..
$ catkin_make
首先启动仿真环境
$ roslaunch scout_gazebo scout_gazebo.launch
然后启动 lio-sam
$ roslaunch lio_sam run.launch
最后启动我们的控制机器人移动的节点,这个节点是ros自带的一个包,通过sudo apt install ros-noetic-teleop-twist-keyboard
命令安装,这个节点主要是发布速度信息到 /cmd_val
控制机器人在gazebo中进行移动,移动机器人即可进行建图
$ rosrun teleop_twist_keyboard teleop_twist_keyboard.py
可以看到机器人在gazebo中接收我们的运动控制指令进行运动,lio-sam节点进行了位姿估计与建图。
这里我把源码上传到我的GitHub仓库,大家可以自行下载进行实验
https://github.com/linzs-online/robot_gazebo.git
原因:PCl库依赖的flann与Opencv冲突。opencv头文件中的一些宏定义和flann库中的冲突
解决:保证pcl库中依赖的flann在opencv头文件之前先包含进去。我这里是把opencv的头文件放在PCL库之后就解决 了
原因:lio-sam会对点云进行下采样滤波,滤波体素设置太大了,匹配过程出现误差,导致机器人优化出来的位姿反复横跳。
解决: 因为我们这里是在室内建图,所以在lio-sam的配置文件中把体素大小设置小一些
解决: gtsam编译时带上这个参数,cmake -DGTSAM_BUILD_WITH_MARCH_NATIVE=OFF …
解决: sudo ln -s /usr/local/lib/libmetis-gtsam.so /usr/lib/libmetis-gtsam.so
原因:机器人TF变换不正常
解决:通过运行
roswtf
命令分析目前环境中的TF变换,这里查到是base_link
和odom
这两个坐标之间的变换产生了冲突显然,是我们的gazebo仿真中的控制已经发布了
base_link
到odom
的TF变换,但是我们的 SLAM节点又发布了一次,这两个产生了冲突,下面我们通过修改lio-sam发布的TF变换来解决这个问题,修改lio-sam的配置文件,把SLAM位姿估计结果发布的坐标换个名字即可