blob: cb108a90a3630755ce960bb1f9b7930de1346806 [file] [log] [blame]
/**********************************************************************************************************************
This file is part of the Control Toolbox (https://adrlab.bitbucket.io/ct), copyright by ETH Zurich, Google Inc.
Authors: Michael Neunert, Markus Giftthaler, Markus Stäuble, Diego Pardo, Farbod Farshidian
Licensed under Apache2 license (see LICENSE file in main directory)
**********************************************************************************************************************/
#include <ct/rbd/rbd.h>
#include "ct/rbd/state/RigidBodyPose.h"
#include <memory>
#include <array>
#include <gtest/gtest.h>
using namespace ct::rbd;
void testEqual(const RigidBodyPose& pose1, const RigidBodyPose& pose2)
{
ASSERT_TRUE(pose1.isNear(pose2));
ASSERT_TRUE(pose2.isNear(pose1));
ASSERT_TRUE(pose2.getEulerAnglesXyz().isNear(pose1.getEulerAnglesXyz(), 1e-10));
ASSERT_TRUE(pose2.getRotationQuaternion().isNear(pose1.getRotationQuaternion(), 1e-10));
ASSERT_TRUE(pose2.getRotationMatrix().isNear(pose1.getRotationMatrix(), 1e-10));
ASSERT_TRUE(pose2.position().toImplementation().isApprox(pose1.position().toImplementation(), 1e-10));
ASSERT_TRUE(pose2.computeGravityB().isApprox(pose1.computeGravityB(), 1e-10));
ASSERT_TRUE(pose2.computeGravityB6D().isApprox(pose1.computeGravityB6D(), 1e-10));
}
void testNotEqual(const RigidBodyPose& pose1, const RigidBodyPose& pose2)
{
ASSERT_FALSE(pose1.isNear(pose2));
ASSERT_FALSE(pose2.isNear(pose1));
ASSERT_FALSE(pose2.getEulerAnglesXyz().isNear(pose1.getEulerAnglesXyz(), 1e-10));
ASSERT_FALSE(pose2.getRotationQuaternion().isNear(pose1.getRotationQuaternion(), 1e-10));
ASSERT_FALSE(pose2.getRotationMatrix().isNear(pose1.getRotationMatrix(), 1e-10));
ASSERT_FALSE(pose2.computeGravityB().isApprox(pose1.computeGravityB(), 1e-10));
ASSERT_FALSE(pose2.computeGravityB6D().isApprox(pose1.computeGravityB6D(), 1e-10));
}
TEST(RigidBodyPoseTest, storageTest)
{
RigidBodyPose poseQuat(RigidBodyPose::QUAT);
RigidBodyPose poseEuler(RigidBodyPose::EULER);
ASSERT_EQ(poseQuat.getStorageType(), RigidBodyPose::QUAT);
ASSERT_EQ(poseEuler.getStorageType(), RigidBodyPose::EULER);
}
TEST(RigidBodyPoseTest, asignmentTest)
{
RigidBodyPose poseQuat(RigidBodyPose::QUAT);
RigidBodyPose poseEuler(RigidBodyPose::EULER);
poseQuat.setRandom();
poseEuler.setRandom();
testNotEqual(poseQuat, poseEuler);
poseEuler = poseQuat;
testEqual(poseQuat, poseEuler);
}
TEST(RigidBodyPoseTest, conversionTest)
{
RigidBodyPose poseQuat(RigidBodyPose::QUAT);
RigidBodyPose poseEuler(RigidBodyPose::EULER);
poseQuat.setRandom();
poseEuler.setRandom();
poseEuler.setFromEulerAnglesXyz(poseQuat.getEulerAnglesXyz());
poseEuler.position() = poseQuat.position();
testEqual(poseQuat, poseEuler);
poseQuat.setRandom();
poseEuler.setRandom();
poseEuler.setFromRotationQuaternion(poseQuat.getRotationQuaternion());
poseEuler.position() = poseQuat.position();
testEqual(poseQuat, poseEuler);
poseQuat.setIdentity();
poseEuler.setIdentity();
testEqual(poseQuat, poseEuler);
}
TEST(RigidBodyPoseTest, gravityTest)
{
RigidBodyPose poseQuat(RigidBodyPose::QUAT);
RigidBodyPose poseEuler(RigidBodyPose::EULER);
poseQuat.setRandom();
poseEuler.setRandom();
poseQuat = poseEuler;
auto gQuat6d = poseQuat.computeGravityB6D();
auto gEuler6d = poseEuler.computeGravityB6D();
ASSERT_TRUE(gQuat6d.head<3>().isApprox(Eigen::Vector3d::Zero()));
ASSERT_TRUE(gEuler6d.head<3>().isApprox(Eigen::Vector3d::Zero()));
// test for orientation 0 0 0
poseQuat.setIdentity();
poseEuler.setIdentity();
auto gQuat = poseQuat.computeGravityB();
auto gEuler = poseEuler.computeGravityB();
Eigen::Vector3d gravityW;
gravityW << 0.0, 0.0, -9.81;
ASSERT_TRUE(gQuat.isApprox(gravityW));
ASSERT_TRUE(gEuler.isApprox(gravityW));
// test for 180° rotations
for (size_t i = 0; i < 3; i++)
{
poseQuat.setIdentity();
poseEuler.setIdentity();
// perturb one rotation to 180°
Eigen::Vector3d orientationXyz(Eigen::Vector3d::Zero());
orientationXyz(i) = M_PI;
poseQuat.setFromEulerAnglesXyz(orientationXyz);
poseEuler.setFromEulerAnglesXyz(orientationXyz);
// if we perturb in x or y gravity should point upwards
if (i < 2)
{
Eigen::Vector3d gravityUp;
gravityUp << 0.0, 0.0, 9.81;
ASSERT_TRUE(poseQuat.computeGravityB().isApprox(gravityUp));
ASSERT_TRUE(poseEuler.computeGravityB().isApprox(gravityUp));
}
else
{
// otherwise gravity is normal
Eigen::Vector3d gravityDown;
gravityDown << 0.0, 0.0, -9.81;
ASSERT_TRUE(poseQuat.computeGravityB().isApprox(gravityDown));
ASSERT_TRUE(poseEuler.computeGravityB().isApprox(gravityDown));
}
}
// test for 30° roll
poseQuat.setIdentity();
poseEuler.setIdentity();
Eigen::Vector3d orientationXyz(Eigen::Vector3d::Zero());
orientationXyz(0) = 30.0 / 180.0 * M_PI;
poseQuat.setFromEulerAnglesXyz(orientationXyz);
poseEuler.setFromEulerAnglesXyz(orientationXyz);
// x component should be zero
ASSERT_NEAR(poseQuat.computeGravityB()(0), 0.0, 1e-10);
ASSERT_NEAR(poseEuler.computeGravityB()(0), 0.0, 1e-10);
// y component should be negative
ASSERT_LT(poseQuat.computeGravityB()(1), 0.0);
ASSERT_LT(poseEuler.computeGravityB()(1), 0.0);
// z component should be negative
ASSERT_LT(poseQuat.computeGravityB()(2), 0.0);
ASSERT_LT(poseEuler.computeGravityB()(2), 0.0);
}
TEST(RigidBodyPoseTest, rotationTest)
{
RigidBodyPose poseQuat(RigidBodyPose::QUAT);
RigidBodyPose poseEuler(RigidBodyPose::EULER);
Eigen::Vector3d testVector;
testVector.setRandom();
Eigen::Vector3d rotatedVectorQuat;
Eigen::Vector3d rotatedVectorEigen;
Eigen::Vector3d baseVectorQuat = poseQuat.rotateBaseToInertia(testVector);
Eigen::Vector3d baseVectorEuler = poseEuler.rotateBaseToInertia(testVector);
Eigen::Vector3d baseVectorQuatRotMatrix = poseQuat.getRotationMatrix().toImplementation() * testVector;
Eigen::Vector3d baseVectorEulerRotMatrix = poseEuler.getRotationMatrix().toImplementation() * testVector;
ASSERT_TRUE(baseVectorQuat.isApprox(baseVectorEuler, 1e-10));
ASSERT_TRUE(baseVectorQuat.isApprox(baseVectorQuatRotMatrix, 1e-10));
ASSERT_TRUE(baseVectorQuat.isApprox(baseVectorEulerRotMatrix, 1e-10));
ASSERT_TRUE(poseQuat.rotateInertiaToBase(baseVectorQuat).isApprox(testVector, 1e-10));
ASSERT_TRUE(poseEuler.rotateInertiaToBase(baseVectorEuler).isApprox(testVector, 1e-10));
}
int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}