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

tf2_sensor_msgs in ROS Galactic: ModuleNotFoundError

asked 2022-03-03 04:27:16 -0500

sebastianb gravatar image

Hi all, I am somewhat new to ROS. I have installed ROS Galactic from the official Debian/Ubuntu packages. I managed to write a few simple nodes in Python that subscribe to or publish PointCloud2 messages.

Now I am trying to transform a PointCloud2. I found this example: https://github.com/lucasw/transform_p...

The magic line is: from tf2_sensor_msgs.tf2_sensor_msgs import do_transform_cloud

Even though I apt installed ros-galactic-tf2-sensor-msgs, the module is not found when I try to run the script:

ModuleNotFoundError: No module named 'tf2_sensor_msgs'

What else do I need to install to get do_transform_cloud()? If this is the wrong approach: How to correctly transform a PointCloud2 in Python on ROS Galactic?

Thanks!

edit retag flag offensive close merge delete

Comments

Did you try to install sudo apt-get install ros-galactic-geometry2/build it from sources? This package is in geometry2 set of ROS packages. Maybe there was some hidden dependency with installing only one of these packages. You can try to use rosdep install --from-paths src --ignore-src -r -y in your workspace too.

ljaniec gravatar image ljaniec  ( 2022-03-04 05:20:31 -0500 )edit

I think I have all the dependencies installed:

$ sudo apt-get install ros-galactic-geometry2
Reading package lists... Done
Building dependency tree       
Reading state information... Done
ros-galactic-geometry2 is already the newest version (0.17.2-1focal.20220203.030151).
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
$ grep tf2_sensor_msgs src/target_transformer/package.xml 
  <exec_depend>tf2_sensor_msgs</exec_depend>
$ rosdep install --from-paths src --ignore-src -r -y
#All required rosdeps installed successfully

Should tf2_sensor_msgs exist and work in Galatic or is it something old and deprecated?

sebastianb gravatar image sebastianb  ( 2022-03-04 05:34:03 -0500 )edit

It seems you have everything, right. I will write down more in the answer in a moment, this comment section is a bit small.

ljaniec gravatar image ljaniec  ( 2022-03-04 05:58:15 -0500 )edit

2 Answers

Sort by » oldest newest most voted
1

answered 2022-03-04 00:58:18 -0500

sebastianb gravatar image

updated 2022-03-08 01:22:54 -0500

Hi all,

I figured out how to manually transform my points on by one. This way tf2_sensor_msgs is not needed. Maybe this will help someone.

Note that in C++, pcl_ros::transformPointCloud() can be used to achieve the same thing with less code and in a small fraction of the time... I just couldn't figure out how to call pcl_ros::transformPointCloud from Python.

import numpy as np
import rclpy
from rclpy.node import Node
from std_msgs.msg import Header
from sensor_msgs.msg import PointCloud2
import sensor_msgs_py.point_cloud2 as pc2
from geometry_msgs.msg import Point
from tf2_ros import TransformException
from tf2_ros.buffer import Buffer
from tf2_ros.transform_listener import TransformListener
import tf_transformations


def transform_point(trans, pt):
    # https://answers.ros.org/question/249433/tf2_ros-buffer-transform-pointstamped/
    quat = [
        trans.transform.rotation.x,
        trans.transform.rotation.y,
        trans.transform.rotation.z,
        trans.transform.rotation.w
    ]
    mat = tf_transformations.quaternion_matrix(quat)
    pt_np = [pt.x, pt.y, pt.z, 1.0]
    pt_in_map_np = np.dot(mat, pt_np)

    pt_in_map = Point()
    pt_in_map.x = pt_in_map_np[0] + trans.transform.translation.x
    pt_in_map.y = pt_in_map_np[1] + trans.transform.translation.y
    pt_in_map.z = pt_in_map_np[2] + trans.transform.translation.z

    return pt_in_map


class FrameListener(Node):

    def __init__(self):
        super().__init__('target_transformer')

        self.subscription = self.create_subscription(PointCloud2, 'pc2_raw', self.listener_callback, 10)
        self.publisher = self.create_publisher(PointCloud2, 'pc2_transformed', 10)

        self.declare_parameter('target_frame', 'base_link')
        self.target_frame = self.get_parameter('target_frame').get_parameter_value().string_value

        self.tf_buffer = Buffer()
        self.tf_listener = TransformListener(self.tf_buffer, self)


    def listener_callback(self, msg):

        timestamp = msg.header.stamp
        source_frame = msg.header.frame_id

        # Look up for the transformation between target_frame and source_frame
        # frames at a specific time
        try:
            trans = self.tf_buffer.lookup_transform(
                self.target_frame,
                source_frame,
                timestamp)
        except TransformException as ex:
            self.get_logger().info(f'Could not transform {source_frame} to {self.target_frame}: {ex}')
            pass

        new_points = []

        # walk through list of points and transform each point one by one
        for x, y, z in pc2.read_points(msg, field_names=('x', 'y', 'z')):

            pt = Point()
            pt.x, pt.y, pt.z = x, y, z

            new_pt = transform_point(trans, pt)
            new_points.append((new_pt.x, new_pt.y, new_pt.z))

        # stick transformed point into new PointCloud2 message for easy visualization
        # in the actual application, the points would be transformed and used locally
        header = Header()
        header.stamp = msg.header.stamp
        header.frame_id = self.target_frame
        pc_relative = pc2.create_cloud_xyz32(header=header, points=new_points)
        self.publisher.publish(pc_relative)


def main():
    rclpy.init()
    node = FrameListener()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass

    rclpy.shutdown()
edit flag offensive delete link more
0

answered 2022-03-04 06:03:02 -0500

ljaniec gravatar image

Well, your example code for a PointCloud2 is for ROS1 by info from the README.md on this repository.

Your best shot would be use of PCL (Point Cloud Library) ROS interface stack:

For your question in the comments about deprecation of tf2_sensor_msgs- it is still used widely, good example would be https://github.com/SteveMacenski/slam... (look in the CMakeLists.txt there). It is C++ only for now as far as I know.

edit flag offensive delete link more

Comments

Thanks for your help! So I guess trying to get tf2_sensor_msgs to work with Python is out of the question.

Would you have an example on how to transform a point to a different reference frame using PCL and Python? I am having trouble figuring out how to use the library. All the examples are for ROS1 and/or in C++.

As a workaround, I managed to get the correct rotation using another code snippet from lucasw (https://answers.ros.org/question/2494...). But having to do the rotation by hand feels very wrong.

I'll keep searching for PCL+Python examples.

sebastianb gravatar image sebastianb  ( 2022-03-04 08:15:07 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2022-03-03 04:27:16 -0500

Seen: 1,420 times

Last updated: Mar 08 '22