Convert Figma logo to code with AI

RobustFieldAutonomyLab logoLeGO-LOAM

LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain

2,354
1,111
2,354
35

Top Related Projects

2,089

Advanced implementation of LOAM

3,328

LIO-SAM: Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping

A Robust and Versatile Monocular Visual-Inertial State Estimator

Cartographer is a system that provides real-time simultaneous localization and mapping (SLAM) in 2D and 3D across multiple platforms and sensor configurations.

Quick Overview

LeGO-LOAM (Lightweight and Ground-Optimized Lidar Odometry and Mapping) is an open-source project for real-time 3D SLAM (Simultaneous Localization and Mapping) using LiDAR sensors. It's designed to be computationally efficient and optimized for ground vehicles, making it suitable for autonomous driving and robotics applications.

Pros

  • Lightweight and computationally efficient, allowing for real-time performance on embedded systems
  • Optimized for ground vehicles, providing accurate localization and mapping in urban environments
  • Robust to dynamic objects and uneven terrain
  • Open-source with active community support

Cons

  • Primarily designed for ground vehicles, may not be optimal for aerial or underwater applications
  • Requires careful parameter tuning for optimal performance in different environments
  • Limited support for multi-sensor fusion (e.g., LiDAR + IMU)
  • May struggle in environments with limited geometric features

Code Examples

  1. Subscribing to LiDAR point cloud data:
ros::Subscriber subLaserCloud = nh.subscribe<sensor_msgs::PointCloud2>
    ("/velodyne_points", 1, laserCloudHandler);
  1. Performing feature extraction:
void extractFeatures()
{
    cornerSharpNum = 0;
    cornerLessSharpNum = 0;
    surfFlatNum = 0;
    surfLessFlatNum = 0;

    for (int i = 0; i < N_SCAN; i++)
    {
        sp = scanStartInd[i];
        ep = scanEndInd[i] - 1;

        extractFeatures(sp, ep, scanStartInd, scanEndInd, cloudSmoothness, cloudCurvature,
                        cloudNeighborPicked, cloudLabel, cornerPointsSharp, cornerPointsLessSharp,
                        surfPointsFlat, surfPointsLessFlat);
    }
}
  1. Publishing odometry results:
void publishOdometry()
{
    // Publish odometry for ROS
    nav_msgs::Odometry laserOdometry;
    laserOdometry.header.frame_id = "/camera_init";
    laserOdometry.child_frame_id = "/laser_odom";
    laserOdometry.header.stamp = cloudHeader.stamp;
    laserOdometry.pose.pose.position.x = transformTobeMapped[3];
    laserOdometry.pose.pose.position.y = transformTobeMapped[4];
    laserOdometry.pose.pose.position.z = transformTobeMapped[5];
    laserOdometry.pose.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw
        (transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]);
    pubLaserOdometry.publish(laserOdometry);
}

Getting Started

  1. Clone the repository:

    git clone https://github.com/RobustFieldAutonomyLab/LeGO-LOAM.git
    
  2. Build the project:

    cd LeGO-LOAM
    mkdir build && cd build
    cmake ..
    make
    
  3. Run the LeGO-LOAM node:

    roslaunch lego_loam run.launch
    
  4. Play your ROS bag file or connect your LiDAR sensor to start mapping.

Competitor Comparisons

2,089

Advanced implementation of LOAM

Pros of A-LOAM

  • Simpler implementation, making it easier to understand and modify
  • Faster processing speed due to its lightweight design
  • More suitable for aerial robotics applications

Cons of A-LOAM

  • Less robust in challenging environments with uneven terrain
  • Lacks advanced features like ground segmentation and loop closure

Code Comparison

A-LOAM:

void BasicLaserOdometry::extractFeatures()
{
    cornerPointsSharp->clear();
    cornerPointsLessSharp->clear();
    surfPointsFlat->clear();
    surfPointsLessFlat->clear();
    
    pcl::PointCloud<PointType> laserCloudScans[N_SCANS];
    // ... (feature extraction logic)
}

LeGO-LOAM:

void FeatureAssociation::extractFeatures(const pcl::PointCloud<PointType>::Ptr& pc_in, pcl::PointCloud<PointType>::Ptr& pc_out_edge, pcl::PointCloud<PointType>::Ptr& pc_out_surf)
{
    std::vector<int> scanStartInd(N_SCANS, 0);
    std::vector<int> scanEndInd(N_SCANS, 0);
    
    pcl::PointCloud<PointType> laserCloudScans[N_SCANS];
    // ... (feature extraction logic with ground segmentation)
}

The code comparison shows that LeGO-LOAM has a more complex feature extraction process, including ground segmentation, while A-LOAM uses a simpler approach. This reflects the trade-off between robustness and processing speed in the two implementations.

3,328

LIO-SAM: Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping

Pros of LIO-SAM

  • Integrates IMU data for improved accuracy and robustness
  • Supports loop closure for better global consistency
  • More recent development with active maintenance

