00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/mapping/detect_floors.h"
00018
00019 #include <algorithm>
00020 #include <fstream>
00021 #include <vector>
00022
00023 #include "Eigen/Core"
00024 #include "cartographer/transform/transform.h"
00025 #include "glog/logging.h"
00026
00027 namespace cartographer {
00028 namespace mapping {
00029
00030 namespace {
00031
00032
00033
00034
00035
00036 using Levels = std::map<int, int>;
00037
00038 constexpr double kMaxShortSpanLengthMeters = 25.;
00039 constexpr double kLevelHeightMeters = 2.5;
00040 constexpr double kMinLevelSeparationMeters = 1.;
00041
00042
00043 struct Span {
00044 int start_index;
00045 int end_index;
00046 std::vector<double> z_values;
00047
00048 bool operator<(const Span& other) const {
00049 return std::forward_as_tuple(start_index, end_index) <
00050 std::forward_as_tuple(other.start_index, other.end_index);
00051 }
00052 };
00053
00054
00055 int LevelFind(const int i, const Levels& levels) {
00056 auto it = levels.find(i);
00057 CHECK(it != levels.end());
00058 if (it->first == it->second) {
00059 return it->second;
00060 }
00061 return LevelFind(it->second, levels);
00062 }
00063
00064 void LevelUnion(int i, int j, Levels* levels) {
00065 const int repr_i = LevelFind(i, *levels);
00066 const int repr_j = LevelFind(j, *levels);
00067 (*levels)[repr_i] = repr_j;
00068 }
00069
00070 void InsertSorted(const double val, std::vector<double>* vals) {
00071 vals->insert(std::upper_bound(vals->begin(), vals->end(), val), val);
00072 }
00073
00074 double Median(const std::vector<double>& sorted) {
00075 CHECK(!sorted.empty());
00076 return sorted.at(sorted.size() / 2);
00077 }
00078
00079
00080
00081 std::vector<Span> SliceByAltitudeChange(const proto::Trajectory& trajectory) {
00082 CHECK_GT(trajectory.node_size(), 0);
00083
00084 std::vector<Span> spans;
00085 spans.push_back(Span{0, 0, {trajectory.node(0).pose().translation().z()}});
00086 for (int i = 1; i < trajectory.node_size(); ++i) {
00087 const auto& node = trajectory.node(i);
00088 const double z = node.pose().translation().z();
00089 if (std::abs(Median(spans.back().z_values) - z) > kLevelHeightMeters) {
00090 spans.push_back(Span{i, i, {}});
00091 }
00092 InsertSorted(z, &spans.back().z_values);
00093 spans.back().end_index = i + 1;
00094 }
00095 return spans;
00096 }
00097
00098
00099 double SpanLength(const proto::Trajectory& trajectory, const Span& span) {
00100 double length = 0;
00101 for (int i = span.start_index + 1; i < span.end_index; ++i) {
00102 const auto a =
00103 transform::ToEigen(trajectory.node(i - 1).pose().translation());
00104 const auto b = transform::ToEigen(trajectory.node(i).pose().translation());
00105 length += (a - b).head<2>().norm();
00106 }
00107 return length;
00108 }
00109
00110
00111
00112 bool IsShort(const proto::Trajectory& trajectory, const Span& span) {
00113 return SpanLength(trajectory, span) < kMaxShortSpanLengthMeters;
00114 }
00115
00116
00117 void GroupSegmentsByAltitude(const proto::Trajectory& trajectory,
00118 const std::vector<Span>& spans, Levels* levels) {
00119 for (size_t i = 0; i < spans.size(); ++i) {
00120 for (size_t j = i + 1; j < spans.size(); ++j) {
00121 if (std::abs(Median(spans[i].z_values) - Median(spans[j].z_values)) <
00122 kMinLevelSeparationMeters) {
00123 LevelUnion(i, j, levels);
00124 }
00125 }
00126 }
00127 }
00128
00129 std::vector<Floor> FindFloors(const proto::Trajectory& trajectory,
00130 const std::vector<Span>& spans,
00131 const Levels& levels) {
00132 std::map<int, std::vector<Span>> level_spans;
00133
00134
00135 for (size_t i = 0; i < spans.size(); ++i) {
00136 const Span& span = spans[i];
00137 if (!IsShort(trajectory, span)) {
00138 level_spans[LevelFind(i, levels)].push_back(span);
00139 }
00140 }
00141
00142 for (size_t i = 0; i < spans.size(); ++i) {
00143 const Span& span = spans[i];
00144 if (!IsShort(trajectory, span)) {
00145 continue;
00146 }
00147
00148
00149
00150 int level = LevelFind(i, levels);
00151 if (!level_spans[level].empty()) {
00152 level_spans[level].push_back(span);
00153 continue;
00154 }
00155
00156
00157
00158 size_t index = i - 1;
00159 if (index < spans.size()) {
00160 level_spans[LevelFind(index, levels)].push_back(span);
00161 }
00162 index = i + 1;
00163 if (index < spans.size()) {
00164 level_spans[LevelFind(index, levels)].push_back(span);
00165 }
00166 }
00167
00168
00169 std::vector<Floor> floors;
00170 for (auto& level : level_spans) {
00171 if (level.second.empty()) {
00172 continue;
00173 }
00174
00175 std::vector<double> z_values;
00176 std::sort(level.second.begin(), level.second.end());
00177 floors.emplace_back();
00178 for (const auto& span : level.second) {
00179 if (!IsShort(trajectory, span)) {
00180
00181
00182
00183 z_values.insert(z_values.end(), span.z_values.begin(),
00184 span.z_values.end());
00185 }
00186 floors.back().timespans.push_back(Timespan{
00187 common::FromUniversal(trajectory.node(span.start_index).timestamp()),
00188 common::FromUniversal(
00189 trajectory.node(span.end_index - 1).timestamp())});
00190 }
00191 std::sort(z_values.begin(), z_values.end());
00192 floors.back().z = Median(z_values);
00193 }
00194 return floors;
00195 }
00196
00197 }
00198
00199 std::vector<Floor> DetectFloors(const proto::Trajectory& trajectory) {
00200 const std::vector<Span> spans = SliceByAltitudeChange(trajectory);
00201 Levels levels;
00202 for (size_t i = 0; i < spans.size(); ++i) {
00203 levels[i] = i;
00204 }
00205 GroupSegmentsByAltitude(trajectory, spans, &levels);
00206
00207 std::vector<Floor> floors = FindFloors(trajectory, spans, levels);
00208 std::sort(floors.begin(), floors.end(),
00209 [](const Floor& a, const Floor& b) { return a.z < b.z; });
00210 return floors;
00211 }
00212
00213 }
00214 }