-
Notifications
You must be signed in to change notification settings - Fork 332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deskewing...again #421
Deskewing...again #421
Conversation
Some more insights on this: We always thought it did not matter which timestamp of the scan duration we set the reference for deskewing; see #299. However, there is one thing we always missed: In our current implementation, it does mar at which timestamp we estimate the pose. If we set the deskewing reference timestamp to Why does it matter, and why do we want to change KISS to estimate the pose at the end of the scan? Because we use the same constant velocity estimate Let's do the same by estimating the pose at the end of scan In the case of non-linear motion (surprise, this is reality), this is a big deal. We observed that if we estimate the pose at the beginning (by setting Estimating the pose at the middle of the scan instead of at the end will yield better results. The constant velocity model is more accurate for deskewing. TL;DRWhen estimating the poses at the end of the scan duration, the constant velocity estimate we also use for deskewing is more accurate because it is closer in time to the actual motion during the current scan. |
Hey folks, I've been confused by these topics for a while now and still don't fully understand it 😅 So I wanted to take this chance to wrestle with these ideas with you a bit. Do you mind? 😉 @benemer I think I largely agree with what you wrote especially about the time difference between various scans under various assumptions. However, it seems that the code in this PR could be implemented a bit simpler if I understand it correctly by essentially picking Definition of motion compensationFirst, the setup. Let's say we get need to compensate motion between two scans taken at times We can denote these poses for every point as Motion compensation algorithmWithout loss of generality let's focus on motion compensating the first scan taken at times
It seems there is a couple of options of how to pick the reference frame and then how to compute the resulting per-point transformation. Reference point selectionBefore this PR, we chose the timestamp of the midpoint of the cloud as a reference: Reference transform computationWe can compute the reference transformation for a point at time Where the Sophus::SE3d::exp(stamp_fraction * t_0_T_t_1.log()), that essentially interpolates the transform In this PR we essentially assume We can see here that What do you guys think? This topic breaks my head for a long time and in my own experiments with my own code (similar but not the same as KISS-ICP) indicate that the best performance is achieved with That is why I was super stoked to see this PR of yours 😆 I'd like to figure this out once and for all. |
Hey Igor, First of all, thanks for the write-up, this is a perfect future reference if someone wants to understand what's happening! I am happy to hear that we are not the only ones struggling/dealing with de-skewing 😆 You are right, this PR does the same as setting diff --git a/cpp/kiss_icp/core/Preprocessing.cpp b/cpp/kiss_icp/core/Preprocessing.cpp
index aacf0f2..e9911cd 100644
--- a/cpp/kiss_icp/core/Preprocessing.cpp
+++ b/cpp/kiss_icp/core/Preprocessing.cpp
@@ -60,7 +60,6 @@ std::vector<Eigen::Vector3d> Preprocessor::Preprocess(const std::vector<Eigen::V
return frame;
} else {
const auto &omega = relative_motion.log();
- const Sophus::SE3d &inverse_motion = relative_motion.inverse();
std::vector<Eigen::Vector3d> deskewed_frame(frame.size());
tbb::parallel_for(
// Index Range
@@ -70,7 +69,7 @@ std::vector<Eigen::Vector3d> Preprocessor::Preprocess(const std::vector<Eigen::V
for (size_t idx = r.begin(); idx < r.end(); ++idx) {
const auto &point = frame.at(idx);
const auto &stamp = timestamps.at(idx);
- const auto pose = inverse_motion * Sophus::SE3d::exp(stamp * omega);
+ const auto pose = Sophus::SE3d::exp((stamp - 1.0) * omega);
deskewed_frame.at(idx) = pose * point;
};
});
I also like this more. We did split it to avoid confusion about the subtraction of Regarding your different results with For example, we also experienced better results on the KITTI Odometry benchmark we used back when using In general, I expect to get the best results when using |
Thanks for a quick reply @benemer 🙏 My comment was not a prompt to do force any changes upon you but more of a post to make sure I understand what you did and how it aligns with how I understand things. I'm happy that we agree that they are the same but you guys decide if you want to change the code from this point on, I do not pressure you in any direction. 😅
Mostly in a very stupid way. The falls seem less "fluffy" when I use midpoint than the end point. And, as I mentioned before, odometry that assumes constant velocity and predicts the point clouds forward with the same motion plainly diverges if the reference point is at the start of the scan 🤷 I don't fully understand why though. |
This is my insight on this: If your reference point is at the start of the scan, you estimate the pose Let's now compare with having the reference point at the end of the scan: We estimate the pose If the sensor moves nonlinearly, the second case provides a better approximation because we use a more recent estimate of its motion. In other words, we always need an estimate of our recent motion for de-skewing, so it is better to have an estimate of where the last scan ended ( |
This totally makes sense from a cursory look. Thanks! I'll need to sleep on this a bit to make sure I fully understand though 😅 |
Motivation
Since the beginning of time we decided to deskew the input scans at the middle of the scan duration (0.5), the motivation for this was given in #299, and it is an heritage of our initial development based on KITTI (everybody has his dark little secrets). This PR aim at removing the magic parameter 0.5, and deskew the scans in a more principled way.
This PR
Our final solution is to first deskew the scans at the beginning of the scan duration. We made this choice as there is no easy way to know if the a scan has been stamped at the beginning or the end of the scan collection, especially from a python perspective. We go for the beginning as this is the most common, and also the "right" way of timestamping. We then transform the resulting point cloud in the local frame of the scan after applying the constant velocity initial guess, basically moving the scan to the end of the predicted motion. This new deskewed frame is than passed to the successive steps of the pipeline.
Results
On all tested sequences there is no significant difference between deskeing at 0.5 and the current version, so this can be seen as a style change and a way of having things in the right reference frame. This might be more relevant for low frequency scanners than for typical LiDARS running at 10Hz.