FixedFramePose in optimization 2d (#1580)
							parent
							
								
									d7016fdbbc
								
							
						
					
					
						commit
						5899bff425
					
				|  | @ -229,7 +229,14 @@ void PoseGraph2D::AddOdometryData(const int trajectory_id, | |||
| void PoseGraph2D::AddFixedFramePoseData( | ||||
|     const int trajectory_id, | ||||
|     const sensor::FixedFramePoseData& fixed_frame_pose_data) { | ||||
|   LOG(FATAL) << "Not yet implemented for 2D."; | ||||
|   AddWorkItem([=]() LOCKS_EXCLUDED(mutex_) { | ||||
|     absl::MutexLock locker(&mutex_); | ||||
|     if (CanAddWorkItemModifying(trajectory_id)) { | ||||
|       optimization_problem_->AddFixedFramePoseData(trajectory_id, | ||||
|                                                    fixed_frame_pose_data); | ||||
|     } | ||||
|     return WorkItem::Result::kDoNotRunOptimization; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| void PoseGraph2D::AddLandmarkData(int trajectory_id, | ||||
|  | @ -753,7 +760,24 @@ void PoseGraph2D::AddNodeFromProto(const transform::Rigid3d& global_pose, | |||
| 
 | ||||
| void PoseGraph2D::SetTrajectoryDataFromProto( | ||||
|     const proto::TrajectoryData& data) { | ||||
|   LOG(ERROR) << "not implemented"; | ||||
|   TrajectoryData trajectory_data; | ||||
|   // gravity_constant and imu_calibration are omitted as its not used in 2d
 | ||||
| 
 | ||||
|   if (data.has_fixed_frame_origin_in_map()) { | ||||
|     trajectory_data.fixed_frame_origin_in_map = | ||||
|         transform::ToRigid3(data.fixed_frame_origin_in_map()); | ||||
| 
 | ||||
|     const int trajectory_id = data.trajectory_id(); | ||||
|     AddWorkItem([this, trajectory_id, trajectory_data]() | ||||
|                     LOCKS_EXCLUDED(mutex_) { | ||||
|                       absl::MutexLock locker(&mutex_); | ||||
|                       if (CanAddWorkItemModifying(trajectory_id)) { | ||||
|                         optimization_problem_->SetTrajectoryData( | ||||
|                             trajectory_id, trajectory_data); | ||||
|                       } | ||||
|                       return WorkItem::Result::kDoNotRunOptimization; | ||||
|                     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void PoseGraph2D::AddNodeToSubmap(const NodeId& node_id, | ||||
|  | @ -984,15 +1008,14 @@ PoseGraph2D::GetLandmarkNodes() const { | |||
| 
 | ||||
| std::map<int, PoseGraphInterface::TrajectoryData> | ||||
| PoseGraph2D::GetTrajectoryData() const { | ||||
|   // The 2D optimization problem does not have any 'TrajectoryData'.
 | ||||
|   return {}; | ||||
|   absl::MutexLock locker(&mutex_); | ||||
|   return optimization_problem_->trajectory_data(); | ||||
| } | ||||
| 
 | ||||
| sensor::MapByTime<sensor::FixedFramePoseData> | ||||
| PoseGraph2D::GetFixedFramePoseData() const { | ||||
|   // FixedFramePoseData is not yet implemented for 2D. We need to return empty
 | ||||
|   // so serialization works.
 | ||||
|   return {}; | ||||
|   absl::MutexLock locker(&mutex_); | ||||
|   return optimization_problem_->fixed_frame_pose_data(); | ||||
| } | ||||
| 
 | ||||
| std::vector<PoseGraphInterface::Constraint> PoseGraph2D::constraints() const { | ||||
|  |  | |||
|  | @ -42,6 +42,35 @@ namespace { | |||
| 
 | ||||
| using ::cartographer::mapping::optimization::CeresPose; | ||||
| using LandmarkNode = ::cartographer::mapping::PoseGraphInterface::LandmarkNode; | ||||
| using TrajectoryData = | ||||
|     ::cartographer::mapping::PoseGraphInterface::TrajectoryData; | ||||
| 
 | ||||
| // For fixed frame pose.
 | ||||
| std::unique_ptr<transform::Rigid3d> Interpolate( | ||||
|     const sensor::MapByTime<sensor::FixedFramePoseData>& map_by_time, | ||||
|     const int trajectory_id, const common::Time time) { | ||||
|   const auto it = map_by_time.lower_bound(trajectory_id, time); | ||||
|   if (it == map_by_time.EndOfTrajectory(trajectory_id) || | ||||
|       !it->pose.has_value()) { | ||||
|     return nullptr; | ||||
|   } | ||||
|   if (it == map_by_time.BeginOfTrajectory(trajectory_id)) { | ||||
|     if (it->time == time) { | ||||
|       return absl::make_unique<transform::Rigid3d>(it->pose.value()); | ||||
|     } | ||||
|     return nullptr; | ||||
|   } | ||||
|   const auto prev_it = std::prev(it); | ||||
|   if (prev_it->pose.has_value()) { | ||||
|     return absl::make_unique<transform::Rigid3d>( | ||||
|         Interpolate(transform::TimestampedTransform{prev_it->time, | ||||
|                                                     prev_it->pose.value()}, | ||||
|                     transform::TimestampedTransform{it->time, it->pose.value()}, | ||||
|                     time) | ||||
|             .transform); | ||||
|   } | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| // Converts a pose into the 3 optimization variable format used for Ceres:
 | ||||
| // translation in x and y, followed by the rotation angle representing the
 | ||||
|  | @ -154,20 +183,36 @@ void OptimizationProblem2D::AddOdometryData( | |||
|   odometry_data_.Append(trajectory_id, odometry_data); | ||||
| } | ||||
| 
 | ||||
| void OptimizationProblem2D::AddFixedFramePoseData( | ||||
|     const int trajectory_id, | ||||
|     const sensor::FixedFramePoseData& fixed_frame_pose_data) { | ||||
|   fixed_frame_pose_data_.Append(trajectory_id, fixed_frame_pose_data); | ||||
| } | ||||
| 
 | ||||
| void OptimizationProblem2D::AddTrajectoryNode(const int trajectory_id, | ||||
|                                               const NodeSpec2D& node_data) { | ||||
|   node_data_.Append(trajectory_id, node_data); | ||||
|   trajectory_data_[trajectory_id]; | ||||
| } | ||||
| 
 | ||||
| void OptimizationProblem2D::SetTrajectoryData( | ||||
|     int trajectory_id, const TrajectoryData& trajectory_data) { | ||||
|   trajectory_data_[trajectory_id] = trajectory_data; | ||||
| } | ||||
| 
 | ||||
| void OptimizationProblem2D::InsertTrajectoryNode(const NodeId& node_id, | ||||
|                                                  const NodeSpec2D& node_data) { | ||||
|   node_data_.Insert(node_id, node_data); | ||||
|   trajectory_data_[node_id.trajectory_id]; | ||||
| } | ||||
| 
 | ||||
| void OptimizationProblem2D::TrimTrajectoryNode(const NodeId& node_id) { | ||||
|   imu_data_.Trim(node_data_, node_id); | ||||
|   odometry_data_.Trim(node_data_, node_id); | ||||
|   node_data_.Trim(node_id); | ||||
|   if (node_data_.SizeOfTrajectoryOrZero(node_id.trajectory_id) == 0) { | ||||
|     trajectory_data_.erase(node_id.trajectory_id); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void OptimizationProblem2D::AddSubmap( | ||||
|  | @ -301,6 +346,53 @@ void OptimizationProblem2D::Solve( | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   std::map<int, std::array<double, 3>> C_fixed_frames; | ||||
|   for (auto node_it = node_data_.begin(); node_it != node_data_.end();) { | ||||
|     const int trajectory_id = node_it->id.trajectory_id; | ||||
|     const auto trajectory_end = node_data_.EndOfTrajectory(trajectory_id); | ||||
|     if (!fixed_frame_pose_data_.HasTrajectory(trajectory_id)) { | ||||
|       node_it = trajectory_end; | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     const TrajectoryData& trajectory_data = trajectory_data_.at(trajectory_id); | ||||
|     bool fixed_frame_pose_initialized = false; | ||||
|     for (; node_it != trajectory_end; ++node_it) { | ||||
|       const NodeId node_id = node_it->id; | ||||
|       const NodeSpec2D& node_data = node_it->data; | ||||
| 
 | ||||
|       const std::unique_ptr<transform::Rigid3d> fixed_frame_pose = | ||||
|           Interpolate(fixed_frame_pose_data_, trajectory_id, node_data.time); | ||||
|       if (fixed_frame_pose == nullptr) { | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       const Constraint::Pose constraint_pose{ | ||||
|           *fixed_frame_pose, options_.fixed_frame_pose_translation_weight(), | ||||
|           options_.fixed_frame_pose_rotation_weight()}; | ||||
| 
 | ||||
|       if (!fixed_frame_pose_initialized) { | ||||
|         transform::Rigid2d fixed_frame_pose_in_map; | ||||
|         if (trajectory_data.fixed_frame_origin_in_map.has_value()) { | ||||
|           fixed_frame_pose_in_map = transform::Project2D( | ||||
|               trajectory_data.fixed_frame_origin_in_map.value()); | ||||
|         } else { | ||||
|           fixed_frame_pose_in_map = node_data.global_pose_2d; | ||||
|         } | ||||
| 
 | ||||
|         C_fixed_frames.emplace( | ||||
|             std::piecewise_construct, std::forward_as_tuple(trajectory_id), | ||||
|             std::forward_as_tuple(FromPose(fixed_frame_pose_in_map))); | ||||
|         fixed_frame_pose_initialized = true; | ||||
|       } | ||||
| 
 | ||||
|       problem.AddResidualBlock(CreateAutoDiffSpaCostFunction(constraint_pose), | ||||
|                                nullptr /* loss function */, | ||||
|                                C_fixed_frames.at(trajectory_id).data(), | ||||
|                                C_nodes.at(node_id).data()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Solve.
 | ||||
|   ceres::Solver::Summary summary; | ||||
|   ceres::Solve( | ||||
|  | @ -319,6 +411,10 @@ void OptimizationProblem2D::Solve( | |||
|     node_data_.at(C_node_id_data.id).global_pose_2d = | ||||
|         ToPose(C_node_id_data.data); | ||||
|   } | ||||
|   for (const auto& C_fixed_frame : C_fixed_frames) { | ||||
|     trajectory_data_.at(C_fixed_frame.first).fixed_frame_origin_in_map = | ||||
|         transform::Embed3D(ToPose(C_fixed_frame.second)); | ||||
|   } | ||||
|   for (const auto& C_landmark : C_landmarks) { | ||||
|     landmark_data_[C_landmark.first] = C_landmark.second.ToRigid(); | ||||
|   } | ||||
|  |  | |||
|  | @ -101,6 +101,21 @@ class OptimizationProblem2D | |||
|     return odometry_data_; | ||||
|   } | ||||
| 
 | ||||
|   void AddFixedFramePoseData( | ||||
|       int trajectory_id, | ||||
|       const sensor::FixedFramePoseData& fixed_frame_pose_data); | ||||
|   void SetTrajectoryData( | ||||
|       int trajectory_id, | ||||
|       const PoseGraphInterface::TrajectoryData& trajectory_data); | ||||
|   const sensor::MapByTime<sensor::FixedFramePoseData>& fixed_frame_pose_data() | ||||
|       const { | ||||
|     return fixed_frame_pose_data_; | ||||
|   } | ||||
|   const std::map<int, PoseGraphInterface::TrajectoryData>& trajectory_data() | ||||
|       const { | ||||
|     return trajectory_data_; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   std::unique_ptr<transform::Rigid3d> InterpolateOdometry( | ||||
|       int trajectory_id, common::Time time) const; | ||||
|  | @ -115,6 +130,8 @@ class OptimizationProblem2D | |||
|   std::map<std::string, transform::Rigid3d> landmark_data_; | ||||
|   sensor::MapByTime<sensor::ImuData> imu_data_; | ||||
|   sensor::MapByTime<sensor::OdometryData> odometry_data_; | ||||
|   sensor::MapByTime<sensor::FixedFramePoseData> fixed_frame_pose_data_; | ||||
|   std::map<int, PoseGraphInterface::TrajectoryData> trajectory_data_; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace optimization
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue