# Rotations & Transformations¶

The most common representations for 3D rotations are implemented in RobWork. In this page we will consider the Rotation Matrix, Axis-Angle (EAA), Roll Pitch Yaw Angle (RPY), and Quaternion representations, and how to convert between these representations. Finally, Transformations are considered.

## Rotation Matrix¶

A 3x3 rotation matrix can be constructed using the Rotation3D type. The default Rotation3D<> type uses double precision, while Rotation3D<float> uses float precision. Notice that it is only possible to specify the templated types in C++. The equivalent types in the script interfaces (Python, Java and LUA) is Rotation3d and Rotation3f for double and float precision respectively.

The constructor for Rotation3D takes the elements of the rotation matrix $$\mathbf{R} = \left[\begin{array}{ccc} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \end{array} \right]$$

in the following order: Rotation3D($$r_{11},r_{12},r_{13},r_{21},r_{22},r_{23},r_{31},r_{32},r_{33}$$).

Code examples are shown below for different languages.

Warning

There are two functions for finding the inverse rotation matrix, namely inverse(rot) and rot.inverse(). The inverse(rot) returns a new rotation without altering the original rotation, while rot.inverse() calculates the inverse by changing the original rotation matrix.

C++

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include using rw::math::Rotation3D; int main(int argc, char** argv) { Rotation3D<> rotd = Rotation3D<>(1,0,0,0,0,-1,0,1,0); Rotation3D rotf = Rotation3D(1,0,0,0,0,-1,0,1,0); std::cout << "Rotation double:" << std::endl << rotd << std::endl; std::cout << "Rotation float:" << std::endl << rotf << std::endl; std::cout << "Rotation inverse:" << std::endl << inverse(rotd) << std::endl; std::cout << "Identity:" << std::endl << rotd*inverse(rotd) << std::endl; return 0; } 

API Reference: rw::math::Rotation3D

Python

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 from rw import * if __name__ == '__main__': rotd = Rotation3d(1,0,0,0,0,-1,0,1,0); rotf = Rotation3f(1,0,0,0,0,-1,0,1,0); print("Rotation double:"); print(str(rotd)); print("Rotation float:"); print(str(rotf)); print("Rotation inverse:"); print(str(inverse(rotd))); print("Identity:"); print(str(rotd*inverse(rotd))); 

API Reference:

Java

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import org.robwork.LoaderRW; import org.robwork.rw.*; import static org.robwork.rw.rw.*; public class ExRotation3D { public static void main(String[] args) throws Exception { LoaderRW.load("rw"); Rotation3d rotd = new Rotation3d(1,0,0,0,0,-1,0,1,0); Rotation3f rotf = new Rotation3f(1,0,0,0,0,-1,0,1,0); System.out.println("Rotation double:"); System.out.println(rotd); System.out.println("Rotation float:"); System.out.println(rotf); System.out.println("Rotation inverse:"); System.out.println(rotd.inverse()); System.out.println("Identity:"); System.out.println(rotd.multiply(inverse(rotd))); } } 

API Reference:

LUA

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 require("rw") using("rw") rotd = Rotation3d(1,0,0,0,0,-1,0,1,0); rotf = Rotation3f(1,0,0,0,0,-1,0,1,0); print("Rotation double:"); print(tostring(rotd)); print("Rotation float:"); print(tostring(rotf)); print("Rotation inverse:"); print(tostring(inverse(rotd))); print("Identity:"); print(tostring(rotd*inverse(rotd))); 

Output

Rotation double:
Rotation3D(1, 0, 0, 0, 0, -1, 0, 1, 0)
Rotation float:
Rotation3D(1, 0, 0, 0, 0, -1, 0, 1, 0)
Rotation inverse:
Rotation3D(1, 0, 0, 0, 0, 1, 0, -1, 0)
Identity:
Rotation3D(1, 0, 0, 0, 1, 0, 0, 0, 1)


## Axis-Angle (EAA)¶

