Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Why do we publish the inverted pose in the tf tree
KISS ICP takes an input point cloud in the lidar frame/robot frame and estimates the pose of the lidar/robot incrementally. This, in tf parlance, will read as (taking the robot frame as example):
As a reminder, a wheel odometry node will do something similar. Given the encoder readings, the wheel odometer will produce the transformation from an odometric frame "odom" to the base_link:
Ok, fantastic, but what happens if we now want to publish these two transformations to the tf tree? This is how the final tf tree would look like:
It turns out that the tf2 implementation, by design ( REP-105):
Which means that the tree you dreamed about is not possible. For two years at KISS-ICP, I needed help figuring out how to solve this issue, and then, we did not publish ANY lidar odometry output to the tf tree. You can't just spin a TF2 listener and look for transformations from the LiDAR odometry system with interpolation, time travel, and all the excellent tools TF2 provides us. In the past, I even tried to hack it around by publishing alias transformations, which was horrible and not working. This topic was already discussed at ros/geometry2#437
The solution: Inject an inverted transformation in the tf tree
Our beloved William realized that if you add not the transformation we compute but the inverse of that (base_link -> odom_lidar), then this is not violating at all the tf conventions:
This has many benefits:
No more nasty hacks in the visualization pipeline to make sure we can see the clouds (get the kiss map, convert back to lidar frame usingWIPkiss_icp.pose().inverse()
and put a fake header on this msg.tf2::lookUpTransform
Sincetf2_buffer->lookupTransform(target_frame, source_frame
, we can dotf2_buffer->lookupTransform("odom_lidar", "base_link)
, and this will give us the last LiDAR odometry pose. Ture, internally the tf2 buffer will need to invert the transformation that has coded inside, soinverse(tf2_buffer->lookupTransform("base_link", "odom_lidar")
, but this is transparent to the user and doesn't even need to knowThe only disadvantages I see are
PublishOdom(pose.inverse()
and then when querying with the tfreturn inverse(pose.inverse())
which might introduce some numerical errors/tf
and see inside the tf RAW, the transformation you are looking at is inverted, so you can't just plot it with plotjuggler. Let's say you will always need to post-process it and invert it; this information is barely present in theframe_id
andchild_frame_id
inside the tf message; it's clear, but it might be confusing.Changes
invert_odom_tf
: Introduce a new boolean flag,true
by default, to control in the feature whether we want or not to internally publish the inverted transformation through the tf tree. An example would be: the wheel odometry is not part of the tf tree, or we don't have any wheel odometry. Or tf now support multiple parents' IDs? It doesn't matter, but as the proposed solution is slightly hacky, it's fair to guard it with a configurable flag.rviz2
default "Fixed Frame" toodom_lidar
. A true dream come true! We don't even need to know what the frames are in the robot system; 100% of the frames are defined at launch time, and everything is now tightly coupled in the tf tree.odom_lidar
by defaultRelated discussions
Open questions
Ack
This idea was proposed by William the Great, aka @doisyg , so kudos to him for this kick-ass idea that has been hunting me for months!