Skip to content
Snippets Groups Projects
angle-estimator.cpp 11.55 KiB
/*
 * Copyright 2010,
 * François Bleibel,
 * Olivier Stasse,
 *
 * CNRS/AIST
 *
 * This file is part of sot-dynamic-pinocchio.
 * sot-dynamic-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.
 * sot-dynamic-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 Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-dynamic-pinocchio.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <sot-dynamic-pinocchio/angle-estimator.h>
#include <sot/core/debug.hh>
#include <dynamic-graph/factory.h>
#include <dynamic-graph/command.h>
#include <dynamic-graph/command-setter.h>
#include <dynamic-graph/command-getter.h>


using namespace dynamicgraph::sot;
using namespace dynamicgraph;

DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(AngleEstimator,"AngleEstimator");

AngleEstimator::
AngleEstimator( const std::string & name )
  :Entity(name)
  ,sensorWorldRotationSIN(NULL,"sotAngleEstimator("+name
			  +")::input(MatrixRotation)::sensorWorldRotation")
  ,sensorEmbeddedPositionSIN(NULL,"sotAngleEstimator("+name
			     +")::input(MatrixHomo)::sensorEmbeddedPosition")
  ,contactWorldPositionSIN(NULL,"sotAngleEstimator("+name
			   +")::input(MatrixHomo)::contactWorldPosition")
  ,contactEmbeddedPositionSIN(NULL,"sotAngleEstimator("+name
			      +")::input(MatrixHomo)::contactEmbeddedPosition")

  ,anglesSOUT( boost::bind(&AngleEstimator::computeAngles,this,_1,_2),
	       sensorWorldRotationSIN<<sensorEmbeddedPositionSIN
	       <<contactWorldPositionSIN<<contactEmbeddedPositionSIN,
	       "sotAngleEstimator("+name+")::output(Vector)::angles" )
   ,flexibilitySOUT( boost::bind(&AngleEstimator::computeFlexibilityFromAngles
				 ,this,_1,_2),
		     anglesSOUT,
		     "sotAngleEstimator("+name+")::output(matrixRotation)::flexibility" )
   ,driftSOUT( boost::bind(&AngleEstimator::computeDriftFromAngles,this,_1,_2),
	       anglesSOUT,
	       "sotAngleEstimator("+name+")::output(matrixRotation)::drift" )
   ,sensorWorldRotationSOUT( boost::bind(&AngleEstimator::computeSensorWorldRotation
					 ,this,_1,_2),
			     anglesSOUT<<sensorWorldRotationSIN,
			     "sotAngleEstimator("+name
			     +")::output(matrixRotation)::sensorCorrectedRotation" )
   ,waistWorldRotationSOUT( boost::bind(&AngleEstimator::computeWaistWorldRotation
					,this,_1,_2),
			    sensorWorldRotationSOUT<<sensorEmbeddedPositionSIN,
			    "sotAngleEstimator("+name
			    +")::output(matrixRotation)::waistWorldRotation" )
   ,waistWorldPositionSOUT( boost::bind(&AngleEstimator::computeWaistWorldPosition
					,this,_1,_2),
			    flexibilitySOUT << contactEmbeddedPositionSIN,
			    "sotAngleEstimator("+name
			    +")::output(MatrixHomogeneous)::waistWorldPosition" )
   ,waistWorldPoseRPYSOUT( boost::bind(&AngleEstimator::computeWaistWorldPoseRPY
				       ,this,_1,_2),
			   waistWorldPositionSOUT,
			    "sotAngleEstimator("+name
			    +")::output(vectorRollPitchYaw)::waistWorldPoseRPY" )

  ,jacobianSIN(NULL,"sotAngleEstimator("+name
			     +")::input()::jacobian")
  ,qdotSIN(NULL,"sotAngleEstimator("+name
			     +")::input()::qdot")
  ,xff_dotSOUT( boost::bind(&AngleEstimator::compute_xff_dotSOUT,this,_1,_2)
		,jacobianSIN<<qdotSIN
		,"sotAngleEstimator("+name+")::output(vector)::xff_dot" )
  ,qdotSOUT( boost::bind(&AngleEstimator::compute_qdotSOUT,this,_1,_2)
	     ,xff_dotSOUT<<qdotSIN
	     ,"sotAngleEstimator("+name+")::output(vector)::qdotOUT" )

   ,fromSensor_(true)
{
  sotDEBUGIN(5);

  signalRegistration(sensorWorldRotationSIN);
  signalRegistration(sensorEmbeddedPositionSIN);
  signalRegistration(contactWorldPositionSIN);
  signalRegistration(contactEmbeddedPositionSIN);
  signalRegistration(anglesSOUT);
  signalRegistration(flexibilitySOUT);
  signalRegistration(driftSOUT);
  signalRegistration(sensorWorldRotationSOUT);
  signalRegistration(waistWorldRotationSOUT);
  signalRegistration(waistWorldPositionSOUT);
  signalRegistration(waistWorldPoseRPYSOUT);
  signalRegistration(jacobianSIN);
  signalRegistration(qdotSIN);
  signalRegistration(xff_dotSOUT);
  signalRegistration(qdotSOUT);

  /* Commands. */
  {
    std::string docstring;
    docstring = "    \n"
      "    Set flag specifying whether angle is measured from sensors or simulated.\n"
      "    \n"
      "      Input:\n"
      "        - a boolean value.\n"
      "    \n";
    addCommand("setFromSensor",
	       new ::dynamicgraph::command::Setter<AngleEstimator, bool>
	       (*this, &AngleEstimator::fromSensor, docstring));

    docstring = "    \n"
      "    Get flag specifying whether angle is measured from sensors or simulated.\n"
      "    \n"
      "      No input,\n"
      "      return a boolean value.\n"
      "    \n";
    addCommand("getFromSensor",
	       new ::dynamicgraph::command::Getter<AngleEstimator, bool>
	       (*this, &AngleEstimator::fromSensor, docstring));
  }

  sotDEBUGOUT(5);
}


