OdometryLOAM.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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         // determine scan start and end orientations
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         // clear all scanline points
00130         std::for_each(laserCloudScans.begin(), laserCloudScans.end(), [](auto&&v) {v.clear(); });
00131 
00132         // extract valid points from input cloud
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                 // skip NaN and INF valued points
00139                 if (!pcl_isfinite(point.x) ||
00140                                 !pcl_isfinite(point.y) ||
00141                                 !pcl_isfinite(point.z)) {
00142                         continue;
00143                 }
00144 
00145                 // skip zero valued points
00146                 if (point.x * point.x + point.y * point.y + point.z * point.z < 0.0001) {
00147                         continue;
00148                 }
00149 
00150                 // calculate vertical point angle and scan ID
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                 // calculate horizontal point angle
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                 // calculate relative scan time based on point orientation
00180                 float relTime = SCAN_PERIOD * (ori - startOri) / (endOri - startOri);
00181                 point.intensity = scanID + relTime;
00182 
00183                 // imu not used...
00184                 //scanRegistration_.projectPointToStartOfSweep(point, relTime);
00185 
00186                 laserCloudScans[scanID].push_back(point);
00187         }
00188 
00189         return laserCloudScans;
00190 }
00191 #endif
00192 
00193 // return not null transform if odometry is correctly computed
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; // incremental
00263                         lastPose_ = pose;
00264 
00265                         const Transform & localTransform = data.laserScanRaw().localTransform();
00266                         if(!t.isNull() && !t.isIdentity() && !localTransform.isIdentity() && !localTransform.isNull())
00267                         {
00268                                 // from laser frame to base frame
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 } // namespace rtabmap


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:21