odometer ok, a nan bug needs to be located
parent
38b85ab8f2
commit
f47143f01b
|
@ -29,7 +29,7 @@ class Pose3d {
|
||||||
Pose3d Inv() const {
|
Pose3d Inv() const {
|
||||||
Eigen::Quaterniond r_inv = r_quat_.inverse();
|
Eigen::Quaterniond r_inv = r_quat_.inverse();
|
||||||
Eigen::Vector3d t_inv = r_inv * t_vec_;
|
Eigen::Vector3d t_inv = r_inv * t_vec_;
|
||||||
return {r_inv, -t_inv};
|
return Pose3d(r_inv, -t_inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pose3d operator*(const Pose3d &rhs) const {
|
Pose3d operator*(const Pose3d &rhs) const {
|
||||||
|
@ -54,16 +54,11 @@ class Pose3d {
|
||||||
return r_quat_ * vec;
|
return r_quat_ * vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spherical linear interpolation to `pose_to`
|
// Spherical linear interpolation to `pose_to`, t \belong [0,1]
|
||||||
Pose3d Interpolate(const Pose3d &pose_to, double t) const {
|
Pose3d Interpolate(const Pose3d &pose_to, double t) const {
|
||||||
Pose3d pose_dst = t > 0 ? pose_to : (*this) * pose_to.Inv() * (*this);
|
Eigen::Quaterniond r_interp = r_quat_.slerp(t, pose_to.r_quat_);
|
||||||
t = t > 0 ? t : -t;
|
Eigen::Vector3d t_interp = (pose_to.t_vec_ - t_vec_) * t + t_vec_;
|
||||||
int whole = std::floor(t);
|
return Pose3d(r_interp, t_interp);
|
||||||
double frac = t - whole;
|
|
||||||
Eigen::Quaterniond r_interp = r_quat_.slerp(frac, pose_dst.r_quat_);
|
|
||||||
while (whole--) r_interp *= pose_dst.r_quat_;
|
|
||||||
Eigen::Vector3d t_interp = (pose_dst.t_vec_ - t_vec_) * t + t_vec_;
|
|
||||||
return {r_interp, t_interp};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ToString() const {
|
std::string ToString() const {
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace oh_my_loam {
|
||||||
|
|
||||||
void TransformToStart(const Pose3d &pose, const TPoint &pt_in,
|
void TransformToStart(const Pose3d &pose, const TPoint &pt_in,
|
||||||
TPoint *const pt_out) {
|
TPoint *const pt_out) {
|
||||||
Pose3d pose_interp = Pose3d().Interpolate(pose, pt_in.time);
|
Pose3d pose_interp = Pose3d().Interpolate(pose, GetTime(pt_in));
|
||||||
TransformPoint<TPoint>(pose_interp, pt_in, pt_out);
|
TransformPoint<TPoint>(pose_interp, pt_in, pt_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,21 @@ namespace oh_my_loam {
|
||||||
|
|
||||||
using common::Pose3d;
|
using common::Pose3d;
|
||||||
|
|
||||||
|
inline int GetScanId(const TPoint &pt) {
|
||||||
|
return static_cast<int>(pt.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float GetTime(const TPoint &pt) {
|
||||||
|
return pt.time - GetScanId(pt);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename PT>
|
template <typename PT>
|
||||||
void TransformPoint(const Pose3d &pose, const PT &pt_in, PT *const pt_out) {
|
void TransformPoint(const Pose3d &pose, const PT &pt_in, PT *const pt_out) {
|
||||||
*pt_out = pt_in;
|
*pt_out = pt_in;
|
||||||
Eigen::Vector3d pnt = pose * Eigen::Vector3d(pt_in.x, pt_in.y, pt_in.z);
|
Eigen::Vector3d p = pose * Eigen::Vector3d(pt_in.x, pt_in.y, pt_in.z);
|
||||||
pt_out->x = pnt.x();
|
pt_out->x = p.x();
|
||||||
pt_out->y = pnt.y();
|
pt_out->y = p.y();
|
||||||
pt_out->z = pnt.z();
|
pt_out->z = p.z();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT>
|
template <typename PT>
|
||||||
|
|
|
@ -7,24 +7,24 @@ vis: true
|
||||||
# configs for extractor
|
# configs for extractor
|
||||||
extractor_config:
|
extractor_config:
|
||||||
vis: false
|
vis: false
|
||||||
verbose: true
|
verbose: false
|
||||||
min_point_num: 66
|
min_point_num: 66
|
||||||
sharp_corner_point_num: 2
|
sharp_corner_point_num: 2
|
||||||
corner_point_num: 20
|
corner_point_num: 10
|
||||||
flat_surf_point_num: 4
|
flat_surf_point_num: 4
|
||||||
surf_point_num: 30
|
surf_point_num: 20
|
||||||
corner_point_curvature_th: 0.5
|
corner_point_curvature_th: 0.5
|
||||||
surf_point_curvature_th: 0.5
|
surf_point_curvature_th: 0.5
|
||||||
neighbor_point_dist_th: 0.1
|
neighbor_point_dist_sq_th: 0.1
|
||||||
downsample_voxel_size: 0.3
|
|
||||||
|
|
||||||
# configs for odometer
|
# configs for odometer
|
||||||
odometer_config:
|
odometer_config:
|
||||||
vis: true
|
vis: true
|
||||||
verbose: true
|
verbose: true
|
||||||
icp_iter_num: 2
|
icp_iter_num: 2
|
||||||
solve_iter_num: 5
|
solve_iter_num: 4
|
||||||
match_dist_sq_th: 1
|
corn_match_dist_sq_th: 1.0
|
||||||
|
surf_match_dist_sq_th: 1.0
|
||||||
|
|
||||||
# configs for mapper
|
# configs for mapper
|
||||||
mapper_config:
|
mapper_config:
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace oh_my_loam {
|
||||||
namespace {
|
namespace {
|
||||||
const int kScanSegNum = 6;
|
const int kScanSegNum = 6;
|
||||||
const double kTwoPi = 2 * M_PI;
|
const double kTwoPi = 2 * M_PI;
|
||||||
|
const double kEps = 1e-6;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool Extractor::Init() {
|
bool Extractor::Init() {
|
||||||
|
@ -70,7 +71,7 @@ void Extractor::SplitScan(const common::PointCloud &cloud,
|
||||||
half_passed = true;
|
half_passed = true;
|
||||||
yaw_start += kTwoPi;
|
yaw_start += kTwoPi;
|
||||||
}
|
}
|
||||||
double time = std::min(yaw_diff / kTwoPi, 1.0) + scan_id;
|
double time = std::min(yaw_diff / kTwoPi, 1 - kEps) + scan_id;
|
||||||
scans->at(scan_id).push_back(
|
scans->at(scan_id).push_back(
|
||||||
{pt.x, pt.y, pt.z, static_cast<float>(time), std::nanf("")});
|
{pt.x, pt.y, pt.z, static_cast<float>(time), std::nanf("")});
|
||||||
}
|
}
|
||||||
|
@ -173,15 +174,10 @@ void Extractor::GenerateFeature(const TCTPointCloud &scan,
|
||||||
feature->cloud_corner->push_back(point);
|
feature->cloud_corner->push_back(point);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
feature->cloud_surf->push_back(point);
|
// feature->cloud_surf->push_back(point);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TPointCloudPtr dowm_sampled(new TPointCloud);
|
|
||||||
common::VoxelDownSample<TPoint>(
|
|
||||||
feature->cloud_surf, dowm_sampled.get(),
|
|
||||||
config_["downsample_voxel_size"].as<double>());
|
|
||||||
feature->cloud_surf = dowm_sampled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extractor::Visualize(const common::PointCloudConstPtr &cloud,
|
void Extractor::Visualize(const common::PointCloudConstPtr &cloud,
|
||||||
|
@ -199,17 +195,18 @@ void Extractor::UpdateNeighborsPicked(const TCTPointCloud &scan, size_t ix,
|
||||||
auto dist_sq = [&](size_t i, size_t j) -> double {
|
auto dist_sq = [&](size_t i, size_t j) -> double {
|
||||||
return common::DistanceSqure<TCTPoint>(scan[i], scan[j]);
|
return common::DistanceSqure<TCTPoint>(scan[i], scan[j]);
|
||||||
};
|
};
|
||||||
double neighbor_point_dist_th = config_["neighbor_point_dist_th"].as<float>();
|
double neighbor_point_dist_sq_th =
|
||||||
|
config_["neighbor_point_dist_sq_th"].as<float>();
|
||||||
for (size_t i = 1; i <= 5; ++i) {
|
for (size_t i = 1; i <= 5; ++i) {
|
||||||
if (ix < i) break;
|
if (ix < i) break;
|
||||||
if (picked->at(ix - i)) continue;
|
if (picked->at(ix - i)) continue;
|
||||||
if (dist_sq(ix - i, ix - i + 1) > neighbor_point_dist_th) break;
|
if (dist_sq(ix - i, ix - i + 1) > neighbor_point_dist_sq_th) break;
|
||||||
picked->at(ix - i) = true;
|
picked->at(ix - i) = true;
|
||||||
}
|
}
|
||||||
for (size_t i = 1; i <= 5; ++i) {
|
for (size_t i = 1; i <= 5; ++i) {
|
||||||
if (ix + i >= scan.size()) break;
|
if (ix + i >= scan.size()) break;
|
||||||
if (picked->at(ix + i)) continue;
|
if (picked->at(ix + i)) continue;
|
||||||
if (dist_sq(ix + i, ix + i - 1) > neighbor_point_dist_th) break;
|
if (dist_sq(ix + i, ix + i - 1) > neighbor_point_dist_sq_th) break;
|
||||||
picked->at(ix + i) = true;
|
picked->at(ix + i) = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,6 @@ namespace oh_my_loam {
|
||||||
namespace {
|
namespace {
|
||||||
int kNearScanN = 2;
|
int kNearScanN = 2;
|
||||||
size_t kMinMatchNum = 10;
|
size_t kMinMatchNum = 10;
|
||||||
int GetScanId(const TPoint &point) {
|
|
||||||
return static_cast<int>(point.time);
|
|
||||||
}
|
|
||||||
float GetTime(const TPoint &point) {
|
|
||||||
return point.time - GetScanId(point);
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool Odometer::Init() {
|
bool Odometer::Init() {
|
||||||
|
@ -64,10 +58,10 @@ void Odometer::Process(double timestamp, const std::vector<Feature> &features,
|
||||||
}
|
}
|
||||||
PoseSolver solver(pose_curr2last_);
|
PoseSolver solver(pose_curr2last_);
|
||||||
for (const auto &pair : pl_pairs) {
|
for (const auto &pair : pl_pairs) {
|
||||||
solver.AddPointLinePair(pair, pair.pt.time);
|
solver.AddPointLinePair(pair, GetTime(pair.pt));
|
||||||
}
|
}
|
||||||
for (const auto &pair : pp_pairs) {
|
for (const auto &pair : pp_pairs) {
|
||||||
solver.AddPointPlanePair(pair, pair.pt.time);
|
solver.AddPointPlanePair(pair, GetTime(pair.pt));
|
||||||
}
|
}
|
||||||
solver.Solve(config_["solve_iter_num"].as<int>(), verbose_,
|
solver.Solve(config_["solve_iter_num"].as<int>(), verbose_,
|
||||||
&pose_curr2last_);
|
&pose_curr2last_);
|
||||||
|
@ -84,103 +78,81 @@ void Odometer::Process(double timestamp, const std::vector<Feature> &features,
|
||||||
|
|
||||||
void Odometer::MatchCorn(const TPointCloud &src,
|
void Odometer::MatchCorn(const TPointCloud &src,
|
||||||
std::vector<PointLinePair> *const pairs) const {
|
std::vector<PointLinePair> *const pairs) const {
|
||||||
double dist_sq_thresh = config_["match_dist_sq_th"].as<double>();
|
double dist_sq_thresh = config_["corn_match_dist_sq_th"].as<double>();
|
||||||
for (const auto &point : src) {
|
for (const auto &pt : src) {
|
||||||
TPoint query_pt = TransformToStart(pose_curr2last_, point);
|
TPoint query_pt = TransformToStart(pose_curr2last_, pt);
|
||||||
std::vector<int> indices(1);
|
std::vector<int> indices;
|
||||||
std::vector<float> dists(1);
|
std::vector<float> dists;
|
||||||
if (kdtree_corn_.nearestKSearch(query_pt, 1, indices, dists) != 1) {
|
if (kdtree_corn_.nearestKSearch(query_pt, 1, indices, dists) < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (dists[0] >= dist_sq_thresh) continue;
|
if (dists[0] >= dist_sq_thresh) continue;
|
||||||
TPoint pt1 = kdtree_corn_.getInputCloud()->at(indices[0]);
|
TPoint pt1 = kdtree_corn_.getInputCloud()->at(indices[0]);
|
||||||
int pt1_scan_id = GetScanId(pt1);
|
int pt1_scan_id = GetScanId(pt1);
|
||||||
|
|
||||||
bool pt2_fount = false;
|
|
||||||
float min_pt2_dist_squre = dist_sq_thresh;
|
|
||||||
TPoint pt2;
|
TPoint pt2;
|
||||||
|
bool pt2_fount = false;
|
||||||
|
float min_pt2_dist_sq = dist_sq_thresh;
|
||||||
int i_begin = std::max<int>(0, pt1_scan_id - kNearScanN);
|
int i_begin = std::max<int>(0, pt1_scan_id - kNearScanN);
|
||||||
int i_end =
|
int i_end =
|
||||||
std::min<int>(kdtrees_scan_corn_.size(), pt1_scan_id + kNearScanN + 1);
|
std::min<int>(kdtrees_scan_corn_.size(), pt1_scan_id + kNearScanN + 1);
|
||||||
for (int i = i_begin; i < i_end && i != pt1_scan_id; ++i) {
|
for (int i = i_begin; i < i_end; ++i) {
|
||||||
|
if (i == pt1_scan_id) continue;
|
||||||
const auto &kdtree = kdtrees_scan_corn_[i];
|
const auto &kdtree = kdtrees_scan_corn_[i];
|
||||||
if (kdtree.nearestKSearch(query_pt, 1, indices, dists) != 0) {
|
if (kdtree.nearestKSearch(query_pt, 1, indices, dists) < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (dists[0] < min_pt2_dist_squre) {
|
if (dists[0] < min_pt2_dist_sq) {
|
||||||
pt2_fount = true;
|
pt2_fount = true;
|
||||||
pt2 = kdtree.getInputCloud()->at(indices[0]);
|
pt2 = kdtree.getInputCloud()->at(indices[0]);
|
||||||
min_pt2_dist_squre = dists[0];
|
min_pt2_dist_sq = dists[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pt2_fount) continue;
|
if (!pt2_fount) continue;
|
||||||
|
|
||||||
TPoint pt(point.x, point.y, point.z, GetTime(point));
|
|
||||||
pt1.time = GetTime(pt1);
|
|
||||||
pt2.time = GetTime(pt2);
|
|
||||||
pairs->emplace_back(pt, pt1, pt2);
|
pairs->emplace_back(pt, pt1, pt2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Odometer::MatchSurf(const TPointCloud &src,
|
void Odometer::MatchSurf(const TPointCloud &src,
|
||||||
std::vector<PointPlanePair> *const pairs) const {
|
std::vector<PointPlanePair> *const pairs) const {
|
||||||
double dist_sq_thresh = config_["match_dist_sq_th"].as<double>();
|
double dist_sq_thresh = config_["surf_match_dist_sq_th"].as<double>();
|
||||||
for (const auto &point : src) {
|
for (const auto &pt : src) {
|
||||||
TPoint query_pt = TransformToStart(pose_curr2last_, point);
|
TPoint query_pt = TransformToStart(pose_curr2last_, pt);
|
||||||
std::vector<int> indices;
|
std::vector<int> indices;
|
||||||
std::vector<float> dists;
|
std::vector<float> dists;
|
||||||
if (kdtree_surf_.nearestKSearch(query_pt, 2, indices, dists) != 2) {
|
if (kdtree_surf_.nearestKSearch(query_pt, 1, indices, dists) < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (dists[0] >= dist_sq_thresh || dists[1] >= dist_sq_thresh) continue;
|
if (dists[0] >= dist_sq_thresh) continue;
|
||||||
TPoint pt1 = kdtree_surf_.getInputCloud()->at(indices[0]);
|
TPoint pt1 = kdtree_surf_.getInputCloud()->at(indices[0]);
|
||||||
int pt1_scan_id = GetScanId(pt1);
|
int pt1_scan_id = GetScanId(pt1);
|
||||||
|
|
||||||
TPoint pt2 = kdtree_surf_.getInputCloud()->at(indices[1]), pt3;
|
TPoint pt2;
|
||||||
bool pt2_found = true, pt3_found = false;
|
bool pt2_fount = false;
|
||||||
int pt2_scan_id = GetScanId(pt2);
|
float min_pt2_dist_sq = dist_sq_thresh;
|
||||||
if (pt2_scan_id != pt1_scan_id) {
|
int i_begin = std::max<int>(0, pt1_scan_id - kNearScanN);
|
||||||
pt2_found = false;
|
int i_end =
|
||||||
if (std::abs(pt2_scan_id - pt1_scan_id) <= kNearScanN) {
|
std::min<int>(kdtrees_scan_surf_.size(), pt1_scan_id + kNearScanN + 1);
|
||||||
pt3 = pt2;
|
for (int i = i_begin; i < i_end; ++i) {
|
||||||
pt3_found = true;
|
if (i == pt1_scan_id) continue;
|
||||||
|
const auto &kdtree = kdtrees_scan_surf_[i];
|
||||||
|
if (kdtree.nearestKSearch(query_pt, 1, indices, dists) < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dists[0] < min_pt2_dist_sq) {
|
||||||
|
pt2_fount = true;
|
||||||
|
pt2 = kdtree.getInputCloud()->at(indices[0]);
|
||||||
|
min_pt2_dist_sq = dists[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!pt2_fount) continue;
|
||||||
|
|
||||||
if (!pt2_found) {
|
const auto &kdtree = kdtrees_scan_surf_[pt1_scan_id];
|
||||||
const auto &kdtree = kdtrees_scan_surf_[pt1_scan_id];
|
if (kdtree.nearestKSearch(query_pt, 2, indices, dists) < 2) continue;
|
||||||
if (kdtree.nearestKSearch(query_pt, 2, indices, dists) == 2) {
|
if (dists[1] >= dist_sq_thresh) continue;
|
||||||
if (dists[1] < dist_sq_thresh) {
|
TPoint pt3 = kdtree.getInputCloud()->at(indices[1]);
|
||||||
pt2 = kdtree.getInputCloud()->at(indices[1]);
|
|
||||||
pt2_found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pt2_found) continue;
|
|
||||||
|
|
||||||
if (!pt3_found) {
|
|
||||||
float min_pt3_dist_squre = dist_sq_thresh;
|
|
||||||
int i_begin = std::max<int>(0, pt1_scan_id - kNearScanN);
|
|
||||||
int i_end = std::min<int>(kdtrees_scan_corn_.size(),
|
|
||||||
pt1_scan_id + kNearScanN + 1);
|
|
||||||
for (int i = i_begin; i < i_end && i != pt1_scan_id; ++i) {
|
|
||||||
const auto &kdtree = kdtrees_scan_surf_[i];
|
|
||||||
if (kdtree.nearestKSearch(query_pt, 1, indices, dists) != 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dists[0] < min_pt3_dist_squre) {
|
|
||||||
pt3 = kdtree.getInputCloud()->at(indices[0]);
|
|
||||||
pt3_found = true;
|
|
||||||
min_pt3_dist_squre = dists[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pt3_found) continue;
|
|
||||||
|
|
||||||
TPoint pt(point.x, point.y, point.z, GetTime(point));
|
|
||||||
pt1.time = GetTime(pt1);
|
|
||||||
pt2.time = GetTime(pt2);
|
|
||||||
pt3.time = GetTime(pt3);
|
|
||||||
pairs->emplace_back(pt, pt1, pt2, pt3);
|
pairs->emplace_back(pt, pt1, pt2, pt3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,12 +160,12 @@ void Odometer::MatchSurf(const TPointCloud &src,
|
||||||
void Odometer::UpdatePre(const std::vector<Feature> &features) {
|
void Odometer::UpdatePre(const std::vector<Feature> &features) {
|
||||||
kdtrees_scan_corn_.resize(features.size());
|
kdtrees_scan_corn_.resize(features.size());
|
||||||
kdtrees_scan_surf_.resize(features.size());
|
kdtrees_scan_surf_.resize(features.size());
|
||||||
TPointCloudPtr corn_pre(new TPointCloud);
|
|
||||||
TPointCloudPtr surf_pre(new TPointCloud);
|
TPointCloudPtr surf_pre(new TPointCloud);
|
||||||
TPointCloudPtr scan_corn_pre(new TPointCloud);
|
TPointCloudPtr corn_pre(new TPointCloud);
|
||||||
TPointCloudPtr scan_surf_pre(new TPointCloud);
|
|
||||||
for (size_t i = 0; i < features.size(); ++i) {
|
for (size_t i = 0; i < features.size(); ++i) {
|
||||||
const auto &feature = features[i];
|
const auto &feature = features[i];
|
||||||
|
TPointCloudPtr scan_corn_pre(new TPointCloud);
|
||||||
|
TPointCloudPtr scan_surf_pre(new TPointCloud);
|
||||||
scan_corn_pre->resize(feature.cloud_corner->size());
|
scan_corn_pre->resize(feature.cloud_corner->size());
|
||||||
scan_surf_pre->resize(feature.cloud_surf->size());
|
scan_surf_pre->resize(feature.cloud_surf->size());
|
||||||
for (size_t j = 0; j < feature.cloud_corner->size(); ++j) {
|
for (size_t j = 0; j < feature.cloud_corner->size(); ++j) {
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
#include <ceres/ceres.h>
|
#include <ceres/ceres.h>
|
||||||
|
|
||||||
|
#include <eigen3/Eigen/Dense>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "oh_my_loam/base/helper.h"
|
#include "oh_my_loam/base/helper.h"
|
||||||
|
|
||||||
|
@ -13,7 +16,8 @@ class PointLineCostFunction {
|
||||||
: pair_(pair), time_(time){};
|
: pair_(pair), time_(time){};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool operator()(const T *const q, const T *const p, T *residual) const;
|
bool operator()(const T *const r_quat, const T *const t_vec,
|
||||||
|
T *residual) const;
|
||||||
|
|
||||||
static ceres::CostFunction *Create(const PointLinePair &pair, double time) {
|
static ceres::CostFunction *Create(const PointLinePair &pair, double time) {
|
||||||
return new ceres::AutoDiffCostFunction<PointLineCostFunction, 3, 4, 3>(
|
return new ceres::AutoDiffCostFunction<PointLineCostFunction, 3, 4, 3>(
|
||||||
|
@ -33,7 +37,8 @@ class PointPlaneCostFunction {
|
||||||
: pair_(pair), time_(time){};
|
: pair_(pair), time_(time){};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool operator()(const T *const q, const T *const p, T *residual) const;
|
bool operator()(const T *const r_quat, const T *const t_vec,
|
||||||
|
T *residual) const;
|
||||||
|
|
||||||
static ceres::CostFunction *Create(const PointPlanePair &pair, double time) {
|
static ceres::CostFunction *Create(const PointPlanePair &pair, double time) {
|
||||||
return new ceres::AutoDiffCostFunction<PointPlaneCostFunction, 1, 4, 3>(
|
return new ceres::AutoDiffCostFunction<PointPlaneCostFunction, 1, 4, 3>(
|
||||||
|
@ -47,46 +52,56 @@ class PointPlaneCostFunction {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool PointLineCostFunction::operator()(const T *const q, const T *const p,
|
bool PointLineCostFunction::operator()(const T *const r_quat,
|
||||||
|
const T *const t_vec,
|
||||||
T *residual) const {
|
T *residual) const {
|
||||||
const auto pt = pair_.pt, pt1 = pair_.line.pt1, pt2 = pair_.line.pt2;
|
const auto &pt = pair_.pt, &pt1 = pair_.line.pt1, &pt2 = pair_.line.pt2;
|
||||||
Eigen::Matrix<T, 3, 1> pnt(T(pt.x), T(pt.y), T(pt.z));
|
Eigen::Matrix<T, 3, 1> p(T(pt.x), T(pt.y), T(pt.z));
|
||||||
Eigen::Matrix<T, 3, 1> pnt1(T(pt1.x), T(pt1.y), T(pt1.z));
|
Eigen::Matrix<T, 3, 1> p1(T(pt1.x), T(pt1.y), T(pt1.z));
|
||||||
Eigen::Matrix<T, 3, 1> pnt2(T(pt2.x), T(pt2.y), T(pt2.z));
|
Eigen::Matrix<T, 3, 1> p2(T(pt2.x), T(pt2.y), T(pt2.z));
|
||||||
|
|
||||||
Eigen::Quaternion<T> r(q[3], q[0], q[1], q[2]);
|
Eigen::Quaternion<T> r(r_quat[3], r_quat[0], r_quat[1], r_quat[2]);
|
||||||
Eigen::Quaternion<T> q_identity{T(1), T(0), T(0), T(0)};
|
Eigen::Quaternion<T> r_interp =
|
||||||
r = q_identity.slerp(T(time_), r);
|
Eigen::Quaternion<T>::Identity().slerp(T(time_), r);
|
||||||
Eigen::Matrix<T, 3, 1> t(T(time_) * p[0], T(time_) * p[1], T(time_) * p[2]);
|
Eigen::Matrix<T, 3, 1> t(T(time_) * t_vec[0], T(time_) * t_vec[1],
|
||||||
Eigen::Matrix<T, 3, 1> pnt_n = r * pnt + t;
|
T(time_) * t_vec[2]);
|
||||||
|
Eigen::Matrix<T, 3, 1> p0 = r_interp * p + t;
|
||||||
|
|
||||||
// norm of cross product: triangle area x 2
|
// norm of cross product: triangle area x 2
|
||||||
Eigen::Matrix<T, 3, 1> area = (pnt_n - pnt1).cross(pnt_n - pnt2) * 0.5;
|
Eigen::Matrix<T, 3, 1> area = (p0 - p1).cross(p0 - p2) * 0.5;
|
||||||
T base_length = (pnt2 - pnt1).norm();
|
T base_length = (p2 - p1).norm();
|
||||||
residual[0] = area[0] / base_length;
|
residual[0] = area[0] / base_length;
|
||||||
residual[1] = area[1] / base_length;
|
residual[1] = area[1] / base_length;
|
||||||
residual[2] = area[2] / base_length;
|
residual[2] = area[2] / base_length;
|
||||||
|
if constexpr (!std::is_arithmetic<T>::value) {
|
||||||
|
AERROR << p.transpose() << ", ";
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool PointPlaneCostFunction::operator()(const T *const q, const T *const p,
|
bool PointPlaneCostFunction::operator()(const T *const r_quat,
|
||||||
|
const T *const t_vec,
|
||||||
T *residual) const {
|
T *residual) const {
|
||||||
const auto &pt = pair_.pt, &pt1 = pair_.plane.pt1, &pt2 = pair_.plane.pt2,
|
const auto &pt = pair_.pt, &pt1 = pair_.plane.pt1, &pt2 = pair_.plane.pt2,
|
||||||
&pt3 = pair_.plane.pt3;
|
&pt3 = pair_.plane.pt3;
|
||||||
Eigen::Matrix<T, 3, 1> pnt(T(pt.x), T(pt.y), T(pt.z));
|
Eigen::Matrix<T, 3, 1> p(T(pt.x), T(pt.y), T(pt.z));
|
||||||
Eigen::Matrix<T, 3, 1> pnt1(T(pt1.x), T(pt1.y), T(pt1.z));
|
Eigen::Matrix<T, 3, 1> p1(T(pt1.x), T(pt1.y), T(pt1.z));
|
||||||
Eigen::Matrix<T, 3, 1> pnt2(T(pt2.x), T(pt2.y), T(pt2.z));
|
Eigen::Matrix<T, 3, 1> p2(T(pt2.x), T(pt2.y), T(pt2.z));
|
||||||
Eigen::Matrix<T, 3, 1> pnt3(T(pt3.x), T(pt3.y), T(pt3.z));
|
Eigen::Matrix<T, 3, 1> p3(T(pt3.x), T(pt3.y), T(pt3.z));
|
||||||
|
|
||||||
Eigen::Quaternion<T> r(q[3], q[0], q[1], q[2]);
|
Eigen::Quaternion<T> r(r_quat[3], r_quat[0], r_quat[1], r_quat[2]);
|
||||||
Eigen::Quaternion<T> q_identity{T(1), T(0), T(0), T(0)};
|
Eigen::Quaternion<T> r_interp =
|
||||||
r = q_identity.slerp(T(time_), r);
|
Eigen::Quaternion<T>::Identity().slerp(T(time_), r);
|
||||||
Eigen::Matrix<T, 3, 1> t(T(time_) * p[0], T(time_) * p[1], T(time_) * p[2]);
|
Eigen::Matrix<T, 3, 1> t(T(time_) * t_vec[0], T(time_) * t_vec[1],
|
||||||
Eigen::Matrix<T, 3, 1> pnt_n = r * pnt + t;
|
T(time_) * t_vec[2]);
|
||||||
|
Eigen::Matrix<T, 3, 1> p0 = r_interp * p + t;
|
||||||
|
|
||||||
Eigen::Matrix<T, 3, 1> normal = (pnt2 - pnt1).cross(pnt3 - pnt1).normalized();
|
Eigen::Matrix<T, 3, 1> normal = (p2 - p1).cross(p3 - p1).normalized();
|
||||||
residual[0] = (pnt_n - pnt1).dot(normal);
|
residual[0] = (p0 - p1).dot(normal);
|
||||||
|
if constexpr (!std::is_arithmetic<T>::value) {
|
||||||
|
AERROR << "ppres" << residual[0].a;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <Eigen/src/Core/Matrix.h>
|
#include <Eigen/src/Core/Matrix.h>
|
||||||
#include <ceres/loss_function.h>
|
#include <ceres/loss_function.h>
|
||||||
|
#include <ceres/types.h>
|
||||||
|
|
||||||
#include "common/log/log.h"
|
#include "common/log/log.h"
|
||||||
|
|
||||||
|
@ -29,9 +30,10 @@ bool PoseSolver::Solve(int max_iter_num, bool verbose,
|
||||||
ceres::Solver::Summary summary;
|
ceres::Solver::Summary summary;
|
||||||
ceres::Solve(options, &problem_, &summary);
|
ceres::Solve(options, &problem_, &summary);
|
||||||
AINFO_IF(verbose) << summary.BriefReport();
|
AINFO_IF(verbose) << summary.BriefReport();
|
||||||
AWARN_IF(!summary.IsSolutionUsable()) << "Solution may be unusable";
|
AWARN_IF(summary.termination_type != ceres::CONVERGENCE)
|
||||||
|
<< "Solve: no convergence";
|
||||||
if (pose) *pose = common::Pose3d(r_quat_, t_vec_);
|
if (pose) *pose = common::Pose3d(r_quat_, t_vec_);
|
||||||
return summary.IsSolutionUsable();
|
return summary.termination_type == ceres::CONVERGENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseSolver::AddPointLinePair(const PointLinePair &pair, double time) {
|
void PoseSolver::AddPointLinePair(const PointLinePair &pair, double time) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "odometer_visualizer.h"
|
#include "odometer_visualizer.h"
|
||||||
|
|
||||||
|
#include "common/color/color.h"
|
||||||
|
|
||||||
namespace oh_my_loam {
|
namespace oh_my_loam {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -8,31 +10,31 @@ using namespace common;
|
||||||
|
|
||||||
void OdometerVisualizer::Draw() {
|
void OdometerVisualizer::Draw() {
|
||||||
auto frame = GetCurrentFrame<OdometerVisFrame>();
|
auto frame = GetCurrentFrame<OdometerVisFrame>();
|
||||||
TPointCloudPtr src_corn_pts(new TPointCloud);
|
TPointCloudPtr src_corn(new TPointCloud);
|
||||||
TPointCloudPtr tgt_corn_pts(new TPointCloud);
|
TPointCloudPtr tgt_corn(new TPointCloud);
|
||||||
src_corn_pts->resize(frame.pl_pairs.size());
|
src_corn->resize(frame.pl_pairs.size());
|
||||||
tgt_corn_pts->resize(frame.pl_pairs.size() * 2);
|
tgt_corn->resize(frame.pl_pairs.size() * 2);
|
||||||
for (size_t i = 0; i < frame.pl_pairs.size(); ++i) {
|
for (size_t i = 0; i < frame.pl_pairs.size(); ++i) {
|
||||||
const auto &pair = frame.pl_pairs[i];
|
const auto &pair = frame.pl_pairs[i];
|
||||||
TransformToStart(frame.pose_curr2last, pair.pt, &src_corn_pts->points[i]);
|
TransformToStart(frame.pose_curr2last, pair.pt, &src_corn->points[i]);
|
||||||
tgt_corn_pts->points[2 * i] = pair.line.pt1;
|
tgt_corn->points[2 * i] = pair.line.pt1;
|
||||||
tgt_corn_pts->points[2 * i + 1] = pair.line.pt2;
|
tgt_corn->points[2 * i + 1] = pair.line.pt2;
|
||||||
}
|
}
|
||||||
TPointCloudPtr src_surf_pts(new TPointCloud);
|
TPointCloudPtr src_surf(new TPointCloud);
|
||||||
TPointCloudPtr tgt_surf_pts(new TPointCloud);
|
TPointCloudPtr tgt_surf(new TPointCloud);
|
||||||
src_surf_pts->resize(frame.pp_pairs.size());
|
src_surf->resize(frame.pp_pairs.size());
|
||||||
tgt_surf_pts->resize(frame.pp_pairs.size() * 3);
|
tgt_surf->resize(frame.pp_pairs.size() * 3);
|
||||||
for (size_t i = 0; i < frame.pp_pairs.size(); ++i) {
|
for (size_t i = 0; i < frame.pp_pairs.size(); ++i) {
|
||||||
const auto &pair = frame.pp_pairs[i];
|
const auto &pair = frame.pp_pairs[i];
|
||||||
TransformToStart(frame.pose_curr2last, pair.pt, &src_surf_pts->points[i]);
|
TransformToStart(frame.pose_curr2last, pair.pt, &src_surf->points[i]);
|
||||||
tgt_surf_pts->points[3 * i] = pair.plane.pt1;
|
tgt_surf->points[3 * i] = pair.plane.pt1;
|
||||||
tgt_surf_pts->points[3 * i + 1] = pair.plane.pt2;
|
tgt_surf->points[3 * i + 1] = pair.plane.pt2;
|
||||||
tgt_surf_pts->points[3 * i + 2] = pair.plane.pt3;
|
tgt_surf->points[3 * i + 2] = pair.plane.pt3;
|
||||||
}
|
}
|
||||||
DrawPointCloud<TPoint>(src_corn_pts, CYAN, "src_corn_pts", 7);
|
DrawPointCloud<TPoint>(tgt_corn, YELLOW, "tgt_corn", 4);
|
||||||
DrawPointCloud<TPoint>(tgt_corn_pts, BLUE, "tgt_corn_pts", 4);
|
DrawPointCloud<TPoint>(src_corn, RED, "src_corn", 4);
|
||||||
DrawPointCloud<TPoint>(src_surf_pts, PURPLE, "src_surf_pts", 7);
|
DrawPointCloud<TPoint>(tgt_surf, BLUE, "tgt_surf", 4);
|
||||||
DrawPointCloud<TPoint>(tgt_surf_pts, RED, "tgt_surf_pts", 4);
|
DrawPointCloud<TPoint>(src_surf, CYAN, "src_surf", 4);
|
||||||
std::vector<Pose3d> poses_n;
|
std::vector<Pose3d> poses_n;
|
||||||
poses_n.reserve((poses_.size()));
|
poses_n.reserve((poses_.size()));
|
||||||
Pose3d pose_inv = frame.pose_curr2world.Inv();
|
Pose3d pose_inv = frame.pose_curr2world.Inv();
|
||||||
|
|
Loading…
Reference in New Issue