14 #include <pinocchio/algorithm/frames.hpp> 15 #include <pinocchio/algorithm/jacobian.hpp> 16 #include <pinocchio/algorithm/joint-configuration.hpp> 17 #include <pinocchio/algorithm/kinematics.hpp> 18 #include <pinocchio/multibody/data.hpp> 19 #include <pinocchio/multibody/liegroup/liegroup.hpp> 20 #include <pinocchio/multibody/model.hpp> 21 #include <pinocchio/parsers/sample-models.hpp> 23 #define BOOST_TEST_MODULE features 24 #include <dynamic-graph/factory.h> 28 #include <boost/test/unit_test.hpp> 48 template <Representation_t representation>
61 #define EIGEN_VECTOR_IS_APPROX(Va, Vb, precision) \ 62 BOOST_CHECK_MESSAGE((Va).isApprox(Vb, precision), \ 63 "check " #Va ".isApprox(" #Vb \ 66 << (Va).transpose() << "\n!=\n" \ 67 << (Vb).transpose() << "\n]") 68 #define EIGEN_MATRIX_IS_APPROX(Va, Vb, precision) \ 69 BOOST_CHECK_MESSAGE((Va).isApprox(Vb, precision), "check " #Va \ 83 : task_(
"task" + name), time_(0) {
84 expectedTaskOutput_.resize(dim);
93 const Vector &errorDrift) {
95 expectedTaskOutput_ = -gain * error - errorDrift;
98 template <
typename LG_t>
100 const Vector &sDesDot,
const LG_t &lg) {
102 lg.difference(sdes, s, s_sd);
104 Eigen::Matrix<typename LG_t::Scalar, LG_t::NV, LG_t::NV> Jminus(lg.nv(),
106 lg.template dDifference<pinocchio::ARG0>(sdes, s, Jminus);
108 computeExpectedTaskOutput(s_sd, Jminus * sDesDot);
113 expectedTaskOutput_.size());
114 Vector taskOutput(expectedTaskOutput_.size());
115 for (
int i = 0;
i < expectedTaskOutput_.size(); ++
i)
126 template <
typename SignalType,
typename ValueType>
135 virtual void setInputs() = 0;
171 feature_(
"feature" + name),
172 featureDes_(
"featureDes" + name),
192 BOOST_TEST_MESSAGE(
" ----- Test Velocity -----");
199 BOOST_TEST_MESSAGE(
" ----- Test Position -----");
206 BOOST_TEST_MESSAGE(
" ----- Test both -----");
235 BOOST_TEST_MESSAGE(
"----- inputs -----");
237 "feature_.errorSIN: " << feature_.
errorSIN(time_).transpose());
239 "featureDes_.errorSIN: " << featureDes_.
errorSIN(time_).transpose());
240 BOOST_TEST_MESSAGE(
"featureDes_.errordotSIN: " 242 BOOST_TEST_MESSAGE(
"task.controlGain: " << task_.controlGainSIN(time_));
252 computeExpectedTaskOutput(s - sd, -vd);
258 BOOST_TEST_MESSAGE(
"----- output -----");
259 BOOST_TEST_MESSAGE(
"time: " << time_);
261 "feature.errorSOUT: " << feature_.
errorSOUT(time_).transpose());
263 "feature.errordotSOUT: " << feature_.
errordotSOUT(time_).transpose());
264 BOOST_TEST_MESSAGE(
"task.taskSOUT: " << task_.taskSOUT(time_));
269 "Expected task output: " << expectedTaskOutput_.transpose());
273 BOOST_AUTO_TEST_SUITE(feature_generic)
276 std::string srobot(
"test");
277 unsigned int dim = 6;
281 for (
int i = 0;
i < 10; ++
i) testFeatureGeneric.
checkValue();
288 M.translation().setRandom();
289 Eigen::Vector3d
w(Eigen::Vector3d::Random());
290 M.linear() = Eigen::AngleAxisd(w.norm(), w.normalized()).matrix();
298 v.head<3>() = M.translation();
305 for (
int i = 0;
i < (int)in.size(); ++
i) out[
i] = in[
i].getSingleBound();
309 template <Representation_t representation>
312 typedef typename dg::sot::internal::LG_t<representation>::type
LieGroup_t;
322 feature_(
"feature" + name),
361 model_.
frames[fa_].placement.setIdentity();
362 model_.
frames[fb_].placement.setIdentity();
367 model_.
frames[fa_].placement.setRandom();
368 model_.
frames[fb_].placement.setRandom();
380 setSignal(feature_.
oMjb,
383 setSignal(feature_.
oMja,
391 setSignal(feature_.
jbJjb, J);
395 setSignal(feature_.
jaJja, J);
399 setSignal(feature_.
faMfbDes, randomM());
400 setSignal(feature_.
faNufafbDes, Vector::Random(6));
405 if (time_ % 2 != 0) gain = 1;
410 BOOST_TEST_MESSAGE(
"----- inputs -----");
413 BOOST_TEST_MESSAGE(
"task.controlGain: " << task_.controlGainSIN(time_));
419 const SE3 oMfb = data_.oMf[fb_], oMfa = data_.oMf[fa_],
424 computeExpectedTaskOutput(
426 (boost::is_same<LieGroup_t, SE3_t>::value
427 ? faMfbDes.toActionMatrixInverse() * nu
428 : (Vector6d() << nu.head<3>() -
429 faMfb.translation().cross(nu.tail<3>()),
430 faMfbDes.rotation().transpose() * nu.tail<3>())
438 BOOST_TEST_MESSAGE(
"----- output -----");
439 BOOST_TEST_MESSAGE(
"time: " << time_);
441 "feature.errorSOUT: " << feature_.
errorSOUT(time_).transpose());
443 "feature.errordotSOUT: " << feature_.
errordotSOUT(time_).transpose());
444 BOOST_TEST_MESSAGE(
"task.taskSOUT: " << task_.taskSOUT(time_));
449 "Expected task output: " << expectedTaskOutput_.transpose());
463 setSignal(feature_.
oMjb,
466 setSignal(feature_.
oMja,
474 setSignal(feature_.
jbJjb, J);
478 setSignal(feature_.
jaJja, J);
482 setSignal(feature_.
faMfbDes, randomM());
485 Vector e_q = task_.errorSOUT.access(time_);
486 J = task_.jacobianSOUT.access(time_);
488 Eigen::IOFormat PyVectorFmt(Eigen::FullPrecision, 0,
", ",
", ",
"",
"",
490 Eigen::IOFormat PyMatrixFmt(Eigen::FullPrecision, 0,
", ",
",\n",
"[",
"]",
493 Vector qdot(Vector::Zero(model_.
nv));
496 data_.oMi[ja_].toHomogeneousMatrix().format(PyMatrixFmt)
497 << data_.oMi[jb_].toHomogeneousMatrix().format(PyMatrixFmt)
498 << model_.
frames[fa_].placement.toHomogeneousMatrix().format(
500 << model_.
frames[fb_].placement.toHomogeneousMatrix().format(
502 << J.format(PyMatrixFmt));
504 for (
int i = 0;
i < model_.
nv; ++
i) {
511 setSignal(feature_.
oMjb,
514 setSignal(feature_.
oMja,
519 Vector e_q_dq = task_.errorSOUT.access(time_);
521 (((e_q_dq - e_q) / eps) - J.col(
i)).maxCoeff() < 1e-4,
522 "Jacobian col " <<
i <<
" does not match finite difference.\n" 523 << ((e_q_dq - e_q) / eps).format(PyVectorFmt) <<
'\n' 524 << J.col(
i).format(PyVectorFmt) <<
'\n');
545 SE3 faMfb = data_.oMf[fa_].actInv(data_.oMf[fb_]);
548 setSignal(feature_.
oMjb,
551 setSignal(feature_.
oMja,
559 setSignal(feature_.
jbJjb, J);
563 setSignal(feature_.
jaJja, J);
569 faJfafb = faMfb.toActionMatrix() * J;
575 setSignal(feature_.
faMfbDes, randomM());
578 task_.jacobianSOUT.recompute(time_);
579 J = task_.jacobianSOUT.accessCopy();
580 Eigen::JacobiSVD<Matrix> svd(J, Eigen::ComputeThinU | Eigen::ComputeThinV);
582 Vector faNufafbDes(Vector::Zero(6));
584 for (
int i = 0;
i < 6; ++
i) {
588 task_.taskSOUT.recompute(time_);
592 Vector faNufafb = faJfafb * qdot;
601 template <
typename TestClass>
605 for (
int i = 0;
i <
N; ++
i) runner.checkValue();
606 for (
int i = 0;
i < N; ++
i) runner.checkJacobian();
607 for (
int i = 0;
i < N; ++
i) runner.checkFeedForward();
610 BOOST_AUTO_TEST_SUITE(feature_pose)
612 template <Representation_t representation>
614 BOOST_TEST_MESSAGE(
"absolute " << repr);
626 feature_pose_absolute_tpl<R3xSO3Representation>(
"R3xSO3");
630 feature_pose_absolute_tpl<SE3Representation>(
"SE3");
635 template <Representation_t representation>
636 void feature_pose_relative_tpl(
const std::string &repr) {
637 BOOST_TEST_MESSAGE(
"relative " << repr);
645 BOOST_AUTO_TEST_SUITE(relative)
648 feature_pose_relative_tpl<R3xSO3Representation>(
"R3xSO3");
652 feature_pose_relative_tpl<SE3Representation>(
"SE3");
dynamicgraph::SignalPtr< MatrixHomogeneous, int > jaMfa
Input pose of Frame A wrt to Joint A.
TestFeaturePose(bool relative, const std::string &name)
void computeExpectedTaskOutput(const Vector &s, const Vector &sdes, const Vector &sDesDot, const LG_t &lg)
dg::sot::internal::LG_t< representation >::type LieGroup_t
FeatureAbstract & featureAbstract()
BOOST_AUTO_TEST_CASE(check_value)
TestFeatureGeneric(unsigned dim, const std::string &name)
SignalTimeDependent< dynamicgraph::Vector, int > errordotSOUT
Derivative of the error with respect to time: .
virtual void checkJacobian()
SignalPtr< Flags, int > selectionSIN
This vector specifies which dimension are used to perform the computation. For instance let us assume...
Eigen::Matrix< double, 7, 1 > Vector7
Eigen::Transform< double, 3, Eigen::Affine > MatrixHomogeneous
void setGain(double gain)
dynamicgraph::SignalTimeDependent< VectorMultiBound, int > taskSOUT
dynamicgraph::SignalPtr< double, int > controlGainSIN
void addFeature(FeatureAbstract &s)
virtual void setReference(const T *t, typename Signal< T, Time >::Mutex *m=NULL)
ConfigVectorType lowerPositionLimit
void computeExpectedTaskOutput(const Vector &error, const Vector &errorDrift)
Signal< dynamicgraph::Matrix, int > sig("matrix")
pinocchio::SpecialEuclideanOperationTpl< 3, double > SE3_t
pinocchio::JointIndex jb_
void setWithDerivative(const bool &s)
dynamicgraph::SignalPtr< MatrixHomogeneous, int > oMja
Input pose of Joint A wrt to world frame.
virtual void printInputs()
dynamicgraph::SignalPtr< dynamicgraph::Matrix, int > jacobianSIN
Input for the Jacobian.
void getJointJacobian(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const typename ModelTpl< Scalar, Options, JointCollectionTpl >::JointIndex jointId, const ReferenceFrame rf, const Eigen::MatrixBase< Matrix6Like > &J)
void integrate(const LieGroupGenericTpl< LieGroupCollection > &lg, const Eigen::MatrixBase< ConfigIn_t > &q, const Eigen::MatrixBase< Tangent_t > &v, const Eigen::MatrixBase< ConfigOut_t > &qout)
SignalTimeDependent< MatrixHomogeneous, int > faMfb
Pose of Frame B wrt to Frame A.
dynamicgraph::SignalTimeDependent< dynamicgraph::Vector, int > errorSOUT
void humanoid(ModelTpl< Scalar, Options, JointCollectionTpl > &model, bool usingFF=true)
dynamicgraph::SignalPtr< MatrixHomogeneous, int > jbMfb
Input pose of Frame B wrt to Joint B.
virtual void printOutputs()
SignalPtr< dynamicgraph::Vector, int > errordotSIN
Derivative of the reference value.
pinocchio::CartesianProductOperation< pinocchio::VectorSpaceOperationTpl< 3, double >, pinocchio::SpecialOrthogonalOperationTpl< 3, double > > R3xSO3_t
void feature_pose_absolute_tpl(const std::string &repr)
void setSignal(SignalType &sig, const ValueType &v)
void runTest(TestClass &runner, int N=2)
boost::mpl::if_c< representation==SE3Representation, SE3_t, R3xSO3_t >::type type
FeatureAbstract & featureAbstract()
virtual void checkFeedForward()
pinocchio::FrameIndex fb_
virtual const T & access(const Time &t)
FeatureGeneric featureDes_
void randomConfiguration(const LieGroupGenericTpl< LieGroupCollection > &lg, const Eigen::MatrixBase< ConfigL_t > &q0, const Eigen::MatrixBase< ConfigR_t > &q1, const Eigen::MatrixBase< ConfigOut_t > &qout)
FrameIndex getFrameId(const std::string &name, const FrameType &type=(FrameType)(JOINT|FIXED_JOINT|BODY|OP_FRAME|SENSOR)) const
virtual void setReference(FeatureAbstract *sdes)=0
virtual const T & accessCopy() const
dynamicgraph::SignalPtr< Matrix, int > jaJja
Jacobian of the input Joint A, expressed in Joint A
void init(bool compute_local_aabb=true)
virtual void recompute(const Time &t)
FeatureTestBase(unsigned dim, const std::string &name)
FrameIndex addFrame(const Frame &frame, const bool append_inertia=true)
JointIndex getJointId(const std::string &name) const
This class gives the abstract definition of a feature.
const DataTpl< Scalar, Options, JointCollectionTpl >::Matrix6x & computeJointJacobians(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< ConfigVectorType > &q)
BOOST_AUTO_TEST_SUITE_END() MatrixHomogeneous randomM()
Feature that controls the relative (or absolute) pose between two frames A (or world) and B...
dynamicgraph::SignalTimeDependent< dynamicgraph::Vector, int > errorTimeDerivativeSOUT
dynamicgraph::SignalPtr< Matrix, int > jbJjb
Jacobian of the input Joint B, expressed in Joint B
Vector7 toVector(const pinocchio::SE3 &M)
ConfigVectorType upperPositionLimit
virtual void checkValue()
dynamicgraph::SignalPtr< MatrixHomogeneous, int > faMfbDes
The desired pose of Frame B wrt to Frame A.
Class that defines the basic elements of a task.
virtual const T & accessCopy() const
dynamicgraph::SignalPtr< MatrixHomogeneous, int > oMjb
Input pose of Joint B wrt to world frame.
void setReady(const bool sready=true)
dynamicgraph::SignalPtr< dynamicgraph::Vector, int > errorSIN
Input for the error.
dynamicgraph::SignalPtr< Vector, int > faNufafbDes
SignalTimeDependent< dynamicgraph::Vector, int > errorSOUT
This signal returns the error between the desired value and the current value : . ...
virtual const Time & getTime() const
#define EIGEN_VECTOR_IS_APPROX(Va, Vb, precision)
void getFrameJacobian(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const FrameIndex frame_id, const ReferenceFrame rf, const Eigen::MatrixBase< Matrix6xLike > &J)
dynamicgraph::Vector expectedTaskOutput_
FeaturePose< representation > feature_
Eigen::Map< Quaternion > SOT_CORE_EXPORT QuaternionMap
void framesForwardKinematics(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< ConfigVectorType > &q)
Class that defines a generic implementation of the abstract interface for features.