Skip to content
Snippets Groups Projects
pseudo-robot-dynamic.cpp 10.86 KiB
/*
 * Copyright 2011, Nicolas Mansard, LAAS-CNRS
 *
 * This file is part of sot-dyninv.
 * sot-dyninv 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-dyninv 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-dyninv.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <sot-dyninv/pseudo-robot-dynamic.h>
#include <sot/core/debug.hh>

#include <dynamic-graph/factory.h>
#include <dynamic-graph/pool.h>

#include <sot-dyninv/commands-helper.h>
#include <sot-dyninv/mal-to-eigen.h>


namespace dynamicgraph
{
  namespace sot
  {
    namespace dyninv
    {

      namespace dg = ::dynamicgraph;
      using namespace dg;

      /* --- DG FACTORY ------------------------------------------------------- */
      DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(PseudoRobotDynamic,"PseudoRobotDynamic");

      /* --- CONSTRUCTION ----------------------------------------------------- */
      /* --- CONSTRUCTION ----------------------------------------------------- */
      /* --- CONSTRUCTION ----------------------------------------------------- */
      PseudoRobotDynamic::
      PseudoRobotDynamic( const std::string & name )
	: DynamicIntegrator(name)

	,CONSTRUCT_SIGNAL_IN(control,ml::Vector)
	,CONSTRUCT_SIGNAL_OUT(qdot,ml::Vector,controlSIN)

	,CONSTRUCT_SIGNAL(rotation,OUT,ml::Vector)
	,CONSTRUCT_SIGNAL(translation,OUT,ml::Vector)
	,stateSOUT( &positionSOUT,getClassName()+"("+getName()+")::output(vector)::state" )

	,formerOpenHRP( NULL )
      {
	Entity::signalRegistration( controlSIN << qdotSOUT
				    << rotationSOUT << translationSOUT
				    << stateSOUT );

	/* --- COMMANDS --- */
	std::string doc
	  = docCommandVoid2("Replace in the pool a robot entity by this,"
			    "and modify the plugs (if 2de arg is true).",
			    "string (entity name)","bool (plug)");
	addCommand("replace",
		   makeCommandVoid2(*this,&PseudoRobotDynamic::replaceSimulatorEntity,
				    doc));
	doc = docCommandVoid1("Set the root position, and forward to the real simulator.",
			      "matrix homogeneous");
	addCommand("setRoot",
		   makeCommandVoid1(*this,&PseudoRobotDynamic::setRoot,
				    doc));

	doc = docCommandVoid1("Add to the current entity the command of the previous simu.",
			      "string (command name)");
	addCommand("addForward",
		   makeCommandVoid1(*this,&PseudoRobotDynamic::addForward,
				    doc));

      }

      /* --- SIGNALS ---------------------------------------------------------- */
      /* --- SIGNALS ---------------------------------------------------------- */
      /* --- SIGNALS ---------------------------------------------------------- */

      /* Force the recomputation of the DynInt::controlSIN, and one step
       * of the integrator. Then, export the resulting joint velocity,
       * along with the 6D position of the free floating through signals
       * rotationSOUT and translationSOUT.
       */
      ml::Vector& PseudoRobotDynamic::
      qdotSOUT_function( ml::Vector& mlqdot, int time )
      {
	sotDEBUGIN(5);

	controlSIN(time);
	integrateFromSignals(time);

	EIGEN_CONST_VECTOR_FROM_SIGNAL(v,velocity );
	EIGEN_VECTOR_FROM_VECTOR( qdot,mlqdot,v.size()-6 );
	qdot = v.tail(v.size()-6);

	EIGEN_VECTOR_FROM_SIGNAL(p,position );
	{
	  ml::Vector mlv3;
	  EIGEN_VECTOR_FROM_VECTOR( r,mlv3,3 );
	  r = p.segment(3,3);
	  rotationSOUT = mlv3;
	  r = p.head(3);
	  translationSOUT = mlv3;
	}

	sotDEBUGOUT(5);
	return mlqdot;
      }

      /* --- TOOLS ------------------------------------------------------------- */
      /* --- TOOLS ------------------------------------------------------------- */
      /* --- TOOLS ------------------------------------------------------------- */

      namespace PseudoRobotDynamic_Static
      {
	using namespace Eigen;

	template< typename D1 >
	Vector3d computeEulerFromRotationMatrix ( const MatrixBase<D1> & rotation )
	{
	  Vector3d euler;

	  double rotationMatrix00 = rotation(0,0);
	  double rotationMatrix10 = rotation(1,0);
	  double rotationMatrix20 = rotation(2,0);
	  double rotationMatrix01 = rotation(0,1);
	  double rotationMatrix11 = rotation(1,1);
	  double rotationMatrix21 = rotation(2,1);
	  double rotationMatrix02 = rotation(0,2);
	  double rotationMatrix12 = rotation(1,2);
	  double rotationMatrix22 = rotation(2,2);

	  double cosTheta = sqrt(0.5 * ( rotationMatrix00*rotationMatrix00
					 + rotationMatrix10*rotationMatrix10
					 + rotationMatrix21*rotationMatrix21
					 + rotationMatrix22*rotationMatrix22 ));
	  double sinTheta = -rotationMatrix20;
	  euler[1] = atan2 (sinTheta, cosTheta);

	  double cosTheta_cosPhi = 0.5 * (rotationMatrix22 * rotationMatrix11
					  - rotationMatrix21 * rotationMatrix12);
	  double cosTheta_sinPhi = 0.5 * (rotationMatrix21 * rotationMatrix02
					  - rotationMatrix22 * rotationMatrix01);
	  double cosTheta_cosPsi = 0.5 * (rotationMatrix00 * rotationMatrix11
					  - rotationMatrix01 * rotationMatrix10);
	  double cosTheta_sinPsi = 0.5 * (rotationMatrix10 * rotationMatrix02
					  - rotationMatrix00 * rotationMatrix12);

	  //if cosTheta == 0
	  if (fabs(cosTheta) < 1e-9 )
	    {
	      if (sinTheta > 0.5) // sinTheta ~= 1
		{
		  //phi_psi = phi - psi
		  double phi_psi = atan2(- rotationMatrix10, rotationMatrix11);
		  double psi = euler[2];

		  double phi = phi_psi + psi;
		  euler[0] = phi;
		}
	      else  //sinTheta  ~= -1
		{
		  //phi_psi = phi + psi
		  double phi_psi = atan2(- rotationMatrix10,  rotationMatrix11);

		  double psi = euler[2];

		  double phi = phi_psi;
		  euler[0] = phi - psi;
		}
	    }
	  else
	    {
	      double cosPsi = cosTheta_cosPsi / cosTheta;
	      double sinPsi = cosTheta_sinPsi / cosTheta;
	      euler[0] = atan2 (sinPsi, cosPsi);

	      double cosPhi = cosTheta_cosPhi / cosTheta;
	      double sinPhi = cosTheta_sinPhi / cosTheta;
	      euler[2] = atan2 (sinPhi, cosPhi);
	    }

	  return euler;
	}

      } // namespace PseudoRobotDynamic_Static

      /* --- COMMANDS ---------------------------------------------------------- */
      /* --- COMMANDS ---------------------------------------------------------- */
      /* --- COMMANDS ---------------------------------------------------------- */


      void PseudoRobotDynamic::
      replaceSimulatorEntity( const std::string& formerName, const bool & plug )
      {
	assert( formerOpenHRP == NULL );
	formerOpenHRP = &dg::g_pool().getEntity( formerName );
	dg::g_pool().deregisterEntity( formerName );
	// former.name = formerName+".old";
	dg::g_pool().registerEntity( formerName+"-old",formerOpenHRP );

	entityDeregistration(); name = formerName; entityRegistration();
	if( plug )
	  {
	    formerOpenHRP->getSignal("control").plug( & qdotSOUT );

	    try
	      {
		formerOpenHRP->getSignal("attitudeIN").plug( & rotationSOUT );
		formerOpenHRP->getSignal("translation").plug( & translationSOUT );
	      }
	    catch (...) {}

	    const ml::Vector& pos
	      = dynamic_cast< dg::Signal<ml::Vector,int>& >
	      ( formerOpenHRP->getSignal("state") ).accessCopy();
	    try
	      {
		const ml::Vector& vel
		  = dynamic_cast< dg::Signal<ml::Vector,int>& >
		  ( formerOpenHRP->getSignal("velocity") ).accessCopy();
		setState(pos,vel);
	      }
	    catch (... )
	      {
		ml::Vector velzero( pos.size() ); velzero.setZero();
		setState(pos,velzero);
	      }
	  }
      }
      void PseudoRobotDynamic::
      setRoot( const ml::Matrix & mlM )
      {
	sotDEBUG(15) << "Set root with " << mlM << std::endl;
	using namespace Eigen;
	using PseudoRobotDynamic_Static::computeEulerFromRotationMatrix;

	EIGEN_CONST_MATRIX_FROM_SIGNAL(M,mlM);
	Vector3d r = computeEulerFromRotationMatrix( M.topLeftCorner(3,3) );
	EIGEN_VECTOR_FROM_SIGNAL( q,position );
	if( q.size()<6 )
	  {
	    throw; // TODO
	  }
	q.head(3) = M.col(3).head(3);
	q.segment(3,3) = r;

	if( formerOpenHRP )
	  try
	    {
	      forwardVoidCommandToSimu( "setRoot",mlM );
	    }
	  catch(...) {}
      }


      /* --- FORWARD ---------------------------------------------------------- */

      /* This function is a forward on the command on the former simu entity
       * <formerOpenHRP>: when calling it, the parameters are send to the named
       * command, that is executed.
       */
      template< typename T1 >
      void PseudoRobotDynamic::
      forwardVoidCommandToSimu( const std::string& cmdName,
				const T1& arg1 )
      {
	/* Forward to previous entity. */
	assert( formerOpenHRP );

	using dg::command::Command;
	using dg::command::Value;

	Command* command = formerOpenHRP->getNewStyleCommand(cmdName);
	std::vector<Value> valuesArg;
	valuesArg.push_back( Value( arg1 ) );
	command->setParameterValues(valuesArg);
	command->execute();
      }

      /* Add the named command of the former simu entity <formerOpenHRP> to the
       * commands of the entity.
       */
      void PseudoRobotDynamic::
      addForward( const std::string& cmdName )
      {
	assert( formerOpenHRP );
	addCommand(cmdName,formerOpenHRP->getNewStyleCommand(cmdName));
      }


      /* --- ENTITY ----------------------------------------------------------- */
      /* --- ENTITY ----------------------------------------------------------- */
      /* --- ENTITY ----------------------------------------------------------- */

      void PseudoRobotDynamic::
      display( std::ostream& os ) const
      {
	os << "PseudoRobotDynamic "<<getName() << ". " << std::endl;
      }

      void PseudoRobotDynamic::
      commandLine( const std::string& cmdLine,
		   std::istringstream& cmdArgs,
		   std::ostream& os )
      {
	sotDEBUGIN(15);

	if( cmdLine == "help" )
	  {
	    os << "PseudoRobotDynamic:" << std::endl
	       << " - replace <OpenHRP> [plug]" << std::endl;
	  }
	else if( cmdLine == "replace" )
	  {
	    if( cmdArgs >> std::ws, cmdArgs.good() )
	      {
		std::string repName; cmdArgs >> repName >> std::ws;
		bool plug = cmdArgs.good();
		replaceSimulatorEntity( repName,plug );
	      }
	  }
	else if( cmdLine=="sbs" || cmdLine=="play" || cmdLine =="withForces"
		 || cmdLine == "periodicCall" || cmdLine == "periodicCallBefore"
		 || cmdLine == "periodicCallAfter"  )
	  {
	    formerOpenHRP ->commandLine( cmdLine,cmdArgs,os );
	  }
	else if( cmdLine=="root" )
	  {
	    if( cmdArgs >> std::ws, cmdArgs.good() )
	      {
		ml::Matrix M; cmdArgs >> M; setRoot(M);
		std::ostringstream osback;
		osback << M.accessToMotherLib(); cmdArgs.str(osback.str());
		formerOpenHRP ->commandLine( cmdLine,cmdArgs,os );
	      }
	    else
	      {
		os << "TODO" << std::endl;
	      }
	  }
	else
	  {
	    Entity::commandLine( cmdLine,cmdArgs,os );
	  }
	sotDEBUGOUT(15);
      }

    } // namespace dyninv
  } // namespace sot
} // namespace dynamicgraph