Blender  V2.59
CopyPose.cpp
Go to the documentation of this file.
00001 
00004 /* $Id: CopyPose.cpp 35155 2011-02-25 11:45:16Z jesterking $
00005  * CopyPose.cpp
00006  *
00007  *  Created on: Mar 17, 2009
00008  *      Author: benoit bolsee
00009  */
00010 
00011 #include "CopyPose.hpp"
00012 #include "kdl/kinfam_io.hpp"
00013 #include <math.h>
00014 #include <string.h>
00015 
00016 namespace iTaSC
00017 {
00018 
00019 const unsigned int maxPoseCacheSize = (2*(3+3*2));
00020 CopyPose::CopyPose(unsigned int control_output, unsigned int dynamic_output, double armlength, double accuracy, unsigned int maximum_iterations):
00021     ConstraintSet(),
00022         m_cache(NULL),
00023     m_poseCCh(-1),m_poseCTs(0)
00024 {
00025         m_maxerror = armlength/2.0;
00026         m_outputControl = (control_output & CTL_ALL);
00027         unsigned int _nc = nBitsOn(m_outputControl);
00028         if (!_nc) 
00029                 return;
00030         // reset the constraint set
00031         reset(_nc, accuracy, maximum_iterations);
00032         _nc = 0;
00033         m_nvalues = 0;
00034         int nrot = 0, npos = 0;
00035         int nposCache = 0, nrotCache = 0;
00036         m_outputDynamic = (dynamic_output & m_outputControl);
00037         memset(m_values, 0, sizeof(m_values));
00038         memset(m_posData, 0, sizeof(m_posData));
00039         memset(m_rotData, 0, sizeof(m_rotData));
00040         memset(&m_rot, 0, sizeof(m_rot));
00041         memset(&m_pos, 0, sizeof(m_pos));
00042         if (m_outputControl & CTL_POSITION) {
00043                 m_pos.alpha = 1.0;              
00044                 m_pos.K = 20.0;         
00045                 m_pos.tolerance = 0.05; 
00046                 m_values[m_nvalues].alpha = m_pos.alpha;
00047                 m_values[m_nvalues].feedback = m_pos.K;
00048                 m_values[m_nvalues].tolerance = m_pos.tolerance;
00049                 m_values[m_nvalues].id = ID_POSITION;
00050                 if (m_outputControl & CTL_POSITIONX) {
00051                     m_Wy(_nc) = m_pos.alpha/*/(m_pos.tolerance*m_pos.K)*/;
00052                         m_Cf(_nc++,0)=1.0;
00053                         m_posData[npos++].id = ID_POSITIONX;
00054                         if (m_outputDynamic & CTL_POSITIONX)
00055                                 nposCache++;
00056                 } 
00057                 if (m_outputControl & CTL_POSITIONY) {
00058                     m_Wy(_nc) = m_pos.alpha/*/(m_pos.tolerance*m_pos.K)*/;
00059                         m_Cf(_nc++,1)=1.0;
00060                         m_posData[npos++].id = ID_POSITIONY;
00061                         if (m_outputDynamic & CTL_POSITIONY)
00062                                 nposCache++;
00063                 }
00064                 if (m_outputControl & CTL_POSITIONZ) {
00065                     m_Wy(_nc) = m_pos.alpha/*/(m_pos.tolerance*m_pos.K)*/;
00066                         m_Cf(_nc++,2)=1.0;
00067                         m_posData[npos++].id = ID_POSITIONZ;
00068                         if (m_outputDynamic & CTL_POSITIONZ)
00069                                 nposCache++;
00070                 }
00071                 m_values[m_nvalues].number = npos;
00072                 m_values[m_nvalues++].values = m_posData;
00073                 m_pos.firsty = 0;
00074                 m_pos.ny = npos;
00075         }
00076         if (m_outputControl & CTL_ROTATION) {
00077                 m_rot.alpha = 1.0;              
00078                 m_rot.K = 20.0;         
00079                 m_rot.tolerance = 0.05; 
00080                 m_values[m_nvalues].alpha = m_rot.alpha;
00081                 m_values[m_nvalues].feedback = m_rot.K;
00082                 m_values[m_nvalues].tolerance = m_rot.tolerance;
00083                 m_values[m_nvalues].id = ID_ROTATION;
00084                 if (m_outputControl & CTL_ROTATIONX) {
00085                     m_Wy(_nc) = m_rot.alpha/*/(m_rot.tolerance*m_rot.K)*/;
00086                         m_Cf(_nc++,3)=1.0;
00087                         m_rotData[nrot++].id = ID_ROTATIONX;
00088                         if (m_outputDynamic & CTL_ROTATIONX)
00089                                 nrotCache++;
00090                 }
00091                 if (m_outputControl & CTL_ROTATIONY) {
00092                     m_Wy(_nc) = m_rot.alpha/*/(m_rot.tolerance*m_rot.K)*/;
00093                         m_Cf(_nc++,4)=1.0;
00094                         m_rotData[nrot++].id = ID_ROTATIONY;
00095                         if (m_outputDynamic & CTL_ROTATIONY)
00096                                 nrotCache++;
00097                 }
00098                 if (m_outputControl & CTL_ROTATIONZ) {
00099                     m_Wy(_nc) = m_rot.alpha/*/(m_rot.tolerance*m_rot.K)*/;
00100                         m_Cf(_nc++,5)=1.0;
00101                         m_rotData[nrot++].id = ID_ROTATIONZ;
00102                         if (m_outputDynamic & CTL_ROTATIONZ)
00103                                 nrotCache++;
00104                 }
00105                 m_values[m_nvalues].number = nrot;
00106                 m_values[m_nvalues++].values = m_rotData;
00107                 m_rot.firsty = npos;
00108                 m_rot.ny = nrot;
00109         }
00110         assert(_nc == m_nc);
00111     m_Jf=e_identity_matrix(6,6);
00112         m_poseCacheSize = ((nrotCache)?(3+nrotCache*2):0)+((nposCache)?(3+nposCache*2):0);
00113 }
00114 
00115 CopyPose::~CopyPose()
00116 {
00117 }
00118 
00119 bool CopyPose::initialise(Frame& init_pose)
00120 {
00121     m_externalPose = m_internalPose = init_pose;
00122         updateJacobian();
00123     return true;
00124 }
00125 
00126 void CopyPose::modelUpdate(Frame& _external_pose,const Timestamp& timestamp)
00127 {
00128         m_internalPose = m_externalPose = _external_pose;
00129         updateJacobian();
00130 }
00131 
00132 void CopyPose::initCache(Cache *_cache)
00133 {
00134     m_cache = _cache;
00135     m_poseCCh = -1;
00136     if (m_cache) {
00137         // create one channel for the coordinates
00138         m_poseCCh = m_cache->addChannel(this, "Xf", m_poseCacheSize*sizeof(double));
00139         // don't save initial value, it will be recomputed from external pose
00140         //pushPose(0);
00141     }
00142 }
00143 
00144 double* CopyPose::pushValues(double* item, ControlState* _state, unsigned int mask)
00145 {
00146         ControlState::ControlValue* _yval;
00147         int i;
00148 
00149         *item++ = _state->alpha;
00150         *item++ = _state->K;
00151         *item++ = _state->tolerance;
00152 
00153         for (i=0, _yval=_state->output; i<_state->ny; mask<<=1) {
00154                 if (m_outputControl & mask) {
00155                         if (m_outputDynamic & mask) {
00156                                 *item++ = _yval->yd;
00157                                 *item++ = _yval->yddot;
00158                         }
00159                         _yval++;
00160                         i++;
00161                 }
00162         }
00163         return item;
00164 }
00165 
00166 void CopyPose::pushPose(CacheTS timestamp)
00167 {
00168     if (m_poseCCh >= 0) {
00169                 if (m_poseCacheSize) {
00170                         double buf[maxPoseCacheSize];
00171                         double *item = buf;
00172                         if (m_outputDynamic & CTL_POSITION)
00173                                 item = pushValues(item, &m_pos, CTL_POSITIONX);
00174                         if (m_outputDynamic & CTL_ROTATION)
00175                                 item = pushValues(item, &m_rot, CTL_ROTATIONX);
00176                         m_cache->addCacheVectorIfDifferent(this, m_poseCCh, timestamp, buf, m_poseCacheSize, KDL::epsilon);
00177                 } else
00178                         m_cache->addCacheVectorIfDifferent(this, m_poseCCh, timestamp, NULL, 0, KDL::epsilon);
00179                 m_poseCTs = timestamp;
00180     }
00181 }
00182 
00183 double* CopyPose::restoreValues(double* item, ConstraintValues* _values, ControlState* _state, unsigned int mask)
00184 {
00185         ConstraintSingleValue* _data;
00186         ControlState::ControlValue* _yval;
00187         int i, j;
00188 
00189         _values->alpha = _state->alpha = *item++;
00190         _values->feedback = _state->K = *item++;
00191         _values->tolerance = _state->tolerance = *item++;
00192 
00193         for (i=_state->firsty, j=i+_state->ny, _yval=_state->output, _data=_values->values; i<j; mask<<=1) {
00194                 if (m_outputControl & mask) {
00195                         m_Wy(i) = _state->alpha/*/(_state->tolerance*_state->K)*/;
00196                         if (m_outputDynamic & mask) {
00197                                 _data->yd = _yval->yd = *item++;
00198                                 _data->yddot = _yval->yddot = *item++;
00199                         }
00200                         _data++;
00201                         _yval++;
00202                         i++;
00203                 }
00204         }
00205         return item;
00206 }
00207 
00208 bool CopyPose::popPose(CacheTS timestamp)
00209 {
00210         bool found = false;
00211     if (m_poseCCh >= 0) {
00212         double *item = (double*)m_cache->getPreviousCacheItem(this, m_poseCCh, &timestamp);
00213                 if (item) {
00214                         found = true;
00215                         if (timestamp != m_poseCTs) {
00216                                 int i=0;
00217                                 if (m_outputControl & CTL_POSITION) {
00218                                         if (m_outputDynamic & CTL_POSITION) {
00219                                                 item = restoreValues(item, &m_values[i], &m_pos, CTL_POSITIONX);
00220                                         }
00221                                         i++;
00222                                 }
00223                                 if (m_outputControl & CTL_ROTATION) {
00224                                         if (m_outputDynamic & CTL_ROTATION) {
00225                                                 item = restoreValues(item, &m_values[i], &m_rot, CTL_ROTATIONX);
00226                                         }
00227                                         i++;
00228                                 }
00229                                 m_poseCTs = timestamp;
00230                                 item = NULL;
00231                         }
00232         }
00233     }
00234     return found;
00235 }
00236 
00237 void CopyPose::interpolateOutput(ControlState* _state, unsigned int mask, const Timestamp& timestamp)
00238 {
00239         ControlState::ControlValue* _yval;
00240         int i;
00241 
00242         for (i=0, _yval=_state->output; i<_state->ny; mask <<= 1) {
00243                 if (m_outputControl & mask) {
00244                         if (m_outputDynamic & mask) {
00245                                 if (timestamp.substep && timestamp.interpolate) {
00246                                         _yval->yd += _yval->yddot*timestamp.realTimestep;
00247                                 } else {
00248                                         _yval->yd = _yval->nextyd;
00249                                         _yval->yddot = _yval->nextyddot;
00250                                 }
00251                         }
00252                         i++;
00253                         _yval++;
00254                 }
00255         }
00256 }
00257 
00258 void CopyPose::pushCache(const Timestamp& timestamp)
00259 {
00260         if (!timestamp.substep && timestamp.cache) {
00261         pushPose(timestamp.cacheTimestamp);
00262         }
00263 }
00264 
00265 void CopyPose::updateKinematics(const Timestamp& timestamp)
00266 {
00267         if (timestamp.interpolate) {
00268                 if (m_outputDynamic & CTL_POSITION)
00269                         interpolateOutput(&m_pos, CTL_POSITIONX, timestamp);
00270                 if (m_outputDynamic & CTL_ROTATION)
00271                         interpolateOutput(&m_rot, CTL_ROTATIONX, timestamp);
00272         }
00273         pushCache(timestamp);
00274 }
00275 
00276 void CopyPose::updateJacobian()
00277 {
00278     //Jacobian is always identity at the start of the constraint chain
00279         //instead of going through complicated jacobian operation, implemented direct formula
00280         //m_Jf(1,3) = m_internalPose.p.z();
00281         //m_Jf(2,3) = -m_internalPose.p.y();
00282         //m_Jf(0,4) = -m_internalPose.p.z();
00283         //m_Jf(2,4) = m_internalPose.p.x();
00284         //m_Jf(0,5) = m_internalPose.p.y();
00285         //m_Jf(1,5) = -m_internalPose.p.x();
00286 }
00287 
00288 void CopyPose::updateState(ConstraintValues* _values, ControlState* _state, unsigned int mask, double timestep)
00289 {
00290         unsigned int id = (mask == CTL_ROTATIONX) ? ID_ROTATIONX : ID_POSITIONX;
00291         ControlState::ControlValue* _yval;
00292         ConstraintSingleValue* _data;
00293         int i, j, k;
00294     int action = 0;
00295 
00296     if ((_values->action & ACT_ALPHA) && _values->alpha >= 0.0) {
00297         _state->alpha = _values->alpha;
00298         action |= ACT_ALPHA;
00299     }
00300     if ((_values->action & ACT_TOLERANCE) && _values->tolerance > KDL::epsilon) {
00301         _state->tolerance = _values->tolerance;
00302         action |= ACT_TOLERANCE;
00303     }
00304     if ((_values->action & ACT_FEEDBACK) && _values->feedback > KDL::epsilon) {
00305         _state->K = _values->feedback;
00306         action |= ACT_FEEDBACK;
00307     }
00308         for (i=_state->firsty, j=_state->firsty+_state->ny, _yval=_state->output; i<j; mask <<= 1, id++) {
00309                 if (m_outputControl & mask) {
00310                         if (action)
00311                                 m_Wy(i) = _state->alpha/*/(_state->tolerance*_state->K)*/;
00312                         // check if this controlled output is provided
00313                         for (k=0, _data=_values->values; k<_values->number; k++, _data++) {
00314                                 if (_data->id == id) {
00315                                         switch (_data->action & (ACT_VALUE|ACT_VELOCITY)) {
00316                                         case 0:
00317                                                 // no indication, keep current values
00318                                                 break;
00319                                         case ACT_VELOCITY:
00320                                                 // only the velocity is given estimate the new value by integration
00321                                                 _data->yd = _yval->yd+_data->yddot*timestep;
00322                                                 // walkthrough
00323                                         case ACT_VALUE:
00324                                                 _yval->nextyd = _data->yd;
00325                                                 // if the user sets the value, we assume future velocity is zero
00326                                                 // (until the user changes the value again)
00327                                                 _yval->nextyddot = (_data->action & ACT_VALUE) ? 0.0 : _data->yddot;
00328                                                 if (timestep>0.0) {
00329                                                         _yval->yddot = (_data->yd-_yval->yd)/timestep;
00330                                                 } else {
00331                                                         // allow the user to change target instantenously when this function
00332                                                         // if called from setControlParameter with timestep = 0
00333                                                         _yval->yd = _yval->nextyd;
00334                                                         _yval->yddot = _yval->nextyddot;
00335                                                 }
00336                                                 break;
00337                                         case (ACT_VALUE|ACT_VELOCITY):
00338                                                 // the user should not set the value and velocity at the same time.
00339                                                 // In this case, we will assume that he wants to set the future value
00340                                                 // and we compute the current value to match the velocity
00341                                                 _yval->yd = _data->yd - _data->yddot*timestep;
00342                                                 _yval->nextyd = _data->yd;
00343                                                 _yval->nextyddot = _data->yddot;
00344                                                 if (timestep>0.0) {
00345                                                         _yval->yddot = (_data->yd-_yval->yd)/timestep;
00346                                                 } else {
00347                                                         _yval->yd = _yval->nextyd;
00348                                                         _yval->yddot = _yval->nextyddot;
00349                                                 }
00350                                                 break;
00351                                         }
00352                                 }
00353                         }
00354                         _yval++;
00355                         i++;
00356                 }
00357         }
00358 }
00359 
00360 
00361 bool CopyPose::setControlParameters(struct ConstraintValues* _values, unsigned int _nvalues, double timestep)
00362 {
00363         while (_nvalues > 0) {
00364                 if (_values->id >= ID_POSITION && _values->id <= ID_POSITIONZ && (m_outputControl & CTL_POSITION)) {
00365                         updateState(_values, &m_pos, CTL_POSITIONX, timestep);
00366                 } 
00367                 if (_values->id >= ID_ROTATION && _values->id <= ID_ROTATIONZ && (m_outputControl & CTL_ROTATION)) {
00368                         updateState(_values, &m_rot, CTL_ROTATIONX, timestep);
00369                 }
00370                 _values++;
00371                 _nvalues--;
00372         }
00373     return true;
00374 }
00375 
00376 void CopyPose::updateValues(Vector& vel, ConstraintValues* _values, ControlState* _state, unsigned int mask)
00377 {
00378         ConstraintSingleValue* _data;
00379         ControlState::ControlValue* _yval;
00380         int i, j;
00381 
00382         _values->action = 0;
00383 
00384         for (i=_state->firsty, j=0, _yval=_state->output, _data=_values->values; j<3; j++, mask<<=1) {
00385                 if (m_outputControl & mask) {
00386                         *(double*)&_data->y = vel(j);
00387                         *(double*)&_data->ydot = m_ydot(i);
00388                         _data->yd = _yval->yd;
00389                         _data->yddot = _yval->yddot;
00390                         _data->action = 0;
00391                         i++;
00392                         _data++;
00393                         _yval++;
00394                 }
00395         }
00396 }
00397 
00398 void CopyPose::updateOutput(Vector& vel, ControlState* _state, unsigned int mask)
00399 {
00400         ControlState::ControlValue* _yval;
00401         int i, j;
00402         double coef=1.0;
00403         if (mask & CTL_POSITION) {
00404                 // put a limit on position error
00405                 double len=0.0;
00406                 for (j=0, _yval=_state->output; j<3; j++) {
00407                         if (m_outputControl & (mask<<j)) {
00408                                 len += KDL::sqr(_yval->yd-vel(j));
00409                                 _yval++;
00410                         }
00411                 }
00412                 len = KDL::sqrt(len);
00413                 if (len > m_maxerror)
00414                         coef = m_maxerror/len;
00415         }
00416         for (i=_state->firsty, j=0, _yval=_state->output; j<3; j++) {
00417                 if (m_outputControl & (mask<<j)) {
00418                         m_ydot(i)=_yval->yddot+_state->K*coef*(_yval->yd-vel(j));
00419                         _yval++;
00420                         i++;
00421                 }
00422         }
00423 }
00424 
00425 void CopyPose::updateControlOutput(const Timestamp& timestamp)
00426 {
00427     //IMO this should be done, no idea if it is enough (wrt Distance impl)
00428         Twist y = diff(F_identity, m_internalPose);
00429         bool found = true;
00430         if (!timestamp.substep) {
00431                 if (!timestamp.reiterate) {
00432                         found = popPose(timestamp.cacheTimestamp);
00433                 }
00434         }
00435         if (m_constraintCallback && (m_substep || (!timestamp.reiterate && !timestamp.substep))) {
00436                 // initialize first callback the application to get the current values
00437                 int i=0;
00438                 if (m_outputControl & CTL_POSITION) {
00439                         updateValues(y.vel, &m_values[i++], &m_pos, CTL_POSITIONX);
00440                 }
00441                 if (m_outputControl & CTL_ROTATION) {
00442                         updateValues(y.rot, &m_values[i++], &m_rot, CTL_ROTATIONX);
00443                 }
00444                 if ((*m_constraintCallback)(timestamp, m_values, m_nvalues, m_constraintParam)) {
00445                         setControlParameters(m_values, m_nvalues, (found && timestamp.interpolate)?timestamp.realTimestep:0.0);
00446                 }
00447         }
00448         if (m_outputControl & CTL_POSITION) {
00449                 updateOutput(y.vel, &m_pos, CTL_POSITIONX);
00450         }
00451         if (m_outputControl & CTL_ROTATION) {
00452                 updateOutput(y.rot, &m_rot, CTL_ROTATIONX);
00453         }
00454 }
00455 
00456 const ConstraintValues* CopyPose::getControlParameters(unsigned int* _nvalues)
00457 {
00458         Twist y = diff(m_internalPose,F_identity);
00459         int i=0;
00460         if (m_outputControl & CTL_POSITION) {
00461                 updateValues(y.vel, &m_values[i++], &m_pos, CTL_POSITIONX);
00462         }
00463         if (m_outputControl & CTL_ROTATION) {
00464                 updateValues(y.rot, &m_values[i++], &m_rot, CTL_ROTATIONX);
00465         }
00466         if (_nvalues)
00467                 *_nvalues=m_nvalues; 
00468         return m_values; 
00469 }
00470 
00471 double CopyPose::getMaxTimestep(double& timestep)
00472 {
00473         // CopyPose should not have any limit on linear velocity: 
00474         // in case the target is out of reach, this can be very high.
00475         // We will simply limit on rotation
00476         e_scalar maxChidot = m_chidot.block(3,0,3,1).cwise().abs().maxCoeff();
00477         if (timestep*maxChidot > m_maxDeltaChi) {
00478                 timestep = m_maxDeltaChi/maxChidot;
00479         }
00480         return timestep;
00481 }
00482 
00483 }