00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rtabmap/core/OdometryLOAM.h"
00029 #include "rtabmap/core/OdometryInfo.h"
00030 #include "rtabmap/core/util2d.h"
00031 #include "rtabmap/utilite/ULogger.h"
00032 #include "rtabmap/utilite/UTimer.h"
00033 #include "rtabmap/utilite/UStl.h"
00034 #include "rtabmap/core/util3d.h"
00035 #include <pcl/common/transforms.h>
00036
00037 float SCAN_PERIOD = 0.1f;
00038
00039 namespace rtabmap {
00040
00045 OdometryLOAM::OdometryLOAM(const ParametersMap & parameters) :
00046 Odometry(parameters)
00047 #ifdef RTABMAP_LOAM
00048 ,lastPose_(Transform::getIdentity())
00049 ,scanPeriod_(Parameters::defaultOdomLOAMScanPeriod())
00050 ,linVar_(Parameters::defaultOdomLOAMLinVar())
00051 ,angVar_(Parameters::defaultOdomLOAMAngVar())
00052 ,localMapping_(Parameters::defaultOdomLOAMLocalMapping())
00053 ,lost_(false)
00054 #endif
00055 {
00056 #ifdef RTABMAP_LOAM
00057 int velodyneType = 0;
00058 Parameters::parse(parameters, Parameters::kOdomLOAMSensor(), velodyneType);
00059 Parameters::parse(parameters, Parameters::kOdomLOAMScanPeriod(), scanPeriod_);
00060 UASSERT(scanPeriod_>0.0f);
00061 Parameters::parse(parameters, Parameters::kOdomLOAMLinVar(), linVar_);
00062 UASSERT(linVar_>0.0f);
00063 Parameters::parse(parameters, Parameters::kOdomLOAMAngVar(), angVar_);
00064 UASSERT(angVar_>0.0f);
00065 Parameters::parse(parameters, Parameters::kOdomLOAMLocalMapping(), localMapping_);
00066 if(velodyneType == 1)
00067 {
00068 scanMapper_ = loam::MultiScanMapper::Velodyne_HDL_32();
00069 }
00070 else if(velodyneType == 2)
00071 {
00072 scanMapper_ = loam::MultiScanMapper::Velodyne_HDL_64E();
00073 }
00074 else
00075 {
00076 scanMapper_ = loam::MultiScanMapper::Velodyne_VLP_16();
00077 }
00078 laserOdometry_ = new loam::BasicLaserOdometry(scanPeriod_);
00079 laserMapping_ = new loam::BasicLaserMapping(scanPeriod_);
00080 #endif
00081 }
00082
00083 OdometryLOAM::~OdometryLOAM()
00084 {
00085 #ifdef RTABMAP_LOAM
00086 delete laserOdometry_;
00087 delete laserMapping_;
00088 #endif
00089 }
00090
00091 void OdometryLOAM::reset(const Transform & initialPose)
00092 {
00093 Odometry::reset(initialPose);
00094 #ifdef RTABMAP_LOAM
00095 lastPose_.setIdentity();
00096 scanRegistration_ = loam::BasicScanRegistration();
00097 loam::RegistrationParams regParams;
00098 regParams.scanPeriod = scanPeriod_;
00099 scanRegistration_.configure(regParams);
00100 delete laserOdometry_;
00101 laserOdometry_ = new loam::BasicLaserOdometry(scanPeriod_);
00102 delete laserMapping_;
00103 laserMapping_ = new loam::BasicLaserMapping(scanPeriod_);
00104 transformMaintenance_ = loam::BasicTransformMaintenance();
00105 lost_ = false;
00106 #endif
00107 }
00108
00109 #ifdef RTABMAP_LOAM
00110 std::vector<pcl::PointCloud<pcl::PointXYZI> > OdometryLOAM::segmentScanRings(const pcl::PointCloud<pcl::PointXYZ> & laserCloudIn)
00111 {
00112 std::vector<pcl::PointCloud<pcl::PointXYZI> > laserCloudScans;
00113
00114 size_t cloudSize = laserCloudIn.size();
00115
00116
00117 float startOri = -std::atan2(laserCloudIn[0].y, laserCloudIn[0].x);
00118 float endOri = -std::atan2(laserCloudIn[cloudSize - 1].y,
00119 laserCloudIn[cloudSize - 1].x) + 2 * float(M_PI);
00120 if (endOri - startOri > 3 * M_PI) {
00121 endOri -= 2 * M_PI;
00122 } else if (endOri - startOri < M_PI) {
00123 endOri += 2 * M_PI;
00124 }
00125
00126 bool halfPassed = false;
00127 pcl::PointXYZI point;
00128 laserCloudScans.resize(scanMapper_.getNumberOfScanRings());
00129
00130 std::for_each(laserCloudScans.begin(), laserCloudScans.end(), [](auto&&v) {v.clear(); });
00131
00132
00133 for (size_t i = 0; i < cloudSize; i++) {
00134 point.x = laserCloudIn[i].y;
00135 point.y = laserCloudIn[i].z;
00136 point.z = laserCloudIn[i].x;
00137
00138
00139 if (!pcl_isfinite(point.x) ||
00140 !pcl_isfinite(point.y) ||
00141 !pcl_isfinite(point.z)) {
00142 continue;
00143 }
00144
00145
00146 if (point.x * point.x + point.y * point.y + point.z * point.z < 0.0001) {
00147 continue;
00148 }
00149
00150
00151 float angle = std::atan(point.y / std::sqrt(point.x * point.x + point.z * point.z));
00152 int scanID = scanMapper_.getRingForAngle(angle);
00153 if (scanID >= scanMapper_.getNumberOfScanRings() || scanID < 0 ){
00154 continue;
00155 }
00156
00157
00158 float ori = -std::atan2(point.x, point.z);
00159 if (!halfPassed) {
00160 if (ori < startOri - M_PI / 2) {
00161 ori += 2 * M_PI;
00162 } else if (ori > startOri + M_PI * 3 / 2) {
00163 ori -= 2 * M_PI;
00164 }
00165
00166 if (ori - startOri > M_PI) {
00167 halfPassed = true;
00168 }
00169 } else {
00170 ori += 2 * M_PI;
00171
00172 if (ori < endOri - M_PI * 3 / 2) {
00173 ori += 2 * M_PI;
00174 } else if (ori > endOri + M_PI / 2) {
00175 ori -= 2 * M_PI;
00176 }
00177 }
00178
00179
00180 float relTime = SCAN_PERIOD * (ori - startOri) / (endOri - startOri);
00181 point.intensity = scanID + relTime;
00182
00183
00184
00185
00186 laserCloudScans[scanID].push_back(point);
00187 }
00188
00189 return laserCloudScans;
00190 }
00191 #endif
00192
00193
00194 Transform OdometryLOAM::computeTransform(
00195 SensorData & data,
00196 const Transform & guess,
00197 OdometryInfo * info)
00198 {
00199 Transform t;
00200 #ifdef RTABMAP_LOAM
00201 UTimer timer;
00202
00203 if(data.laserScanRaw().isEmpty())
00204 {
00205 UERROR("LOAM works only with laser scans and the current input is empty. Aborting odometry update...");
00206 return t;
00207 }
00208 else if(data.laserScanRaw().is2d())
00209 {
00210 UERROR("LOAM version used works only with 3D laser scans from Velodyne. Aborting odometry update...");
00211 return t;
00212 }
00213
00214 cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1)*9999;
00215 if(!lost_)
00216 {
00217 pcl::PointCloud<pcl::PointXYZ>::Ptr laserCloudInPtr = util3d::laserScanToPointCloud(data.laserScanRaw());
00218 std::vector<pcl::PointCloud<pcl::PointXYZI> > laserCloudScans = segmentScanRings(*laserCloudInPtr);
00219
00220 ros::Time stampT;
00221 stampT.fromSec(data.stamp());
00222 loam::Time scanTime = loam::fromROSTime(stampT);
00223 scanRegistration_.processScanlines(scanTime, laserCloudScans);
00224
00225 *laserOdometry_->cornerPointsSharp() = scanRegistration_.cornerPointsSharp();
00226 *laserOdometry_->cornerPointsLessSharp() = scanRegistration_.cornerPointsLessSharp();
00227 *laserOdometry_->surfPointsFlat() = scanRegistration_.surfacePointsFlat();
00228 *laserOdometry_->surfPointsLessFlat() = scanRegistration_.surfacePointsLessFlat();
00229 *laserOdometry_->laserCloud() = scanRegistration_.laserCloud();
00230 pcl::PointCloud<pcl::PointXYZ> imuTrans;
00231 imuTrans.resize(4);
00232 laserOdometry_->updateIMU(imuTrans);
00233 laserOdometry_->process();
00234
00235 if(localMapping_)
00236 {
00237 laserMapping_->laserCloudCornerLast() = *laserOdometry_->lastCornerCloud();
00238 laserMapping_->laserCloudSurfLast() = *laserOdometry_->lastSurfaceCloud();
00239 laserMapping_->laserCloud() = *laserOdometry_->laserCloud();
00240 laserMapping_->updateOdometry(laserOdometry_->transformSum());
00241 laserMapping_->process(scanTime);
00242 }
00243
00244 transformMaintenance_.updateOdometry(
00245 laserOdometry_->transformSum().rot_x.rad(),
00246 laserOdometry_->transformSum().rot_y.rad(),
00247 laserOdometry_->transformSum().rot_z.rad(),
00248 laserOdometry_->transformSum().pos.x(),
00249 laserOdometry_->transformSum().pos.y(),
00250 laserOdometry_->transformSum().pos.z());
00251 transformMaintenance_.updateMappingTransform(laserMapping_->transformAftMapped(), laserMapping_->transformBefMapped());
00252 transformMaintenance_.transformAssociateToMap();
00253 const float * tm = transformMaintenance_.transformMapped();
00254 Transform pose = Transform(tm[5], tm[3], tm[4], tm[2], tm[0], tm[1]);
00255
00256 if(!pose.isNull())
00257 {
00258 covariance = cv::Mat::eye(6,6,CV_64FC1);
00259 covariance(cv::Range(0,3), cv::Range(0,3)) *= linVar_;
00260 covariance(cv::Range(3,6), cv::Range(3,6)) *= angVar_;
00261
00262 t = lastPose_.inverse() * pose;
00263 lastPose_ = pose;
00264
00265 const Transform & localTransform = data.laserScanRaw().localTransform();
00266 if(!t.isNull() && !t.isIdentity() && !localTransform.isIdentity() && !localTransform.isNull())
00267 {
00268
00269 t = localTransform * t * localTransform.inverse();
00270 }
00271
00272 if(info)
00273 {
00274 info->type = (int)kTypeLOAM;
00275 info->localScanMapSize = laserMapping_->laserCloudSurroundDS().size();
00276 if(covariance.cols == 6 && covariance.rows == 6 && covariance.type() == CV_64FC1)
00277 {
00278 info->reg.covariance = covariance;
00279 }
00280
00281 if(this->isInfoDataFilled())
00282 {
00283 Transform rot(0,0,1,0,1,0,0,0,0,1,0,0);
00284 pcl::PointCloud<pcl::PointXYZI> out;
00285 pcl::transformPointCloud(laserMapping_->laserCloudSurroundDS(), out, rot.toEigen3f());
00286 info->localScanMap = LaserScan::backwardCompatibility(util3d::laserScanFromPointCloud(out), 0, data.laserScanRaw().maxRange(), data.laserScanRaw().localTransform());
00287 }
00288 }
00289 }
00290 else
00291 {
00292 lost_ = true;
00293 UWARN("LOAM failed to register the latest scan, odometry should be reset.");
00294 }
00295 }
00296 UINFO("Odom update time = %fs, lost=%s", timer.elapsed(), lost_?"true":"false");
00297
00298 #else
00299 UERROR("RTAB-Map is not built with LOAM support! Select another odometry approach.");
00300 #endif
00301 return t;
00302 }
00303
00304 }