Skip to content

Commit c8aea0d

Browse files
committed
support for Scan context loop closure
1 parent 96774ef commit c8aea0d

File tree

7 files changed

+89
-38
lines changed

7 files changed

+89
-38
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
3. [UAV Avoiding Dynamic Obstacles](https://github.com/hku-mars/dyn_small_obs_avoidance): One of the implementation of FAST-LIO in robot's planning.
66
4. [R2LIVE](https://github.com/hku-mars/r2live): A high-precision LiDAR-inertial-Vision fusion work using FAST-LIO as LiDAR-inertial front-end.
77
5. [UGV Demo](https://www.youtube.com/watch?v=wikgrQbE6Cs): Model Predictive Control for Trajectory Tracking on Differentiable Manifolds.
8-
6. [SC-A-LOAM](https://github.com/gisbi-kim/SC-A-LOAM#for-livox-lidar): A [Scan-Context](https://github.com/irapkaist/scancontext) loop closure module that can directly work with FAST-LIO1 (The support for FAST-LIO2 is under developing).
8+
6. [SC-A-LOAM](https://github.com/gisbi-kim/SC-A-LOAM#for-livox-lidar): A [Scan-Context](https://github.com/irapkaist/scancontext) loop closure module that can directly work with FAST-LIO.
99

1010
## FAST-LIO
1111
**FAST-LIO** (Fast LiDAR-Inertial Odometry) is a computationally efficient and robust LiDAR-inertial odometry package. It fuses LiDAR feature points with IMU data using a tightly-coupled iterated extended Kalman filter to allow robust navigation in fast-motion, noisy or cluttered environments where degeneration occurs. Our package address many key issues:
@@ -30,8 +30,8 @@
3030

3131
**New Features:**
3232
1. Incremental mapping using [ikd-Tree](https://github.com/hku-mars/ikd-Tree), achieve faster speed and over 100Hz LiDAR rate.
33-
2. Direct odometry (scan to map) on Raw LiDAR points (feature extraction can be closed), achieving better accuracy.
34-
3. Since no need for feature extraction, FAST-LIO2 can support different LiDAR Types including spinning (Velodyne, Ouster) and solid-state (Avia, horizon) LiDARs, and can be easily extended to support more LiDAR.
33+
2. Direct odometry (scan to map) on Raw LiDAR points (feature extraction can be disabled), achieving better accuracy.
34+
3. Since no requirements for feature extraction, FAST-LIO2 can support may types of LiDAR including spinning (Velodyne, Ouster) and solid-state (Livox Avia, Horizon, MID-70) LiDARs, and can be easily extended to support more LiDARs.
3535
4. Support external IMU.
3636
5. Support ARM-based platforms including Khadas VIM3, Nivida TX2, Raspberry Pi 4B(8G RAM).
3737

@@ -121,7 +121,7 @@ Edit ``` config/velodyne.yaml ``` to set the below parameters:
121121

122122
1. LiDAR point cloud topic name: ``` lid_topic ```
123123
2. IMU topic name: ``` imu_topic ``` (both internal and external, 6-aixes or 9-axies are fine)
124-
3. Line number (we tested 16 and 32 line, but not tested 64 or above): ``` scan_line ```
124+
3. Line number (we tested 16, 32 and 64 line, but not tested 128 or above): ``` scan_line ```
125125
4. Translational extrinsic: ``` extrinsic_T ```
126126
5. Rotational extrinsic: ``` extrinsic_R ``` (only support rotation matrix)
127127
- The extrinsic parameters in FAST-LIO is defined as the LiDAR's pose (position and rotation matrix) in IMU body frame (i.e. the IMU is the base frame).

config/avia.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@ mapping:
1818
extrinsic_T: [ 0.04165, 0.02326, -0.0284 ]
1919
extrinsic_R: [ 1, 0, 0,
2020
0, 1, 0,
21-
0, 0, 1]
21+
0, 0, 1]
22+
23+
publish:
24+
scan_publish_en: true # 'false' will close all the point cloud output
25+
dense_publish_en: ture # false will low down the points number in a global-frame point clouds scan.
26+
scan_bodyframe_pub_en: true # output the point cloud scans in IMU-body-frame

config/horizon.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@ mapping:
1818
extrinsic_T: [ 0.05512, 0.02226, -0.0297 ]
1919
extrinsic_R: [ 1, 0, 0,
2020
0, 1, 0,
21-
0, 0, 1]
21+
0, 0, 1]
22+
23+
publish:
24+
scan_publish_en: true # 'false' will close all the point cloud output
25+
dense_publish_en: ture # false will low down the points number in a global-frame point clouds scan.
26+
scan_bodyframe_pub_en: true # output the point cloud scans in IMU-body-frame

config/ouster64.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@ mapping:
1818
extrinsic_T: [ 0.0, 0.0, 0.0 ]
1919
extrinsic_R: [1, 0, 0,
2020
0, 1, 0,
21-
0, 0, 1]
21+
0, 0, 1]
22+
23+
publish:
24+
scan_publish_en: true # 'false' will close all the point cloud output
25+
dense_publish_en: ture # false will low down the points number in a global-frame point clouds scan.
26+
scan_bodyframe_pub_en: true # output the point cloud scans in IMU-body-frame

config/velodyne.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@ mapping:
1818
extrinsic_T: [ 0, 0, 0.28]
1919
extrinsic_R: [ 1, 0, 0,
2020
0, 1, 0,
21-
0, 0, 1]
21+
0, 0, 1]
22+
23+
publish:
24+
scan_publish_en: true # 'false' will close all the point cloud output
25+
dense_publish_en: ture # false will low down the points number in a global-frame point clouds scan.
26+
scan_bodyframe_pub_en: true # output the point cloud scans in IMU-body-frame

rviz_cfg/loam_livox.rviz

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Panels:
3535
Experimental: false
3636
Name: Time
3737
SyncMode: 0
38-
SyncSource: ""
38+
SyncSource: surround
3939
Preferences:
4040
PromptSaveOnExit: true
4141
Toolbars:
@@ -81,11 +81,11 @@ Visualization Manager:
8181
Class: rviz/PointCloud2
8282
Color: 238; 238; 236
8383
Color Transformer: Intensity
84-
Decay Time: 0
84+
Decay Time: 1000
8585
Enabled: true
8686
Invert Rainbow: false
8787
Max Color: 255; 255; 255
88-
Max Intensity: 150
88+
Max Intensity: 158
8989
Min Color: 0; 0; 0
9090
Min Intensity: 0
9191
Name: surround
@@ -195,7 +195,7 @@ Visualization Manager:
195195
Shaft Length: 0.05000000074505806
196196
Shaft Radius: 0.05000000074505806
197197
Value: Axes
198-
Topic: /aft_mapped_to_init
198+
Topic: /Odometry
199199
Unreliable: false
200200
Value: true
201201
Enabled: true
@@ -302,7 +302,7 @@ Visualization Manager:
302302
Global Options:
303303
Background Color: 0; 0; 0
304304
Default Light: true
305-
Fixed Frame: camera_init
305+
Fixed Frame: global
306306
Frame Rate: 10
307307
Name: root
308308
Tools:
@@ -333,18 +333,18 @@ Visualization Manager:
333333
Swap Stereo Eyes: false
334334
Value: false
335335
Focal Point:
336-
X: 5.488441467285156
337-
Y: -29.57037353515625
338-
Z: 2.2303884179564193e-6
336+
X: 36.65506362915039
337+
Y: 2.3543496131896973
338+
Z: -1.0087411283166148e-5
339339
Focal Shape Fixed Size: false
340340
Focal Shape Size: 0.05000000074505806
341341
Invert Z Axis: false
342342
Name: Current View
343343
Near Clip Distance: 0.009999999776482582
344-
Pitch: 0.740202784538269
345-
Target Frame: camera_init
344+
Pitch: 1.5697963237762451
345+
Target Frame: global
346346
Value: ThirdPersonFollower (rviz)
347-
Yaw: 3.57222843170166
347+
Yaw: 3.0072357654571533
348348
Saved: ~
349349
Window Geometry:
350350
Displays:

src/laserMapping.cpp

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ int effct_feat_num = 0, time_log_counter = 0, scan_count = 0, publish_count =
9292
int iterCount = 0, feats_down_size = 0, NUM_MAX_ITERATIONS = 0, laserCloudValidNum = 0;
9393
bool point_selected_surf[100000] = {0};
9494
bool lidar_pushed, flg_reset, flg_exit = false, flg_EKF_inited;
95-
bool scan_pub_en = false, dense_pub_en = false;
95+
bool scan_pub_en = false, dense_pub_en = false, scan_body_pub_en = false;
9696

9797
vector<vector<int>> pointSearchInd_surf;
9898
vector<BoxPointType> cub_needrm;
@@ -206,6 +206,17 @@ void RGBpointBodyToWorld(PointType const * const pi, PointType * const po)
206206
po->intensity = pi->intensity;
207207
}
208208

209+
void RGBpointBodyLidarToIMU(PointType const * const pi, PointType * const po)
210+
{
211+
V3D p_body_lidar(pi->x, pi->y, pi->z);
212+
V3D p_body_imu(state_point.offset_R_L_I*p_body_lidar + state_point.offset_T_L_I);
213+
214+
po->x = p_body_imu(0);
215+
po->y = p_body_imu(1);
216+
po->z = p_body_imu(2);
217+
po->intensity = pi->intensity;
218+
}
219+
209220
void points_cache_collect()
210221
{
211222
PointVector points_history;
@@ -443,9 +454,8 @@ void map_incremental()
443454

444455
PointCloudXYZI::Ptr pcl_wait_pub(new PointCloudXYZI(500000, 1));
445456
PointCloudXYZI::Ptr pcl_wait_save(new PointCloudXYZI());
446-
void publish_frame_world(const ros::Publisher & pubLaserCloudFullRes)
457+
void publish_frame_world(const ros::Publisher & pubLaserCloudFull)
447458
{
448-
// *pcl_wait_pub += *laserCloudWorld;
449459
if(scan_pub_en)
450460
{
451461
PointCloudXYZI::Ptr laserCloudFullRes(dense_pub_en ? feats_undistort : feats_down_body);
@@ -461,11 +471,10 @@ void publish_frame_world(const ros::Publisher & pubLaserCloudFullRes)
461471

462472
sensor_msgs::PointCloud2 laserCloudmsg;
463473
pcl::toROSMsg(*laserCloudWorld, laserCloudmsg);
464-
laserCloudmsg.header.stamp = ros::Time::now();
474+
laserCloudmsg.header.stamp = ros::Time().fromSec(lidar_end_time);
465475
laserCloudmsg.header.frame_id = "camera_init";
466-
pubLaserCloudFullRes.publish(laserCloudmsg);
476+
pubLaserCloudFull.publish(laserCloudmsg);
467477
publish_count -= PUBFRAME_PERIOD;
468-
// pcl_wait_pub->clear();
469478
}
470479

471480
/**************** save map ****************/
@@ -486,6 +495,25 @@ void publish_frame_world(const ros::Publisher & pubLaserCloudFullRes)
486495
}
487496
}
488497

498+
void publish_frame_body(const ros::Publisher & pubLaserCloudFull_body)
499+
{
500+
int size = feats_undistort->points.size();
501+
PointCloudXYZI::Ptr laserCloudIMUBody(new PointCloudXYZI(size, 1));
502+
503+
for (int i = 0; i < size; i++)
504+
{
505+
RGBpointBodyLidarToIMU(&feats_undistort->points[i], \
506+
&laserCloudIMUBody->points[i]);
507+
}
508+
509+
sensor_msgs::PointCloud2 laserCloudmsg;
510+
pcl::toROSMsg(*laserCloudIMUBody, laserCloudmsg);
511+
laserCloudmsg.header.stamp = ros::Time().fromSec(lidar_end_time);
512+
laserCloudmsg.header.frame_id = "body";
513+
pubLaserCloudFull_body.publish(laserCloudmsg);
514+
publish_count -= PUBFRAME_PERIOD;
515+
}
516+
489517
void publish_effect_world(const ros::Publisher & pubLaserCloudEffect)
490518
{
491519
PointCloudXYZI::Ptr laserCloudWorld( \
@@ -497,7 +525,7 @@ void publish_effect_world(const ros::Publisher & pubLaserCloudEffect)
497525
}
498526
sensor_msgs::PointCloud2 laserCloudFullRes3;
499527
pcl::toROSMsg(*laserCloudWorld, laserCloudFullRes3);
500-
laserCloudFullRes3.header.stamp = ros::Time::now();
528+
laserCloudFullRes3.header.stamp = ros::Time().fromSec(lidar_end_time);
501529
laserCloudFullRes3.header.frame_id = "camera_init";
502530
pubLaserCloudEffect.publish(laserCloudFullRes3);
503531
}
@@ -506,7 +534,7 @@ void publish_map(const ros::Publisher & pubLaserCloudMap)
506534
{
507535
sensor_msgs::PointCloud2 laserCloudMap;
508536
pcl::toROSMsg(*featsFromMap, laserCloudMap);
509-
laserCloudMap.header.stamp = ros::Time::now();
537+
laserCloudMap.header.stamp = ros::Time().fromSec(lidar_end_time);
510538
laserCloudMap.header.frame_id = "camera_init";
511539
pubLaserCloudMap.publish(laserCloudMap);
512540
}
@@ -527,8 +555,8 @@ void set_posestamp(T & out)
527555
void publish_odometry(const ros::Publisher & pubOdomAftMapped)
528556
{
529557
odomAftMapped.header.frame_id = "camera_init";
530-
odomAftMapped.child_frame_id = "aft_mapped";
531-
odomAftMapped.header.stamp = ros::Time::now();//ros::Time().fromSec(last_timestamp_lidar);
558+
odomAftMapped.child_frame_id = "body";
559+
odomAftMapped.header.stamp = ros::Time().fromSec(lidar_end_time);// ros::Time().fromSec(lidar_end_time);
532560
set_posestamp(odomAftMapped.pose);
533561
pubOdomAftMapped.publish(odomAftMapped);
534562
auto P = kf.get_P();
@@ -554,13 +582,13 @@ void publish_odometry(const ros::Publisher & pubOdomAftMapped)
554582
q.setY(odomAftMapped.pose.pose.orientation.y);
555583
q.setZ(odomAftMapped.pose.pose.orientation.z);
556584
transform.setRotation( q );
557-
br.sendTransform( tf::StampedTransform( transform, odomAftMapped.header.stamp, "camera_init", "aft_mapped" ) );
585+
br.sendTransform( tf::StampedTransform( transform, odomAftMapped.header.stamp, "camera_init", "body" ) );
558586
}
559587

560588
void publish_path(const ros::Publisher pubPath)
561589
{
562590
set_posestamp(msg_body_pose);
563-
msg_body_pose.header.stamp = ros::Time::now();
591+
msg_body_pose.header.stamp = ros::Time().fromSec(lidar_end_time);
564592
msg_body_pose.header.frame_id = "camera_init";
565593

566594
/*** if path is too large, the rvis will crash ***/
@@ -682,8 +710,9 @@ int main(int argc, char** argv)
682710
ros::init(argc, argv, "laserMapping");
683711
ros::NodeHandle nh;
684712

685-
nh.param<bool>("scan_publish_enable",scan_pub_en,1);
686-
nh.param<bool>("dense_publish_enable",dense_pub_en,0);
713+
nh.param<bool>("publish/scan_publish_en",scan_pub_en,1);
714+
nh.param<bool>("publish/dense_publish_en",dense_pub_en,0);
715+
nh.param<bool>("publish/scan_bodyframe_pub_en",scan_body_pub_en,1);
687716
nh.param<int>("max_iteration",NUM_MAX_ITERATIONS,4);
688717
nh.param<string>("map_file_path",map_file_path,"");
689718
nh.param<string>("common/lid_topic",lid_topic,"/livox/lidar");
@@ -761,14 +790,16 @@ int main(int argc, char** argv)
761790
nh.subscribe(lid_topic, 200000, livox_pcl_cbk) : \
762791
nh.subscribe(lid_topic, 200000, standard_pcl_cbk);
763792
ros::Subscriber sub_imu = nh.subscribe(imu_topic, 200000, imu_cbk);
764-
ros::Publisher pubLaserCloudFullRes = nh.advertise<sensor_msgs::PointCloud2>
793+
ros::Publisher pubLaserCloudFull = nh.advertise<sensor_msgs::PointCloud2>
765794
("/cloud_registered", 100000);
766-
ros::Publisher pubLaserCloudEffect = nh.advertise<sensor_msgs::PointCloud2>
795+
ros::Publisher pubLaserCloudFull_body = nh.advertise<sensor_msgs::PointCloud2>
796+
("/cloud_registered_body", 100000);
797+
ros::Publisher pubLaserCloudEffect = nh.advertise<sensor_msgs::PointCloud2>
767798
("/cloud_effected", 100000);
768799
ros::Publisher pubLaserCloudMap = nh.advertise<sensor_msgs::PointCloud2>
769800
("/Laser_map", 100000);
770801
ros::Publisher pubOdomAftMapped = nh.advertise<nav_msgs::Odometry>
771-
("/aft_mapped_to_init", 100000);
802+
("/Odometry", 100000);
772803
ros::Publisher pubPath = nh.advertise<nav_msgs::Path>
773804
("/path", 100000);
774805
//------------------------------------------------------------------------------------------------------
@@ -888,8 +919,8 @@ int main(int argc, char** argv)
888919

889920
/******* Publish points *******/
890921
publish_path(pubPath);
891-
if (scan_pub_en || pcd_save_en) publish_frame_world(pubLaserCloudFullRes);
892-
922+
if (scan_pub_en || pcd_save_en) publish_frame_world(pubLaserCloudFull);
923+
if (scan_pub_en && scan_body_pub_en) publish_frame_body(pubLaserCloudFull_body);
893924
// publish_effect_world(pubLaserCloudEffect);
894925
// publish_map(pubLaserCloudMap);
895926

0 commit comments

Comments
 (0)