0
$\begingroup$

Rosanswers logo

Hi all, I am using the pcl_ros package in Groovy in order to transform a point cloud in the /map frame (/map -> /odom is given by a localizer node, while /odom -> /rgb_optical_frame is given by a set of transform publishers):

pcl_ros::transformPointCloud(fixedFrame, *cloud, *tcloud, tf_);

However, an exception is raised that says I do not have the transormation from /rgb_optical_frame to /map. If I open rqt and display the transformation tree, this is all connected as expected.

Could it be some issues about timings? How to check them, how to solve?

EDIT: here I add some additional information from the comments I have two machines, on the first machine (I call it sensor-laptop) the following topics are computed:

  • tf (/map -> /odom, /odom -> /X1_rgb_optical_frame)
  • point clouds from depth and rgb images

on the second machine (visualization-laptop) I compute the following topics:

  • point clouds (again) from depth and rgb images sent over the network from sensor-laptop and I am trying to visualize these point clouds using the transformation computed on the other laptop

the two laptops are time-synchronized using chrony, however, the transformPointCloud function says it does not have the transformation:

[ERROR] [1408639544.612446512]: Unable to lookup transform, cache is empty, when looking up transform from frame [/X1_rgb_optical_frame] to frame [/map]

EDIT2: the output of tf_echo and tf_monitor on the visualizer-laptop these outputs have been obtained on visualizer-laptop by setting ROS_MASTER_URI to the address of sensor-laptop

$ rosrun tf tf_echo /map /X1_rgb_optical_frame
Failure at 1408704324.631461344
Exception thrown:Could not find a connection between '/map' and '/X1_rgb_optical_frame' because they are not part of the same tree.Tf has two or more unconnected trees.
The current list of frames is:
Frame /X1_depth_optical_frame exists with parent /X1_depth_frame.
Frame /X1_depth_frame exists with parent /X1_link.
Frame /X2_depth_frame exists with parent /X2_link.
Frame /X2_link exists with parent /base_link.
Frame /X2_depth_optical_frame exists with parent /X2_depth_frame.
Frame /X1_link exists with parent /base_link.
Frame /base_link exists with parent /base_projected.
Frame /X1_rgb_frame exists with parent /X1_link.
Frame /X2_rgb_frame exists with parent /X2_link.
Frame /X2_rgb_optical_frame exists with parent /X2_rgb_frame.
Frame /base_projected exists with parent NO_PARENT.
Frame /imu exists with parent /base_link.
Frame /X1_rgb_optical_frame exists with parent /X1_rgb_frame.
Frame /odom exists with parent /map.
Frame /map exists with parent NO_PARENT.

At time 1408704324.660
- Translation: [0.110, 0.045, 0.540]
- Rotation: in Quaternion [0.496, 0.504, 0.503, 0.497]
            in RPY [1.571, 0.002, 1.585]
At time 1408704324.660
- Translation: [0.110, 0.045, 0.540]
- Rotation: in Quaternion [0.496, 0.504, 0.503, 0.497]
            in RPY [1.571, 0.002, 1.585]
At time 1408704326.660
- Translation: [0.110, 0.045, 0.540]
- Rotation: in Quaternion [0.496, 0.504, 0.503, 0.497]
            in RPY [1.571, 0.002, 1.585]
At time 1408704326.660
- Translation: [0.110, 0.045, 0.540]
- Rotation: in Quaternion [0.496, 0.504, 0.503, 0.497]
            in RPY [1.571, 0.002, 1.585]
At time 1408704328.663
- Translation: [0.110, 0.045, 0.540]
- Rotation: in Quaternion [0.496, 0.504, 0.503, 0.497]
            in RPY [1.571, 0.002, 1.585]

$ rosrun tf tf_monitor
RESULTS: for all Frames

Frames:
Frame: /X1_depth_frame published by /X1/X1_base_link Average Delay: -0.0932871 Max Delay: 0
Frame: /X1_depth_optical_frame published by /X1/X1_base_link2 Average Delay: -0.0932006 Max Delay: 0
Frame: /X1_link published by /link_broadcaster_200_1 Average Delay: -0.0900222 Max Delay: 0
Frame: /X1_rgb_frame published by /X1/X1_base_link1 Average Delay: -0.0928696 Max Delay: 0
Frame: /X1_rgb_optical_frame published by /X1/X1_base_link3 Average Delay: -0.0931895 Max Delay: 0
Frame: /X2_depth_frame published by /X2/X2_base_link Average Delay: -0.0932177 Max Delay: 0
Frame: /X2_depth_optical_frame published by /X2/X2_base_link2 Average Delay: -0.093197 Max Delay: 0
Frame: /X2_link published by /link_broadcaster_200_2 Average Delay: -0.0927084 Max Delay: 0
Frame: /X2_rgb_frame published by /X2/X2_base_link1 Average Delay: -0.0931225 Max Delay: 0
Frame: /X2_rgb_optical_frame published by /X2/X2_base_link3 Average Delay: -0.0936689 Max Delay: 0
Frame: /base_link published by /link_broadcaster_210 Average Delay: -0.0926389 Max Delay: 0
Frame: /base_projected published by /matildaRed Average Delay: 0.00379103 Max Delay: 0.00379103
Frame: /imu published by /link_broadcaster_330 Average Delay: -0.0924762 Max Delay: 0
Frame: /odom published by /mapper Average Delay: 0.0105839 Max Delay: 0.0109235

