Open goldbattle opened 2 years ago
Dear Patrick,
Thank you very much for the detailed description in the raised issue, which helped a lot! Second, we are sorry for the late response, we just recently saw the issue and I needed some time to get into the topic again.
In general, it would be ideal if both toolboxes, ov_eval
and our trajectory_evaluation
, would lead to the same ATE and NEES values.
I will quickly answer your questions:
Q1: “your paper and I believe it is because you are using the "global" orientation error state as compared to the outputted "local" error-state covariance.”
A1: The trajectory evaluation assumes a “local” orientation error state (https://github.com/aau-cns/cnspy_trajectory_evaluation#definitions-and-metrics) and a globally defined position error state. In our notation we assume: R_G_B_true = R_G_B_est * (I + skew(theta_Best_B))
; with the rotation notation: p_in_G = R_G_N * p_in_N
; meaning R_G_N
maps a vector from the reference frame N to G;
The small angle rotation error in OV is alsotheta_Best_B
(orientation from the estimated body to the true body), right?
Concluding, our toolbox assumes the same error representation as OV.
Q2: Additionally, it seems that the estimated trajectory is transformed as compared to the groundtruth. Ideally, this means that a covariance propagation should be performed since this is changing the underlying error state location. I think this will be an issue for the position and global orientation error state methods. The way to get around this is to just align the groundtruth to the estimate instead (this might not be that big of an effect at the end of the day). A2: Thank you very much for raising that issue, and indeed the covariance of the estimated trajectory needs to be transformed as well. Since both our toolboxes treat the position and orientation uncertainty separately, and as we assume local rotation errors, only the covariance of the global position error needs to be mapped. (Hint: In our next release we plan to support different error definitions and the uncertainty of the estimated trajectory will be accordingly transformed.) I would still suggest aligning the estimated trajectory with the true trajectory as this would support an overlaid plot of multiple estimates to directly compare different approaches in e.g., a 3D plot. Despite having that issue in the implementation, it should lead only to minor errors in the NEES computation, since the true trajectory in VINSEval starts at the identity with an z-offset of 1m and all estimators are initialized at identity. Meaning the posyaw alignment in the first frame, would only result in a translational shift and thus not affecting the estimated covariance. Here are the generated (VINSEval) and estimated trajectory (OpenVINS) (please note the different color assignments in the legend):
Since I was also curious why the NEES values calculated in our toolbox are - in comparison to other approaches - so high, I tried to compute NEES values using your ov_eval
toolbox on the EuRoC machine hall MH01 sequence to directly compare the NEES results.
I ran the freshly downloaded OpenVINS with catkin_ws/test_openvins$ roslaunch ov_msckf subscribe.launch config:=euroc_mav dobag:=true bag:=<my home>/workspace/datasets/machine_hall/MH_01_easy.bag dosave:=true dataset:=MH_01_easy dolivetraj:=true
And executed rosrun ov_eval error_dataset sim3 eval_results/truth/MH_01_easy.txt eval_results/algorithms/
after creating the corresponding folder tree:
eval_results
├── algorithms
│ └── open_vins
│ └── MH_01_easy
│ ├── MH01_ov_est.csv
│ ├── MH01_ov_est.txt
│ └── run1.txt
└── truth
├── MH_01_easy.txt
├── MH01_gt.csv
└── MH01_gt.txt
The NEES result using posyaw
aligment using the first frame:
And using se3
using the first frame:
I have converted the true and estimated txt-files of the trajectories into CSV-files (note that the JPL quaternions were not converted to Hamiltonian ones, thus the rotation is inverted) to process them in our trajectory evaluation toolbox and obtained for posyaw
single frame:
And from sim3
over the entire trajectory:
Both toolboxes indicated, despite differences in the implementation, a similar trend and resulted in the end in high average single run NEES values. Potentially, these values can be improved by manual tuning of the estimator, but I am lacking in experience using OpenVINS to achieve the best results.
As it would be best that both toolboxes are leading to the same results our next release will support the proper transformation of estimated trajectories. Comparing the NEES computation in OV: https://github.com/rpng/open_vins/blob/bf0ada9f4f6d671f472616ab00e5df3bd6d6ce83/ov_eval/src/calc/ResultTrajectory.cpp#L254-L265, our toolbox computes the rotation error as: https://github.com/aau-cns/cnspy_trajectory_evaluation/blob/13857709a3cd38ed24e8a8f1b2c9af7ae7a9a4d1/cnspy_trajectory_evaluation/AbsoluteTrajectoryError.py#L151 and converts it to a tangent space vector (theta in so(3)) in: https://github.com/aau-cns/cnspy_trajectory_evaluation/blob/13857709a3cd38ed24e8a8f1b2c9af7ae7a9a4d1/cnspy_trajectory_evaluation/TrajectoryNEES.py#L131 And computes the NEES according to: https://github.com/aau-cns/cnspy_trajectory_evaluation/blob/13857709a3cd38ed24e8a8f1b2c9af7ae7a9a4d1/cnspy_trajectory_evaluation/TrajectoryNEES.py#L156
The only difference is the negative sign in OV, which can be neglected in the NEES computations, since it will be squared, right? Are high NEES values in general a known issue of OpenVINS? The estimation accuracy is in general pretty astonishing, impressive, and was super robust on the machine hall sequence.
In future we will support different error representations (theta as tangent space element in so(3), theta from first order Taylor expansion of rotation matrices, and theta from a small quaternion approximation) and error definitions (local/global pose, global/local position + global/local orientation). Also the next release will allow the visualization of the N-sigma bounds on top of the estimation error (as shown above), support a full SE(3) covariance, a relative pose error evaluation, and much more. Those topics and improvements should be covered in a short paper and we would be honored to have a discussion with you.
Bests, Roland
Many thanks for the detailed response I will try to respond the best I can. I really appreciate the effort and for you time.
The trajectory evaluation assumes a “local” orientation error state
My apologies I think I had a misunderstanding of the variable names. Is the rotation q_wb_est
here the rotation which rotates a vector from the body frame B to the world / global frame W? If so then I agree that it is local error and I miss understood the notation there. We do have a negative sign due to our error definition, but that will be canceled out as you mentioned.
Thank you very much for raising that issue, and indeed the covariance of the estimated trajectory needs to be transformed as well.
My suggestion is to just do the alignment this way when evaluating NEES, but for visualization align the estimate to the groundtruth (this is what we do).
High NEES values of OpenVINS on MH01
In general we don't like to evaluate the NEES on realworld datasets since there are additional sources of error which can cause the estimator to become over confident. For example the trajectory alignment and the sensor noise properties directly play into this. I see that you show that you use the se3single
in one picture. This probably isn't the best idea since the initialize of estimators can be bad dataset to dataset and thus this will cause an artificial increase in NEES as compared to just se3
.
For the orientation NEES from ov_eval
it shouldn't have been 8 million. There was actually a bug which was that the orientation NEES calculation did not use the aligned trajectory orientation. This causes the much larger NEES values. This didn't solve the generally high NEES though (ori ~200 and pos ~100).
Are high NEES values in general a known issue of OpenVINS?
We have normally dismissed the idea of evaluating the NEES on realworld datasets after alignment. But in retrospect it is a valid practical investigation as downstream application should have an consistent covariance provided to them. I have dug a bit into what could cause this and I think there is one assumption that we have which is causing these high NEES values. Visual-inertial estimators have 4dof unobservable directions which correspond to the global yaw and position of the system. When we talk about estimator consistency, we want to ensure that information is not gained in these unobservable directions since they are unobservable.
Since the yaw and position are unobservable we can freely choose their values. This means we can be 100% certain about their estimates. In our original implementation we set the initial covariance for these values to be 1e-4 sigma / standard deviation. I found that if I picked a prior here that was more reasonable (5cm pos and 1deg ori), then the NEES for position is around 3-5 and orientation is around 100 after alignment in the realworld. Personally, I think this is a type of inflation to hide inconsistencies, but I can see that no information is gained in those directions in simulation, and it allows the true error to be captured so it might be ok?
This gets to the reason why we normally only talk about NEES in simulation. This allow us to initialize the state from the groundtruth (vel and bias included) with a very small prior covariance. The choice of the prior has one of the larger impacts on the average NEES of the system. This is actually a way to find inconsistencies / bugs in Jacobians through simulation (if you have a NEES != 3 your implementation is wrong). My question is how did you initialize the systems in your vinseval paper? The initialization of the mean / prior can bias the results by a large amount. For example using a prior of 1m uncertainty will hide all inconsistency of an estimator! One can argue that the longer the dataset the inconsistencies should become more apparent (i.e. a 30 minute dataset will really test your estimator consistency), but most open datasets are <2min.
Here is an an evaluation using error_singlerun
on the V1_01 EurocMav dataset after making the changes discussed below. I still need to investigate why the orientation roll and pitch are overconfident. Maybe if I initialize from the groundtruth, this could provide some insight or reduce the orientation error?
======================================
Absolute Trajectory Error
======================================
rmse_ori = 0.565 | rmse_pos = 0.055
mean_ori = 0.508 | mean_pos = 0.050
min_ori = 0.055 | min_pos = 0.006
max_ori = 1.298 | max_pos = 0.126
std_ori = 0.248 | std_pos = 0.024
======================================
Relative Pose Error
======================================
seg 8 - median_ori = 0.560 | median_pos = 0.062 (2383 samples)
seg 16 - median_ori = 0.423 | median_pos = 0.062 (2078 samples)
seg 24 - median_ori = 0.546 | median_pos = 0.071 (1811 samples)
seg 32 - median_ori = 0.525 | median_pos = 0.102 (1416 samples)
seg 40 - median_ori = 0.431 | median_pos = 0.110 (1091 samples)
======================================
Normalized Estimation Error Squared
======================================
mean_ori = 133.258 | mean_pos = 0.913
min_ori = 0.098 | min_pos = 0.003
max_ori = 665.875 | max_pos = 4.404
std_ori = 115.505 | std_pos = 0.803
======================================
If you wish to discuss more directly, feel free to reach out to me through email (see my CV on my website). Thanks again for the project.
Hello Patrick,
Thank you again for your detailed answers and the discussion therein. I will try to answer quickly and as good as I can:
_Q1: Is the rotation q_wb_est here the rotation which rotates a vector from the body frame B to the world / global frame W?_ A1: Yes, that is how the variables in our implementation should be interpreted.
Q2: My suggestion is to just do the alignment this way when evaluating NEES, but for visualization align the estimate to the groundtruth (this is what we do). A2: This is indeed a reasonable way to go. I still prefer to transform the covariance of an estimated trajectory object inplace. This would allow for sequential operations on a “TrajectoryEstimated” object (think of an instruction pipeline on an object).
Q3: In general we don't like to evaluate the NEES on realworld datasets since there are additional sources of error which can cause the estimator to become over confident. For example the trajectory alignment and the sensor noise properties directly play into this. I see that you show that you use the se3single in one picture. This probably isn't the best idea since the initialization of estimators can be bad dataset to dataset and thus this will cause an artificial increase in NEES as compared to just se3. A3: That is a good point and bad ground truth information for sure leads directly to artificially higher NEES values. VINSEval is based on a set of synthetically generated trajectories. I have chosen the Machine Hall MH_01 sequence for convenience, as it was already supported by OpenVINS.
_Q4: For the orientation NEES from ov_eval it shouldn't have been 8 million. There was actually a bug which was that the orientation NEES calculation did not use the aligned trajectory orientation._ A4: Great that you found that, I have unfortunately overlooked it as well.
Q5: My question is how did you initialize the systems in your vinseval paper? The initialization of the mean / prior can bias the results by a large amount. For example using a prior of 1m uncertainty will hide all inconsistency of an estimator! One can argue that the longer the dataset the inconsistencies should become more apparent (i.e. a 30 minute dataset will really test your estimator consistency), but most open datasets are <2min. A5: The script that runs the estimators is https://github.com/aau-cns/vins_eval/blob/1fca74087cecd28af2d4167f1c8face1ad11624f/script/estimators_run.sh#L242 with https://github.com/aau-cns/vins_eval/blob/1fca74087cecd28af2d4167f1c8face1ad11624f/src/vinseval/vinseval_bringup/launch/vinseval_ov.launch#L26 and launches this OpenVINS version: https://github.com/rpng/open_vins/tree/e516f7c564c2159b7edfb42a8230b732bf6aebc2. The true (used for generating the data) IMU noise densities characteristics are set within the OV launch file, while the initial uncertainty of the state is set to the default values of the implementation. The initial position and orientation state of OV is set to the identity which differs from the ground truth only for a offset in position in the z direction. The duration of the trajectory is just +100 seconds (see https://github.com/aau-cns/vins_eval/tree/main/trajectories). Since a multi-dimensional parameter sweep is performed, the evaluation time increases drastically with duration of the trajectories and we found this duration to be a good compromise to assess the impact of the individual parameters on the filter credibility. To further improve the NEES/consistency evaluation, one needs to perform a set of Monte-Carlo-Simulation (on the same trajectory with random initial conditions as samples drawn from the initial uncertainty) to obtain the ANEES over the estimated trajectory.
_Q6: Here is an evaluation using error_singlerun on the V101 EurocMav dataset after making the changes discussed below. I still need to investigate why the orientation roll and pitch are overconfident. Maybe if I initialize from the groundtruth, this could provide some insight or reduce the orientation error? A6: Besides the orientation error, I typically look at the estimated biases (error plot and 3-sigma bounds of the gyro and accelerometer biases), to see how they behave, as e.g. the uncertainty of the gyroscope bias has an impact on the uncertainty evolution of the orientation (https://docs.openvins.com/propagation.html).
Q7: If you wish to discuss more directly, feel free to reach out to me through email (see my CV on my website). Thanks again for the project. A7: Thank you! I would like to come back to that offer once the trajectory_evaluation toolbox come towards its second version :)
Bests, Roland
I was taking a look at the weird OpenVINS NEES results, in your paper and I believe it is because you are using the "global" orientation error state as compared to the outputed "local" error-state covariance. See the ATE error and the NEES error computation in the two files below which compute the global error (to my understanding): https://github.com/aau-cns/cnspy_trajectory_evaluation/blob/main/cnspy_trajectory_evaluation/AbsoluteTrajectoryError.py#L152 https://github.com/aau-cns/cnspy_trajectory_evaluation/blob/main/cnspy_trajectory_evaluation/TrajectoryNEES.py#L156
Additionally, it seems that the estimated trajectory is transformed as compared to the groundtruth. Ideally, this means that a covariance propagation should be performed since this is changing the underlying error state location. I think this will be an issue for the position and global orientation error state methods. The way to get around this is to just align the groundtruth to the estimate instead (this might not be that big of an effect at the end of the day). https://github.com/aau-cns/cnspy_trajectory_evaluation/blob/main/cnspy_trajectory_evaluation/AlignedTrajectories.py#L42
OpenVINS outputs the covariance in the local error state for the q_GtoI JPL quaternion orientation: https://github.com/rpng/open_vins/blob/master/ov_msckf/src/ros/ROS1Visualizer.cpp#L524-L534 or in SO(3) terms it is:
(I-skew(theta)) * R_GtoI_hat = R_GtoI_true
or in your notation:(I-skew(theta)) * R_B_G_est = R_B_G_true
As an example, one can inspect the codebase to see how we performed evaluation for NEES: https://github.com/rpng/open_vins/blob/master/ov_eval/src/calc/ResultTrajectory.cpp#L254-L265
Hope this helps.