-
Nicolas Mansard authoredNicolas Mansard authored
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