ceres::Manifold定义pose流形参数

在看lio-mapping源码时发现,其定义的pose参数根据ceres::LocalParameterization,新版本ceres-solver库编译报错,因此改写该类。
ceres位姿参数类型,包含位置(三维向量)跟姿态(四元数),ceres-2.1以前自定义参数需要集成ceres::LocalParameterization类并重载类中的纯虚函数,ceres-solver-2.2以后取消了ceres::LocalParameterization类,并用ceres::Manifold代替,两者的具体区别可参考链接,下面给出使用ceres::Manifold定义的流形位姿参数。

头文件:

//
// Created by liuhuan on 24-5-16.
//

#ifndef SRC_POSEMANIFOLD_H
#define SRC_POSEMANIFOLD_H

#include <ceres/ceres.h>
#include <ceres/manifold.h>
#include <Eigen/Core>

namespace lio {

class PoseManifold : public ceres::Manifold{
public:
    int AmbientSize() const override { return 7; }
    int TangentSize() const override { return 6; }

    bool Plus(const double* x,
              const double* delta,
              double* x_plus_delta) const override;
    bool PlusJacobian(const double* x, double* jacobian) const override;
    bool Minus(const double* y,
               const double* x,
               double* y_minus_x) const override;
    bool MinusJacobian(const double* x, double* jacobian) const override;
    };

} // lio

#endif //SRC_POSEMANIFOLD_H

源文件:

//
// Created by liuhuan on 24-5-16.
//

#include "PoseManifold.h"

namespace lio {

    namespace {

        struct CeresQuaternionOrder {
            static constexpr int kW = 0;
            static constexpr int kX = 1;
            static constexpr int kY = 2;
            static constexpr int kZ = 3;
        };

        struct EigenQuaternionOrder {
            static constexpr int kW = 3;
            static constexpr int kX = 0;
            static constexpr int kY = 1;
            static constexpr int kZ = 2;
        };

        template<typename Order>
        inline void QuaternionPlusImpl(const double *x,
                                       const double *delta,
                                       double *x_plus_delta) {
            // x_plus_delta = QuaternionProduct(q_delta, x), where q_delta is the
            // quaternion constructed from delta.
            const double norm_delta = std::hypot(delta[0], delta[1], delta[2]);

            if (std::fpclassify(norm_delta) == FP_ZERO) {
                // No change in rotation: return the quaternion as is.
                std::copy_n(x, 4, x_plus_delta);
                return;
            }

            const double sin_delta_by_delta = (std::sin(norm_delta) / norm_delta);
            double q_delta[4];
            q_delta[Order::kW] = std::cos(norm_delta);
            q_delta[Order::kX] = sin_delta_by_delta * delta[0];
            q_delta[Order::kY] = sin_delta_by_delta * delta[1];
            q_delta[Order::kZ] = sin_delta_by_delta * delta[2];

            x_plus_delta[Order::kW] =
                    q_delta[Order::kW] * x[Order::kW] - q_delta[Order::kX] * x[Order::kX] -
                    q_delta[Order::kY] * x[Order::kY] - q_delta[Order::kZ] * x[Order::kZ];
            x_plus_delta[Order::kX] =
                    q_delta[Order::kW] * x[Order::kX] + q_delta[Order::kX] * x[Order::kW] +
                    q_delta[Order::kY] * x[Order::kZ] - q_delta[Order::kZ] * x[Order::kY];
            x_plus_delta[Order::kY] =
                    q_delta[Order::kW] * x[Order::kY] - q_delta[Order::kX] * x[Order::kZ] +
                    q_delta[Order::kY] * x[Order::kW] + q_delta[Order::kZ] * x[Order::kX];
            x_plus_delta[Order::kZ] =
                    q_delta[Order::kW] * x[Order::kZ] + q_delta[Order::kX] * x[Order::kY] -
                    q_delta[Order::kY] * x[Order::kX] + q_delta[Order::kZ] * x[Order::kW];
        }

