# Using tf to transform a point

Hello,

I am trying to transform a point from one frame (/kinect_frame) to another (/base_link).

This is the pdf I get from 'rosrun tf view_frames' :

but still when I try to transform my point using a tf::TransformListener and tf::TransformListener::transformPoint like this :

I get the following error :

[ERROR] [1339062545.681343977]: Unable to lookup transform, cache is empty, when looking up transform from frame [/kinect_frame] to frame [/base_link]


But there is a link visible between kinect_frame and base_link, what am I doing wrong ?

edit retag close merge delete

Sort by » oldest newest most voted

You need to make sure that TF has a valid and complete TF tree to transform from the kinect frame at the time stamp of the point you are transforming. That's the case when TF received a transform with a stamp greater or equal than the time stamp of the point you are trying to transform. The reason is that TF tries to interpolate positions and orientations, but does not extrapolate. Of course, for interpolation, TF needs at least two transforms, one after and one before the time stamp you are trying to transform.

The static_transform_publisher future-dates transforms to make sure that all data that uses ros::Time::now() can actually be transformed and to avoid unnecessary delays but it cannot be assumed that frames published by other nodes are future dated as well. For instance, when you have a moving frame (e.g. a PTU), you can only use the current position of the frame (i.e. ros::Time::now()) to publish a frame, everything in the future would be extrapolation again. For that reason, TF provides the method waitForTransform that allows to block until a timeout expires or the transformation into a frame becomes possible. Alternatively, tf::MessageFilter can be used to postpone a subscriber callback on a stamped message until the transformation into a specific frame is possible.

more

Thanks :) One last question, when I have the StampedTransform from lookupTransform, how do I use that to transform a point from frame A to frame B ? I couldn't find it in the tutorials and I don't think it is a big enough question to start a new post :)

( 2012-06-08 02:14:37 -0500 )edit

Use transformPoint instead of lookupTransform. It's a member function of tf::TransformListener (quick link: http://ros.org/doc/fuerte/api/tf/html/c++/classtf_1_1TransformListener.html).

( 2012-06-08 02:16:56 -0500 )edit

Silly me, I thought I had to use lookupTransform after waitForTransform, but transformPoint will do :D thnx again

( 2012-06-08 03:23:37 -0500 )edit

I was trying out some few things and I found out the problem is resolved if I replace my dynamic tf publisher with a static one, like this :

<node pkg="tf" type="static_transform_publisher" name="head_to_kinect_normal_axis" args="-0.03 0.055 0.12 0 0 -0.4 head_frame kinect_normal_axis_frame 20" />


But I really need it to be dynamic ... so this is where my answer ends and a new question arises. The dynamic publishing is done through a tf::TransformBroadcaster. I don't initialize it and I use it like this :

mKinectTFBroadcaster.sendTransform(tf::StampedTransform(mKinectTF, ros::Time::now(), "head_frame", "kinect_normal_axis_frame"));


And as can be seen in the picture of my original question, this does indeed get published. I have no idea what seems to be the problem.

more

According to the picture above, you publish with 10Hz. Did you try adding calls to waitForTransform before calling transformPoint?

( 2012-06-07 04:44:57 -0500 )edit

The static tranform publishers publish at 10Hz, the node publishes at 50Hz, but after I change the static one to 50Hz it still works. So I don't believe it is the frequency. And as you can see by the picture, if I sent it only once, then the frequency would not be 10-50Hz.

( 2012-06-07 05:25:24 -0500 )edit

Is there perhaps something wrong with how I send the time? Thats the only thing I can think of ...

( 2012-06-07 05:26:04 -0500 )edit

Deleted my misleading comment. Of course you are publishing at 50Hz, not 500. Sorry. Did you try adding waitForTransform to your code? Using ros::Time::now() as time stamp should be fine.

( 2012-06-07 05:30:33 -0500 )edit

I think I know what it is: the static_transform_publisher future-dates the transforms it sends, your code doesn't. Instead of using ros::Time::now(), you can do something like ros::Time::now() + ros::Duration(0.1). I think using a tf::MessageFilter or waitForTransform is good practice though.

( 2012-06-07 05:42:32 -0500 )edit

Wow, that was it, so weird ... why does the static transform publisher do that? Could you post it as an answer so I can up it :)

( 2012-06-07 09:00:40 -0500 )edit

Just a guess: are you maybe instantiating a new tf::TransformListener right before you are calling transformPoint, i.e. in the same function you are calling transformPoint? This won't work because it takes some time until new tf messages are received and the TransformListener's cache is filled. Instead, you should instantiate the TransformListener at the beginning of your program.

The same can happen if you call transformPoint too early in your program, i.e. when there were no messages on /tf received so far. To avoid that, or if you are getting extrapolation errors, have a look at waitForTransform and this tutorial or tf::MessageFilter.

more

Thank you for your response. Actually, I'm creating an object which has the tf::TransformListener as a member. I don't initialise it or anything, I thought that was not needed (?).

( 2012-06-07 00:17:31 -0500 )edit

Actually, you can check the code here : http://code.google.com/p/roman-technologies/source/browse/trunk/image_processing/src/PersonTracker.cpp The transformPoint is done in getWorldPoint

( 2012-06-07 00:18:21 -0500 )edit

You are right. No initialization needed. It was just a guess because I've seen people instantiating new TransformListener objects whenever they need to transform anything.

( 2012-06-07 00:19:27 -0500 )edit