diff --git a/CMakeLists.txt b/CMakeLists.txt index 9019c826452137218e61f689b2e1aed76d810a1c..34acf4e90b5eb087402524e575d75239fcfe1ab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ SET(libs integrator-force angle-estimator waist-attitude-from-sensor + zmp-from-forces ) LIST(APPEND libs dynamic) diff --git a/src/dynamic_graph/sot/dynamics/__init__.py b/src/dynamic_graph/sot/dynamics/__init__.py index 5604b54e8ebce7763f55866827b4b5c4f48fe825..dc52898d36dac21b62f09d2d0fc9df9fc13dae4a 100755 --- a/src/dynamic_graph/sot/dynamics/__init__.py +++ b/src/dynamic_graph/sot/dynamics/__init__.py @@ -1,2 +1,3 @@ from dynamic import Dynamic from angle_estimator import AngleEstimator +from zmp_from_forces import ZmpFromForces diff --git a/src/zmp-from-forces.cpp b/src/zmp-from-forces.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81ea9b9fba659ee097cd4b3859d143dfcfbce5d3 --- /dev/null +++ b/src/zmp-from-forces.cpp @@ -0,0 +1,126 @@ +/* + * Copyright 2012, + * Florent Lamiraux + * + * CNRS + * + * This file is part of sot-dynamic. + * sot-dynamic 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. + * sot-dynamic 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 Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with sot-dynamic. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <vector> +#include <sstream> + +#include <dynamic-graph/linear-algebra.h> +#include <dynamic-graph/entity.h> +#include <dynamic-graph/factory.h> +#include <dynamic-graph/signal-ptr.h> +#include <dynamic-graph/signal-time-dependent.h> +#include <sot/core/matrix-homogeneous.hh> + +namespace sot { + namespace dynamic { + using dynamicgraph::Entity; + using dynamicgraph::SignalPtr; + using dynamicgraph::SignalTimeDependent; + using dynamicgraph::sot::MatrixHomogeneous; + using dynamicgraph::Vector; + + class ZmpFromForces : public Entity + { + DYNAMIC_GRAPH_ENTITY_DECL(); + public: + static const unsigned int footNumber = 2; + ZmpFromForces (const std::string& name) : + Entity (name), + zmpSOUT_ (CLASS_NAME + "::output(Vector)::zmp") + { + zmpSOUT_.setFunction (boost::bind + (&ZmpFromForces::computeZmp, this, _1, _2)); + signalRegistration (zmpSOUT_); + for (unsigned int i=0; i<footNumber; i++) { + std::ostringstream forceName, positionName; + forceName << CLASS_NAME << "::input(vector6)::force_" << i; + positionName << CLASS_NAME << "::input(MatrixHomo)::sensorPosition_" + << i; + forcesSIN_ [i] = new SignalPtr <Vector, int> (0, forceName.str ()); + sensorPositionsSIN_ [i] = new SignalPtr <MatrixHomogeneous, int> + (0, positionName.str ()); + signalRegistration (*forcesSIN_ [i]); + signalRegistration (*sensorPositionsSIN_ [i]); + zmpSOUT_.addDependency (*forcesSIN_ [i]); + zmpSOUT_.addDependency (*sensorPositionsSIN_ [i]); + } + } + virtual std::string getDocString () const + { + std::string docstring = + "Compute ZMP from force sensor measures and positions\n" + "\n" + " Takes 4 signals as input:\n" + " - force_0: wrench measured by force sensor 0 as a 6 dimensional vector\n" + " - force_0: wrench measured by force sensor 1 as a 6 dimensional vector\n" + " - sensorPosition_0: position of force sensor 0\n" + " - sensorPosition_1: position of force sensor 1\n" + " \n" + " compute the Zero Momentum Point of the contact forces as measured by the \n" + " input signals under the asumptions that the contact points between the\n" + " robot and the environment are located in the same horizontal plane.\n"; + return docstring; + } + private: + Vector& computeZmp (Vector& zmp, int time) + { + double fz [footNumber]; + double fnormal = 0; + double sumZmpx = 0; + double sumZmpy = 0; + double sumZmpz = 0; + zmp.resize (3); + + for (unsigned int i=0; i<footNumber; ++i) { + const Vector& f = forcesSIN_ [i]->access (time); + // Check that force is of dimension 6 + if (f.size () != 6) { + zmp.fill (0.); + return zmp; + } + const MatrixHomogeneous& M = sensorPositionsSIN_ [i]->access (time); + fz [i] = M (2,0) * f (0) + M(2,1) * f (1) + M (2,2) * f (2); + if (fz[i] > 0) { + double Mx = M (0,0)*f(3) + M (0,1)*f(4) + M (0,2)*f(5) + + M (1,3)*(M(2,0)*f(0)+M(2,1)*f(1)+M(2,2)*f(2)); + double My = M (1,0)*f(3) + M (1,1)*f(4) + M (1,2)*f(5) - + M (1,3)*(M(1,0)*f(0)+M(1,1)*f(1)+M(1,2)*f(2)); + fnormal += fz[i]; + sumZmpx -= My; + sumZmpy += Mx; + sumZmpz += fz [i] * M (2,3); + } + } + if (fnormal != 0) { + zmp (0) = sumZmpx / fnormal; + zmp (1) = sumZmpy / fnormal; + zmp (2) = sumZmpz / fnormal; + } else { + zmp.fill (0.); + } + return zmp; + } + // Force as measured by force sensor on the foot + SignalPtr <Vector, int>* forcesSIN_ [footNumber]; + SignalPtr <MatrixHomogeneous, int>* sensorPositionsSIN_ [footNumber]; + SignalTimeDependent <Vector, int> zmpSOUT_; + }; // class ZmpFromForces + DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN (ZmpFromForces, "ZmpFromForces"); + } // namespace dynamic +} // namespace sot