All Broadcasters:
Node: /X1/X1_base_link 10.4721 Hz, Average Delay: -0.0932871 Max Delay: 0
Node: /X1/X1_base_link1 10.4659 Hz, Average Delay: -0.0928696 Max Delay: 0
Node: /X1/X1_base_link2 10.4712 Hz, Average Delay: -0.0932006 Max Delay: 0
Node: /X1/X1_base_link3 10.4711 Hz, Average Delay: -0.0931895 Max Delay: 0
Node: /X2/X2_base_link 10.471 Hz, Average Delay: -0.0932177 Max Delay: 0
Node: /X2/X2_base_link1 10.466 Hz, Average Delay: -0.0931225 Max Delay: 0
Node: /X2/X2_base_link2 10.4709 Hz, Average Delay: -0.093197 Max Delay: 0
Node: /X2/X2_base_link3 10.4711 Hz, Average Delay: -0.0936689 Max Delay: 0
Node: /link_broadcaster_200_1 10.4553 Hz, Average Delay: -0.0900222 Max Delay: 0
Node: /link_broadcaster_200_2 10.466 Hz, Average Delay: -0.0927084 Max Delay: 0
Node: /link_broadcaster_210 10.4662 Hz, Average Delay: -0.0926389 Max Delay: 0
Node: /link_broadcaster_330 10.4663 Hz, Average Delay: -0.0924762 Max Delay: 0
Node: /mapper 2.00137 Hz, Average Delay: 0.0105839 Max Delay: 0.0109235
Node: /matildaRed 1e+08 Hz, Average Delay: 0.00379103 Max Delay: 0.00379103

EDIT3: Just to add something to the question now I put these lines of codes:

if (!tf_.waitForTransform(fixedFrame, cloud->header.frame_id, ros::Time(0), ros::Duration(3.0))) {
    // whatever...
}   
else {
    cout << "Cannot transform " << fixedFrame << " to " << cloud->header.frame_id << endl;
    cout << "These are all the frames: " << tf_.allFramesAsString() << endl;
}   

that output this:

Cannot transform /map to /X2_rgb_optical_frame
These are all the frames: Frame /X2_depth_optical_frame exists with parent /X2_depth_frame.
Frame /X2_depth_frame exists with parent /X2_link.
Frame /X1_depth_optical_frame exists with parent /X1_depth_frame.
Frame /X1_depth_frame exists with parent /X1_link.
Frame /base_link exists with parent /base_projected.
Frame /base_projected exists with parent /odom.
Frame /imu exists with parent /base_link.
Frame /X2_link exists with parent /base_link.
Frame /X1_rgb_optical_frame exists with parent /X1_rgb_frame.
Frame /X1_rgb_frame exists with parent /X1_link.
Frame /X2_rgb_frame exists with parent /X2_link.
Frame /X2_rgb_optical_frame exists with parent /X2_rgb_frame.
Frame /X1_link exists with parent /base_link.
Frame /odom exists with parent /map.
Frame /map exists with parent NO_PARENT.

Originally posted by madmage on ROS Answers with karma: 293 on 2014-08-21

Post score: 0


Original comments

Comment by dornhege on 2014-08-21:
Yes, it most probably is. The actual exception should tell you what the problem is.

Comment by lucaluca on 2014-08-21:
I have another hypothesis: it could be that you have to somehow tell ROS that the transformation from /rgb_optical_frame to /map is the transformation /rgb_optical_frame->/odom->/map

Comment by paulbovbel on 2014-08-21:
@lucaluca, the tf library takes care of that

Comment by lucaluca on 2014-08-21:
Yeah you're right, I got confused, but if the tree is connected there's no need to tell ROS anything. Sorry :)

Comment by madmage on 2014-08-21:
dornhege, the exception says this: [ERROR] [1408632199.169211408]: Unable to lookup transform, cache is empty, when looking up transform from frame [/X2_rgb_optical_frame] to frame [/map]

so, it does not mention anything about timing issues