        template<typename Order>
        inline void QuaternionPlusJacobianImpl(const double *x, double *jacobian_ptr) {
            Eigen::Map<Eigen::Matrix<double, 7, 6, Eigen::RowMajor>> jacobian(
                    jacobian_ptr);
            jacobian.setZero();

            jacobian(Order::kW+3, 0+3) = -x[Order::kX];
            jacobian(Order::kW+3, 1+3) = -x[Order::kY];
            jacobian(Order::kW+3, 2+3) = -x[Order::kZ];
            jacobian(Order::kX+3, 0+3) = x[Order::kW];
            jacobian(Order::kX+3, 1+3) = x[Order::kZ];
            jacobian(Order::kX+3, 2+3) = -x[Order::kY];
            jacobian(Order::kY+3, 0+3) = -x[Order::kZ];
            jacobian(Order::kY+3, 1+3) = x[Order::kW];
            jacobian(Order::kY+3, 2+3) = x[Order::kX];
            jacobian(Order::kZ+3, 0+3) = x[Order::kY];
            jacobian(Order::kZ+3, 1+3) = -x[Order::kX];
            jacobian(Order::kZ+3, 2+3) = x[Order::kW];
        }

        template<typename Order>
        inline void QuaternionMinusImpl(const double *y,
                                        const double *x,
                                        double *y_minus_x) {
            // ambient_y_minus_x = QuaternionProduct(y, -x) where -x is the conjugate of
            // x.
            double ambient_y_minus_x[4];
            ambient_y_minus_x[Order::kW] =
                    y[Order::kW] * x[Order::kW] + y[Order::kX] * x[Order::kX] +
                    y[Order::kY] * x[Order::kY] + y[Order::kZ] * x[Order::kZ];
            ambient_y_minus_x[Order::kX] =
                    -y[Order::kW] * x[Order::kX] + y[Order::kX] * x[Order::kW] -
                    y[Order::kY] * x[Order::kZ] + y[Order::kZ] * x[Order::kY];
            ambient_y_minus_x[Order::kY] =
                    -y[Order::kW] * x[Order::kY] + y[Order::kX] * x[Order::kZ] +
                    y[Order::kY] * x[Order::kW] - y[Order::kZ] * x[Order::kX];
            ambient_y_minus_x[Order::kZ] =
                    -y[Order::kW] * x[Order::kZ] - y[Order::kX] * x[Order::kY] +
                    y[Order::kY] * x[Order::kX] + y[Order::kZ] * x[Order::kW];

            const double u_norm = std::hypot(ambient_y_minus_x[Order::kX],
                                             ambient_y_minus_x[Order::kY],
                                             ambient_y_minus_x[Order::kZ]);
            if (std::fpclassify(u_norm) != FP_ZERO) {
                const double theta = std::atan2(u_norm, ambient_y_minus_x[Order::kW]);
                y_minus_x[0] = theta * ambient_y_minus_x[Order::kX] / u_norm;
                y_minus_x[1] = theta * ambient_y_minus_x[Order::kY] / u_norm;
                y_minus_x[2] = theta * ambient_y_minus_x[Order::kZ] / u_norm;
            } else {
                std::fill_n(y_minus_x, 3, 0.0);
            }
        }

        template<typename Order>
        inline void QuaternionMinusJacobianImpl(const double *x, double *jacobian_ptr) {
            Eigen::Map<Eigen::Matrix<double, 6, 7, Eigen::RowMajor>> jacobian(
                    jacobian_ptr);

            jacobian.setZero();
            jacobian(0+3, Order::kW+3) = -x[Order::kX];
            jacobian(0+3, Order::kX+3) = x[Order::kW];
            jacobian(0+3, Order::kY+3) = -x[Order::kZ];
            jacobian(0+3, Order::kZ+3) = x[Order::kY];
            jacobian(1+3, Order::kW+3) = -x[Order::kY];
            jacobian(1+3, Order::kX+3) = x[Order::kZ];
            jacobian(1+3, Order::kY+3) = x[Order::kW];
            jacobian(1+3, Order::kZ+3) = -x[Order::kX];
            jacobian(2+3, Order::kW+3) = -x[Order::kZ];
            jacobian(2+3, Order::kX+3) = -x[Order::kY];
            jacobian(2+3, Order::kY+3) = x[Order::kX];
            jacobian(2+3, Order::kZ+3) = x[Order::kW];
        }

        
        using AmbientVector = Eigen::Matrix<double, 3, 1>;
        using MatrixJacobian = Eigen::Matrix<double, 3, 3, Eigen::RowMajor>;
        void PosPlus(const double *x_ptr,
                     const double *delta_ptr,
                     double *x_plus_delta_ptr) {
            Eigen::Map<const AmbientVector> x(x_ptr, 3);
            Eigen::Map<const AmbientVector> delta(delta_ptr, 3);
            Eigen::Map<AmbientVector> x_plus_delta(x_plus_delta_ptr, 3);
            x_plus_delta = x + delta;
        }

