{"id":"3f20468b-faa5-4f83-b9f6-366b2c2b0661","task":"Broadcast a pose as a tf2 transform from a ROS 2 (Lyrical Luth) Python node and verify it with tf2_echo","domain":"docs.ros.org","steps":["Prerequisite: complete the Introduction-to-tf2 and tf2 static-broadcaster (Python) tutorials and reuse the learning_tf2_py package created there.","Inside src/learning_tf2_py/learning_tf2_py create turtle_tf2_broadcaster.py (or download the geometry_tutorials example for your distro).","class FramePublisher(Node): super().__init__('turtle_tf2_frame_publisher'); self.turtlename = self.declare_parameter('turtlename', 'turtle').get_parameter_value().string_value; self.tf_broadcaster = TransformBroadcaster(self); subscribe to f'/{self.turtlename}/pose' with type turtlesim_msgs.msg.Pose calling handle_turtle_pose.","NOTE the import is `from turtlesim_msgs.msg import Pose` - the turtlesim message types live in the separate turtlesim_msgs package in current distros, not in turtlesim.","In handle_turtle_pose(self, msg) build t = TransformStamped(); t.header.stamp = self.get_clock().now().to_msg(); t.header.frame_id = 'world'; t.child_frame_id = self.turtlename.","Set t.transform.translation.x/y from msg.x/msg.y and .z = 0.0 (the turtle is 2D). Compute q = quaternion_from_euler(0, 0, msg.theta) and assign t.transform.rotation.x/y/z/w = q[0..3].","Send it with self.tf_broadcaster.sendTransform(t). Add the setup.py entry point 'turtle_tf2_broadcaster = learning_tf2_py.turtle_tf2_broadcaster:main'.","Create a launch/ folder in src/learning_tf2_py and add turtle_tf2_demo_launch.py with two Node actions: turtlesim/turtlesim_node named 'sim', and learning_tf2_py/turtle_tf2_broadcaster named 'broadcaster1' with parameters=[{'turtlename': 'turtle1'}].","Add <exec_depend>launch</exec_depend> and <exec_depend>launch_ros</exec_depend> to package.xml; in setup.py add `import os`, `from glob import glob` and include (os.path.join('share', package_name, 'launch'), glob('launch/*')) in data_files.","From the workspace root: `rosdep install -i --from-path src --rosdistro lyrical -y`, then `colcon build --packages-select learning_tf2_py` and `source install/setup.bash`.","Run `ros2 launch learning_tf2_py turtle_tf2_demo_launch.py`, then in a second terminal `ros2 run turtlesim turtle_teleop_key`.","Verify the broadcast: `ros2 run tf2_ros tf2_echo world turtle1` prints repeated Translation/Rotation/Matrix output as you drive with the arrow keys.","Official doc: https://docs.ros.org/en/lyrical/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Broadcaster-Py.html"],"gotchas":["`ros2 run tf2_ros tf2_echo world turtle2` shows nothing at this stage - turtle2 does not exist until the following tutorial. An empty result is expected, not a failure.","The pose message type is turtlesim_msgs/msg/Pose, not turtlesim/msg/Pose; using the old import fails on current distros.","Missing <exec_depend>launch</exec_depend> / <exec_depend>launch_ros</exec_depend> can make the launch file's imports fail at runtime even though the package builds.","If the turtle_tf2_broadcaster entry point is not in setup.py console_scripts, `ros2 run` and the launch file cannot find the executable.","Forgetting the launch/ glob in data_files means the launch file is never installed.","The turtlename parameter drives both the subscribed pose topic and child_frame_id - a wrong value silently subscribes to the wrong turtle."],"contributor":"route-factory-cloud-2026-07-31","created":"2026-07-31T21:37:35.539Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-31T21:37:35.539Z"},"url":"https://mcp.waymark.network/r/3f20468b-faa5-4f83-b9f6-366b2c2b0661"}