ROS2 cannot find "base_link"

I am trying to transform points from the camera coordinate frame to the base coordinate frame in ROS 2. Here’s my code:

import tf2_ros
import rclpy
from tf2_geometry_msgs import do_transform_point
from geometry_msgs.msg import Point

rclpy.init()
node = rclpy.create_node('transform_debug')

tf_buffer = tf2_ros.Buffer(rclpy.duration.Duration(seconds=1.0))
tf2_ros.TransformListener(tf_buffer, node)

# Transform point coordinates to the target frame.
source_frame = 'camera_depth_frame'
target_frame = 'base_link'

# get the transformation from source_frame to target_frame.
transformation = tf_buffer.lookup_transform(target_frame,
            source_frame, rclpy.time.Time(), rclpy.duration.Duration(seconds=0.1))

point_source = Point(x=0.1, y=1.2, z=2.3)
point_target = do_transform_point(transformation, point_source)

When I run this with:

ros2 launch stretch_core stretch_driver.launch.py

The code results in the following error:

transformation = tf_buffer.lookup_transform(target_frame,source_frame, rclpy.time.Time(), rclpy.duration.Duration(seconds=3.0))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/ros/humble/lib/python3.10/site-packages/tf2_ros/buffer.py", line 136, in lookup_transform
    return self.lookup_transform_core(target_frame, source_frame, time)
tf2.LookupException: "base_link" passed to lookupTransform argument target_frame does not exist

Any idea why ROS 2 cannot seem to find “base_link”, when this worked perfectly fine in ROS 1?

@bshah would you please be able to take a look? I unfortunately still have not been able to resolve this issue…

Hey @arjung, I’m getting the same error. Although ros2 run tf2_ros tf2_echo camera_depth_frame base_link works just fine. I’ll do a bit more debugging and get back to you.

1 Like

Hi @bshah,

Thanks for looking into this! I was able to make a bit more progress: The following script seems to do the conversion between base_link and camera_depth_frame in ROS 2 (although I haven’t fully tested for correctness just yet):

import rclpy
from rclpy.node import Node
from geometry_msgs.msg import PointStamped
from tf2_ros import Buffer, TransformListener, LookupException, ConnectivityException, ExtrapolationException
from tf2_geometry_msgs import do_transform_point
from rclpy.duration import Duration

class TransformDebugNode(Node):
    def __init__(self):
        super().__init__('transform_debug')
        self.tf_buffer = Buffer(Duration(seconds=10))
        self.tf_listener = TransformListener(self.tf_buffer, self)
        self.source_frame = 'camera_depth_frame'
        self.target_frame = 'base_link'
        self.point_source = PointStamped()
        self.point_source.header.frame_id = self.source_frame
        self.point_source.point.x = 0.1
        self.point_source.point.y = 1.2
        self.point_source.point.z = 2.3
        self.timer = self.create_timer(1.0, self.transform_point)

    def transform_point(self):
        try:
            # Lookup transform with a timeout
            transformation = self.tf_buffer.lookup_transform(
                self.target_frame,
                self.source_frame,
                rclpy.time.Time(),
                Duration(seconds=3.0)
            )
            # Transform the point
            point_target = do_transform_point(self.point_source, transformation)
            self.get_logger().info(f'Transformed point: {point_target.point}')
        except LookupException as ex:
            self.get_logger().error(f'LookupException: {ex}')
        except ConnectivityException as ex:
            self.get_logger().error(f'ConnectivityException: {ex}')
        except ExtrapolationException as ex:
            self.get_logger().error(f'ExtrapolationException: {ex}')

def main():
    rclpy.init()
    node = TransformDebugNode()
    try:
        rclpy.spin(node)
    finally:
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

I am actually interested in converting points in the gripper_camera_depth_frame to the base_link. However, it seems like the stretch_driver.launch.py launch file has base_link but no gripper_camera_depth_frame, while the multi_camera.launch.py launch file has gripper_camera_depth_frame, but it doesn’t seem to be connected to anything which connects back to base_link. Any ideas how I can get this transformation?

Any input will be much appreciated, thanks in advance!