        void PosPlusJacobian(const double *x_ptr, double *jacobian_ptr) {
            Eigen::Map<MatrixJacobian> jacobian(jacobian_ptr, 3, 3);
            jacobian.setIdentity();
        }

        void PosRightMultiplyByPlusJacobian(const double *x,
                                            const int num_rows,
                                            const double *ambient_matrix,
                                            double *tangent_matrix) {
            std::copy_n(ambient_matrix, num_rows * 3, tangent_matrix);
        }

        void PosMinus(const double *y_ptr,
                      const double *x_ptr,
                      double *y_minus_x_ptr) {
            Eigen::Map<const AmbientVector> x(x_ptr, 3);
            Eigen::Map<const AmbientVector> y(y_ptr, 3);
            Eigen::Map<AmbientVector> y_minus_x(y_minus_x_ptr, 3);
            y_minus_x = y - x;
        }

        void PosMinusJacobian(const double *x_ptr, double *jacobian_ptr) {
            Eigen::Map<MatrixJacobian> jacobian(jacobian_ptr, 3, 3);
            jacobian.setIdentity();
        }

    }  // namespace



    bool PoseManifold::Plus(const double* x,
                                       const double* delta,
                                       double* x_plus_delta) const {
        const double p_x[3] = {x[0], x[1], x[2]};
        const double p_delta[3] = {delta[0], delta[1], delta[2]};
        const double q_x[4] = {x[3], x[4], x[5], x[6]};
        const double q_delta[3] = {delta[3], delta[4], delta[5]};
        double* p_x_plus_delta; double* q_x_plus_delta;
        QuaternionPlusImpl<EigenQuaternionOrder>(q_x, q_delta, q_x_plus_delta);
        PosPlus(p_x, p_delta, p_x_plus_delta);

        Eigen::Map<Eigen::VectorXd> e_x_plus_delta(x_plus_delta, 7);
        e_x_plus_delta.segment<3>(0) = Eigen::Map<Eigen::Vector3d>(p_x_plus_delta, 3);
        e_x_plus_delta.segment<4>(3) = Eigen::Map<Eigen::Vector4d>(q_x_plus_delta, 4);

        return true;
    }

    bool PoseManifold::PlusJacobian(const double* x, double* jacobian) const {
        const double q_x[4] = {x[3], x[4], x[5], x[6]};

        QuaternionPlusJacobianImpl<EigenQuaternionOrder>(q_x, jacobian);
        Eigen::Map<Eigen::Matrix<double, 7, 6, Eigen::RowMajor>> jacobian_map(jacobian);
        jacobian_map(0,0) = 1;
        jacobian_map(1,1) = 1;
        jacobian_map(2,2) = 1;
        return true;
    }

    bool PoseManifold::Minus(const double* y, const double* x, double* y_minus_x) const {
        const double p_x[3] = {x[0], x[1], x[2]};
        const double p_y[3] = {y[0], y[1], y[2]};
        const double q_x[4] = {x[3], x[4], x[5], x[6]};
        const double q_y[4] = {y[3], y[4], y[5], y[6]};

        double* p_y_minus_x;
        double* q_y_minus_x;

        QuaternionMinusImpl<EigenQuaternionOrder>(q_y, q_x, q_y_minus_x);
        PosMinus(p_y, p_x, p_y_minus_x);

        Eigen::Map<Eigen::VectorXd> e_y_minus_x(y_minus_x, 6);
        e_y_minus_x.segment<3>(0) = Eigen::Map<Eigen::Vector3d>(p_y_minus_x, 3);
        e_y_minus_x.segment<3>(3) = Eigen::Map<Eigen::Vector3d>(q_y_minus_x, 3);
        return true;
    }

    bool PoseManifold::MinusJacobian(const double* x, double* jacobian) const {
        const double q_x[4] = {x[3], x[4], x[5], x[6]};
        QuaternionMinusJacobianImpl<EigenQuaternionOrder>(q_x, jacobian);

        Eigen::Map<Eigen::Matrix<double, 6, 7, Eigen::RowMajor>> jacobian_map(jacobian);
        jacobian_map(0,0) = 1;
        jacobian_map(1,1) = 1;
        jacobian_map(2,2) = 1;
        return true;
    }
} // lio
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值