Open narutojxl opened 3 years ago
I think the major difference is the choice of left/right perturbation on SO(3)
. Both choices are allowed since they are the approximations. But using the left perturbation can may the Jacobians simpler.
If you are not sure about the derived Jacobian, you can use check()
for the verification. See estimator.cpp
, search if (CHECK_JACOBIAN)
for the usage.
Thanks.
Hi doctor jiao,
If we use left perturbation to derive jacobian, the PoseLocalParameterization::Plus()
, pose_local_parameterization.cpp#L42 , maybe changed to q_plus = (dq *q).normalized();
, as it is a globally pertubation in hamilton. When we parameterization double raw pointer in ceres param blocks.
I guess when you deriving jacobian according to right perturbation, consistent with my derivation process. Thanks for pointing me
out the check()
function, i will read it, thanks again!
Hi author, I find a interesting thing. I did two experiments, the test conditions are:
estimate_extrinsic: 0
in config file.CHECK_JACOBIAN = 1;
estimator.cpp#L816if (CHECK_JACOBIAN && frame_cnt_== 100)
estimator.cpp#L835The first experiment is the raw code's output when frame_cnt_== 100
is:
optimization with pure odometry [LidarPureOdomEdgeFactor] check begins analytical: 0.053 -0.100 0.216 -0.971 -0.823 1.795 0.673 0.000 0.100 -0.216 0.971 0.786 -1.709 -0.637 0.000 0.004 -0.348 0.938 0.786 -1.709 -0.637 0.000 perturbation: 0.053 -0.100 0.216 -0.971 -0.823 1.795 0.673 0.100 -0.216 0.971 0.786 -1.709 -0.637 0.004 -0.348 0.938 0.786 -1.709 -0.637 The second experiment is my experiment, i change the point to line residual r wrt ΔR, lidar_pure_odom_factor.hpp#L274, to
jaco_ex.rightCols<3>() = - eta * Utility::skewSymmetric(ba - bb) * Rp.transpose() * Ri * (Rext * Utility::skewSymmetric(point_))
, namely my derivation jacobian, the output whenframe_cnt_== 100
is:optimization with pure odometry [LidarPureOdomEdgeFactor] check begins analytical: 0.081 0.914 -0.211 -0.348 1.360 -0.203 3.399 0.000 -0.914 0.211 0.348 -1.409 0.286 -3.432 0.000 -0.869 0.314 0.383 -1.409 0.286 -3.432 0.000 perturbation: 0.081 0.914 -0.211 -0.348 1.360 -0.203 3.399 -0.914 0.211 0.348 -1.409 0.286 -3.432 -0.869 0.314 0.383 -1.409 0.286 -3.432
It seems that we can not check the derived jacobian is correct or wrong by check()
function. This is my derivation process.
Thanks for your help and time.
Have you checked that the points (data for calculating the residuals) are the same in two cases?
No, the two case's source points are different. The analytical
jacobians are the same with perturbation
in both case, no matter what the jacobians are.
The Jacobians from analytical and perturbation are the same, meaning that the derived Jacobians are approximate. You can try to change the formulas of Jacobians and check later. They will be different.
Because our jacobian in the point to line residual wrt ΔR exists a small difference, The difference is whether plus Utility::skewSymmetric(t_ext)
, i guess the influnence is small. But our jacobian in the point to plane residual wrt R_p
exists a big difference, The difference is whether Rp.trans() in the skewSymmetric.
, So i did another two experiments for surf points jacobian.
Test conditions are:
estimate_extrinsic: 1
in config fileCHECK_JACOBIAN = 1;
estimator.cpp#L689if (CHECK_JACOBIAN && frame_cnt_== 100)
estimator.cpp#L702raw code 3 experiments: In the 3 experiments, the analytical
wrt R_p
is different from perturbation
wrt R_p
.
########### raw code: surf point ########### size of finding laser_cloud: 17964 21258 lidarTracker: 6.489906ms [NON_LINEAR] build map: 9.367192ms optimization with online calibration [LidarPureOdomPlaneNormFactor] check begins raw point is(1.817, -10.328, -2.810) analytical: 0.040 0.450 -0.873 -0.188 -0.337 -0.351 0.823 0.000 -0.450 0.873 0.188 0.397 0.330 -0.956 0.000 -0.258 0.941 0.218 0.397 0.330 -0.956 0.000 perturbation: 0.040 0.450 -0.873 -0.188 -0.393 -0.301 0.818 -0.450 0.873 0.188 0.397 0.330 -0.956 -0.258 0.941 0.218 0.397 0.330 -0.956 Start Calibration ! 0 D factor: 0.000: 1.000 0.000 0.000 0.000 0.000 0.000 1 D factor: 139.652: -0.098 0.085 -0.979 -0.141 0.070 0.023 2 D factor: 121.216: -0.117 0.131 -0.972 -0.131 0.084 0.028 0: calib eig is 0.000000 1: calib eig is 28.953894 100.000 100.000 100.000 0.000 48.555 evaluate residual: 4.412340ms Ceres Solver Report: Iterations: 5, Initial cost: 2.654929e+02, Final cost: 2.652173e+02, Termination: NO_CONVERGENCE ceres solver costs: 14.114399ms whole marginalization costs: 9.780671ms laser_1, eligible calib size: 0 [ WARN] [1610677361.653727769, 1583835688.268045121]: cir_bufcnt = 4, Qs_.size()=5 frame: 100, odom process time: 52.694ms
########### raw code: surf point ###########
size of finding laser_cloud: 17964 21258
lidarTracker: 9.893504ms
[NON_LINEAR]
build map: 14.813927ms
optimization with online calibration
[LidarPureOdomPlaneNormFactor] check begins
raw point is(-27.480, -37.218, -12.396)
analytical:
-0.000
-0.160 -0.255 0.954 -43.329 19.963 -1.941 0.000
0.160 0.255 -0.954 38.459 -28.468 0.217 0.000
0.183 0.240 -0.954 38.459 -28.468 0.217 0.000
perturbation:
-0.000
-0.160 -0.255 0.954 -38.551 28.159 -0.800
0.160 0.255 -0.954 38.459 -28.468 0.217
0.183 0.240 -0.954 38.459 -28.468 0.217
Start Calibration !
0 D factor: 0.000: 1.000 0.000 0.000 0.000 0.000 0.000
1 D factor: 165.909: -0.106 0.136 -0.984 -0.043 0.024 0.016
2 D factor: 122.130: -0.116 0.128 -0.972 -0.131 0.085 0.028
0: calib eig is 0.000000
1: calib eig is 28.979010
100.000 100.000 100.000 0.000 48.716
evaluate residual: 4.773207ms
Ceres Solver Report: Iterations: 5, Initial cost: 2.624571e+02, Final cost: 2.622181e+02, Termination: NO_CONVERGENCE
ceres solver costs: 14.490101ms
whole marginalization costs: 8.687258ms
laser_1, eligible calib size: 0
[ WARN] [1610678978.611517602, 1583835688.280602612]: cir_buf_cnt_ = 4, Qs_.size()=5
frame: 100, odom process time: 66.411ms
########### raw code: surf point ###########
size of finding laser_cloud: 17964 21258
lidarTracker: 8.304935ms
[NON_LINEAR]
build map: 11.480876ms
optimization with online calibration
[LidarPureOdomPlaneNormFactor] check begins
raw point is(-27.480, -37.218, -12.396)
analytical:
-0.000
-0.159 -0.255 0.954 -43.323 19.984 -1.882 0.000
0.159 0.255 -0.954 38.458 -28.468 0.217 0.000
0.183 0.240 -0.953 38.458 -28.468 0.217 0.000
perturbation:
-0.000
-0.159 -0.255 0.954 -38.545 28.165 -0.881
0.159 0.255 -0.954 38.458 -28.468 0.217
0.183 0.240 -0.953 38.458 -28.468 0.217
Start Calibration !
0 D factor: 0.000: 1.000 0.000 0.000 0.000 0.000 0.000
1 D factor: 157.609: -0.116 0.159 -0.979 -0.047 0.020 0.017
2 D factor: 119.486: 0.125 -0.126 0.971 0.134 -0.086 -0.028
0: calib eig is 0.000000
1: calib eig is 29.628106
100.000 100.000 100.000 0.000 48.716
evaluate residual: 6.931444ms
Ceres Solver Report: Iterations: 5, Initial cost: 2.657323e+02, Final cost: 2.654116e+02, Termination: NO_CONVERGENCE
ceres solver costs: 12.067319ms
whole marginalization costs: 8.665480ms
laser_1, eligible calib size: 0
[ WARN] [1610679281.500481854, 1583835688.271937530]: cir_buf_cnt_ = 4, Qs_.size()=5
frame: 100, odom process time: 57.094ms
change point to plane jacobian with mine, 3 experiments: In the 3 experiments, the analytical
wrt R_p
is the same with perturbation
wrt R_p
.
########### our surf point ########### size of finding laser_cloud: 17964 21258 lidarTracker: 7.970606ms [NON_LINEAR] build map: 10.618513ms optimization with online calibration [LidarPureOdomPlaneNormFactor] check begins raw point is(1.817, -10.328, -2.810) analytical: 0.044 0.457 -0.869 -0.191 -0.406 -0.334 0.927 0.000 -0.457 0.869 0.191 0.402 0.361 -1.066 0.000 -0.268 0.939 0.216 0.402 0.361 -1.066 0.000 perturbation: 0.044 0.457 -0.869 -0.191 -0.406 -0.334 0.927 -0.457 0.869 0.191 0.402 0.361 -1.066 -0.268 0.939 0.216 0.402 0.361 -1.066 Start Calibration ! 0 D factor: 0.000: 1.000 0.000 0.000 0.000 0.000 0.000 1 D factor: 127.805: 0.111 -0.101 0.975 0.146 -0.074 -0.027 2 D factor: 117.959: -0.120 0.139 -0.969 -0.135 0.088 0.029 0: calib eig is 0.000000 1: calib eig is 28.724523 100.000 100.000 100.000 0.000 48.632 evaluate residual: 4.500181ms Ceres Solver Report: Iterations: 5, Initial cost: 2.618356e+02, Final cost: 2.616036e+02, Termination: NO_CONVERGENCE ceres solver costs: 13.804082ms whole marginalization costs: 8.637802ms laser_1, eligible calib size: 0 [ WARN] [1610676678.010147387, 1583835688.265840037]: cir_bufcnt = 4, Qs_.size()=5 frame: 100, odom process time: 55.005ms
########### our surf point ###########
size of finding laser_cloud: 17964 21258
lidarTracker: 10.016887ms
[NON_LINEAR]
build map: 14.010215ms
optimization with online calibration
[LidarPureOdomPlaneNormFactor] check begins
raw point is(1.817, -10.328, -2.810)
analytical:
0.042
0.438 -0.882 -0.175 -0.598 -0.309 0.701 0.000
-0.438 0.882 0.175 0.604 0.335 -0.842 0.000
-0.248 0.948 0.199 0.604 0.335 -0.842 0.000
perturbation:
0.042
0.438 -0.882 -0.175 -0.598 -0.309 0.701
-0.438 0.882 0.175 0.604 0.335 -0.842
-0.248 0.948 0.199 0.604 0.335 -0.842
Start Calibration !
0 D factor: 0.000: 1.000 0.000 0.000 0.000 0.000 0.000
1 D factor: 131.249: -0.102 0.106 -0.975 -0.145 0.073 0.024
2 D factor: 114.680: 0.127 -0.126 0.970 0.135 -0.087 -0.029
0: calib eig is 0.000000
1: calib eig is 29.147198
100.000 100.000 100.000 0.000 48.632
evaluate residual: 6.314779ms
Ceres Solver Report: Iterations: 5, Initial cost: 2.632974e+02, Final cost: 2.630406e+02, Termination: NO_CONVERGENCE
ceres solver costs: 13.676148ms
whole marginalization costs: 8.688113ms
laser_1, eligible calib size: 0
[ WARN] [1610681053.395534104, 1583835688.283631865]: cir_buf_cnt_ = 4, Qs_.size()=5
frame: 100, odom process time: 67.648ms
########### our surf point ###########
size of finding laser_cloud: 17964 21258
lidarTracker: 9.815224ms
[NON_LINEAR]
build map: 14.035856ms
optimization with online calibration
[LidarPureOdomPlaneNormFactor] check begins
raw point is(1.817, -10.328, -2.810)
analytical:
0.048
0.449 -0.877 -0.171 -0.629 -0.344 0.807 0.000
-0.449 0.877 0.171 0.628 0.368 -0.946 0.000
-0.258 0.946 0.197 0.628 0.368 -0.946 0.000
perturbation:
0.048
0.449 -0.877 -0.171 -0.629 -0.344 0.807
-0.449 0.877 0.171 0.628 0.368 -0.946
-0.258 0.946 0.197 0.628 0.368 -0.946
Start Calibration !
0 D factor: 0.000: 1.000 0.000 0.000 0.000 0.000 0.000
1 D factor: 137.559: -0.112 0.107 -0.976 -0.135 0.068 0.023
2 D factor: 121.488: -0.122 0.131 -0.971 -0.133 0.084 0.027
0: calib eig is 0.000000
1: calib eig is 29.169096
100.000 100.000 100.000 0.000 48.770
evaluate residual: 4.457903ms
Ceres Solver Report: Iterations: 5, Initial cost: 2.660389e+02, Final cost: 2.658291e+02, Termination: NO_CONVERGENCE
ceres solver costs: 14.873410ms
whole marginalization costs: 8.657054ms
laser_1, eligible calib size: 0
[ WARN] [1610681208.987375236, 1583835688.280467081]: cir_buf_cnt_ = 4, Qs_.size()=5
frame: 100, odom process time: 65.797ms
Thanks for your experiments, I will check later.
Hi doctor jiao, Thanks for your hard work firsly! I'm curious about the jacobians in
lidar_pure_odom_factor.hpp
andlidar_online_calib_factor.hpp
, so i carefully calculate them, according to right pertubation ofSO(3)
and the jacobian's type is numerator layout. Jacobians inlidar_online_calib_factor.hpp
are all consistent with my result, but there are there mismatchs inlidar_pure_odom_factor.hpp
. I'm not sure whether there are still some errors in my derivation, although i carefully checked the result twice. Thanks for your time and help a lot !Jacobians of point to plane with point to line, the only difference is : In point-to-plane there is a
w.transpose()
in the front. In point-to-linew.transpose()
is replaced byeta * Utility::skewSymmetric(ba - bb)
in the code, according to link rules of derivate.r
wrtR_p
, line 69, whereR_p
is the primary laser's pose at pivot frame. My result isjaco_pivot.rightCols<3>() = w.transpose() * Utility::skewSymmetric(Rp.transpose() * (Ri * Rext * point_ + Ri * t_ext + t_i - t_pivot))
, In code it isjaco_pivot.rightCols<3>() = w.transpose() * (Rp.transpose() * Utility::skewSymmetric(Ri * Rext * point_ + Ri * t_ext + t_i - t_pivot));
The difference is whetherRp.trans()
in the skewSymmetric.We can see jacobians of point to line residual wrt
R_p
, line 249,Rp.trans()
is in the skewSymmetric.point to plane residual
r
wrtΔR
, line 95, whereΔR
is from primary laser to auxiliary laser extrinsic rotation. My result isjaco_ex.rightCols<3>() = -w.transpose() * Rp.transpose() * Ri * Utility::skewSymmetric(Rext * point_) * Rext;
In code it isjaco_ex.rightCols<3>() = -w.transpose() * Rp.transpose() * Ri * Utility::skewSymmetric(Rext * point_);
The difference is whether multiplyRext
, namellyΔR
.point to line residual
r
wrtΔR
, line 274. My result isjaco_ex.rightCols<3>() =- eta * Utility::skewSymmetric(ba - bb) * Rp.transpose() * Ri * (Rext * Utility::skewSymmetric(point_)
In code it isjaco_ex.rightCols<3>() =- eta * Utility::skewSymmetric(ba - bb) * Rp.transpose() * Ri * (Rext * Utility::skewSymmetric(point_) + Utility::skewSymmetric(t_ext));
The difference is whether plusUtility::skewSymmetric(t_ext)