Skip to content

Commit 5d16968

Browse files
committed
Add decentralized solving functions for pcm
1 parent 1ad3c2c commit 5d16968

File tree

4 files changed

+211
-14
lines changed

4 files changed

+211
-14
lines changed

cpp/include/pairwise_consistency_maximization/distributed_pcm/distributed_pcm.h

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace distributed_pcm {
2222
DistributedPCM(){};
2323

2424
/**
25-
* \brief Function that solves the global maps according to the current constraints with perfect information
25+
* \brief Function that solves the pairwise consistency maximization according to the current constraints with perfect information
2626
*
2727
* @param dist_mappers is the different distributed mappers in the system (one by robot)
2828
* @param graph_and_values is the collection of factors of all graph used for evaluation
@@ -32,20 +32,50 @@ namespace distributed_pcm {
3232
std::vector<gtsam::GraphAndValues>& graph_and_values_vector,
3333
const double& confidence_probability, const bool& use_covariance);
3434

35+
/**
36+
* \brief Function that solves the pairwise consistency maximization according to the current constraints with limited information
37+
*
38+
* @param dist_mappers is the different distributed mappers in the system (one by robot)
39+
* @param graph_and_values is the collection of factors of all graph used for evaluation
40+
* @returns size of the maximum clique of pairwise consistent measurements
41+
*/
42+
static int solveDecentralized(const int& other_robot_id,
43+
boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper,
44+
gtsam::GraphAndValues& local_graph_and_values,
45+
const gtsam::Values& other_robot_poses,
46+
const double& confidence_probability, const bool& use_covariance);
47+
3548
private:
3649

37-
static void fillInRequiredInformation(std::vector<graph_utils::LoopClosures>& separators_by_robot,
50+
static void fillInRequiredInformationCentralized(std::vector<graph_utils::LoopClosures>& separators_by_robot,
3851
std::vector<graph_utils::Transforms>& transforms_by_robot,
3952
std::map<std::pair<char, char>,graph_utils::Transforms>& separators_transforms_by_pair,
4053
const std::vector< boost::shared_ptr<distributed_mapper::DistributedMapper> >& dist_mappers,
4154
const bool& use_covariance);
4255

43-
static int executePCM(const int& roboti, const int& robotj, const std::vector<graph_utils::Transforms>& transforms_by_robot,
44-
const std::vector<graph_utils::LoopClosures>& separators_by_robot,
45-
const std::map<std::pair<char, char>,graph_utils::Transforms>& separators_transforms_by_pair,
46-
std::vector< boost::shared_ptr<distributed_mapper::DistributedMapper> >& dist_mappers,
47-
std::vector<gtsam::GraphAndValues>& graph_and_values_vector,
48-
const double& confidence_probability);
56+
static void fillInRequiredInformationDecentralized(graph_utils::LoopClosures& separators,
57+
graph_utils::Transforms& transforms,
58+
graph_utils::Trajectory& other_robot_trajectory,
59+
graph_utils::Transforms& separators_transforms,
60+
const boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper,
61+
const gtsam::Values& other_robot_poses,
62+
const int& other_robot_id,
63+
const bool& use_covariance);
64+
65+
static int executePCMCentralized(const int& roboti, const int& robotj, const std::vector<graph_utils::Transforms>& transforms_by_robot,
66+
const std::vector<graph_utils::LoopClosures>& separators_by_robot,
67+
const std::map<std::pair<char, char>,graph_utils::Transforms>& separators_transforms_by_pair,
68+
std::vector< boost::shared_ptr<distributed_mapper::DistributedMapper> >& dist_mappers,
69+
std::vector<gtsam::GraphAndValues>& graph_and_values_vector,
70+
const double& confidence_probability);
71+
72+
static int executePCMDecentralized(const int& other_robot_id, const graph_utils::Transforms& transforms,
73+
const graph_utils::LoopClosures& separators,
74+
const graph_utils::Trajectory& other_robot_trajectory,
75+
const graph_utils::Transforms& separators_transforms,
76+
boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper,
77+
gtsam::GraphAndValues& local_graph_and_values,
78+
const double& confidence_probability);
4979

5080
static bool isSeparatorToBeRejected(const std::vector<int>& max_clique, const int& separtor_id, const graph_utils::Transforms& separators_transforms,
5181
const graph_utils::LoopClosures& loop_closures, boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper);

cpp/include/pairwise_consistency_maximization/robot_measurements/robot_local_map.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@ namespace robot_measurements {
1313
public:
1414
/**
1515
* \brief Constructor
16-
* @param file_name Name of the file containing the robot measurements.
1716
*/
1817
RobotLocalMap(const graph_utils::Transforms& transforms,
1918
const graph_utils::LoopClosures& loop_closures);
2019

20+
/**
21+
* \brief Constructor
22+
*/
23+
RobotLocalMap(const graph_utils::Trajectory& trajectory,
24+
const graph_utils::Transforms& transforms,
25+
const graph_utils::LoopClosures& loop_closures);
26+
2127
/*
2228
* Accessors
2329
*/

cpp/src/pairwise_consistency_maximization/distributed_pcm/distributed_pcm.cpp

Lines changed: 159 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ namespace distributed_pcm {
1212
std::vector<graph_utils::Transforms> transforms_by_robot;
1313
std::map<std::pair<char, char>,graph_utils::Transforms> separators_transforms_by_pair;
1414

15-
fillInRequiredInformation(separators_by_robot, transforms_by_robot, separators_transforms_by_pair,
15+
fillInRequiredInformationCentralized(separators_by_robot, transforms_by_robot, separators_transforms_by_pair,
1616
dist_mappers, use_covariance);
1717

1818
// Apply PCM for each pair of robots
19-
// For now I will work with perfect information
2019
int total_max_clique_sizes = 0;
2120
for (int roboti = 0; roboti < dist_mappers.size(); roboti++) {
2221
for (int robotj = roboti+1; robotj < dist_mappers.size(); robotj++) {
2322

24-
int max_clique_size = executePCM(roboti, robotj, transforms_by_robot, separators_by_robot,
23+
int max_clique_size = executePCMCentralized(roboti, robotj, transforms_by_robot, separators_by_robot,
2524
separators_transforms_by_pair, dist_mappers,
2625
graph_and_values_vector, confidence_probability);
2726

@@ -32,7 +31,30 @@ namespace distributed_pcm {
3231
return total_max_clique_sizes;
3332
}
3433

35-
void DistributedPCM::fillInRequiredInformation(std::vector<graph_utils::LoopClosures>& separators_by_robot,
34+
int DistributedPCM::solveDecentralized(const int& other_robot_id,
35+
boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper,
36+
gtsam::GraphAndValues& local_graph_and_values,
37+
const gtsam::Values& other_robot_poses,
38+
const double& confidence_probability, const bool& use_covariance) {
39+
40+
graph_utils::LoopClosures separators;
41+
graph_utils::Transforms transforms;
42+
graph_utils::Trajectory other_robot_trajectory;
43+
graph_utils::Transforms separators_transforms;
44+
45+
fillInRequiredInformationDecentralized(separators, transforms, other_robot_trajectory, separators_transforms,
46+
dist_mapper, other_robot_poses, other_robot_id, use_covariance);
47+
48+
// Apply PCM for each pair of robots
49+
int max_clique_size = executePCMDecentralized(other_robot_id, transforms,
50+
separators, other_robot_trajectory,
51+
separators_transforms, dist_mapper,
52+
local_graph_and_values, confidence_probability);
53+
54+
return max_clique_size;
55+
}
56+
57+
void DistributedPCM::fillInRequiredInformationCentralized(std::vector<graph_utils::LoopClosures>& separators_by_robot,
3658
std::vector<graph_utils::Transforms>& transforms_by_robot,
3759
std::map<std::pair<char, char>,graph_utils::Transforms>& separators_transforms_by_pair,
3860
const std::vector< boost::shared_ptr<distributed_mapper::DistributedMapper> >& dist_mappers,
@@ -93,7 +115,84 @@ namespace distributed_pcm {
93115
}
94116
}
95117

96-
int DistributedPCM::executePCM(const int& roboti, const int& robotj, const std::vector<graph_utils::Transforms>& transforms_by_robot,
118+
void DistributedPCM::fillInRequiredInformationDecentralized(graph_utils::LoopClosures& separators,
119+
graph_utils::Transforms& transforms,
120+
graph_utils::Trajectory& other_robot_trajectory,
121+
graph_utils::Transforms& separators_transforms,
122+
const boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper,
123+
const gtsam::Values& other_robot_poses,
124+
const int& other_robot_id,
125+
const bool& use_covariance){
126+
// Store separators key pairs
127+
for (auto id : dist_mapper->separatorEdge()) {
128+
auto separator_edge = boost::dynamic_pointer_cast<gtsam::BetweenFactor<gtsam::Pose3> >(
129+
dist_mapper->currentGraph().at(id));
130+
separators.emplace_back(std::make_pair(separator_edge->key1(), separator_edge->key2()));
131+
}
132+
133+
bool id_initialized = false;
134+
for (const auto& factor_ptr : dist_mapper->currentGraph()) {
135+
auto edge_ptr = boost::dynamic_pointer_cast<gtsam::BetweenFactor<gtsam::Pose3> >(factor_ptr);
136+
if (edge_ptr) { // Do nothing with the prior in the first robot graph
137+
graph_utils::Transform transform;
138+
transform.i = edge_ptr->key1();
139+
transform.j = edge_ptr->key2();
140+
transform.pose.pose = edge_ptr->measured();
141+
if (use_covariance) {
142+
transform.pose.covariance_matrix =
143+
boost::dynamic_pointer_cast< gtsam::noiseModel::Gaussian >(edge_ptr->noiseModel())->covariance();
144+
} else {
145+
transform.pose.covariance_matrix = graph_utils::FIXED_COVARIANCE;
146+
}
147+
transform.is_separator = std::find(separators.begin(), separators.end(),
148+
std::make_pair(edge_ptr->key1(), edge_ptr->key2())) !=
149+
separators.end();
150+
if (!transform.is_separator) {
151+
if (!id_initialized) {
152+
transforms.start_id = transform.i;
153+
transforms.end_id = transform.j;
154+
id_initialized = true;
155+
} else {
156+
transforms.start_id = std::min(transforms.start_id, transform.i);
157+
transforms.end_id = std::max(transforms.end_id, transform.j);
158+
}
159+
transforms.transforms.insert(
160+
std::make_pair(std::make_pair(edge_ptr->key1(), edge_ptr->key2()), transform));
161+
} else {
162+
auto id_1 = gtsam::Symbol(edge_ptr->key1()).chr()-97;
163+
auto id_2 = gtsam::Symbol(edge_ptr->key2()).chr()-97;
164+
if (id_1 == other_robot_id || id_2 == other_robot_id) {
165+
separators_transforms.transforms.insert(
166+
std::make_pair(std::make_pair(edge_ptr->key1(), edge_ptr->key2()), transform));
167+
}
168+
}
169+
}
170+
}
171+
172+
// Fill in the other robot poses in a trajectory structure
173+
gtsam::Key first_key, last_key;
174+
bool init_first = false;
175+
bool init_last = false;
176+
for (const gtsam::Values::ConstKeyValuePair& key_value_pair : other_robot_poses) {
177+
if (first_key > key_value_pair.key || !init_first) {
178+
first_key = key_value_pair.key;
179+
init_first = true;
180+
}
181+
if (last_key < key_value_pair.key || !init_last) {
182+
last_key = key_value_pair.key;
183+
init_last = true;
184+
}
185+
186+
graph_utils::TrajectoryPose trajectory_pose;
187+
trajectory_pose.id = key_value_pair.key;
188+
trajectory_pose.pose.pose = other_robot_poses.at<gtsam::Pose3>(key_value_pair.key);
189+
other_robot_trajectory.trajectory_poses.insert(std::make_pair(key_value_pair.key, trajectory_pose));
190+
}
191+
other_robot_trajectory.start_id = first_key;
192+
other_robot_trajectory.end_id = last_key;
193+
}
194+
195+
int DistributedPCM::executePCMCentralized(const int& roboti, const int& robotj, const std::vector<graph_utils::Transforms>& transforms_by_robot,
97196
const std::vector<graph_utils::LoopClosures>& separators_by_robot,
98197
const std::map<std::pair<char, char>,graph_utils::Transforms>& separators_transforms_by_pair,
99198
std::vector< boost::shared_ptr<distributed_mapper::DistributedMapper> >& dist_mappers,
@@ -146,6 +245,61 @@ namespace distributed_pcm {
146245
return max_clique.size();
147246
}
148247

248+
int DistributedPCM::executePCMDecentralized(const int& other_robot_id, const graph_utils::Transforms& transforms,
249+
const graph_utils::LoopClosures& separators,
250+
const graph_utils::Trajectory& other_robot_trajectory,
251+
const graph_utils::Transforms& separators_transforms,
252+
boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper,
253+
gtsam::GraphAndValues& local_graph_and_values,
254+
const double& confidence_probability){
255+
256+
auto robot_local_map = robot_measurements::RobotLocalMap(transforms, separators);
257+
graph_utils::Transforms empty_transforms;
258+
auto other_robot_local_info = robot_measurements::RobotLocalMap(other_robot_trajectory, empty_transforms, separators);
259+
auto roboti_robotj_separators_transforms = separators_transforms;
260+
auto interrobot_measurements = robot_measurements::InterRobotMeasurements(roboti_robotj_separators_transforms,
261+
dist_mapper->robotName(), ((char) other_robot_id + 97));
262+
263+
auto global_map = global_map::GlobalMap(robot_local_map, other_robot_local_info, interrobot_measurements, confidence_probability);
264+
std::vector<int> max_clique = global_map.pairwiseConsistencyMaximization();
265+
266+
// Retrieve indexes of rejected measurements
267+
auto separators_ids = dist_mapper->separatorEdge();
268+
std::vector<int> rejected_separator_ids;
269+
for (int i = 0; i < separators_ids.size(); i++) {
270+
if (isSeparatorToBeRejected(max_clique, separators_ids[i], roboti_robotj_separators_transforms,
271+
interrobot_measurements.getLoopClosures(), dist_mapper)) {
272+
rejected_separator_ids.emplace_back(i);
273+
}
274+
}
275+
// Remove measurements not in the max clique
276+
int number_separator_ids_removed = 0;
277+
for (const auto& index : rejected_separator_ids) {
278+
auto id = separators_ids[index] - number_separator_ids_removed;
279+
number_separator_ids_removed++;
280+
dist_mapper->eraseFactor(id);
281+
local_graph_and_values.first->erase(local_graph_and_values.first->begin()+id);
282+
}
283+
// Update separator ids
284+
std::vector<size_t> new_separator_ids;
285+
int number_of_edges = dist_mapper->currentGraph().size();
286+
if (((int) dist_mapper->robotName()-97) == 0){
287+
// Do not count the prior in the first robot graph
288+
number_of_edges--;
289+
}
290+
for (int i = 0; i < number_of_edges; i++) {
291+
auto keys = dist_mapper->currentGraph().at(i)->keys();
292+
char robot0 = gtsam::symbolChr(keys.at(0));
293+
char robot1 = gtsam::symbolChr(keys.at(1));
294+
if (robot0 != robot1) {
295+
new_separator_ids.push_back(i);
296+
}
297+
}
298+
dist_mapper->setSeparatorIds(new_separator_ids);
299+
300+
return max_clique.size();
301+
}
302+
149303
bool DistributedPCM::isSeparatorToBeRejected(const std::vector<int>& max_clique, const int& separtor_id, const graph_utils::Transforms& separators_transforms,
150304
const graph_utils::LoopClosures& loop_closures, boost::shared_ptr<distributed_mapper::DistributedMapper>& dist_mapper) {
151305

cpp/src/pairwise_consistency_maximization/robot_measurements/robot_local_map.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ RobotLocalMap::RobotLocalMap(const graph_utils::Transforms& transforms,
1111
trajectory_ = graph_utils::buildTrajectory(transforms_);
1212
}
1313

14+
RobotLocalMap::RobotLocalMap(const graph_utils::Trajectory& trajectory,
15+
const graph_utils::Transforms& transforms,
16+
const graph_utils::LoopClosures& loop_closures):
17+
RobotMeasurements(transforms, loop_closures){
18+
trajectory_ = trajectory;
19+
}
20+
1421
const graph_utils::Trajectory& RobotLocalMap::getTrajectory() const {
1522
return trajectory_;
1623
}

0 commit comments

Comments
 (0)