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

Revision history [back]

click to hide/show revision 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

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

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

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