Equivalent Angle-Axis (EAA) is the RobWork type for rotations defined by the product of a unit vector and an angle of rotation. The direction of the vector gives the axis of rotation, and the length of the vector gives the amount of rotation in radians.

C++

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include #include #include using namespace rw::math; int main(int argc, char** argv) { const EAA<> eaa = EAA<>(sqrt(2)/2*Pi,sqrt(2)/2*Pi,0); std::cout << "EAA: " << eaa << std::endl; std::cout << " angle: " << eaa.angle() << std::endl; std::cout << " axis: " << eaa.axis() << std::endl; const Rotation3D<> rotationFromEAA = eaa.toRotation3D(); std::cout << "Rotation from EAA: " << rotationFromEAA << std::endl; const Rotation3D<> rot = Rotation3D<>(-1,0,0,0,0,1,0,1,0); std::cout << "Rotation: " << rot << std::endl; const EAA<> eaaFromRotation = EAA<>(rot); std::cout << "EAA from Rotation: " << eaaFromRotation << std::endl; std::cout << " angle: " << eaaFromRotation.angle() << std::endl; std::cout << " axis: " << eaaFromRotation.axis() << std::endl; return 0; } 

API Reference: rw::math::EAA

Python

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from rw import * import math if __name__ == '__main__': eaa = EAAd(math.sqrt(2)/2*Pi,math.sqrt(2)/2*Pi,0); print("EAA: " + str(eaa)) print(" angle: " + str(eaa.angle())) print(" axis: " + str(eaa.axis())); rotationFromEAA = eaa.toRotation3D(); print("Rotation from EAA: " + str(rotationFromEAA)); rot = Rotation3d(-1,0,0,0,0,1,0,1,0); print("Rotation: " + str(rot)); eaaFromRotation = EAAd(rot); print("EAA from Rotation: " + str(eaaFromRotation)); print(" angle: " + str(eaaFromRotation.angle())); print(" axis: " + str(eaaFromRotation.axis())); 

API Reference:

Java

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import org.robwork.LoaderRW; import org.robwork.rw.*; import static org.robwork.rw.rwConstants.*; import java.lang.Math; public class ExEAA { public static void main(String[] args) throws Exception { LoaderRW.load("rw"); EAAd eaa = new EAAd(Math.sqrt(2)/2*Pi,Math.sqrt(2)/2*Pi,0); System.out.println("EAA: " + eaa); System.out.println(" angle: " + eaa.angle()); System.out.println(" axis: " + eaa.axis()); Rotation3d rotationFromEAA = eaa.toRotation3D(); System.out.println("Rotation from RPY: " + rotationFromEAA); Rotation3d rot = new Rotation3d(-1,0,0,0,0,1,0,1,0); System.out.println("Rotation: " + rot); EAAd eaaFromRotation = new EAAd(rot); System.out.println("EAA from Rotation: " + eaaFromRotation); System.out.println(" angle: " + eaaFromRotation.angle()); System.out.println(" axis: " + eaaFromRotation.axis()); } } 

API Reference:

LUA

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 require("rw") using("rw") eaa = EAAd(math.sqrt(2)/2*Pi,math.sqrt(2)/2*Pi,0); print("EAA: " .. tostring(eaa)) print(" angle: " .. eaa:angle()) print(" axis: " .. tostring(eaa:axis())); rotationFromEAA = eaa:toRotation3D(); print("Rotation from EAA: " .. tostring(rotationFromEAA)); rot = Rotation3d(-1,0,0,0,0,1,0,1,0); print("Rotation: " .. tostring(rot)); eaaFromRotation = EAAd(rot); print("EAA from Rotation: " .. tostring(eaaFromRotation)) print(" angle: " .. eaaFromRotation:angle()) print(" axis: " .. tostring(eaaFromRotation:axis())); 

Output