Cons of LIO-SAM

  • Higher computational requirements due to additional sensor fusion
  • Potentially more complex setup and configuration
  • May require more fine-tuning for optimal performance

Code Comparison

LIO-SAM:

void imuHandler(const sensor_msgs::Imu::ConstPtr& imuMsg)
{
    sensor_msgs::Imu thisImu = imuConverter(*imuMsg);
    std::lock_guard<std::mutex> lock(imuLock);
    imuQueue.push_back(thisImu);
}

LeGO-LOAM:

void laserCloudHandler(const sensor_msgs::PointCloud2ConstPtr& laserCloudMsg)
{
    cloudHeader = laserCloudMsg->header;
    timeScanCur = cloudHeader.stamp.toSec();
    cloudQueue.push_back(*laserCloudMsg);
}

LIO-SAM incorporates IMU data handling, while LeGO-LOAM focuses solely on LiDAR point cloud processing. This difference reflects the core distinction between the two approaches, with LIO-SAM leveraging multi-sensor fusion for potentially improved accuracy and robustness in challenging environments.

A Robust and Versatile Monocular Visual-Inertial State Estimator

Pros of VINS-Mono

  • Utilizes visual-inertial fusion for more robust pose estimation
  • Supports monocular camera setups, making it suitable for a wider range of platforms
  • Includes loop closure for improved accuracy in long-term operation

Cons of VINS-Mono

  • May struggle in environments with limited visual features
  • Higher computational requirements due to visual processing
  • Less effective in large-scale outdoor environments compared to LiDAR-based systems

Code Comparison

VINS-Mono (C++):

void FeatureTracker::readImage(const cv::Mat &_img, double _cur_time)
{
    cv::Mat img;
    TicToc t_r;
    frame_cnt++;
    cv::remap(_img, img, undist_map1_, undist_map2_, CV_INTER_LINEAR);
    // ... (additional image processing code)
}

LeGO-LOAM (C++):

void featureAssociation::extractCornerFeatures()
{
    cloudSmoothness.resize(N_SCAN*Horizon_SCAN);
    for (int i = 5; i < cloudSize - 5; i++)
    {
        float diffRange = cloudCurvature[i-5] + cloudCurvature[i-4]
            + cloudCurvature[i-3] + cloudCurvature[i-2]
            + cloudCurvature[i-1] - cloudCurvature[i] * 10
            + cloudCurvature[i+1] + cloudCurvature[i+2]
            + cloudCurvature[i+3] + cloudCurvature[i+4]
            + cloudCurvature[i+5];            
        cloudSmoothness[i].value = diffRange*diffRange;
        cloudSmoothness[i].ind = i;
    }
    // ... (additional feature extraction code)
}

Cartographer is a system that provides real-time simultaneous localization and mapping (SLAM) in 2D and 3D across multiple platforms and sensor configurations.

Pros of Cartographer

  • Multi-sensor fusion: Supports various sensor types (LiDAR, IMU, odometry)
  • Real-time performance: Optimized for online SLAM in real-time applications
  • Versatility: Works in 2D and 3D environments, suitable for different robotics platforms

Cons of Cartographer

  • Complexity: Steeper learning curve due to its comprehensive feature set
  • Resource intensity: May require more computational resources for optimal performance
  • Less specialized: Not specifically optimized for LiDAR-only SLAM like LeGO-LOAM

Code Comparison

LeGO-LOAM (C++):

void laserCloudCornerLastHandler(const sensor_msgs::PointCloud2ConstPtr& msg) {
    timeLaserCloudCornerLast = msg->header.stamp.toSec();
    laserCloudCornerLast->clear();
    pcl::fromROSMsg(*msg, *laserCloudCornerLast);
    newLaserCloudCornerLast = true;
}

Cartographer (C++):

void HandleLaserScan(const sensor_msgs::LaserScan::ConstPtr& msg) {
    carto::sensor::PointCloudWithIntensities point_cloud;
    carto::common::Time time;
    std::tie(point_cloud, time) = ToPointCloudWithIntensities(*msg);
    trajectory_builder_->AddSensorData(
        kLaserScanTopic, carto::sensor::TimedPointCloudData{
            time, Eigen::Vector3f::Zero(), point_cloud.points});
}

Both examples show sensor data handling, but Cartographer's approach is more generalized and integrated with its multi-sensor fusion system.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

LeGO-LOAM

This repository contains code for a lightweight and ground optimized lidar odometry and mapping (LeGO-LOAM) system for ROS compatible UGVs. The system takes in point cloud from a Velodyne VLP-16 Lidar (palced horizontally) and optional IMU data as inputs. It outputs 6D pose estimation in real-time. A demonstration of the system can be found here -> https://www.youtube.com/watch?v=O3tz_ftHV48

drawing

Lidar-inertial Odometry

An updated lidar-initial odometry package, LIO-SAM, has been open-sourced and available for testing.

Dependency

  • ROS (tested with indigo, kinetic, and melodic)
  • gtsam (Georgia Tech Smoothing and Mapping library, 4.0.0-alpha2)
    wget -O ~/Downloads/gtsam.zip https://github.com/borglab/gtsam/archive/4.0.0-alpha2.zip
    cd ~/Downloads/ && unzip gtsam.zip -d ~/Downloads/
    cd ~/Downloads/gtsam-4.0.0-alpha2/
    mkdir build && cd build
    cmake ..
    sudo make install
    

Compile

You can use the following commands to download and compile the package.

cd ~/catkin_ws/src
git clone https://github.com/RobustFieldAutonomyLab/LeGO-LOAM.git
cd ..
catkin_make -j1

When you compile the code for the first time, you need to add "-j1" behind "catkin_make" for generating some message types. "-j1" is not needed for future compiling.

The system

LeGO-LOAM is speficifally optimized for a horizontally placed VLP-16 on a ground vehicle. It assumes there is always a ground plane in the scan. The UGV we are using is Clearpath Jackal. It has a built-in IMU.

drawing

The package performs segmentation before feature extraction.

drawing

Lidar odometry performs two-step Levenberg Marquardt optimization to get 6D transformation.

drawing

New Lidar

The key thing to adapt the code to a new sensor is making sure the point cloud can be properly projected to an range image and ground can be correctly detected. For example, VLP-16 has a angular resolution of 0.2° and 2° along two directions. It has 16 beams. The angle of the bottom beam is -15°. Thus, the parameters in "utility.h" are listed as below. When you implement new sensor, make sure that the ground_cloud has enough points for matching. Before you post any issues, please read this.

extern const int N_SCAN = 16;
extern const int Horizon_SCAN = 1800;
extern const float ang_res_x = 0.2;
extern const float ang_res_y = 2.0;
extern const float ang_bottom = 15.0;
extern const int groundScanInd = 7;

Another example for Velodyne HDL-32e range image projection:

extern const int N_SCAN = 32;
extern const int Horizon_SCAN = 1800;
extern const float ang_res_x = 360.0/Horizon_SCAN;
extern const float ang_res_y = 41.333/float(N_Scan-1);
extern const float ang_bottom = 30.666666;
extern const int groundScanInd = 20;

New: a new useCloudRing flag has been added to help with point cloud projection (i.e., VLP-32C, VLS-128). Velodyne point cloud has "ring" channel that directly gives the point row id in a range image. Other lidars may have a same type of channel, i.e., "r" in Ouster. If you are using a non-Velodyne lidar but it has a similar "ring" channel, you can change the PointXYZIR definition in utility.h and the corresponding code in imageProjection.cpp.

For KITTI users, if you want to use our algorithm with HDL-64e, you need to write your own implementation for such projection. If the point cloud is not projected properly, you will lose many points and performance.

If you are using your lidar with an IMU, make sure your IMU is aligned properly with the lidar. The algorithm uses IMU data to correct the point cloud distortion that is cause by sensor motion. If the IMU is not aligned properly, the usage of IMU data will deteriorate the result. Ouster lidar IMU is not supported in the package as LeGO-LOAM needs a 9-DOF IMU.

Run the package

  1. Run the launch file:
roslaunch lego_loam run.launch

Notes: The parameter "/use_sim_time" is set to "true" for simulation, "false" to real robot usage.

  1. Play existing bag files:
rosbag play *.bag --clock --topic /velodyne_points /imu/data

Notes: Though /imu/data is optinal, it can improve estimation accuracy greatly if provided. Some sample bags can be downloaded from here.

New data-set

This dataset, Stevens data-set, is captured using a Velodyne VLP-16, which is mounted on an UGV - Clearpath Jackal, on Stevens Institute of Technology campus. The VLP-16 rotation rate is set to 10Hz. This data-set features over 20K scans and many loop-closures.

drawing

drawing

Cite LeGO-LOAM

Thank you for citing our LeGO-LOAM paper if you use any of this code:

@inproceedings{legoloam2018,
  title={LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain},
  author={Shan, Tixiao and Englot, Brendan},
  booktitle={IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
  pages={4758-4765},
  year={2018},
  organization={IEEE}
}

Loop Closure

The loop-closure method implemented in this package is a naive ICP-based method. It often fails when the odometry drift is too large. For more advanced loop-closure methods, there is a package called SC-LeGO-LOAM, which features utilizing point cloud descriptor.

Speed Optimization

An optimized version of LeGO-LOAM can be found here. All credits go to @facontidavide. Improvements in this directory include but not limited to:

+ To improve the quality of the code, making it more readable, consistent and easier to understand and modify.
+ To remove hard-coded values and use proper configuration files to describe the hardware.
+ To improve performance, in terms of amount of CPU used to calculate the same result.
+ To convert a multi-process application into a single-process / multi-threading one; this makes the algorithm more deterministic and slightly faster.
+ To make it easier and faster to work with rosbags: processing a rosbag should be done at maximum speed allowed by the CPU and in a deterministic way.
+ As a consequence of the previous point, creating unit and regression tests will be easier.