Newer
Older
//
// This file is part of Pinocchio
// Pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// Pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// Pinocchio If not, see
// <http://www.gnu.org/licenses/>.
#include <iostream>
#include "pinocchio/spatial/force.hpp"
#include "pinocchio/spatial/motion.hpp"
#include "pinocchio/spatial/se3.hpp"
#include "pinocchio/spatial/inertia.hpp"
#include "pinocchio/spatial/explog.hpp"
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE tspatialTest
#include <boost/test/unit_test.hpp>
#include <boost/utility/binary.hpp>
BOOST_AUTO_TEST_SUITE ( tspatialTest)
BOOST_AUTO_TEST_CASE ( test_SE3 )
typedef Eigen::Matrix<double,4,4> Matrix4;
typedef SE3::Matrix6 Matrix6;
typedef SE3::Vector3 Vector3;
SE3 amb = SE3::Random();
SE3 bmc = SE3::Random();
SE3 amc = amb*bmc;
Matrix4 aMb = amb;
Matrix4 bMc = bmc;
// Test internal product
Matrix4 aMc = amc;
Valenza Florian
committed
BOOST_CHECK(aMc.isApprox(aMb*bMc, 1e-12));
Matrix4 bMa = amb.inverse();
Valenza Florian
committed
BOOST_CHECK(bMa.isApprox(aMb.inverse(), 1e-12));
// Test point action
Vector3 p = Vector3::Random();
Eigen::Matrix<double,4,1> p4; p4.head(3) = p; p4[3] = 1;
Vector3 Mp = (aMb*p4).head(3);
Valenza Florian
committed
BOOST_CHECK(amb.act(p).isApprox(Mp, 1e-12));
Vector3 Mip = (aMb.inverse()*p4).head(3);
Valenza Florian
committed
BOOST_CHECK(amb.actInv(p).isApprox(Mip, 1e-12));
// Test action matrix
Matrix6 aXb = amb;
Matrix6 bXc = bmc;
Matrix6 aXc = amc;
Valenza Florian
committed
BOOST_CHECK(aXc.isApprox(aXb*bXc, 1e-12));
Matrix6 bXa = amb.inverse();
Valenza Florian
committed
BOOST_CHECK(bXa.isApprox(aXb.inverse(), 1e-12));
// Test isIdentity
SE3 identity = SE3::Identity();
BOOST_CHECK(identity.isIdentity());
// Test isApprox
BOOST_CHECK(identity.isApprox(identity));
BOOST_AUTO_TEST_CASE ( test_Motion )
using namespace se3;
typedef SE3::Matrix6 Matrix6;
typedef Motion::Vector6 Vector6;
SE3 amb = SE3::Random();
SE3 bmc = SE3::Random();
SE3 amc = amb*bmc;
Motion bv = Motion::Random();
Motion bv2 = Motion::Random();
Vector6 bv_vec = bv;
Vector6 bv2_vec = bv2;
// Test .+.
Vector6 bvPbv2_vec = bv+bv2;
Valenza Florian
committed
BOOST_CHECK(bvPbv2_vec.isApprox(bv_vec+bv2_vec, 1e-12));
// Test -.
Vector6 Mbv_vec = -bv;
Valenza Florian
committed
BOOST_CHECK( Mbv_vec.isApprox(-bv_vec, 1e-12));
// Test .+=.
Motion bv3 = bv; bv3 += bv2;
Valenza Florian
committed
BOOST_CHECK( bv3.toVector().isApprox(bv_vec+bv2_vec, 1e-12));
// Test .=V6
bv3 = bv2_vec;
Valenza Florian
committed
BOOST_CHECK( bv3.toVector().isApprox(bv2_vec, 1e-12));
// Test constructor from V6
Motion bv4(bv2_vec);
Valenza Florian
committed
BOOST_CHECK( bv4.toVector().isApprox(bv2_vec, 1e-12));
// Test action
Matrix6 aXb = amb;
Valenza Florian
committed
BOOST_CHECK(amb.act(bv).toVector().isApprox(aXb*bv_vec, 1e-12));
// Test action inverse
Matrix6 bXc = bmc;
Valenza Florian
committed
BOOST_CHECK(bmc.actInv(bv).toVector().isApprox(bXc.inverse()*bv_vec, 1e-12));
// Test double action
Motion cv = Motion::Random();
bv = bmc.act(cv);
Valenza Florian
committed
BOOST_CHECK(amb.act(bv).toVector().isApprox(amc.act(cv).toVector(), 1e-12));
// Simple test for cross product vxv
Motion vxv = bv.cross(bv);
BOOST_CHECK_SMALL(vxv.toVector().tail(3).norm(), 1e-3); //previously ensure that (vxv.toVector().tail(3).isMuchSmallerThan(1e-3));
// Simple test for cross product vxf
Force vxf = bv.cross(f);
Valenza Florian
committed
BOOST_CHECK(vxf.linear().isApprox(bv.angular().cross(f.linear()), 1e-12));
BOOST_CHECK_SMALL(vxf.angular().norm(), 1e-3);//previously ensure that ( vxf.angular().isMuchSmallerThan(1e-3));
// Test frame change for vxf
Motion av = Motion::Random();
Force af = Force::Random();
bv = amb.actInv(av);
Force bf = amb.actInv(af);
Force avxf = av.cross(af);
Force bvxf = bv.cross(bf);
Valenza Florian
committed
BOOST_CHECK(avxf.toVector().isApprox(amb.act(bvxf).toVector(), 1e-12));
// Test frame change for vxv
av = Motion::Random();
Motion aw = Motion::Random();
bv = amb.actInv(av);
Motion bw = amb.actInv(aw);
Motion avxw = av.cross(aw);
Motion bvxw = bv.cross(bw);
Valenza Florian
committed
BOOST_CHECK(avxw.toVector().isApprox(amb.act(bvxw).toVector(), 1e-12));
BOOST_AUTO_TEST_CASE ( test_Force )
using namespace se3;
typedef SE3::Matrix6 Matrix6;
typedef Force::Vector6 Vector6;
SE3 amb = SE3::Random();
SE3 bmc = SE3::Random();
SE3 amc = amb*bmc;
Force bf = Force::Random();
Force bf2 = Force::Random();
Vector6 bf_vec = bf;
Vector6 bf2_vec = bf2;
// Test .+.
Vector6 bfPbf2_vec = bf+bf2;
Valenza Florian
committed
BOOST_CHECK(bfPbf2_vec.isApprox(bf_vec+bf2_vec, 1e-12));
// Test -.
Vector6 Mbf_vec = -bf;
Valenza Florian
committed
BOOST_CHECK(Mbf_vec.isApprox(-bf_vec, 1e-12));
// Test .+=.
Force bf3 = bf; bf3 += bf2;
Valenza Florian
committed
BOOST_CHECK(bf3.toVector().isApprox(bf_vec+bf2_vec, 1e-12));
// Test .= V6
bf3 = bf2_vec;
Valenza Florian
committed
BOOST_CHECK(bf3.toVector().isApprox(bf2_vec, 1e-12));
// Test constructor from V6
Force bf4(bf2_vec);
Valenza Florian
committed
BOOST_CHECK(bf4.toVector().isApprox(bf2_vec, 1e-12));
// Test action
Matrix6 aXb = amb;
Valenza Florian
committed
BOOST_CHECK(amb.act(bf).toVector().isApprox(aXb.inverse().transpose()*bf_vec, 1e-12));
// Test action inverse
Matrix6 bXc = bmc;
Valenza Florian
committed
BOOST_CHECK(bmc.actInv(bf).toVector().isApprox(bXc.transpose()*bf_vec, 1e-12));
// Test double action
Force cf = Force::Random();
bf = bmc.act(cf);
Valenza Florian
committed
BOOST_CHECK(amb.act(bf).toVector().isApprox(amc.act(cf).toVector(), 1e-12));
// Simple test for cross product
// Force vxv = bf.cross(bf);
// ensure that (vxv.toVector().isMuchSmallerThan(bf.toVector()));
BOOST_AUTO_TEST_CASE ( test_Inertia )
using namespace se3;
typedef Inertia::Matrix6 Matrix6;
Inertia aI = Inertia::Random();
Matrix6 matI = aI;
BOOST_CHECK_EQUAL(matI(0,0), aI.mass());
BOOST_CHECK_EQUAL(matI(1,1), aI.mass());
BOOST_CHECK_EQUAL(matI(2,2), aI.mass()); // 1,1 before unifying
BOOST_CHECK_SMALL((matI-matI.transpose()).norm(),matI.norm()); //previously ensure that( (matI-matI.transpose()).isMuchSmallerThan(matI) );
BOOST_CHECK_SMALL((matI.topRightCorner<3,3>()*aI.lever()).norm(),
aI.lever().norm()); //previously ensure that( (matI.topRightCorner<3,3>()*aI.lever()).isMuchSmallerThan(aI.lever()) );
Valenza Florian
committed
BOOST_CHECK(I1.matrix().isApprox(Matrix6::Identity(), 1e-12));
// Test motion-to-force map
Motion v = Motion::Random();
Force f = I1 * v;
Valenza Florian
committed
BOOST_CHECK(f.toVector().isApprox(v.toVector(), 1e-12));
// Test Inertia group application
SE3 bma = SE3::Random();
Inertia bI = bma.act(aI);
Matrix6 bXa = bma;
Valenza Florian
committed
BOOST_CHECK((bma.rotation()*aI.inertia().matrix()*bma.rotation().transpose())
.isApprox(bI.inertia().matrix(), 1e-12));
Valenza Florian
committed
BOOST_CHECK((bXa.transpose().inverse() * aI.matrix() * bXa.inverse())
.isApprox(bI.matrix(), 1e-12));
Valenza Florian
committed
BOOST_CHECK((bXa.transpose() * bI.matrix() * bXa)
.isApprox(bma.actInv(bI).matrix(), 1e-12));
// Test vxIv cross product
v = Motion::Random();
f = aI*v;
Force vxf = v.cross(f);
Force vxIv = aI.vxiv(v);
Valenza Florian
committed
BOOST_CHECK(vxf.toVector().isApprox(vxIv.toVector(), 1e-12));
// Test operator+
I1 = Inertia::Random();
Inertia I2 = Inertia::Random();
Valenza Florian
committed
BOOST_CHECK((I1.matrix()+I2.matrix()).isApprox((I1+I2).matrix(), 1e-12));