EAA:  EAA { 2.22144, 2.22144, 0}
angle: 3.14159
axis: Vector3D(0.707107, 0.707107, 0)
Rotation from EAA: Rotation3D(2.22045e-16, 1, 8.65956e-17, 1, 2.22045e-16, -8.65956e-17, -8.65956e-17, 8.65956e-17, -1)
Rotation: Rotation3D(-1, 0, 0, 0, 0, 1, 0, 1, 0)
EAA from Rotation:  EAA { 0, 2.22144, 2.22144}
angle: 3.14159
axis: Vector3D(0, 0.707107, 0.707107)


## Roll Pitch Yaw Angle (RPY)¶

Roll Pitch Yaw angles is one form of Euler angles where the rotation is defined by three consecutive rotations around the axes of a coordinate system. In RobWork, RPY is the rotation around the z, y and x axes (in that order). Notice that the rotation around the y axis is the y axis after doing the rotation around z. The rotation around the x axis is the x axis after doing the rotations around both z and y.

C++

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include #include #include using namespace rw::math; int main(int argc, char** argv) { const RPY<> rpy = RPY<>(Pi,Pi/2,0); std::cout << "RPY: " << rpy << std::endl; const Rotation3D<> rotationFromRPY = rpy.toRotation3D(); std::cout << "Rotation from RPY: " << rotationFromRPY << std::endl; const Rotation3D<> rot = Rotation3D<>(-1,0,0,0,0,1,0,1,0); std::cout << "Rotation: " << rot << std::endl; const RPY<> rpyFromRotation = RPY<>(rot); std::cout << "RPY from Rotation: " << rpyFromRotation << std::endl; return 0; } 

API Reference: rw::math::RPY

Python

  1 2 3 4 5 6 7 8 9 10 11 12 13 from rw import * if __name__ == '__main__': rpy = RPYd(Pi,Pi/2,0); print("RPY: " + str(rpy)); rotationFromRPY = rpy.toRotation3D(); print("Rotation from RPY: " + str(rotationFromRPY)); rot = Rotation3d(-1,0,0,0,0,1,0,1,0); print("Rotation: " + str(rot)); rpyFromRotation = RPYd(rot); print("RPY from Rotation: " + str(rpyFromRotation)); rot = Rotation3d(1,0,0,0,1,0,0,0,1) 

API Reference:

Java

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import org.robwork.LoaderRW; import org.robwork.rw.*; import static org.robwork.rw.rwConstants.*; public class ExRPY { public static void main(String[] args) throws Exception { LoaderRW.load("rw"); RPYd rpy = new RPYd(Pi,Pi/2,0); System.out.println("RPY: " + rpy); Rotation3d rotationFromRPY = rpy.toRotation3D(); System.out.println("Rotation from RPY: " + rotationFromRPY); Rotation3d rot = new Rotation3d(-1,0,0,0,0,1,0,1,0); System.out.println("Rotation: " + rot); RPYd rpyFromRotation = new RPYd(rot); System.out.println("RPY from Rotation: " + rpyFromRotation); } } 

API Reference:

LUA

  1 2 3 4 5 6 7 8 9 10 11 12 require("rw") using("rw") rpy = RPYd(Pi,Pi/2,0); print("RPY: " .. tostring(rpy)); rotationFromRPY = rpy:toRotation3D(); print("Rotation from RPY: " .. tostring(rotationFromRPY)); rot = Rotation3d(-1,0,0,0,0,1,0,1,0); print("Rotation: " .. tostring(rot)); rpyFromRotation = RPYd(rot); print("RPY from Rotation: " .. tostring(rpyFromRotation)); 

Output

RPY: RPY {3.14159, 1.5708, 0}
Rotation from RPY: Rotation3D(-6.12323e-17, -1.22465e-16, -1, 7.4988e-33, -1, 1.22465e-16, -1, 0, 6.12323e-17)
Rotation: Rotation3D(-1, 0, 0, 0, 0, 1, 0, 1, 0)
RPY from Rotation: RPY {3.14159, -0, 1.5708}


## Quaternion¶

