ROS 2 for Robot Arms, step 4
Frames with tf2
Be the robot_state_publisher: broadcast every link's frame, then let tf2 find the gripper and move camera detections into the arm's frame.
The tf tree
Every link of the arm, and every sensor, has a coordinate frame. tf2 keeps the transforms between frames as a tree: each frame has one parent, and its transform says where the child is in that parent. To relate any two frames, tf2 chains the transforms through their common ancestor. The table camera hangs off the same root:
base_link → turret_link → … → hand_link → tool0, and base_link → camera_link → camera_optical_frame
An optical frame follows the camera convention of REP 103: z forward, x right, y down.
Broadcasting
A geometry_msgs/msg/TransformStamped has a header (frame_id is the parent), a child_frame_id, a translation and a rotation quaternion (x, y, z, w). quaternion_from_matrix is given, because Jazzy has no tf_transformations.
- Moving joints go on
/tfthrough aTransformBroadcaster, every time they move, stamped with the joint state's stamp. - Fixed joints never change: send them once on
/tf_staticthrough aStaticTransformBroadcaster, which latches like/robot_description. Pass them all to onesendTransform([...]).
The robot's own robot_state_publisher is off in this step: your node takes its place.
Listening
self.buffer = Buffer()
self.listener = TransformListener(self.buffer, self)
t = self.buffer.lookup_transform("base_link", "tool0", Time())
The listener fills the buffer from /tf and /tf_static through your node, so the node must spin. Time() means "the latest you have". self.buffer.transform(point, "base_link") moves a stamped point into another frame (it needs import tf2_geometry_msgs). Wrap lookups in try / except TransformException: until the first transforms arrive, the tree is empty.
Here vs a real robot
As in tf2, the buffer keeps a few seconds of history and interpolates between stamps. The camera's detections arrive ready-made on /ball_detector/points: each ball it sees, as a PointStamped in camera_optical_frame.
Your task
make_transform(parent, child, T, stamp): a 4×4 transform as aTransformStamped.- In
StatePublisher, send the fixed joints once when the description arrives, and every moving joint (found by name) with each joint state. - In
BallLocator, publish wheretool0is on/tool_position(aPointStampedinbase_link), and every ball detection moved intobase_linkon/ball_positions.