Nicolas Mansard
committed
// operator +=
Inertia I12 = I1;
I12 += I2;
Valenza Florian
committed
BOOST_CHECK((I1.matrix()+I2.matrix()).isApprox(I12.matrix(), 1e-12));
// Test operator vtiv
double kinetic_ref = v.toVector().transpose() * aI.matrix() * v.toVector();
double kinetic = aI.vtiv(v);
BOOST_CHECK_SMALL(kinetic_ref - kinetic, 1e-12);
// Test constructor (Matrix6)
Inertia I1_bis(I1.matrix());
Valenza Florian
committed
BOOST_CHECK(I1.matrix().isApprox(I1_bis.matrix(), 1e-12));
// Test Inertia from ellipsoid
I1 = Inertia::FromEllipsoid(2., 3., 4., 5.);
BOOST_CHECK_SMALL(I1.mass() - 2, 1e-12);
BOOST_CHECK_SMALL(I1.lever().norm(), 1e-12);
BOOST_CHECK(I1.inertia().matrix().isApprox(Symmetric3(
16.4, 0., 13.6, 0., 0., 10.).matrix(), 1e-12));
// Test Inertia from Cylinder
I1 = Inertia::FromCylinder(2., 4., 6.);
BOOST_CHECK_SMALL(I1.mass() - 2, 1e-12);
BOOST_CHECK_SMALL(I1.lever().norm(), 1e-12);
BOOST_CHECK(I1.inertia().matrix().isApprox(Symmetric3(
14., 0., 14., 0., 0., 16.).matrix(), 1e-12));
// Test Inertia from Box
I1 = Inertia::FromBox(2., 6., 12., 18.);
BOOST_CHECK_SMALL(I1.mass() - 2, 1e-12);
BOOST_CHECK_SMALL(I1.lever().norm(), 1e-12);
BOOST_CHECK(I1.inertia().matrix().isApprox(Symmetric3(
78., 0., 60., 0., 0., 30.).matrix(), 1e-12));
BOOST_AUTO_TEST_CASE ( test_ActOnSet )
{
const int N = 20;
typedef Eigen::Matrix<double,6,N> Matrix6N;
se3::SE3 jMi = se3::SE3::Random();
Matrix6N iF = Matrix6N::Random(),jF;
se3::forceSet::se3Action(jMi,iF,jF);
for( int k=0;k<N;++k )
Valenza Florian
committed
BOOST_CHECK(jMi.act(se3::Force(iF.col(k))).toVector().isApprox(jF.col(k), 1e-12));
Matrix6N iV = Matrix6N::Random(),jV;
se3::motionSet::se3Action(jMi,iV,jV);
for( int k=0;k<N;++k )
Valenza Florian
committed
BOOST_CHECK(jMi.act(se3::Motion(iV.col(k))).toVector().isApprox(jV.col(k), 1e-12));
BOOST_AUTO_TEST_SUITE_END ()