This describes how to relate the tf2 transforms conventions with your standard T_X_to_Y notations, for ros2 (humble and onwards)
Concrete example: Say foo is the parent frame / fixed frame. You want to go to bar. You do these transformations in that order:
- translate 1m in X, 2m in Y, 3m in Z
- rotate 90deg about Z, ie, yaw = 90deg
- rotate -180deg about X, ie, roll = -180deg
Hand-verified ground-truth solution:
T_foo_to_bar = [
[0, 1, 0, -2],
[1, 0, 0, -1],
[0, 0, -1, 3],
[0, 0, 0, 1]
]
Below, we'll reproduce this exactly using tf2 commandline, python3 and c++ apis.
ros2 run tf2_ros static_transform_publisher 1 2 3 1.57 0.0 -3.14 foo bar: this applies the translation (x=1, y=2, z=3), and then the body-fixed rotations (yaw, pitch, roll) in that sequence, from parent frame (foo) to child frame (bar)
Output:
[WARN] [1760894974.136992725] []: Old-style arguments are deprecated; see --help for new-style arguments
[INFO] [1760894974.159561405] [static_transform_publisher_qbaLLikc4FSCUcWX]: Spinning until stopped - publishing transform
translation: ('1.000000', '2.000000', '3.000000')
rotation: ('-0.707388', '-0.706825', '0.000563', '0.000563')
from 'foo' to 'bar'
ros2 run tf2_ros tf2_echo bar foo -p 1: echo the transform from foo to bar (same as above essentially). Note the order of frames args is reversed. Also, the output of this command lists Matrix, which is what you should focus on, the rest of the entries I think are inverted, as in, if you do args as foo bar, it might show what you would expect
Output:
[INFO] [1760895230.843096430] [tf2_echo]: Waiting for transform bar -> foo: Invalid frame ID "bar" passed to canTransform argument target_frame - frame does not exist
At time 0.0
- Translation: [-2.0, -1.0, 3.0]
- Rotation: in Quaternion (xyzw) [0.7, 0.7, -0.0, 0.0]
- Rotation: in RPY (radian) [3.1, 0.0, 1.6]
- Rotation: in RPY (degree) [180.0, 0.1, 90.0]
- Matrix:
0.0 1.0 0.0 -2.0
1.0 -0.0 -0.0 -1.0
-0.0 0.0 -1.0 3.0
0.0 0.0 0.0 1.0
- static transforms api:
static_pub.py - dynamic transforms api:
dynamic_pub.py
sub.py
- static transforms api:
static_pub.cpp - dynamic transforms api:
dynamic_pub.cpp
sub.cpp