ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange |
1 | initial version |
Hi, I believe this is a perfectly valid question still in 2022, and not immediately clear from the tf/tf2 documentation and papers or REP 103, due to lack of the "intrinsic" and "extrinsic" rotation in the terminology.
Doing a bit reverse-engineering, one could see that
static_transform_publisher x y z yaw pitch roll frame_id child_frame_id
way of using static tf, calls the following lines: https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2_ros/src/static_transform_broadcaster_program.cpp#L80
tf2::Quaternion quat;
quat.setRPY(atof(argv[6]), atof(argv[5]), atof(argv[4]));
msg.transform.rotation.x = quat.x();
msg.transform.rotation.y = quat.y();
msg.transform.rotation.z = quat.z();
msg.transform.rotation.w = quat.w();
which in turn calls : https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2/include/tf2/LinearMath/Quaternion.h#L95
/**@brief Set the quaternion using fixed axis RPY
* @param roll Angle around X
* @param pitch Angle around Y
* @param yaw Angle around Z*/
void setRPY(const tf2Scalar& roll, const tf2Scalar& pitch, const tf2Scalar& yaw)
{
tf2Scalar halfYaw = tf2Scalar(yaw) * tf2Scalar(0.5);
tf2Scalar halfPitch = tf2Scalar(pitch) * tf2Scalar(0.5);
tf2Scalar halfRoll = tf2Scalar(roll) * tf2Scalar(0.5);
tf2Scalar cosYaw = tf2Cos(halfYaw);
tf2Scalar sinYaw = tf2Sin(halfYaw);
tf2Scalar cosPitch = tf2Cos(halfPitch);
tf2Scalar sinPitch = tf2Sin(halfPitch);
tf2Scalar cosRoll = tf2Cos(halfRoll);
tf2Scalar sinRoll = tf2Sin(halfRoll);
setValue( sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x
cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z
cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx
}
This is the exact notation in https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Euler_angles_to_quaternion_conversion, which is indicated as lab1-2-3 sequence, where lab frame is fixed during the rotation. Therefore, it seems that it's following extrinsic rotation
Furthermore, in REP103 (https://www.ros.org/reps/rep-0103.html#axis-orientation), it's mentioned that the rotation convention is "fixed axis roll, pitch, yaw". Although, this does not make it immediately clear, since fixed axis could also be interpreted as rotation around a fixed axis of a rigid body.
A nice summary of the conventions used in similar 3d tools can be found in: https://rock-learning.github.io/pytransform3d/transformation_ambiguities.html
2 | No.2 Revision |
Hi, I believe this is a perfectly valid question still in 2022, and not immediately clear from the tf/tf2 documentation and papers or REP 103, due to lack of the "intrinsic" and "extrinsic" rotation in the terminology.
Doing a bit reverse-engineering, one could see that
static_transform_publisher x y z yaw pitch roll frame_id child_frame_id
way of using static tf, calls the following lines: https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2_ros/src/static_transform_broadcaster_program.cpp#L80
tf2::Quaternion quat;
quat.setRPY(atof(argv[6]), atof(argv[5]), atof(argv[4]));
msg.transform.rotation.x = quat.x();
msg.transform.rotation.y = quat.y();
msg.transform.rotation.z = quat.z();
msg.transform.rotation.w = quat.w();
which in turn calls : https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2/include/tf2/LinearMath/Quaternion.h#L95
/**@brief Set the quaternion using fixed axis RPY
* @param roll Angle around X
* @param pitch Angle around Y
* @param yaw Angle around Z*/
void setRPY(const tf2Scalar& roll, const tf2Scalar& pitch, const tf2Scalar& yaw)
{
tf2Scalar halfYaw = tf2Scalar(yaw) * tf2Scalar(0.5);
tf2Scalar halfPitch = tf2Scalar(pitch) * tf2Scalar(0.5);
tf2Scalar halfRoll = tf2Scalar(roll) * tf2Scalar(0.5);
tf2Scalar cosYaw = tf2Cos(halfYaw);
tf2Scalar sinYaw = tf2Sin(halfYaw);
tf2Scalar cosPitch = tf2Cos(halfPitch);
tf2Scalar sinPitch = tf2Sin(halfPitch);
tf2Scalar cosRoll = tf2Cos(halfRoll);
tf2Scalar sinRoll = tf2Sin(halfRoll);
setValue( sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x
cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z
cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx
}
This is the exact notation in https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Euler_angles_to_quaternion_conversion, which is indicated as lab1-2-3 sequence, where lab frame is fixed during the rotation. Therefore, it seems that it's following extrinsic rotation
Furthermore, in REP103 (https://www.ros.org/reps/rep-0103.html#axis-orientation), it's mentioned that the rotation convention is "fixed axis roll, pitch, yaw". Although, this does not make it immediately clear, since fixed axis could also be interpreted as rotation around a fixed axis of a rigid body.
A nice summary of the conventions used in similar 3d tools can be found in: https://rock-learning.github.io/pytransform3d/transformation_ambiguities.html
3 | No.3 Revision |
Hi, I believe this is a perfectly valid question still in 2022, and not immediately clear from the tf/tf2 documentation and papers or REP 103, due to lack of the "intrinsic" and "extrinsic" rotation in the terminology.
Doing Firstly, verbal overview in http://wiki.ros.org/tf/Overview/Transformations states that
"the rotation of the frame A in W's coordinate system." which hints that rotation of A is represented in the external coordinate system of W, hence extrinsic rotation
Secondly, doing a bit reverse-engineering, one could see that
static_transform_publisher x y z yaw pitch roll frame_id child_frame_id
way of using static tf, calls the following lines: https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2_ros/src/static_transform_broadcaster_program.cpp#L80
tf2::Quaternion quat;
quat.setRPY(atof(argv[6]), atof(argv[5]), atof(argv[4]));
msg.transform.rotation.x = quat.x();
msg.transform.rotation.y = quat.y();
msg.transform.rotation.z = quat.z();
msg.transform.rotation.w = quat.w();
which in turn calls : https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2/include/tf2/LinearMath/Quaternion.h#L95
/**@brief Set the quaternion using fixed axis RPY
* @param roll Angle around X
* @param pitch Angle around Y
* @param yaw Angle around Z*/
void setRPY(const tf2Scalar& roll, const tf2Scalar& pitch, const tf2Scalar& yaw)
{
tf2Scalar halfYaw = tf2Scalar(yaw) * tf2Scalar(0.5);
tf2Scalar halfPitch = tf2Scalar(pitch) * tf2Scalar(0.5);
tf2Scalar halfRoll = tf2Scalar(roll) * tf2Scalar(0.5);
tf2Scalar cosYaw = tf2Cos(halfYaw);
tf2Scalar sinYaw = tf2Sin(halfYaw);
tf2Scalar cosPitch = tf2Cos(halfPitch);
tf2Scalar sinPitch = tf2Sin(halfPitch);
tf2Scalar cosRoll = tf2Cos(halfRoll);
tf2Scalar sinRoll = tf2Sin(halfRoll);
setValue( sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x
cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z
cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx
}
This is the exact notation in https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Euler_angles_to_quaternion_conversion, which is indicated as lab1-2-3 sequence, where lab frame is fixed during the rotation. Therefore, it seems that it's following extrinsic rotation
Furthermore, in REP103 (https://www.ros.org/reps/rep-0103.html#axis-orientation), it's mentioned that the rotation convention is "fixed axis roll, pitch, yaw". Although, this does not make it immediately clear, since fixed axis could also be interpreted as rotation around a fixed axis of a rigid body.
A nice summary of the conventions used in similar 3d tools can be found in: https://rock-learning.github.io/pytransform3d/transformation_ambiguities.html
4 | No.4 Revision |
Hi, I believe this is a perfectly valid question still in 2022, and not immediately clear from the tf/tf2 documentation and papers or REP 103, due to lack of the "intrinsic" and "extrinsic" rotation in the terminology.
Firstly, verbal overview in http://wiki.ros.org/tf/Overview/Transformations states that
"the rotation of the frame A in W's coordinate
system."system."
which hints that rotation of A is represented in the external coordinate system of W, hence extrinsic rotation
Secondly, doing a bit reverse-engineering, one could see that
static_transform_publisher x y z yaw pitch roll frame_id child_frame_id
way of using static tf, calls the following lines: https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2_ros/src/static_transform_broadcaster_program.cpp#L80
tf2::Quaternion quat;
quat.setRPY(atof(argv[6]), atof(argv[5]), atof(argv[4]));
msg.transform.rotation.x = quat.x();
msg.transform.rotation.y = quat.y();
msg.transform.rotation.z = quat.z();
msg.transform.rotation.w = quat.w();
which in turn calls : https://github.com/ros/geometry2/blob/c73b5939723db078c9bbe18523230ad54f859682/tf2/include/tf2/LinearMath/Quaternion.h#L95
/**@brief Set the quaternion using fixed axis RPY
* @param roll Angle around X
* @param pitch Angle around Y
* @param yaw Angle around Z*/
void setRPY(const tf2Scalar& roll, const tf2Scalar& pitch, const tf2Scalar& yaw)
{
tf2Scalar halfYaw = tf2Scalar(yaw) * tf2Scalar(0.5);
tf2Scalar halfPitch = tf2Scalar(pitch) * tf2Scalar(0.5);
tf2Scalar halfRoll = tf2Scalar(roll) * tf2Scalar(0.5);
tf2Scalar cosYaw = tf2Cos(halfYaw);
tf2Scalar sinYaw = tf2Sin(halfYaw);
tf2Scalar cosPitch = tf2Cos(halfPitch);
tf2Scalar sinPitch = tf2Sin(halfPitch);
tf2Scalar cosRoll = tf2Cos(halfRoll);
tf2Scalar sinRoll = tf2Sin(halfRoll);
setValue( sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x
cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z
cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx
}
This is the exact notation in https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Euler_angles_to_quaternion_conversion, which is indicated as lab1-2-3 sequence, where lab frame is fixed during the rotation. Therefore, it seems that it's following extrinsic rotation
Furthermore, in REP103 (https://www.ros.org/reps/rep-0103.html#axis-orientation), it's mentioned that the rotation convention is "fixed axis roll, pitch, yaw". Although, this does not make it immediately clear, since fixed axis could also be interpreted as rotation around a fixed axis of a rigid body.
A nice summary of the conventions used in similar 3d tools can be found in: https://rock-learning.github.io/pytransform3d/transformation_ambiguities.html