53 #include <pcl/pcl_base.h> 59 int odomTypeInt = Parameters::defaultOdomStrategy();
62 return create(type, parameters);
67 UDEBUG(
"type=%d", (
int)type);
111 UERROR(
"Unknown odometry type %d, using F2M instead...", (
int)type);
223 if(z != 0.0
f || roll != 0.0
f || pitch != 0.0
f)
225 UWARN(
"Force2D=true and the initial pose contains z, roll or pitch values (%s). They are set to null.", initialPose.
prettyPrint().c_str());
230 Transform pose(x, y, z, roll, pitch, yaw);
260 const Transform & Odometry::previousVelocityTransform()
const 267 if(transforms.size())
269 float tvx=0.0f,tvy=0.0f,tvz=0.0f, tvroll=0.0f,tvpitch=0.0f,tvyaw=0.0f;
270 for(std::list<std::pair<std::vector<float>,
double> >::const_iterator iter=transforms.begin(); iter!=transforms.end(); ++iter)
272 UASSERT(iter->first.size() == 6);
276 tvroll+=iter->first[3];
277 tvpitch+=iter->first[4];
278 tvyaw+=iter->first[5];
280 tvx/=float(transforms.size());
281 tvy/=float(transforms.size());
282 tvz/=float(transforms.size());
283 tvroll/=float(transforms.size());
284 tvpitch/=float(transforms.size());
285 tvyaw/=float(transforms.size());
286 return Transform(tvx, tvy, tvz, tvroll, tvpitch, tvyaw);
298 UASSERT_MSG(data.
id() >= 0,
uFormat(
"Input data should have ID greater or equal than 0 (id=%d)!", data.
id()).c_str());
316 Transform newFramePose =
Transform(previous.
x(), previous.
y(), previous.
z(), imuQuat.x(), imuQuat.y(), imuQuat.z(), imuQuat.w());
317 UWARN(
"Updated initial pose from %s to %s with IMU orientation", previous.
prettyPrint().c_str(), newFramePose.
prettyPrint().c_str());
318 this->
reset(newFramePose);
321 imus_.insert(std::make_pair(data.
stamp(), imuT));
322 if(
imus_.size() > 1000)
360 UWARN(
"%s parameter is set to false but the selected odometry approach cannot " 361 "process raw stereo images. We will rectify them for convenience.",
362 Parameters::kRtabmapImagesAlreadyRectified().c_str());
366 UERROR(
"Odometry approach chosen cannot process raw stereo images (not rectified images) " 367 "and we cannot rectify them as the rectification map failed to initialize (valid calibration?). " 368 "Make sure images are rectified and set %s parameter back to true, or " 369 "make sure calibration is valid for rectification",
370 Parameters::kRtabmapImagesAlreadyRectified().c_str());
388 cv::Mat rectifiedLeftImages = data.
imageRaw().clone();
389 cv::Mat rectifiedRightImages = data.
imageRaw().clone();
392 cv::Mat rectifiedLeft =
stereoModels_[i].left().rectifyImage(cv::Mat(data.
imageRaw(), cv::Rect(subImageWidth*i, 0, subImageWidth, data.
imageRaw().rows)));
393 cv::Mat rectifiedRight =
stereoModels_[i].right().rectifyImage(cv::Mat(data.
rightRaw(), cv::Rect(subImageWidth*i, 0, subImageWidth, data.
rightRaw().rows)));
394 rectifiedLeft.copyTo(cv::Mat(rectifiedLeftImages, cv::Rect(subImageWidth*i, 0, subImageWidth, data.
imageRaw().rows)));
395 rectifiedRight.copyTo(cv::Mat(rectifiedRightImages, cv::Rect(subImageWidth*i, 0, subImageWidth, data.
imageRaw().rows)));
411 for(
size_t i=0; i<data.
cameraModels().size() && valid; ++i)
413 valid =
models_[i].isRectificationMapInitialized() &&
422 for(
size_t i=0; i<
models_.size() && valid; ++i)
424 valid =
models_[i].initRectificationMap();
428 UWARN(
"%s parameter is set to false but the selected odometry approach cannot " 429 "process raw images. We will rectify them for convenience (only " 430 "rgb is rectified, we assume depth image is already rectified!).",
431 Parameters::kRtabmapImagesAlreadyRectified().c_str());
435 UERROR(
"Odometry approach chosen cannot process raw images (not rectified images) " 436 "and we cannot rectify them as the rectification map failed to initialize (valid calibration?). " 437 "Make sure images are rectified and set %s parameter back to true, or " 438 "make sure calibration is valid for rectification",
439 Parameters::kRtabmapImagesAlreadyRectified().c_str());
454 cv::Mat rectifiedImages = data.
imageRaw().clone();
455 for(
size_t i=0; i<
models_.size() && valid; ++i)
457 cv::Mat rectifiedImage =
models_[i].rectifyImage(cv::Mat(data.
imageRaw(), cv::Rect(subImageWidth*i, 0, subImageWidth, data.
imageRaw().rows)));
458 rectifiedImage.copyTo(cv::Mat(rectifiedImages, cv::Rect(subImageWidth*i, 0, subImageWidth, data.
imageRaw().rows)));
466 UERROR(
"Odometry approach chosen cannot process raw images (not rectified images). Make sure images " 467 "are rectified, and set %s parameter back to true, or make sure that calibration is valid " 468 "for rectification so we can rectifiy them for convenience",
469 Parameters::kRtabmapImagesAlreadyRectified().c_str());
478 UWARN(
"\"%s\" is true but the input has no depth information, ignoring alignment with ground...", Parameters::kOdomAlignWithGround().c_str());
483 pcl::IndicesPtr indices(
new std::vector<int>);
484 pcl::IndicesPtr ground, obstacles;
486 bool success =
false;
490 util3d::segmentObstaclesFromGround<pcl::PointXYZ>(cloud, ground, obstacles, 20,
M_PI/4.0f, 0.02, 200,
true);
493 pcl::ModelCoefficients coefficients;
495 if(coefficients.values.at(3) >= 0)
497 UWARN(
"Ground detected! coefficients=(%f, %f, %f, %f) time=%fs",
498 coefficients.values.at(0),
499 coefficients.values.at(1),
500 coefficients.values.at(2),
501 coefficients.values.at(3),
506 UWARN(
"Ceiling detected! coefficients=(%f, %f, %f, %f) time=%fs",
507 coefficients.values.at(0),
508 coefficients.values.at(1),
509 coefficients.values.at(2),
510 coefficients.values.at(3),
513 Eigen::Vector3f n(coefficients.values.at(0), coefficients.values.at(1), coefficients.values.at(2));
514 Eigen::Vector3f z(0,0,1);
517 R = Eigen::Quaternionf().setFromTwoVectors(n,z);
519 R(0,0), R(0,1), R(0,2), 0,
520 R(1,0), R(1,1), R(1,2), 0,
521 R(2,0), R(2,1), R(2,2), coefficients.values.at(3));
528 UERROR(
"Odometry failed to detect the ground. You have this " 529 "error because parameter \"%s\" is true. " 530 "Make sure the camera is seeing the ground (e.g., tilt ~30 " 531 "degrees toward the ground).", Parameters::kOdomAlignWithGround().c_str());
543 UERROR(
"Guess from motion is set but dt is invalid! Odometry is then computed without guess. (dt=%f previous transform=%s)", dt,
velocityGuess_.
prettyPrint().c_str());
547 UERROR(
"Kalman filtering is enabled but dt is invalid! Odometry is then computed without Kalman filtering. (dt=%f previous transform=%s)", dt,
velocityGuess_.
prettyPrint().c_str());
560 float vx,vy,vz, vroll,vpitch,vyaw;
562 guess =
Transform(vx*dt, vy*dt, vz*dt, vroll*dt, vpitch*dt, vyaw*dt);
566 float vx,vy,vz, vroll,vpitch,vyaw;
568 guess =
Transform(vx*dt, vy*dt, vz*dt, vroll*dt, vpitch*dt, vyaw*dt);
582 else if(!
imus_.empty())
590 orientation.
r11(), orientation.
r12(), orientation.
r13(), guess.
x(),
591 orientation.
r21(), orientation.
r22(), orientation.
r23(), guess.
y(),
592 orientation.
r31(), orientation.
r32(), orientation.
r33(), guess.
z());
600 UWARN(
"Could not find imu transform at %f", data.
stamp());
617 if(targetSize >= data.
depthRaw().rows)
623 decimationDepth = (int)
ceil(
float(data.
depthRaw().rows) /
float(targetSize));
630 std::vector<CameraModel> cameraModels = decimatedData.
cameraModels();
631 for(
unsigned int i=0; i<cameraModels.size(); ++i)
635 if(!cameraModels.empty())
637 decimatedData.
setRGBDImage(rgbLeft, depthRight, cameraModels);
642 for(
unsigned int i=0; i<stereoModels.size(); ++i)
646 if(!stereoModels.empty())
657 std::vector<cv::KeyPoint> kpts = decimatedData.
keypoints();
659 for(
unsigned int i=0; i<kpts.size(); ++i)
664 kpts[i].octave += log2value;
672 for(
unsigned int i=0; i<info->
newCorners.size(); ++i)
682 for(std::multimap<int, cv::KeyPoint>::iterator iter=info->
words.begin(); iter!=info->
words.end(); ++iter)
687 iter->second.octave += log2value;
728 float vx,vy,vz, vroll,vpitch,vyaw;
788 float tmpY = vyaw!=0.0f ? vx /
tan((CV_PI-vyaw)/2.0
f) : 0.0f;
789 if(fabs(tmpY) < fabs(vy) || (tmpY<=0 && vy >=0) || (tmpY>=0 && vy<=0))
795 vyaw = (
atan(vx/vy)*2.0f-CV_PI)*-1;
815 vy = vyaw!=0.0f ? vx /
tan((CV_PI-vyaw)/2.0
f) : 0.0f;
828 t =
Transform(vx*dt, vy*dt, vz*dt, vroll*dt, vpitch*dt, vyaw*dt);
832 t =
Transform(vx, vy, vz, vroll, vpitch, vyaw);
843 UWARN(
"Null stamp detected");
858 std::vector<float> v(6);
893 UWARN(
"Odometry lost! Odometry will be reset after next %d consecutive unsuccessful odometry updates...",
_resetCurrentCount);
898 UWARN(
"Odometry automatically reset to latest pose!");
923 int nMeasurements = 6;
1080 *vx = prediction.at<
float>(3);
1082 *vy = prediction.at<
float>(4);
1084 *vz =
_force3DoF?0.0f:prediction.at<
float>(5);
1086 *vroll =
_force3DoF?0.0f:prediction.at<
float>(12);
1088 *vpitch =
_force3DoF?0.0f:prediction.at<
float>(13);
1090 *vyaw = prediction.at<
float>(
_force3DoF?7:14);
1096 cv::Mat measurements;
1099 measurements = cv::Mat(6,1,CV_32FC1);
1100 measurements.at<
float>(0) = vx;
1101 measurements.at<
float>(1) = vy;
1102 measurements.at<
float>(2) = vz;
1103 measurements.at<
float>(3) = vroll;
1104 measurements.at<
float>(4) = vpitch;
1105 measurements.at<
float>(5) = vyaw;
1109 measurements = cv::Mat(3,1,CV_32FC1);
1110 measurements.at<
float>(0) = vx;
1111 measurements.at<
float>(1) = vy;
1112 measurements.at<
float>(2) = vyaw;
1117 const cv::Mat & estimated =
kalmanFilter_.correct(measurements);
1120 vx = estimated.at<
float>(3);
1121 vy = estimated.at<
float>(4);
1123 vroll =
_force3DoF?0.0f:estimated.at<
float>(12);
1124 vpitch =
_force3DoF?0.0f:estimated.at<
float>(13);
GLM_FUNC_DECL genType log(genType const &x)
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
bool _imagesAlreadyRectified
std::vector< cv::Point2f > refCorners
constexpr T pow(const T base, const std::size_t exponent)
float _kalmanMeasurementNoise
Transform transformGroundTruth
const std::vector< cv::Point3f > & keypoints3D() const
void setLaserScan(const LaserScan &laserScan, bool clearPreviousData=true)
cv::KalmanFilter kalmanFilter_
virtual void reset(const Transform &initialPose=Transform::getIdentity())
Transform transformFiltered
unsigned int framesProcessed() const
unsigned int framesProcessed_
const cv::Mat & depthOrRightRaw() const
virtual bool canProcessAsyncIMU() const
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
void setRGBDImage(const cv::Mat &rgb, const cv::Mat &depth, const CameraModel &model, bool clearPreviousData=true)
const std::vector< StereoCameraModel > & stereoCameraModels() const
std::map< std::string, std::string > ParametersMap
const std::vector< cv::KeyPoint > & keypoints() const
float _kalmanProcessNoise
const cv::Vec4d & orientation() const
float timeParticleFiltering
Some conversion functions.
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
float guessSmoothingDelay_
void predictKalmanFilter(float dt, float *vx=0, float *vy=0, float *vz=0, float *vroll=0, float *vpitch=0, float *vyaw=0)
Transform process(SensorData &data, OdometryInfo *info=0)
std::vector< StereoCameraModel > stereoModels_
#define UASSERT(condition)
void updateKalmanFilter(float &vx, float &vy, float &vz, float &vroll, float &vpitch, float &vyaw)
const std::vector< CameraModel > & cameraModels() const
static Odometry * create(const ParametersMap ¶meters=ParametersMap())
#define UASSERT_MSG(condition, msg_str)
const Transform & getVelocityGuess() const
const cv::Mat & imageRaw() const
cv::Mat RTABMAP_EXP decimate(const cv::Mat &image, int d)
GLM_FUNC_DECL genType atan(genType const &y, genType const &x)
const cv::Mat & descriptors() const
Transform previousGroundTruthPose_
virtual Transform computeTransform(SensorData &data, const Transform &guess=Transform(), OdometryInfo *info=0)=0
void setStereoImage(const cv::Mat &left, const cv::Mat &right, const StereoCameraModel &stereoCameraModel, bool clearPreviousData=true)
std::vector< ParticleFilter * > particleFilters_
GLM_FUNC_DECL detail::tquat< T, P > rotation(detail::tvec3< T, P > const &orig, detail::tvec3< T, P > const &dest)
std::vector< CameraModel > models_
const Transform & localTransform() const
Transform getMeanVelocity(const std::list< std::pair< std::vector< float >, double > > &transforms)
const Transform & groundTruth() const
GLM_FUNC_DECL genType tan(genType const &angle)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP cloudFromSensorData(const SensorData &sensorData, int decimation=1, float maxDepth=0.0f, float minDepth=0.0f, std::vector< int > *validIndices=0, const ParametersMap &stereoParameters=ParametersMap(), const std::vector< float > &roiRatios=std::vector< float >())
const LaserScan & laserScanRaw() const
std::multimap< int, cv::KeyPoint > words
pcl::IndicesPtr extractPlane(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, float distanceThreshold, int maxIterations=100, pcl::ModelCoefficients *coefficientsOut=0)
static long int getMemoryUsage()
unsigned int _imageDecimation
virtual bool canProcessRawImages() const
ULogger class and convenient macros.
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
std::vector< cv::Point2f > newCorners
Odometry(const rtabmap::ParametersMap ¶meters)
const Transform & getPose() const
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP voxelize(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, float voxelSize)
Transform imuLastTransform_
std::map< double, Transform > imus_
std::list< std::pair< std::vector< float >, double > > previousVelocities_
std::string UTILITE_EXP uFormat(const char *fmt,...)
GLM_FUNC_DECL genType ceil(genType const &x)
void setFeatures(const std::vector< cv::KeyPoint > &keypoints, const std::vector< cv::Point3f > &keypoints3D, const cv::Mat &descriptors)
GLM_FUNC_DECL detail::tmat4x4< T, P > orientation(detail::tvec3< T, P > const &Normal, detail::tvec3< T, P > const &Up)
void initKalmanFilter(const Transform &initialPose=Transform::getIdentity(), float vx=0.0f, float vy=0.0f, float vz=0.0f, float vroll=0.0f, float vpitch=0.0f, float vyaw=0.0f)