diff --git a/CMakeLists.txt b/CMakeLists.txt index 4349318021..bcc5284fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ OPTION(ENABLE_VECTORIZATION "Enable vectorization and further processor-related OPTION(BUILD_PYTHON_INTERFACE "Build the python binding" ON) OPTION(BUILD_BENCHMARK "Build the benchmark" ON) OPTION(BUILD_EXAMPLES "Build the examples" ON) +OPTION(BUILD_UNIT_TESTS "Build the unitary tests" OFF) IF(DEFINED BUILD_UNIT_TESTS) MESSAGE(AUTHOR_WARNING "BUILD_UNIT_TESTS is deprecated. Use BUILD_TESTING instead.\ diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt new file mode 100644 index 0000000000..ed97d539c0 --- /dev/null +++ b/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/bindings/python/crocoddyl/__init__.py b/bindings/python/crocoddyl/__init__.py index 6f552a8a41..b43783ddb6 100644 --- a/bindings/python/crocoddyl/__init__.py +++ b/bindings/python/crocoddyl/__init__.py @@ -180,7 +180,8 @@ def getForceTrajectoryFromSolver(self, solver): joint = model.differential.state.pinocchio.frames[contact.frame].parent oMf = contact.pinocchio.oMi[joint] * contact.jMf fiMo = pinocchio.SE3(contact.pinocchio.oMi[joint].rotation.T, contact.jMf.translation) - force = fiMo.actInv(contact.f) + # force = fiMo.actInv(contact.f) + force = contact.jMf.actInv(contact.f) R = np.eye(3) mu = 0.7 for k, c in model.differential.costs.costs.todict().items(): diff --git a/bindings/python/crocoddyl/core/core.cpp b/bindings/python/crocoddyl/core/core.cpp index 4f2dff9164..c386d34e66 100644 --- a/bindings/python/crocoddyl/core/core.cpp +++ b/bindings/python/crocoddyl/core/core.cpp @@ -28,6 +28,7 @@ void exposeCore() { exposeIntegratedActionEuler(); exposeIntegratedActionRK(); exposeIntegratedActionRK4(); + exposeIntegratedActionLPF(); exposeCostAbstract(); exposeResidualControl(); exposeCostSum(); diff --git a/bindings/python/crocoddyl/core/core.hpp b/bindings/python/crocoddyl/core/core.hpp index 6e2a29c9bd..3c11927dd6 100644 --- a/bindings/python/crocoddyl/core/core.hpp +++ b/bindings/python/crocoddyl/core/core.hpp @@ -30,6 +30,7 @@ void exposeDataCollectorActuation(); void exposeIntegratedActionEuler(); void exposeIntegratedActionRK(); void exposeIntegratedActionRK4(); +void exposeIntegratedActionLPF(); void exposeCostAbstract(); void exposeResidualControl(); void exposeCostSum(); diff --git a/bindings/python/crocoddyl/core/integrator/lpf.cpp b/bindings/python/crocoddyl/core/integrator/lpf.cpp new file mode 100644 index 0000000000..82b7a24315 --- /dev/null +++ b/bindings/python/crocoddyl/core/integrator/lpf.cpp @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (C) 2019-2020, LAAS-CNRS, University of Edinburgh +// Copyright note valid unless otherwise stated in individual files. +// All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#include // to avoid compilation error (https://github.com/loco-3d/crocoddyl/issues/205) + +#include "python/crocoddyl/core/core.hpp" +#include "python/crocoddyl/core/action-base.hpp" +#include "crocoddyl/core/integrator/lpf.hpp" + +namespace crocoddyl { +namespace python { + +void exposeIntegratedActionLPF() { + bp::class_ >( + "IntegratedActionModelLPF", + "Sympletic Euler integrator for differential action models.\n\n" + "This class implements a sympletic Euler integrator (a.k.a semi-implicit\n" + "integrator) give a differential action model, i.e.:\n" + " [q+, v+, tau+] = StateLPF.integrate([q, v], [v + a * dt, a * dt] * dt, [alpha*tau + (1-alpha)*w]).", + bp::init, bp::optional >( + bp::args("self", "diffModel", "stepTime", "withCostResidual", + "fc", "cost_weight_w_reg", "cost_ref_w_reg", "w_gravity_reg", "cost_weight_w_lim", "tau_plus_integration", "filter", "is_terminal"), + "Initialize the sympletic Euler integrator.\n\n" + ":param diffModel: differential action model\n" + ":param stepTime: step time\n" + ":param withCostResidual: includes the cost residuals and derivatives\n" + ":param fc: LPF parameter depending on cut-off frequency alpha=1/(1+2*Pi*dt*fc)\n" + ":param cost_weight_w_reg: cost weight on unfiltered torque regularization\n" + ":param cost_ref_w_reg: cost reference on unfiltered torque regularization\n" + ":param w_gravity_reg: use gravity regularization on unfiltered torque (True) or user-provided constant reference (False) " + ":param cost_weight_w_lim: cost weight on unfiltered torque limit\n" + ":param tau_plus_integration: use tau+=LPF(tau,w) in acceleration computation, or tau\n" + ":param filter: type of low-pass filter (0 = Expo Moving Avg, 1 = Classical, 2 = Exact)\n" + ":param is_terminal: terminal model or not.")) + .def&, + const Eigen::Ref&, + const Eigen::Ref&)>( + "calc", &IntegratedActionModelLPF::calc, bp::args("self", "data", "x", "u"), + "Compute the time-discrete evolution of a differential action model.\n\n" + "It describes the time-discrete evolution of action model.\n" + ":param data: action data\n" + ":param x: state vector\n" + ":param u: control input") + .def&, + const Eigen::Ref&)>( + "calc", &ActionModelAbstract::calc, bp::args("self", "data", "x")) + .def&, + const Eigen::Ref&, + const Eigen::Ref&)>( + "calcDiff", &IntegratedActionModelLPF::calcDiff, bp::args("self", "data", "x", "u"), + "Computes the derivatives of the integrated action model wrt state and control. \n\n" + "This function builds a quadratic approximation of the\n" + "action model (i.e. dynamical system and cost function).\n" + "It assumes that calc has been run first.\n" + ":param data: action data\n" + ":param x: state vector\n" + ":param u: control input\n") + .def&, + const Eigen::Ref&)>( + "calcDiff", &ActionModelAbstract::calcDiff, bp::args("self", "data", "x")) + .def("createData", &IntegratedActionModelLPF::createData, bp::args("self"), + "Create the Euler integrator data.") + .add_property("differential", + bp::make_function(&IntegratedActionModelLPF::get_differential, + bp::return_value_policy()), + &IntegratedActionModelLPF::set_differential, "differential action model") + .add_property( + "dt", bp::make_function(&IntegratedActionModelLPF::get_dt, bp::return_value_policy()), + &IntegratedActionModelLPF::set_dt, "step time") + .add_property( + "fc", bp::make_function(&IntegratedActionModelLPF::get_fc, bp::return_value_policy()), + &IntegratedActionModelLPF::set_fc, "cut-off frequency of low-pass filter"); + + bp::register_ptr_to_python >(); + + bp::class_ >( + "IntegratedActionDataLPF", "Sympletic Euler integrator data.", + bp::init(bp::args("self", "model"), + "Create sympletic Euler integrator data.\n\n" + ":param model: sympletic Euler integrator model")) + .add_property( + "differential", + bp::make_getter(&IntegratedActionDataLPF::differential, bp::return_value_policy()), + "differential action data") + .add_property("dy", bp::make_getter(&IntegratedActionDataLPF::dy, bp::return_internal_reference<>()), + "state rate."); +} + +} // namespace python +} // namespace crocoddyl diff --git a/bindings/python/crocoddyl/multibody/multibody.cpp b/bindings/python/crocoddyl/multibody/multibody.cpp index 149a8be10e..193174a195 100644 --- a/bindings/python/crocoddyl/multibody/multibody.cpp +++ b/bindings/python/crocoddyl/multibody/multibody.cpp @@ -17,6 +17,7 @@ void exposeMultibody() { exposeWrenchCone(); exposeCoPSupport(); exposeStateMultibody(); + exposeStateLPF(); exposeActuationFloatingBase(); exposeActuationFull(); exposeActuationModelMultiCopterBase(); diff --git a/bindings/python/crocoddyl/multibody/multibody.hpp b/bindings/python/crocoddyl/multibody/multibody.hpp index 1477bbe8d5..c5f154bbc4 100644 --- a/bindings/python/crocoddyl/multibody/multibody.hpp +++ b/bindings/python/crocoddyl/multibody/multibody.hpp @@ -20,6 +20,7 @@ void exposeFrictionCone(); void exposeWrenchCone(); void exposeCoPSupport(); void exposeStateMultibody(); +void exposeStateLPF(); void exposeActuationFloatingBase(); void exposeActuationFull(); void exposeActuationModelMultiCopterBase(); diff --git a/bindings/python/crocoddyl/multibody/states/statelpf.cpp b/bindings/python/crocoddyl/multibody/states/statelpf.cpp new file mode 100644 index 0000000000..7f3b7e3a12 --- /dev/null +++ b/bindings/python/crocoddyl/multibody/states/statelpf.cpp @@ -0,0 +1,86 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (C) 2019-2020, LAAS-CNRS, University of Edinburgh +// Copyright note valid unless otherwise stated in individual files. +// All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#include "python/crocoddyl/multibody/multibody.hpp" +#include "python/crocoddyl/core/state-base.hpp" +#include "crocoddyl/multibody/states/statelpf.hpp" + +namespace crocoddyl { +namespace python { + +void exposeStateLPF() { + bp::class_ >( + "StateLPF", + "LPF state defined using Pinocchio.\n\n" + "Pinocchio defines operators for integrating or differentiating the robot's\n" + "configuration space. And here we assume that the state is defined by the\n" + "robot's configuration, joint velocities and torques (y=[q,v,u]). Generally speaking,\n" + "q lies on the manifold configuration manifold (M) and v in its tangent space\n" + "(Ty M). Additionally the Pinocchio allows us to compute analytically the\n" + "Jacobians for the differentiate and integrate operators. Note that this code\n" + "can be reused in any robot that is described through its Pinocchio model.", + bp::init, bp::optional >( + bp::args("self", "pinocchioModel", "nu"), + "Initialize the multibody state given a Pinocchio model.\n\n" + ":param pinocchioModel: pinocchio model (i.e. multibody model)\n" + ":param nu: size of control vector.")[bp::with_custodian_and_ward<1, 2>()]) + .def("zero", &StateLPF::zero, bp::args("self"), + "Return the neutral robot configuration with zero velocity.\n\n" + ":return neutral robot configuration with zero velocity") + .def("rand", &StateLPF::rand, bp::args("self"), + "Return a random reference state.\n\n" + ":return random reference state") + .def("diff", &StateLPF::diff_dx, bp::args("self", "y0", "y1"), + "Operator that differentiates the two robot states.\n\n" + "It returns the value of y1 [-] y0 operation. This operator uses the Lie\n" + "algebra since the robot's root could lie in the SE(3) manifold.\n" + ":param y0: current state (dim state.ny()).\n" + ":param y1: next state (dim state.ny()).\n" + ":return y1 - y0 value (dim state.ny()).") + .def("integrate", &StateLPF::integrate_x, bp::args("self", "y", "dy"), + "Operator that integrates the current robot state.\n\n" + "It returns the value of y [+] dy operation. This operator uses the Lie\n" + "algebra since the robot's root could lie in the SE(3) manifold.\n" + "Futhermore there is no timestep here (i.e. dy = v*dt), note this if you're\n" + "integrating a velocity v during an interval dt.\n" + ":param y: current state (dim state.ny()).\n" + ":param dy: displacement of the state (dim state.ndy()).\n" + ":return y + dy value (dim state.ny()).") + .def("Jdiff", &StateLPF::Jdiff_Js, + Jdiffs(bp::args("self", "y0", "y1", "firstsecond"), + "Compute the partial derivatives of the diff operator.\n\n" + "Both Jacobian matrices are represented throught an identity matrix, with the exception\n" + "that the robot's root is defined as free-flying joint (SE(3)). By default, this\n" + "function returns the derivatives of the first and second argument (i.e.\n" + "firstsecond='both'). However we ask for a specific partial derivative by setting\n" + "firstsecond='first' or firstsecond='second'.\n" + ":param y0: current state (dim state.ny()).\n" + ":param y1: next state (dim state.ny()).\n" + ":param firstsecond: desired partial derivative\n" + ":return the partial derivative(s) of the diff(y0, y1) function")) + .def("Jintegrate", &StateLPF::Jintegrate_Js, + Jintegrates(bp::args("self", "y", "dy", "firstsecond"), + "Compute the partial derivatives of arithmetic addition.\n\n" + "Both Jacobian matrices are represented throught an identity matrix. with the exception\n" + "that the robot's root is defined as free-flying joint (SE(3)). By default, this\n" + "function returns the derivatives of the first and second argument (i.e.\n" + "firstsecond='both'). However we ask for a specific partial derivative by setting\n" + "firstsecond='first' or firstsecond='second'.\n" + ":param x: current state (dim state.ny()).\n" + ":param dy: displacement of the state (dim state.ndy()).\n" + ":param firstsecond: desired partial derivative\n" + ":return the partial derivative(s) of the integrate(x, dy) function")) + .add_property("pinocchio", + bp::make_function(&StateLPF::get_pinocchio, bp::return_value_policy()), + "pinocchio model"); + // .add_property("ny", bp::make_getter(&StateLPF::ny_, bp::return_internal_reference<>())); + // .add_property("nw", bp::make_getter(&StateLPF::ny_, bp::return_internal_reference<>())); +} + +} // namespace python +} // namespace crocoddyl diff --git a/include/crocoddyl/core/fwd.hpp b/include/crocoddyl/core/fwd.hpp index cee2702ae1..21c44429a5 100644 --- a/include/crocoddyl/core/fwd.hpp +++ b/include/crocoddyl/core/fwd.hpp @@ -76,6 +76,10 @@ template class ResidualModelAbstractTpl; template struct ResidualDataAbstractTpl; +template +class IntegratedActionModelLPFTpl; +template +struct IntegratedActionDataLPFTpl; // activation template @@ -276,6 +280,10 @@ typedef ResidualModelAbstractTpl ResidualModelAbstract; typedef ResidualDataAbstractTpl ResidualDataAbstract; typedef ResidualModelControlTpl ResidualModelControl; typedef ResidualDataControlTpl ResidualDataControl; +typedef IntegratedActionModelRK4Tpl IntegratedActionModelRK4; +typedef IntegratedActionDataRK4Tpl IntegratedActionDataRK4; +typedef IntegratedActionModelLPFTpl IntegratedActionModelLPF; +typedef IntegratedActionDataLPFTpl IntegratedActionDataLPF; typedef ActivationDataQuadraticBarrierTpl ActivationDataQuadraticBarrier; typedef ActivationModelQuadraticBarrierTpl ActivationModelQuadraticBarrier; diff --git a/include/crocoddyl/core/integrator/lpf.hpp b/include/crocoddyl/core/integrator/lpf.hpp new file mode 100644 index 0000000000..8d63d78caa --- /dev/null +++ b/include/crocoddyl/core/integrator/lpf.hpp @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (C) 2018-2020, LAAS-CNRS, University of Edinburgh +// Copyright note valid unless otherwise stated in individual files. +// All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef CROCODDYL_CORE_INTEGRATOR_LPF_HPP_ +#define CROCODDYL_CORE_INTEGRATOR_LPF_HPP_ + +#include "crocoddyl/core/fwd.hpp" + +#include "crocoddyl/core/action-base.hpp" // IAMAbs IADabs +#include "crocoddyl/core/diff-action-base.hpp" // DAMabs, DADabs + +#include "crocoddyl/multibody/states/statelpf.hpp" +#include "crocoddyl/multibody/states/multibody.hpp" // for static cast into state multibody +#include "crocoddyl/multibody/data/multibody.hpp" // for pinocchio data? + +#include "crocoddyl/multibody/fwd.hpp" // DAMffwd and DADffwd + +#include "crocoddyl/multibody/actions/free-fwddyn.hpp" + +#include "crocoddyl/core/activations/quadratic-barrier.hpp" + +#include + +#include +#include + +namespace crocoddyl { + +template +class IntegratedActionModelLPFTpl : public ActionModelAbstractTpl<_Scalar> { + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + typedef _Scalar Scalar; + typedef MathBaseTpl MathBase; + typedef ActionModelAbstractTpl Base; + typedef IntegratedActionDataLPFTpl Data; + typedef ActionDataAbstractTpl ActionDataAbstract; + typedef DifferentialActionModelAbstractTpl DifferentialActionModelAbstract; + typedef typename MathBase::VectorXs VectorXs; + typedef typename MathBase::MatrixXs MatrixXs; + typedef StateLPFTpl StateLPF; + typedef StateMultibodyTpl StateMultibody; + typedef pinocchio::ModelTpl PinocchioModel; + typedef ActivationModelQuadraticBarrierTpl ActivationModelQuadraticBarrier; + typedef ActivationBoundsTpl ActivationBounds; + + IntegratedActionModelLPFTpl(boost::shared_ptr model, + const Scalar& time_step = Scalar(1e-3), + const bool& with_cost_residual = true, + const Scalar& fc = 0, + const Scalar& cost_weight_w_reg = 2e-2, + const VectorXs& cost_ref_w_reg = VectorXs::Zero(7), + const bool& w_gravity_reg = true, + const Scalar& cost_weight_w_lim = 1., + const bool& tau_plus_integration = true, + const int& filter = 0, + const bool& is_terminal = false); + virtual ~IntegratedActionModelLPFTpl(); + + virtual void calc(const boost::shared_ptr& data, const Eigen::Ref& y, + const Eigen::Ref& w); + virtual void calcDiff(const boost::shared_ptr& data, const Eigen::Ref& y, + const Eigen::Ref& w); + // virtual void setAlpha(const Scalar& f_c); + virtual boost::shared_ptr createData(); + virtual bool checkData(const boost::shared_ptr& data); + + virtual void quasiStatic(const boost::shared_ptr& data, Eigen::Ref u, + const Eigen::Ref& x, const std::size_t& maxiter = 100, + const Scalar& tol = Scalar(1e-9)); + + const boost::shared_ptr& get_differential() const; + const Scalar& get_dt() const; + const Scalar& get_fc() const; + + void set_dt(const Scalar& dt); + void set_fc(const Scalar& fc); + void set_differential(boost::shared_ptr model); + + void compute_alpha(const Scalar& fc); + + protected: + using Base::has_control_limits_; //!< Indicates whether any of the control limits are active + using Base::nr_; //!< Dimension of the cost residual + using Base::nu_; //!< Control dimension + using Base::u_lb_; //!< Lower control limits + using Base::u_ub_; //!< Upper control limits + using Base::unone_; //!< Neutral state + std::size_t nw_; //!< Unfiltered torque dimension + std::size_t ny_; //!< Augmented state dimension + using Base::state_; //!< Model of the state + + public: + boost::shared_ptr activation_model_w_lim_; //!< for lim cost + ActivationBounds activation_bounds_w_lim_; //!< for lim cost + + private: + boost::shared_ptr differential_; + Scalar time_step_; + Scalar time_step2_; + Scalar fc_; + Scalar alpha_; + bool with_cost_residual_; + bool enable_integration_; + Scalar cost_weight_w_reg_; //!< Cost weight for unfiltered torque regularization + VectorXs cost_ref_w_reg_; //!< Cost reference for unfiltered torque regularization + bool w_gravity_reg_; //!< Use gravity torque for unfiltered torque reg, or user-provided reference? + Scalar cost_weight_w_lim_; //!< Cost weight for unfiltered torque limits + bool tau_plus_integration_; //!< Use tau+ = LPF(tau,w) in acceleration computation, or tau + int filter_; //!< Type of LPF used> + boost::shared_ptr pin_model_; //!< for reg cost + bool is_terminal_; //!< is it a terminal model or not ? (deactivate cost on w if true) + +}; + +template +struct IntegratedActionDataLPFTpl : public ActionDataAbstractTpl<_Scalar> { + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + typedef _Scalar Scalar; + typedef MathBaseTpl MathBase; + typedef ActionDataAbstractTpl Base; + typedef typename MathBase::VectorXs VectorXs; + typedef typename MathBase::MatrixXs MatrixXs; + typedef pinocchio::DataTpl PinocchioData; + typedef DifferentialActionDataAbstractTpl DifferentialActionDataAbstract; + typedef DifferentialActionDataFreeFwdDynamicsTpl DifferentialActionDataFreeFwdDynamics; + typedef ActivationDataQuadraticBarrierTpl ActivationDataQuadraticBarrier; // for lim cost + + template