Quaternions are complex numbers, storing the rotation as 4 values.

C++

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include #include using namespace rw::math; int main(int argc, char** argv) { const Quaternion<> quat = Quaternion<>(sqrt(2)/2,sqrt(2)/2,0,0); std::cout << "Quaternion: " << quat << std::endl; const Rotation3D<> rotationFromQuat = quat.toRotation3D(); std::cout << "Rotation from Quaternion: " << rotationFromQuat << std::endl; const Rotation3D<> rot = Rotation3D<>(-1,0,0,0,0,1,0,1,0); std::cout << "Rotation: " << rot << std::endl; const Quaternion<> quatFromRotation = Quaternion<>(rot); std::cout << "Quaternion from Rotation: " << quatFromRotation << std::endl; return 0; } 

API Reference: rw::math::Quaternion

Python

  1 2 3 4 5 6 7 8 9 10 11 12 13 from rw import * import math if __name__ == '__main__': quat = Quaterniond(math.sqrt(2)/2,math.sqrt(2)/2,0,0) print("Quaternion: " + str(quat)) rotationFromQuat = quat.toRotation3D() print("Rotation from Quaternion: " + str(rotationFromQuat)); rot = Rotation3d(-1,0,0,0,0,1,0,1,0); print("Rotation: " + str(rot)); quatFromRotation = Quaterniond(rot); print("Quaternion from Rotation: " + str(quatFromRotation)); 

API Reference:

Java

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import org.robwork.LoaderRW; import org.robwork.rw.*; import java.lang.Math; public class ExQuaternion { public static void main(String[] args) throws Exception { LoaderRW.load("rw"); Quaterniond quat = new Quaterniond(Math.sqrt(2)/2,Math.sqrt(2)/2,0,0); System.out.println("Quaternion: " + quat); Rotation3d rotationFromQuat = quat.toRotation3D(); System.out.println("Rotation from Quaternion: " + rotationFromQuat); Rotation3d rot = new Rotation3d(-1,0,0,0,0,1,0,1,0); System.out.println("Rotation: " + rot); Quaterniond quatFromRotation = new Quaterniond(rot); System.out.println("Quaternion from Rotation: " + quatFromRotation); } } 

API Reference:

LUA

  1 2 3 4 5 6 7 8 9 10 11 12 require("rw") using("rw") quat = Quaterniond(math.sqrt(2)/2,math.sqrt(2)/2,0,0); print("Quaternion: " .. tostring(quat)) rotationFromQuat = quat:toRotation3D(); print("Rotation from Quaternion: " .. tostring(rotationFromQuat)); rot = Rotation3d(-1,0,0,0,0,1,0,1,0); print("Rotation: " .. tostring(rot)); quatFromRotation = Quaterniond(rot); print("Quaternion from Rotation: " .. tostring(quatFromRotation)) 

Output

Quaternion: Quaternion {0.707107, 0.707107, 0, 0}
Rotation from Quaternion: Rotation3D(-2.22045e-16, 1, 0, 1, -2.22045e-16, 0, 0, 0, -1)
Rotation: Rotation3D(-1, 0, 0, 0, 0, 1, 0, 1, 0)
Quaternion from Rotation: Quaternion {0, 0.707107, 0.707107, 0}


## Converting Rotations¶

To convert between EAA, RPY and Quaternions, it is in general possible to convert the types via the full Rotation3D representation. First convert to Rotation3D using the toRotation3D() function and then construct the new target type from this rotation matrix.

The RobWork Math class provides special functions for converting between EAA and Quaternion. Please see the quaternionToEAA and eaaToQuaternion functions.

API Reference:

## Transformations¶

The Transform3D type is a full 4x4 homogeneous transformation matrix. A transformation matrix combines a rotation and a translation. It can be constructed from a Vector3D and any of the rotation types above.

Alternatively, the Pose6D stores a pose using six values. Three values for the position and three values for the EAA orientation.

API Reference: