1、涉及到的类型

1.  MapById<SubmapId, SubmapSpec2D> submap_data_;

SubmapId              int trajectory_id; int submap_index;

struct SubmapSpec2D {transform::Rigid2d global_pose;};

2.transform::Rigid2d   translation_;   Rotation2D rotation_;   两个平移量和一个旋转量

   transform::Rigid3d    Vector translation_;    Quaternion rotation_;  三个平移量和四元素

3.struct NodeSpec2D {
  common::Time time;
  transform::Rigid2d local_pose_2d;
  transform::Rigid2d global_pose_2d;
  Eigen::Quaterniond gravity_alignment;
};

2、具体形式调用

1.pose_graph_2d.cc   void PoseGraph2D::RunOptimization()函数中调用:
  optimization_problem_->Solve(data_.constraints, GetTrajectoryStates(),
                               data_.landmark_nodes);
参数::data_.constraints  所有数据的约束

GetTrajectoryStates()  轨迹的状态 ACTIVE, FINISHED, FROZEN, DELETED

data_.landmark_nodes   landmark的所有数据

2.optimization_problem_2d.cc    Solve函数:


void OptimizationProblem2D::Solve(
    const std::vector<Constraint>& constraints,
    const std::map<int, PoseGraphInterface::TrajectoryState>&
        trajectories_state,
    const std::map<std::string, LandmarkNode>& landmark_nodes)


中涉及到的子图节点的优化:

1.for (const auto& submap_id_data : submap_data_)      //for start

 首先在冻结轨迹中寻找该子图id是否存在,确定该子图是否为冻结子图

2.C_submaps.Insert(submap_id_data.id, FromPose(submap_id_data.data.global_pose));

3.添加一个参数块  problem.AddParameterBlock(C_submaps.at(submap_id_data.id).data(), 3);

4.如果为第一个子图或者是冻结子图,则固定子图的数据,也就是位姿。  //for end

problem.SetParameterBlockConstant(C_submaps.at(submap_id_data.id).data());

5. for (const auto& node_id_data : node_data_)     //for start

首先在冻结轨迹中寻找该node是否存在,确定该node_id_data是否为冻结node

6.添加一个参数块 problem.AddParameterBlock(C_nodes.at(node_id_data.id).data(), 3);

7.如果为冻结node数据,则将该node_id_data数据设为固定值     //for end

8.为子图内和子图间的约束添加代价函数 for (const Constraint& constraint : constraints)  //for start

9.CreateAutoDiffSpaCostFunction(constraint.pose)   

ceres::CostFunction* CreateAutoDiffSpaCostFunction(
    const PoseGraphInterface::Constraint::Pose& observed_relative_pose) {
  return new ceres::AutoDiffCostFunction<SpaCostFunction2D, 3 /* residuals */,
                                         3 /* start pose variables */,
                                         3 /* end pose variables */>(
      new SpaCostFunction2D(observed_relative_pose));
}
 

SpaCostFunction2D中  私有成员observed_relative_pose_      重要成员函数: operator()函数

  template <typename T>
  bool operator()(const T* const start_pose, const T* const end_pose,
                  T* e) const {
    const std::array<T, 3> error =
        ScaleError(ComputeUnscaledError(
                       transform::Project2D(observed_relative_pose_.zbar_ij),
                       start_pose, end_pose),
                   observed_relative_pose_.translation_weight,
                   observed_relative_pose_.rotation_weight);
    std::copy(std::begin(error), std::end(error), e);
    return true;
  }
static std::array<T, 3> ComputeUnscaledError( const transform::Rigid2d& relative_pose, const T* const start,
    const T* const end) 计算偏差错误

首先首先计算start到end的位姿   然后计算 相对位姿与其所求相对位姿的參差

.

std::array<T, 3> ScaleError(const std::array<T, 3>& error,double translation_weight, double rotation_weight) {
  return {{  error[0] * translation_weight,  error[1] * translation_weight,error[2] * rotation_weight}};

    //for end

10.添加违反测距或连续节点之间更改的惩罚如果没有里程计

  for (auto node_it = node_data_.begin(); node_it != node_data_.end();)   //for start

11.如果该node_it 所对应的轨迹冻结,则该node_it迭代器指向下一个迭代器,continue

12. auto prev_node_it = node_it;

13.    for (++node_it; node_it != trajectory_end; ++node_it)   //for start

14.   求数据   const NodeId first_node_id = prev_node_it->id;  second_node_id
    const NodeSpec2D& first_node_data = prev_node_it->data;  second_node_data

      if (second_node_id.node_index != first_node_id.node_index + 1) {continue;}   //保证在同一个轨迹

15.根据里程计(如果可用)添加相对姿势约束。   

  std::unique_ptr<transform::Rigid3d> relative_odometry =
          CalculateOdometryBetweenNodes(trajectory_id, first_node_data, second_node_data)

如果有轨迹则执行,否则返回nullptr   计算first_node_odometry  second_node_odometry 位姿

    const std::unique_ptr<transform::Rigid3d> first_node_odometry =InterpolateOdometry(trajectory_id, first_node_data.time);

求出该时间的里程计位姿,并且求出前一时刻里程计位姿,而 这进行插值求出位姿 Interpolate(pose1,pose2).transform

    transform::Rigid3d relative_odometry =   求解里程计的相对位姿
          transform::Rigid3d::Rotation(first_node_data.gravity_alignment) * first_node_odometry->inverse() *
          (*second_node_odometry) * transform::Rigid3d::Rotation(second_node_data.gravity_alignment.inverse());

16.创建里程计的代价    跟上述一致

        problem.AddResidualBlock(
            CreateAutoDiffSpaCostFunction(Constraint::Pose{
                *relative_odometry, options_.odometry_translation_weight(),
                options_.odometry_rotation_weight()}),
            nullptr /* loss function */, C_nodes.at(first_node_id).data(),
            C_nodes.at(second_node_id).data());

17.基于连续的本地SLAM姿势添加相对姿势约束。   

  const transform::Rigid3d relative_local_slam_pose =
          transform::Embed3D(first_node_data.local_pose_2d.inverse() * second_node_data.local_pose_2d);

18.优化   ceres::Solve(common::CreateCeresSolverOptions(options_.ceres_solver_options()), &problem, &summary);

上面的所有 约束都加到   problem中  进行非线性优化 ceres

19.存储结果  跟新submap_data_的全局位姿 node_data_的全局位姿 landmark_data_的位姿(全局)

//for end //for end