NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
loc_factor_adder.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The Astrobee platform is licensed under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18 
19 #ifndef FACTOR_ADDERS_LOC_FACTOR_ADDER_H_
20 #define FACTOR_ADDERS_LOC_FACTOR_ADDER_H_
21 
30 
31 #include <vector>
32 
33 namespace factor_adders {
34 // SingleMeasurementBasedFactorAdder that adds either loc projection factors and loc pose priors for given matched
35 // projection measurements.
36 template <typename PoseNodeAdderType>
38  : public SingleMeasurementBasedFactorAdder<localization_measurements::MatchedProjectionsMeasurement> {
40 
41  public:
42  LocFactorAdder(const LocFactorAdderParams& params, const std::shared_ptr<PoseNodeAdderType> node_adder);
43 
44  // Default constructor for serialization only.
45  LocFactorAdder() = default;
46 
47  private:
48  // Adds loc projection factor or loc pose factor depending on params.
49  // If the loc projection factor is selected but fails due to a reprojection error, adds a loc pose factor
50  // as a fallback.
51  int AddFactorsForSingleMeasurement(
52  const localization_measurements::MatchedProjectionsMeasurement& matched_projections_measurement,
53  gtsam::NonlinearFactorGraph& factors) final;
54 
55  // Returns whether the node adder can add a node at the provided time.
56  bool CanAddFactor(const localization_measurements::MatchedProjectionsMeasurement& measurement) const final;
57 
58  // Adds a loc pose factor (pose prior)
59  int AddLocPoseFactor(const localization_measurements::MatchedProjectionsMeasurement& matched_projections_measurement,
60  gtsam::NonlinearFactorGraph& factors);
61 
62  // Adds a loc projection factor. If a reprojection error occurs, adds a loc pose factor.
63  int AddLocProjectionFactor(
64  const localization_measurements::MatchedProjectionsMeasurement& matched_projections_measurement,
65  gtsam::NonlinearFactorGraph& factors);
66 
67  // Helper function to add a pose node if needed and return the node's key.
68  boost::optional<gtsam::Key> AddPoseNode(const localization_common::Time timestamp,
69  gtsam::NonlinearFactorGraph& factors);
70 
71  // Serialization function
73  template <class Archive>
74  void serialize(Archive& ar, const unsigned int file_version) {
75  ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
76  ar& BOOST_SERIALIZATION_NVP(node_adder_);
77  ar& BOOST_SERIALIZATION_NVP(params_);
78  ar& BOOST_SERIALIZATION_NVP(num_landmarks_averager_);
79  ar& BOOST_SERIALIZATION_NVP(pose_prior_noise_sigmas_);
80  }
81 
82  std::shared_ptr<PoseNodeAdderType> node_adder_;
83  LocFactorAdderParams params_;
84  localization_common::Averager num_landmarks_averager_ = localization_common::Averager("Num Landmarks");
85  gtsam::Vector6 pose_prior_noise_sigmas_;
86 };
87 
88 // Implementation
89 template <typename PoseNodeAdderType>
91  std::shared_ptr<PoseNodeAdderType> node_adder)
92  : Base(params), params_(params), node_adder_(node_adder) {
93  pose_prior_noise_sigmas_ = (gtsam::Vector(6) << params_.prior_translation_stddev, params_.prior_translation_stddev,
96  .finished();
97 }
98 
99 template <typename PoseNodeAdderType>
101  const localization_measurements::MatchedProjectionsMeasurement& matched_projections_measurement,
102  gtsam::NonlinearFactorGraph& factors) {
103  if (matched_projections_measurement.matched_projections.empty()) {
104  LogDebug("AddFactorsForSingleMeasurement: Empty measurement.");
105  return 0;
106  }
107 
108  if (static_cast<int>(matched_projections_measurement.matched_projections.size()) <
109  params_.min_num_matches_per_measurement) {
110  LogDebug("AddFactorsForSingleMeasurement: Not enough matches in projection measurement.");
111  return 0;
112  }
113 
114  const int num_landmarks = matched_projections_measurement.matched_projections.size();
115  num_landmarks_averager_.Update(num_landmarks);
116  int num_loc_projection_factors = 0;
117  int num_loc_pose_factors = 0;
118  if (params_.add_projection_factors) {
119  num_loc_projection_factors = AddLocProjectionFactor(matched_projections_measurement, factors);
120  // Add loc pose factors as a fallback if all projection factors failed and fallback
121  // enabled
122  if (num_loc_projection_factors == 0 && params_.add_prior_if_projection_factors_fail) {
123  num_loc_pose_factors = AddLocPoseFactor(matched_projections_measurement, factors);
124  }
125  }
126  // Add loc pose factors if enabled and fallback hasn't already been triggered
127  if (params_.add_pose_priors && num_loc_pose_factors == 0) {
128  num_loc_pose_factors = AddLocPoseFactor(matched_projections_measurement, factors);
129  }
130  return num_loc_pose_factors + num_loc_projection_factors;
131 }
132 
133 template <typename PoseNodeAdderType>
134 bool LocFactorAdder<PoseNodeAdderType>::CanAddFactor(
136  return node_adder_->CanAddNode(measurement.timestamp);
137 }
138 
139 template <typename PoseNodeAdderType>
140 int LocFactorAdder<PoseNodeAdderType>::AddLocProjectionFactor(
141  const localization_measurements::MatchedProjectionsMeasurement& matched_projections_measurement,
142  gtsam::NonlinearFactorGraph& factors) {
143  double noise_scale = params_.projection_noise_scale;
144  if (params_.scale_projection_noise_with_num_landmarks) {
145  const int num_landmarks = matched_projections_measurement.matched_projections.size();
146  noise_scale *= std::pow((num_landmarks_averager_.average() / static_cast<double>(num_landmarks)), 2);
147  }
148  const auto pose_key = AddPoseNode(matched_projections_measurement.timestamp, factors);
149  if (!pose_key) {
150  LogError("AddLocProjectionFactors: Failed to get pose key.");
151  return 0;
152  }
153  const auto world_T_body = node_adder_->nodes().template Value<gtsam::Pose3>(*pose_key);
154  if (!world_T_body) {
155  LogError("AddLocProjectionFactors: Failed to get world_T_body at timestamp "
156  << matched_projections_measurement.timestamp << ".");
157  return 0;
158  }
159 
160  int num_loc_projection_factors = 0;
161  for (const auto& matched_projection : matched_projections_measurement.matched_projections) {
162  gtsam::SharedNoiseModel noise;
163  // Use the landmark distance from the camera to inversely scale the noise if desired.
164  if (params_.scale_projection_noise_with_landmark_distance) {
165  const Eigen::Vector3d& world_t_landmark = matched_projection.map_point;
166  const Eigen::Isometry3d nav_cam_T_world =
167  localization_common::EigenPose(*world_T_body * params_.body_T_cam).inverse();
168  const gtsam::Point3 nav_cam_t_landmark = nav_cam_T_world * world_t_landmark;
169  // Don't use robust cost here to more effectively correct a drift occurance
170  noise = gtsam::SharedIsotropic(
171  gtsam::noiseModel::Isotropic::Sigma(2, params_.projection_noise_scale * 1.0 / nav_cam_t_landmark.z()));
172  } else {
174  gtsam::SharedIsotropic(gtsam::noiseModel::Isotropic::Sigma(2, noise_scale * params_.cam_noise->sigma())),
175  params_.huber_k);
176  }
177  gtsam::LocProjectionFactor<>::shared_ptr loc_projection_factor(
178  new gtsam::LocProjectionFactor<>(matched_projection.image_point, matched_projection.map_point, noise, *pose_key,
179  params_.cam_intrinsics, params_.body_T_cam));
180  // Check for errors, discard factor if too large of projection error occurs
181  // or a cheirality error occurs
182  const auto error = (loc_projection_factor->evaluateError(*world_T_body)).norm();
183  if (error > params_.max_valid_projection_error) continue;
184  const auto cheirality_error = loc_projection_factor->cheiralityError(*world_T_body);
185  if (cheirality_error) continue;
186  factors.push_back(loc_projection_factor);
187  ++num_loc_projection_factors;
188  if (num_loc_projection_factors >= params_.max_num_projection_factors) break;
189  }
190 
191  LogDebug("AddFactorsForSingleMeasurement: Added " << num_loc_projection_factors
192  << " loc projection factors at timestamp "
193  << matched_projections_measurement.timestamp << ".");
194  return num_loc_projection_factors;
195 }
196 
197 template <typename PoseNodeAdderType>
198 int LocFactorAdder<PoseNodeAdderType>::AddLocPoseFactor(
199  const localization_measurements::MatchedProjectionsMeasurement& matched_projections_measurement,
200  gtsam::NonlinearFactorGraph& factors) {
201  double noise_scale = params_.pose_noise_scale;
202  if (params_.scale_pose_noise_with_num_landmarks) {
203  const int num_landmarks = matched_projections_measurement.matched_projections.size();
204  noise_scale *= std::pow((num_landmarks_averager_.average() / static_cast<double>(num_landmarks)), 2);
205  }
206  const auto pose_key = AddPoseNode(matched_projections_measurement.timestamp, factors);
207  if (!pose_key) {
208  LogError("AddLocProjectionFactors: Failed to get pose key.");
209  return 0;
210  }
211 
212  const auto pose_noise = localization_common::Robust(
213  gtsam::noiseModel::Diagonal::Sigmas(Eigen::Ref<const Eigen::VectorXd>(noise_scale * pose_prior_noise_sigmas_)),
214  params_.huber_k);
215 
217  *pose_key, matched_projections_measurement.global_T_cam * params_.body_T_cam.inverse(), pose_noise));
218  factors.push_back(pose_prior_factor);
219  LogDebug("AddLocPoseFactor: Added loc pose prior factor at timestamp " << matched_projections_measurement.timestamp
220  << ".");
221  return 1;
222 }
223 
224 template <typename PoseNodeAdderType>
225 boost::optional<gtsam::Key> LocFactorAdder<PoseNodeAdderType>::AddPoseNode(const localization_common::Time timestamp,
226  gtsam::NonlinearFactorGraph& factors) {
227  if (!node_adder_->AddNode(timestamp, factors)) {
228  LogError("AddLocPoseFactor: Failed to add node for timestamp " << timestamp << ".");
229  return boost::none;
230  }
231  const auto keys = node_adder_->Keys(timestamp);
232  if (keys.empty()) {
233  LogError("AddLocPoseFactor: Failed to get keys for timestamp " << timestamp << ".");
234  return boost::none;
235  }
236 
237  // Assumes first key is pose
238  const auto& pose_key = keys[0];
239  return pose_key;
240 }
241 } // namespace factor_adders
242 
243 #endif // FACTOR_ADDERS_LOC_FACTOR_ADDER_H_
Value
std::pair< std::string, Keywords > Value
Definition: eps_driver_tool.cc:72
factor_adders::SingleMeasurementBasedFactorAdder
Definition: single_measurement_based_factor_adder.h:28
gtsam::LocPoseFactor::shared_ptr
boost::shared_ptr< LocPoseFactor > shared_ptr
Definition: loc_pose_factor.h:33
factor_adders::LocFactorAdderParams
Definition: loc_factor_adder_params.h:29
logger.h
factor_adders::LocFactorAdder::access
friend class boost::serialization::access
Definition: loc_factor_adder.h:72
localization_measurements::Measurement::timestamp
localization_common::Time timestamp
Definition: measurement.h:29
gtsam::LocProjectionFactor
Definition: loc_projection_factor.h:38
LogError
#define LogError(msg)
Definition: logger.h:55
utilities.h
localization_common::Averager
Definition: averager.h:34
loc_pose_factor.h
loc_projection_factor.h
factor_adders::LocFactorAdderParams::prior_translation_stddev
double prior_translation_stddev
Definition: loc_factor_adder_params.h:38
loc_factor_adder_params.h
gtsam::LocPoseFactor
Definition: loc_pose_factor.h:28
matched_projections_measurement.h
localization_common::EigenPose
Eigen::Isometry3d EigenPose(const CombinedNavState &combined_nav_state)
Definition: utilities.cc:64
localization_measurements::MatchedProjectionsMeasurement::matched_projections
MatchedProjections matched_projections
Definition: matched_projections_measurement.h:30
averager.h
localization_common::Isometry3d
Eigen::Isometry3d Isometry3d(const Eigen::Vector3d &translation, const RotationType &rotation)
Definition: utilities.h:226
point_cloud_common::Vector3d
Eigen::Vector3d Vector3d(const PointType &point)
Definition: utilities.h:328
gtsam::LocProjectionFactor::shared_ptr
boost::shared_ptr< This > shared_ptr
shorthand for a smart pointer to a factor
Definition: loc_projection_factor.h:60
localization_measurements::MatchedProjectionsMeasurement::global_T_cam
gtsam::Pose3 global_T_cam
Definition: matched_projections_measurement.h:32
factor_adders::LocFactorAdderParams::prior_quaternion_stddev
double prior_quaternion_stddev
Definition: loc_factor_adder_params.h:40
single_measurement_based_factor_adder.h
factor_adders::LocFactorAdder::LocFactorAdder
LocFactorAdder()=default
factor_adders
Definition: depth_odometry_factor_adder.h:31
error
uint8_t error
Definition: signal_lights.h:89
LogDebug
#define LogDebug(msg)
Definition: logger.h:69
localization_common::Robust
gtsam::noiseModel::Robust::shared_ptr Robust(const gtsam::SharedNoiseModel &noise, const double huber_k)
Definition: utilities.cc:334
localization_measurements::MatchedProjectionsMeasurement
Definition: matched_projections_measurement.h:29
localization_common::Time
double Time
Definition: time.h:23
factor_adders::LocFactorAdder
Definition: loc_factor_adder.h:37