Basic Knowledge:
GEM是我和潘一源师兄合作的一篇做建图的文章,全名叫GEM: Online Globally Consistent Dense Elevation Mapping for Unstructured Terrain ,旨在处理户外资源受限场景下带闭环的建图问题。局部地图是基于ETHZ的Elevation map的,当时测试下来,ETHZ的Elevation map是CPU实现的,不太适合实时性较强的移动机器人应用场景,ETHZ用在四足上,运动速度慢,所以基本可行。我们提出了一种实时可扩展的GPU实现的全局Elevation map. 在整个原始Elevation map的框架中,将部分可并行部分进行cuda加速,此外实现了ray tracing算法进行了实时障碍物消除。原始几何数据的基础上进行了可行域分析,并添加了相应的地图层,为地面移动机器人避障与导航提供了较为便捷的地图。
Motivation for this blog
写这一篇blog主要是因为,这个Mapping太泛用了,我研究生接的移动机器人项目中,都会用到它,很多师弟师妹也在用。但是,他们用的时候总是会反馈给我好多问题,基本上都是配置和安装方面的问题。我自己用的比较熟,所以基本不会关注到这些问题,有点知识诅咒了。所以在此写一个教程,从头开始把GEM跑起来。
Dependencies
- Ubuntu: 16.04-20.04
- ROS: kinetic-noetic(会有一些frame_id要不要加”/”的问题)
- Packages (以kinetic为例)
# apt sudo apt install ros-kinetic-grid-map* ros-kinetic-octomap* ros-kinetic-costmap* ros-kinetic-nav* # kindr git clone https://github.com/ANYbotics/kindr.git cd kindr && mkdir build && cd build cmake .. make && make install
Install GEM
cd catkin_workspace/src
git clone https://github.com/ZJU-Robotics-Lab/GEM.git
git clone https://github.com/ZJU-Robotics-Lab/slam_msg.git
git clone https://github.com/ANYbotics/kindr_ros.git
cd ../
catkin_make
Configuration
配置文件主要有两块,一个是local map的参数,一个是基础参数
- elevation_maps/simple_demo_map.yaml
length_in_x: 12.0 # 单位m,局部地图x方向大小 length_in_y: 12.0 position_x: 0.0 # 单位m,机器人在局部地图中的位置,中心为(0,0) position_y: 0.0 track_point_x: 0.0 # 单位m,地图跟随点的位置,默认(0,0) track_point_y: 0.0 resolution: 0.1 # 单位m,地图分辨率 travers_threshold: 0.8 # 判断可通行的阈值,> travers_threshold 为可通行,范围(0~1) min_variance: 0.0001 max_variance: 10000.0 mahalanobis_distance_threshold: 2.5 multi_height_noise: 0.00002
- robots/simple_demo_robot.yaml
robot_id: "0" # 机器人id,用于多机器人系统 robot_name: "robot0" # 机器人名字,用于多机器人系统,需在最后带robotid map_frame_id: "/robot0/odom" # 机器人里程坐标系 sensor_frame_id: "/PandarQT" # 机器人传感器坐标系 robot_base_frame_id: "/PandarQT" # 机器人本体坐标系 track_point_frame_id: "/PandarQT" # 机器人跟随点的坐标系,一般与机器人本体坐标系保持一致 robot_pose_cache_size: 200 robot_local_map_size: 20 # 子地图大小 octomap_road_resolution: 0.2 # 可通行区域octomap分辨率 octomap_obs_resolution: 0.1 # 不可通行区域octomap分辨率 map_saving_file: "./map.pcd" # 地图存储路径 (optional) submap_saving_dir: "./submaps/" # 子地图存储路径 (optional) camera_params_yaml: "./param.yaml" # 相机内参以及激光与相机外参路径,绝对路径 (required) orthomosaic_saving_dir: "./image/" # 正视图存储路径 (optional)
Use your own bag
使用自己设备采集的bag,需要配套定位算法,GEM仅提供建图,需要做的修改如下:
- launch文件中 需要设置 use_sim_time 为 true; camera_topic 和 lidar_topic 需要相应修改
- Camera需要与LiDAR同步,即时间戳需要一致,如不需要camera,则可以使用仓库提供的 fake_img.py
- 需要修改 robots/simple_demo_robot.yaml 中 sensor_frame_id,robot_base_frame_id,track_point_frame_id 为定位算法提供的tf的坐标系;camera_params_yaml 需要修改为绝对位置,否则会报错
FAQ
- catkin_make报错
"/usr/local/cuda-10.1/include/crt/common_functions.h:74:24: error: token ""CUDACC_VER is no longer supported. Use CUDACC_VER_MAJOR, CUDACC_VER_MINOR, and CUDACC_VER_BUILD instead."" is not valid in preprocessor expressions #define CUDACC_VER "CUDACC_VER is no longer supported. Use CUDACC_VER_MAJOR, CUDACC_VER_MINOR, and CUDACC_VER_BUILD instead."
- 解决方案:找到/usr/local/cuda-10.1/include/crt/common_functions.h:74 这一行,注释掉。
- ERROR: Wrong path to settings
- 解决方案:elevation_mapping/elevation_mapping_demos/config/robots/simple_demo_robot.yaml中的camera_params_yaml需要修改为绝对路径
- 进不去回调函数
-
因为GEM默认是激光+相机的,因此相机和激光需要时间戳对齐,这里如果不想用图像,又不想折腾纯激光版本。可以复制一下下面的代码到fake_img.py,用python发一个假的img。
-
#!/usr/bin/env python #coding:utf-8 import rospy import sys sys.path.append('.') import cv2 import os import numpy as np from sensor_msgs.msg import Image from cv_bridge import CvBridge, CvBridgeError def pubImage(): rospy.init_node('pubFakeImage',anonymous = True) pub = rospy.Publisher('robot_1/image_rect', Image, queue_size = 10) rate = rospy.Rate(10) bridge = CvBridge() while not rospy.is_shutdown(): image = np.zeros((640,480,3), np.uint8) msg = bridge.cv2_to_imgmsg(image,"bgr8") msg.header.stamp = rospy.Time.now() pub.publish(msg) rate.sleep() if __name__ == '__main__': try: pubImage() except rospy.ROSInterruptException: pass
-
- 建图非常慢
- GPU虽然并行计算快,但是招架不住输入的点云太大,单帧点云控制在10w点以下比较好,建议用仓库里的filter,先滤一下点云。
- 如果点云非常大,我见过realsense的深度图出的点云,单帧962000个点,filter一下都要好几百毫秒,那建图也没戏。