worldsim/src/physuspension.cpp

00001 /********************************************************************************
00002  *  WorldSim -- library for robot simulations                                   *
00003  *  Copyright (C) 2008-2013 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #include "physuspension.h"
00021 #include "private/phyjointprivate.h"
00022 #include "private/phyobjectprivate.h"
00023 #include "private/worldprivate.h"
00024 
00025 // This is needed because the isnan and isinf functions are not present windows
00026 #ifdef FARSA_WIN
00027     #include <float.h>
00028     #define isnan(x) _isnan(x)
00029 #endif
00030 
00031 namespace farsa {
00032 
00033 PhySuspension::PhySuspension( const wVector& axis, const wVector& centre, const wVector& x_axis, PhyObject* parent, PhyObject* child, bool cp )
00034     : PhyJoint( parent, child ) {
00035     dof = new PhyDOF( this, axis, centre, false );
00036     dofsv << dof;
00037     dofv = 1;
00038     //--- calculate the localMatrixParent
00039     //--- supposing that axis and x_axis are ortogonals
00040     localMatrixParent.x_ax = x_axis;
00041     localMatrixParent.y_ax = axis * x_axis;
00042     localMatrixParent.z_ax = axis;
00043     localMatrixParent.w_pos = centre;
00044     localMatrixParent.sanitifize();
00045     
00046     //--- calculate the local matrix respect to child object
00047     if ( parent ) {
00048         globalMatrixParent = localMatrixParent * parent->matrix();
00049     } else {
00050         globalMatrixParent = localMatrixParent;
00051     }
00052     localMatrixChild = globalMatrixParent * child->matrix().inverse();
00053     if ( parent ) {
00054         globalMatrixParent = localMatrixParent * parent->matrix();
00055     } else {
00056         globalMatrixParent = localMatrixParent;
00057     }
00058 
00059     dof->setAxis( globalMatrixParent.z_ax );
00060     dof->setXAxis( globalMatrixParent.x_ax );
00061     dof->setYAxis( globalMatrixParent.y_ax );
00062     dof->setCentre( globalMatrixParent.w_pos );
00063     
00064     if ( !localMatrixParent.sanityCheck() ) {
00065         qWarning( "Sanity Check Failed on localMatrixParent" );
00066     }
00067     if ( !localMatrixChild.sanityCheck() ) {
00068         qWarning( "Sanity Check Failed on localMatrixChild" );
00069     }
00070     
00071     if ( cp ) {
00072         createPrivateJoint();
00073     }
00074 }
00075 
00076 wVector PhySuspension::centre() const {
00077     //--- calculate global matrix if necessary
00078     if ( parent() ) {
00079         globalMatrixParent = localMatrixParent * parent()->matrix();
00080     }
00081     return globalMatrixParent.w_pos;
00082 }
00083 
00084 void PhySuspension::createPrivateJoint() {
00085 #ifdef WORLDSIM_USE_NEWTON
00086     priv->joint = NewtonConstraintCreateUserJoint( worldpriv->world, 6, PhyJointPrivate::userBilateralHandler, 0, priv->child, priv->parent );
00087     NewtonJointSetUserData( priv->joint, this );
00088 #endif
00089 }
00090 
00091 void PhySuspension::updateJointInfo() {
00092     //--- calculate the global matrices
00093     //--- if parent doesn't exist, then globalMatrixParent and localMatrixParent coincide and
00094     //--- there is no need to re-assign it because it was already done in constructor
00095     if ( parent() ) {
00096         globalMatrixParent = localMatrixParent * parent()->matrix();
00097     }
00098     globalMatrixChild = localMatrixChild * child()->matrix();
00099 
00100     if ( !globalMatrixParent.sanityCheck() ) {
00101         qWarning( "Sanity Check Failed on globalMatrixParent" );
00102     }
00103     if ( !globalMatrixChild.sanityCheck() ) {
00104         qWarning( "Sanity Check Failed on globalMatrixChild" );
00105     }
00106 
00107     dof->setAxis( globalMatrixParent.z_ax );
00108     dof->setXAxis( globalMatrixParent.x_ax );
00109     dof->setYAxis( globalMatrixParent.y_ax );
00110     dof->setCentre( globalMatrixParent.w_pos );
00111 
00112     PhyDOF* dof = dofsv[0];
00113     //--- calculate the rotation assuming the local X axis of joint frame as 0
00114     //--- and following the right-hand convention
00115     real sinAngle = (globalMatrixParent.x_ax * globalMatrixChild.x_ax) % globalMatrixChild.z_ax;
00116     real cosAngle = globalMatrixChild.x_ax % globalMatrixParent.x_ax;
00117     real angle = atan2( sinAngle, cosAngle );
00118     real vel;
00119     // Velocity is computed in two different ways depending on whether the joint is enabled or not:
00120     // if it is, we use Newton functions to get the angular velocities (for a better result), otherwise
00121     // we revert to computing the difference with the previous position divided by the timestep
00122     if (enabled) {
00123         //--- the velocity is calculated projecting the angular velocity of objects on the main axis (z_ax)
00124         //    This code is not general, becuase it is not appliable in the case of parent==NULL
00125         //    and also return different results respect to the kinematic way
00126         //    Then [Gianluca] comment it and replaced with the same code used in the kinematic mode
00127         wVector omegaParent, omegaChild;
00128 #ifdef WORLDSIM_USE_NEWTON
00129         if ( parent() ) {
00130             NewtonBodyGetOmega( priv->parent, &omegaParent[0] );
00131         } else {
00132             omegaParent = wVector(0, 0, 0);
00133         }
00134         NewtonBodyGetOmega( priv->child, &omegaChild[0] );
00135 #endif
00136         real velP = omegaParent % globalMatrixChild.z_ax;
00137         real velC = omegaChild % globalMatrixChild.z_ax;
00138         vel = velC - velP;
00139         //vel = (angle - dof->position()) / (world()->timeStep());
00140     } else {
00141         vel = (angle - dof->position()) / (world()->timeStep());
00142     }
00143     dof->setPosition( angle );
00144     dof->setVelocity( vel );
00145 }
00146 
00147 void PhySuspension::updateJoint( real timestep ) {
00148     // If the joint is disabled, we don't do anything here
00149     if (!enabled) {
00150         return;
00151     }
00152 
00153     // Updating the global matrices and the dof
00154     updateJointInfo();
00155 
00156     const real angle = dof->position();
00157     const real vel = dof->velocity();
00158 
00159 #ifdef WORLDSIM_USE_NEWTON
00160     //--- Restrict the movement on the centre of the joint along all tree orthonormal direction
00161     NewtonUserJointAddLinearRow( priv->joint, &globalMatrixChild.w_pos[0], &globalMatrixParent.w_pos[0], &globalMatrixParent.x_ax[0] );
00162     NewtonUserJointSetRowStiffness( priv->joint, 0.98f );
00163     //NewtonUserJointSetRowSpringDamperAcceleration( priv->joint, 20, 10 );
00164     NewtonUserJointAddLinearRow( priv->joint, &globalMatrixChild.w_pos[0], &globalMatrixParent.w_pos[0], &globalMatrixParent.y_ax[0] );
00165     NewtonUserJointSetRowStiffness( priv->joint, 1.0f );
00166     NewtonUserJointAddLinearRow( priv->joint, &globalMatrixChild.w_pos[0], &globalMatrixParent.w_pos[0], &globalMatrixParent.z_ax[0] );
00167     NewtonUserJointSetRowStiffness( priv->joint, 1.0f );
00168 
00169     //--- In order to constraint the rotation about X and Y axis of the joint
00170     //--- we use LinearRow (that are stronger) getting a point far from objects along
00171     //--- the Z axis. Doing this if the two object rotates about X or Y axes then
00172     //--- the difference between qChild and qParent augments and then Newton Engine will apply
00173     //--- a corresponding force (that applyied outside the centre of the object will become
00174     //--- a torque) that will blocks any rotation about X and Y axis
00175     real len = 5000.0;
00176     wVector qChild( globalMatrixChild.w_pos + globalMatrixChild.z_ax.scale(len) );
00177     wVector qParent( globalMatrixParent.w_pos + globalMatrixParent.z_ax.scale(len) );
00178     NewtonUserJointAddLinearRow( priv->joint, &qChild[0], &qParent[0], &globalMatrixParent.x_ax[0] );
00179     NewtonUserJointSetRowStiffness( priv->joint, 1.0 );
00180     NewtonUserJointAddLinearRow( priv->joint, &qChild[0], &qParent[0], &globalMatrixParent.y_ax[0] );
00181     NewtonUserJointSetRowStiffness( priv->joint, 1.0 );
00182 //  NewtonUserJointAddAngularRow( priv->joint, 0.0f, &globalMatrixParent.x_ax[0] );
00183 //  NewtonUserJointSetRowStiffness( priv->joint, 1.0f );
00184 //  NewtonUserJointAddAngularRow( priv->joint, 0.0f, &globalMatrixParent.y_ax[0] );
00185 //  NewtonUserJointSetRowStiffness( priv->joint, 0.98f );
00186 
00187     //--- The only motion supported is by velocity
00188     if ( dof->motion() == PhyDOF::vel ) {
00189         //--- I'm not sure that this implementation is correct
00190         real accel = 0.8f*( dof->desiredVelocity() - vel ) / ( timestep );
00191         NewtonUserJointAddAngularRow( priv->joint, 0.0f, &globalMatrixParent.z_ax[0] );
00192         NewtonUserJointSetRowAcceleration( priv->joint, accel );
00193         NewtonUserJointSetRowStiffness( priv->joint, dof->stiffness() );
00194     }
00195 #endif
00196 
00197 }
00198 
00199 } // end namespace farsa