AngleEstimator::
~AngleEstimator( void )
{
  sotDEBUGIN(5);

  sotDEBUGOUT(5);
  return;
}

/* --- SIGNALS -------------------------------------------------------------- */
/* --- SIGNALS -------------------------------------------------------------- */
/* --- SIGNALS -------------------------------------------------------------- */
dynamicgraph::Vector& AngleEstimator::
computeAngles( dynamicgraph::Vector& res,
	       const int& time )
{
  sotDEBUGIN(15);

  res.resize(3);

  const MatrixRotation &worldestRchest = sensorWorldRotationSIN( time );
  sotDEBUG(35) << "worldestRchest = " << std::endl << worldestRchest;
  const MatrixHomogeneous &waistMchest = sensorEmbeddedPositionSIN( time );
  MatrixRotation waistRchest; waistRchest = waistMchest.linear();

  const MatrixHomogeneous & waistMleg = contactEmbeddedPositionSIN( time );
  MatrixRotation waistRleg; waistRleg = waistMleg.linear();
  MatrixRotation chestRleg; chestRleg = waistRchest.transpose()*waistRleg;
  MatrixRotation worldestRleg; worldestRleg = worldestRchest*chestRleg;

  sotDEBUG(35) << "worldestRleg = " << std::endl << worldestRleg;

  /* Euler angles with following code: (-z)xy, -z being the yaw drift, x the
   * first flexibility and y the second flexibility. */
  const double TOLERANCE_TH = 1e-6;

  const MatrixRotation &R = worldestRleg;
  if( (fabs(R(0,1))<TOLERANCE_TH)&&(fabs(R(1,1))<TOLERANCE_TH) )
    {
      /* This means that cos(X) is very low, ie flex1 is close to 90deg.
       * I take the case into account, but it is bloody never going
       * to happens. */
      if( R(2,1)>0 ) res(0)=M_PI/2; else res(0) = -M_PI/2;
      res(2) = atan2( -R(0,2),R(0,0) );
      res(1) = 0;

      /* To sum up: if X=PI/2, then Y and Z are in singularity.
       * we cannot decide both of then. I fixed Y=0, which
       * means that all the measurement coming from the sensor
       * is assumed to be drift of the gyro. */
    }
  else
    {
      double &X = res(0);
      double &Y = res(1);
      double &Z = res(2);

      Y = atan2( R(2,0),R(2,2) );
      Z = atan2( R(0,1),R(1,1) );
      if( fabs(R(2,0))>fabs(R(2,2)) )
	{ X=atan2( R(2,1)*sin(Y),R(2,0) ); }
      else
	{ X=atan2( R(2,1)*cos(Y),R(2,2) ); }
    }

  sotDEBUG(35) << "angles = " << res;

  sotDEBUGOUT(15);
  return res;
}

/* compute the transformation matrix of the flexibility, ie
 * feetRleg.
 */
MatrixRotation& AngleEstimator::
computeFlexibilityFromAngles( MatrixRotation& res,
			      const int& time )
{
  sotDEBUGIN(15);

  const dynamicgraph::Vector & angles = anglesSOUT( time );
  double cx= cos( angles(0) );
  double sx= sin( angles(0) );
  double cy= cos( angles(1) );
  double sy= sin( angles(1) );

  res(0,0) = cy;
  res(0,1) = 0;
  res(0,2) = -sy;

  res(1,0) = -sx*sy;
  res(1,1) = cx;
  res(1,2) = -sx*cy;

  res(2,0) = cx*sy;
  res(2,1) = sx;
  res(2,2) = cx*cy;

  sotDEBUGOUT(15);
  return res;
}

