ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

How to use transformPose in Python with Time(0) (most recent common time)?

asked 2021-03-30 01:06:20 -0500

fvd gravatar image

updated 2021-04-30 02:13:49 -0500

I want to use TF to transform a PoseStamped into a frame, perform some operations, and then transform it back to its original frame. The frame is not published to TF, so I set it as a TransformStamped in the TfListener:

m = geometry_msgs.msg.TransformStamped()
m.header.frame_id = surface_origin.header.frame_id
m.header.stamp = rospy.Time.now()-rospy.Duration(0.1)
m.child_frame_id = "tmp_frame__"
m.transform.translation.x = surface_origin.pose.position.x
m.transform.translation.y = surface_origin.pose.position.y
m.transform.translation.z = surface_origin.pose.position.z
m.transform.rotation.x = surface_origin.pose.orientation.x
m.transform.rotation.y = surface_origin.pose.orientation.y
m.transform.rotation.z = surface_origin.pose.orientation.z
m.transform.rotation.w = surface_origin.pose.orientation.w
tf_listener.setTransform(m)

in_pose_in_tmp_frame = tf_listener.transformPose("tmp_frame__", in_pose)
# [...] Do operations here
new_pose_in_original_frame = tf_listener.transformPose(in_pose.header.frame_id, in_pose)

Sadly, I get an ExtrapolationException on the second transformPose because the operations take too long:

tf2.ExtrapolationException: Lookup would require extrapolation at time 1617082915.398905516, but only time 1617082913.271360636 is in the buffe, when looking up transform from frame [tmp_frame__] to frame [surface_frame]

I tried adding rospy.Time(0), since "Time(0) gives you the latest common time". However, it looks the Python API doesn't offer that. Looking at the source code seems to confirm this.

I cannot find documentation for the TF2 Python API. The TF Python documentation is only generated up until Melodic(?), so the link in the wiki is broken. The TF2 source code is not human-readable unless you know how Python bindings are generated from C++.

I also tried using setTransform again before the second transformPose call, to update the transform, but then TF complains about extrapolation into the negative future, which is excessively strange:

tf2.ExtrapolationException: Lookup would require extrapolation -0.099048138s into the future.  Requested time 1617083034.013916254 but the latest data is at time 1617083033.914868116, when looking up transform from frame [tmp_frame__] to frame [surface_frame]

I know I should port to TF2, but I didn't have a pressing reason yet. I only need to use the TF tree here, no extrapolation or time lookup. Is there a "please don't bother me about time" setting in Python? Where is the TF2 Python documentation? How else could I solve this issue without much hassle?

edit:
The tf2 Python API is the C++ documentation, and the tf2_ros API is available here and here for Melodic. It looks like this is not as visible as it should be, but I'm not sure what to do about that.

The extrapolation error about a lookup at -0.099s into the future (although a negative time in the future should be in the past) might be because I did not set the seq of the header.

edit retag flag offensive close merge delete

1 Answer

Sort by » oldest newest most voted
2

answered 2021-03-30 18:20:47 -0500

tfoote gravatar image

Using a time of zero works in python. It's in the tf python listener tutorial

There's a known issue with the epydoc based documentation in noetic. However since this package is deprecated there's been no API changes since melodic and you can use that documentation. It's actually barely changed for years before that too. You can just use the melodic documentation that you already linked to.

However it's not necessarily going to solve your problem because it still needs a "common" time. Aka for all links in the chain it need information at a "common" time aka the same time. tf does interpolation between different samples in time.

The simple solution is that you need to make sure that you have data in your listener from before and after the requested timestamp for all links in the chain. If you use TIme(0) you only have to make sure that you have any timepoint that's consistent and it will return the latest.

And although you don't want to move to tf2 in tf2 we added static transform support which does exactly what you want letting you not worry about time for a link because a static transform is considered to be valid for all times. So if that's what you want, you may actually want to look at moving forward to tf2.

PS As a side note your question makes a lot more assertions than asking for help and a lot of those assertions are inaccurate which means that you end up digging further afield. You may find that being a little more thorough in each step of your investigation may help you get what you want faster.

edit flag offensive delete link more

Comments

1

Thanks for the quick response, it's appreciated. I apologize if my tone sounded off – I wanted to document how I arrived where I was and might have relived a bit too much of the debugging frustration while collecting my breadcrumbs. Take it as a user story. My wording at the end was misleading by the way: I don't mind porting to TF2 at all, but I couldn't find Python-specific documentation, so I couldn't tell if upgrading would solve the problem. I updated the post to clarify and added links.

I have some questions though:
1) In the tutorial, Time(0) is passed to lookupTransform, but not to transformPose. Can you confirm that transformPose does not accept Time in TF1, or if I am missing something?
2) I added an explanation about the extrapolation error. Do you consider this a bug worth reporting, or a user error ...(more)

fvd gravatar image fvd  ( 2021-03-30 20:08:06 -0500 )edit

1) If you set the time to zero inside the trasnsformPose it will call lookupTransform with the timestamp from the input Pose which will then propagate back out in the resultant pose. 2) There are several corner cases in the future/past and this may be a case where we didn't conditionally change the print string. I haven't been in this code base in a while but if I remember correctly there may be issues when you have two or three links and potentially different levels of time continuity where there's no complete solution at any given time but some earlier history for some frames and some newer history for other frames. And thus some frames are in the future and some in the past. And in that case neither future nor past is correct, and I don't know a word for it. 3) Adding transformPose ...(more)

tfoote gravatar image tfoote  ( 2021-03-30 22:46:42 -0500 )edit

I updated the tutorials with deprecation badges on each page and added a transformPose/transform example to the tf and tf2 listener tutorials, but I can't get either transformPose with Time(0), or the tf2 transform examples to work. If you can fix the problems in this PR I'll commit to updating the tutorial pages accordingly.

fvd gravatar image fvd  ( 2021-04-05 09:23:56 -0500 )edit

Could you add the syntax to use Time(0) with transformPose in Python?

fvd gravatar image fvd  ( 2021-04-30 03:41:18 -0500 )edit
1

Set the timestamp of the pose to Time(0)

my_pose_stamped.header.stamp = rospy.Time(0)... fill in the rest of the fields

And then

transformPose('target_frame', my_pose_stamped)

tfoote gravatar image tfoote  ( 2021-07-06 11:50:28 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2021-03-30 01:06:20 -0500

Seen: 1,085 times

Last updated: Apr 30 '21