Skip to content

Commit e7f8d71

Browse files
authored
Merge pull request koide3#72 from koide3/devel
Add functions & edges for interactive SLAM
2 parents f7a0472 + 05fa9c6 commit e7f8d71

15 files changed

+952
-28
lines changed

.travis.yml

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
sudo: required
2-
language: C++
2+
language: generic
3+
dist: xenial
4+
35
services:
46
- docker
7+
8+
matrix:
9+
include:
10+
- name: "Xenial kinetic"
11+
env: ROS_DISTRO=kinetic
12+
- name: "Bionic melodic"
13+
env: ROS_DISTRO=melodic
14+
515
script:
6-
- docker build -f docker/kinetic/Dockerfile .
7-
- docker build -f docker/melodic/Dockerfile .
16+
- docker build -f ./docker/$ROS_DISTRO/Dockerfile .

CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ find_package(catkin REQUIRED COMPONENTS
1616
nmea_msgs
1717
sensor_msgs
1818
message_generation
19+
interactive_markers
1920
ndt_omp
2021
)
2122

@@ -58,7 +59,7 @@ generate_messages(DEPENDENCIES std_msgs)
5859
###################################
5960
catkin_package(
6061
INCLUDE_DIRS include
61-
# LIBRARIES hdl_scan_matching_odometry
62+
LIBRARIES hdl_graph_slam_nodelet
6263
# CATKIN_DEPENDS pcl_ros roscpp sensor_msgs
6364
# DEPENDS system_lib
6465
)
@@ -104,6 +105,7 @@ add_library(hdl_graph_slam_nodelet
104105
src/hdl_graph_slam/map_cloud_generator.cpp
105106
src/hdl_graph_slam/registrations.cpp
106107
src/hdl_graph_slam/information_matrix_calculator.cpp
108+
src/g2o/robust_kernel_io.cpp
107109
)
108110
target_link_libraries(hdl_graph_slam_nodelet
109111
${catkin_LIBRARIES}
@@ -118,3 +120,4 @@ target_link_libraries(hdl_graph_slam_nodelet
118120
${G2O_TYPES_SLAM3D_ADDONS}
119121
)
120122
add_dependencies(hdl_graph_slam_nodelet ${PROJECT_NAME}_gencpp)
123+

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ roslaunch hdl_graph_slam hdl_graph_slam.launch
236236
Kenji Koide, Jun Miura, and Emanuele Menegatti, A Portable 3D LIDAR-based System for Long-term and Wide-area People Behavior Measurement, Advanced Robotic Systems, 2019 [[link]](https://www.researchgate.net/publication/331283709_A_Portable_3D_LIDAR-based_System_for_Long-term_and_Wide-area_People_Behavior_Measurement).
237237

238238
## Contact
239-
Kenji Koide, Active Intelligent Systems Laboratory, Toyohashi University of Technology [\[URL\]](http://www.aisl.cs.tut.ac.jp)
239+
Kenji Koide, [email protected]
240240

241-
241+
Active Intelligent Systems Laboratory, Toyohashi University of Technology, Japan [\[URL\]](http://www.aisl.cs.tut.ac.jp)
242+
Robot Innovation Research Center, National Institute of Advanced Industrial Science and Technology, Japan [\[URL\]](https://unit.aist.go.jp/rirc/en/team/smart_mobility.html)

apps/hdl_graph_slam_nodelet.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -829,14 +829,19 @@ class HdlGraphSlamNodelet : public nodelet::Nodelet {
829829
std::stringstream sst;
830830
sst << boost::format("%s/%06d") % directory % i;
831831

832-
keyframes[i]->dump(sst.str());
832+
keyframes[i]->save(sst.str());
833833
}
834834

835835
if(zero_utm) {
836836
std::ofstream zero_utm_ofs(directory + "/zero_utm");
837837
zero_utm_ofs << *zero_utm << std::endl;
838838
}
839839

840+
std::ofstream ofs(directory + "/special_nodes.csv");
841+
ofs << "anchor_node " << (anchor_node == nullptr ? -1 : anchor_node->id()) << std::endl;
842+
ofs << "anchor_edge " << (anchor_edge == nullptr ? -1 : anchor_edge->id()) << std::endl;
843+
ofs << "floor_node " << (floor_plane_node == nullptr ? -1 : floor_plane_node->id()) << std::endl;
844+
840845
res.success = true;
841846
return true;
842847
}

include/g2o/edge_plane_parallel.hpp

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#ifndef EDGE_PLANE_PARALLEL_HPP
2+
#define EDGE_PLANE_PARALLEL_HPP
3+
4+
#include <Eigen/Dense>
5+
#include <g2o/core/base_binary_edge.h>
6+
#include <g2o/types/slam3d_addons/vertex_plane.h>
7+
8+
namespace g2o {
9+
10+
class EdgePlaneParallel : public BaseBinaryEdge<3, Eigen::Vector3d, VertexPlane, VertexPlane> {
11+
public:
12+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
13+
EdgePlaneParallel() : BaseBinaryEdge<3, Eigen::Vector3d, VertexPlane, VertexPlane>() {
14+
_information.setIdentity();
15+
_error.setZero();
16+
}
17+
18+
void computeError() override {
19+
const VertexPlane* v1 = static_cast<const VertexPlane*>(_vertices[0]);
20+
const VertexPlane* v2 = static_cast<const VertexPlane*>(_vertices[1]);
21+
22+
Eigen::Vector3d normal1 = v1->estimate().normal();
23+
Eigen::Vector3d normal2 = v2->estimate().normal();
24+
25+
if (normal1.dot(normal2) < 0.0) {
26+
normal2 = -normal2;
27+
}
28+
29+
_error = (normal2 - normal1) - _measurement;
30+
}
31+
virtual bool read(std::istream& is) override {
32+
Eigen::Vector3d v;
33+
for (int i = 0; i < 3; ++i) {
34+
is >> v[i];
35+
}
36+
37+
setMeasurement(v);
38+
for (int i = 0; i < 3; ++i) {
39+
for (int j = i; j < 3; ++j) {
40+
is >> information()(i, j);
41+
if (i != j) {
42+
information()(j, i) = information()(i, j);
43+
}
44+
}
45+
}
46+
47+
return true;
48+
}
49+
50+
virtual bool write(std::ostream& os) const override {
51+
for (int i = 0; i < 3; ++i) os << _measurement[i] << " ";
52+
for (int i = 0; i < 3; ++i)
53+
for (int j = i; j < 3; ++j) os << " " << information()(i, j);
54+
return os.good();
55+
}
56+
57+
virtual void setMeasurement(const Eigen::Vector3d& m) override { _measurement = m; }
58+
59+
virtual int measurementDimension() const override { return 3; }
60+
};
61+
62+
class EdgePlanePerpendicular : public BaseBinaryEdge<3, Eigen::Vector3d, VertexPlane, VertexPlane> {
63+
public:
64+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
65+
EdgePlanePerpendicular() : BaseBinaryEdge<3, Eigen::Vector3d, VertexPlane, VertexPlane>() {
66+
_information.setIdentity();
67+
_error.setZero();
68+
}
69+
70+
void computeError() override {
71+
const VertexPlane* v1 = static_cast<const VertexPlane*>(_vertices[0]);
72+
const VertexPlane* v2 = static_cast<const VertexPlane*>(_vertices[1]);
73+
74+
Eigen::Vector3d normal1 = v1->estimate().normal().normalized();
75+
Eigen::Vector3d normal2 = v2->estimate().normal().normalized();
76+
77+
_error = normal1.array() * normal2.array();
78+
}
79+
virtual bool read(std::istream& is) override {
80+
Eigen::Vector3d v;
81+
for (int i = 0; i < 3; ++i) {
82+
is >> v[i];
83+
}
84+
85+
setMeasurement(v);
86+
for (int i = 0; i < 3; ++i) {
87+
for (int j = i; j < 3; ++j) {
88+
is >> information()(i, j);
89+
if (i != j) {
90+
information()(j, i) = information()(i, j);
91+
}
92+
}
93+
}
94+
95+
return true;
96+
}
97+
98+
virtual bool write(std::ostream& os) const override {
99+
for (int i = 0; i < 3; ++i) os << _measurement[i] << " ";
100+
for (int i = 0; i < 3; ++i)
101+
for (int j = i; j < 3; ++j) os << " " << information()(i, j);
102+
return os.good();
103+
}
104+
105+
virtual void setMeasurement(const Eigen::Vector3d& m) override { _measurement = m; }
106+
107+
virtual int measurementDimension() const override { return 3; }
108+
};
109+
110+
} // namespace g2o
111+
112+
#endif // EDGE_PLANE_PARALLEL_HPP

include/g2o/robust_kernel_io.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef ROBUST_KERNEL_IO_HPP
2+
#define ROBUST_KERNEL_IO_HPP
3+
4+
#include <string>
5+
#include <g2o/core/sparse_optimizer.h>
6+
7+
8+
namespace g2o {
9+
10+
bool save_robust_kernels(const std::string& filename, g2o::SparseOptimizer* graph);
11+
12+
bool load_robust_kernels(const std::string& filename, g2o::SparseOptimizer* graph);
13+
14+
}
15+
16+
#endif // ROBUST_KERNEL_IO_HPP

include/hdl_graph_slam/graph_slam.hpp

+23-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <memory>
55
#include <ros/time.h>
66

7-
#include <g2o/core/sparse_optimizer.h>
7+
#include <g2o/core/hyper_graph.h>
88

99
namespace g2o {
1010
class VertexSE3;
@@ -17,6 +17,9 @@ namespace g2o {
1717
class EdgeSE3PriorXYZ;
1818
class EdgeSE3PriorVec;
1919
class EdgeSE3PriorQuat;
20+
class EdgePlane;
21+
class EdgePlaneParallel;
22+
class EdgePlanePerpendicular;
2023
class RobustKernelFactory;
2124
}
2225

@@ -25,7 +28,10 @@ namespace hdl_graph_slam {
2528
class GraphSLAM {
2629
public:
2730
GraphSLAM(const std::string& solver_type = "lm_var");
28-
~GraphSLAM();
31+
virtual ~GraphSLAM();
32+
33+
int num_vertices() const;
34+
int num_edges() const;
2935

3036
/**
3137
* @brief add a SE3 node to the graph
@@ -93,22 +99,33 @@ class GraphSLAM {
9399

94100
g2o::EdgeSE3PriorVec* add_se3_prior_vec_edge(g2o::VertexSE3* v_se3, const Eigen::Vector3d& direction, const Eigen::Vector3d& measurement, const Eigen::MatrixXd& information_matrix);
95101

96-
void add_robust_kernel(g2o::OptimizableGraph::Edge* edge, const std::string& kernel_type, double kernel_size);
102+
g2o::EdgePlane* add_plane_edge(g2o::VertexPlane* v_plane1, g2o::VertexPlane* v_plane2, const Eigen::Vector4d& measurement, const Eigen::Matrix4d& information);
103+
104+
g2o::EdgePlaneParallel* add_plane_parallel_edge(g2o::VertexPlane* v_plane1, g2o::VertexPlane* v_plane2, const Eigen::Vector3d& measurement, const Eigen::Matrix3d& information);
105+
106+
g2o::EdgePlanePerpendicular* add_plane_perpendicular_edge(g2o::VertexPlane* v_plane1, g2o::VertexPlane* v_plane2, const Eigen::Vector3d& measurement, const Eigen::Matrix3d& information);
107+
108+
void add_robust_kernel(g2o::HyperGraph::Edge* edge, const std::string& kernel_type, double kernel_size);
97109

98110
/**
99111
* @brief perform graph optimization
100112
*/
101-
void optimize(int num_iterations);
113+
int optimize(int num_iterations);
102114

103115
/**
104-
* @brief save the pose graph
116+
* @brief save the pose graph to a file
105117
* @param filename output filename
106118
*/
107119
void save(const std::string& filename);
108120

121+
/**
122+
* @brief load the pose graph from file
123+
* @param filename output filename
124+
*/
125+
bool load(const std::string& filename);
109126
public:
110127
g2o::RobustKernelFactory* robust_kernel_factory;
111-
std::unique_ptr<g2o::SparseOptimizer> graph; // g2o graph
128+
std::unique_ptr<g2o::HyperGraph> graph; // g2o graph
112129
};
113130

114131
}

include/hdl_graph_slam/information_matrix_calculator.hpp

+17-2
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,33 @@ class InformationMatrixCalculator {
1111
public:
1212
using PointT = pcl::PointXYZI;
1313

14+
InformationMatrixCalculator(){}
1415
InformationMatrixCalculator(ros::NodeHandle& nh);
1516
~InformationMatrixCalculator();
1617

18+
template<typename ParamServer>
19+
void load(ParamServer& params) {
20+
use_const_inf_matrix = params.template param<bool>("use_const_inf_matrix", false);
21+
const_stddev_x = params.template param<double>("const_stddev_x", 0.5);
22+
const_stddev_q = params.template param<double>("const_stddev_q", 0.1);
23+
24+
var_gain_a = params.template param<double>("var_gain_a", 20.0);
25+
min_stddev_x = params.template param<double>("min_stddev_x", 0.1);
26+
max_stddev_x = params.template param<double>("max_stddev_x", 5.0);
27+
min_stddev_q = params.template param<double>("min_stddev_q", 0.05);
28+
max_stddev_q = params.template param<double>("max_stddev_q", 0.2);
29+
fitness_score_thresh = params.template param<double>("fitness_score_thresh", 0.5);
30+
}
31+
32+
static double calc_fitness_score(const pcl::PointCloud<PointT>::ConstPtr& cloud1, const pcl::PointCloud<PointT>::ConstPtr& cloud2, const Eigen::Isometry3d& relpose, double max_range = std::numeric_limits<double>::max());
33+
1734
Eigen::MatrixXd calc_information_matrix(const pcl::PointCloud<PointT>::ConstPtr& cloud1, const pcl::PointCloud<PointT>::ConstPtr& cloud2, const Eigen::Isometry3d& relpose) const;
1835
private:
1936
double weight(double a, double max_x, double min_y, double max_y, double x) const {
2037
double y = (1.0 - std::exp(-a * x)) / (1.0 - std::exp(-a * max_x));
2138
return min_y + (max_y - min_y) * y;
2239
}
2340

24-
double calc_fitness_score(const pcl::PointCloud<PointT>::ConstPtr& cloud1, const pcl::PointCloud<PointT>::ConstPtr& cloud2, const Eigen::Isometry3d& relpose, double max_range = std::numeric_limits<double>::max()) const;
25-
2641
private:
2742
bool use_const_inf_matrix;
2843
double const_stddev_x;

include/hdl_graph_slam/keyframe.hpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
namespace g2o {
1010
class VertexSE3;
11+
class HyperGraph;
12+
class SparseOptimizer;
1113
}
1214

1315
namespace hdl_graph_slam {
@@ -22,9 +24,14 @@ struct KeyFrame {
2224
using Ptr = std::shared_ptr<KeyFrame>;
2325

2426
KeyFrame(const ros::Time& stamp, const Eigen::Isometry3d& odom, double accum_distance, const pcl::PointCloud<PointT>::ConstPtr& cloud);
25-
~KeyFrame();
27+
KeyFrame(const std::string& directory, g2o::HyperGraph* graph);
28+
virtual ~KeyFrame();
2629

27-
void dump(const std::string& directory);
30+
void save(const std::string& directory);
31+
bool load(const std::string& directory, g2o::HyperGraph* graph);
32+
33+
long id() const;
34+
Eigen::Isometry3d estimate() const;
2835

2936
public:
3037
ros::Time stamp; // timestamp

0 commit comments

Comments
 (0)