/* Compute the rotation matrix of the drift, ie the
 * transfo from the world frame to the estimated (drifted) world
 * frame: worldRworldest.
 */
MatrixRotation& AngleEstimator::
computeDriftFromAngles( MatrixRotation& res,
			const int& time )
{
  sotDEBUGIN(15);

  const dynamicgraph::Vector & angles = anglesSOUT( time );
  double cz = cos( angles(2) );
  double sz = sin( angles(2) );

  res(0,0) = cz;
  res(0,1) = -sz;
  res(0,2) = 0;

  /* z is the positive angle (R_{-z} has been computed
   *in the <angles> function). Thus, the /-/sin(z) is in 0,1. */
  res(1,0) = sz;
  res(1,1) = cz;
  res(1,2) = 0;

  res(2,0) = 0;
  res(2,1) = 0;
  res(2,2) = 1;

  sotDEBUGOUT(15);
  return res;
}

MatrixRotation& AngleEstimator::
computeSensorWorldRotation( MatrixRotation& res,
			    const int& time )
{
  sotDEBUGIN(15);

  const MatrixRotation & worldRworldest = driftSOUT( time );
  const MatrixRotation & worldestRsensor = sensorWorldRotationSIN( time );

  res = worldRworldest*worldestRsensor;

  sotDEBUGOUT(15);
  return res;
}

MatrixRotation& AngleEstimator::
computeWaistWorldRotation( MatrixRotation& res,
			   const int& time )
{
  sotDEBUGIN(15);

  // chest = sensor
  const MatrixRotation & worldRsensor = sensorWorldRotationSOUT( time );
  const MatrixHomogeneous & waistMchest = sensorEmbeddedPositionSIN( time );
  MatrixRotation waistRchest; waistRchest = waistMchest.linear();

  res = worldRsensor* waistRchest.transpose();

  sotDEBUGOUT(15);
  return res;
}



MatrixHomogeneous& AngleEstimator::
computeWaistWorldPosition( MatrixHomogeneous& res,
			   const int& time )
{
  sotDEBUGIN(15);

  const MatrixHomogeneous & waistMleg = contactEmbeddedPositionSIN( time );
  const MatrixHomogeneous& contactPos = contactWorldPositionSIN( time );
  MatrixHomogeneous legMwaist(waistMleg.inverse());
  MatrixHomogeneous tmpRes;
  if( fromSensor_ )
    {
      const MatrixRotation & Rflex = flexibilitySOUT( time ); // footRleg
      MatrixHomogeneous footMleg;
      footMleg.linear() = Rflex; footMleg.translation().setZero();

      tmpRes = footMleg*legMwaist;
    }
  else { tmpRes = legMwaist; }

  res = contactPos*tmpRes;
  sotDEBUGOUT(15);
  return res;
}

dynamicgraph::Vector& AngleEstimator::
computeWaistWorldPoseRPY( dynamicgraph::Vector& res,
			  const int& time )
{
  const MatrixHomogeneous & M = waistWorldPositionSOUT( time );

  VectorRollPitchYaw r = (M.linear().eulerAngles(2,1,0)).reverse();
  dynamicgraph::Vector t(3); t = M.translation();

  res.resize(6);
  for( int i=0;i<3;++i ) { res(i)=t(i); res(i+3)=r(i); }

  return res;
}

/* --- VELOCITY SIGS -------------------------------------------------------- */

dynamicgraph::Vector& AngleEstimator::
compute_xff_dotSOUT( dynamicgraph::Vector& res,
		     const int& time )
{
  const dynamicgraph::Matrix & J = jacobianSIN( time );
  const dynamicgraph::Vector & dq = qdotSIN( time );

  const int nr=J.rows(), nc=J.cols()-6;
  assert( nr==6 );
  dynamicgraph::Matrix Ja( nr,nc ); dynamicgraph::Vector dqa(nc);
  for( int j=0;j<nc;++j )
    {
      for( int i=0;i<nr;++i )
	Ja(i,j) = J(i,j+6);
      dqa(j) = dq(j+6);
    }
  dynamicgraph::Matrix Jff( 6,6 );
  for( int j=0;j<6;++j )
    for( int i=0;i<6;++i )
      Jff(i,j) = J(i,j);

  res.resize(nr); res = (Jff.inverse()*(Ja*dqa))*(-1);
  return res;
}

dynamicgraph::Vector& AngleEstimator::
compute_qdotSOUT( dynamicgraph::Vector& res,
		  const int& time )
{
  const dynamicgraph::Vector & dq = qdotSIN( time );
  const dynamicgraph::Vector & dx = xff_dotSOUT( time );

  assert( dx.size()==6 );

  const int nr=dq.size();
  res.resize( nr ); res=dq;
  for( int i=0;i<6;++i ) res(i)=dx(i);

  return res;
}