Comment by dornhege on 2014-08-21:
I think you're missing the actual content here. Can you verify that the time stamp of the point cloud is in the range of the TF times in the listener. Is everything running on a single machine?

Comment by madmage on 2014-08-21:
dornhege, actually this is run on two machines: one with the sensors and the other with the visualizer in the current configuration: clouds and localization (tf) are computed on the sensor-laptop, then clouds are again computed on visualizer-laptop and I take the tf computed on the sensor-laptop

Comment by madmage on 2014-08-21:
I cannot send clouds over the network (too large), how can I sync the clouds computed on the visualizer-laptop with the tfs computed on the sensor-laptop?

Comment by dornhege on 2014-08-21:
What I am aiming at is: If the time stamps are from two machine and those are not synched, you'll get in trouble. You said clouds are computed on sensor-laptop and visualizer-lap again? I guess based on data from sensor-lap.

Comment by dornhege on 2014-08-21:
In that case those clouds should get time stamps from the incoming data. Basically if ros::Time::now() is called anywhere on the vis-lap something is wrong.

Comment by paulbovbel on 2014-08-21:
@madmage, can you update the question with the full exception output please

Comment by madmage on 2014-08-21:
just to be sure, I synchronized the two laptops using chrony, now they have the same time

however, if you confirm that the clouds should get the time stamps of the input images, they should have been sync'ed also before

Comment by dornhege on 2014-08-22:
Does "Cache is empty" happen once and then it works or all the time? The former is normal.

Comment by madmage on 2014-08-22:
all the time, however once in a while (i.e., once every five minutes or so) one of the clouds got transformed (???)

Comment by dornhege on 2014-08-22:
Something seems broken. Can you check tf_echo and tf_monitor on that same machine.

Comment by madmage on 2014-08-22:
I put them in the initial question as EDIT2

Comment by dornhege on 2014-08-22:
Are you by any chance creating a new TFListener on the fly each time instead of keeping a single one during the program lifetime?

Comment by dornhege on 2014-08-22:
And matildaRed with 100MHz is only a display bug, right?

Comment by madmage on 2014-08-22:
dornhege, only one tf listener, created at the start of the node and then used multiple times yes, I think I took the tf_monitor too early (maybe it is a division by 0 or something), now is

Node: /matildaRed 1.3167 Hz, Average Delay: 0.00965679 Max Delay: 0.0116892

Comment by madmage on 2014-08-22:
Ok, after the synchronization of the two laptops, I had a typo (a "not" where it shouldn't be) in the code: now it is working. I am still not sure why I have to synchronize the two laptops if all the timestamps are related to the origin of the data, that is the RGB/Depth image pair.

Comment by paulbovbel on 2014-08-22:
The errors were probably a combination of you using ros::Time(0) instead of the message timestamp, and the lack of synchronization. If you have deeper questions about TF, try asking another question.

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

You need call waitForTransform(cloud->header.frame_id, fixedFrame, cloud->header.stamp, ros::Duration()) before trying to transform the point cloud.

If waitForTransform returns true, that means the transform is available and you can call transformPointCloud.


Between the 'cache empty' exception, and your waitForTransform returning false, that implies deeper issues in either your time synchronization, network communication, or a typo like spelling the transform names wrong :)


Originally posted by paulbovbel with karma: 4518 on 2014-08-21

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by madmage on 2014-08-21:
it is what I did, I had to remove it in order to read the exception, but actually waitForTransform returns false.. but I have the transform, if I look at rqt tf tree viewer!

Comment by paulbovbel on 2014-08-21:
TF considers time as well, so potentially the times are not lining up. The fact that you're running on separate machines is very important, since your computer clocks may not be in sync.

Comment by paulbovbel on 2014-08-21:
You should be running chrony on your machines to sync time.

Comment by madmage on 2014-08-21:
thanks, I sync'ed the two laptops using chrony, however, dornhege says that the two clouds should get the timestamps of the input images, so they should be lined up

Comment by paulbovbel on 2014-08-21:
Two clouds? Afaik we're talking about one cloud, coming from your sensor. That cloud has a timestamp, determined by the sensor-computer's clock. Once that cloud is transmitted to your viz-computer, if the two computers clocks aren't in sync, the timestamp will be inconsistent and cause tf errors.

Comment by paulbovbel on 2014-08-21:
TF is distributed, for example, a tfbroadcaster on sensor-computer records the transform for frame a-to-b for duration x-to-y, in context of its own clock. It transmits that data to nodes with tflisteners.

Comment by madmage on 2014-08-22:
I said "the two clouds" but I was thinking on the two images (one depth image and one RGB image) that are used to produce one cloud. dornhege says that the timestamp of the resulting cloud should be that of the input images, is that wrong?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.