worldsim/src/motorcontrollers.cpp

00001 /********************************************************************************
00002  *  WorldSim -- library for robot simulations                                   *
00003  *  Copyright (C) 2008-2011 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 "worldsimconfig.h"
00021 #include "motorcontrollers.h"
00022 #include "phyjoint.h"
00023 #include "world.h"
00024 
00025 #ifdef __GNUC__
00026 #pragma GCC diagnostic ignored "-Wunused-parameter"
00027 #endif
00028     #include <yarp/os/Searchable.h>
00029 #ifdef __GNUC__
00030 #pragma GCC diagnostic warning "-Wunused-parameter"
00031 #endif
00032 
00033 #ifdef FARSA_USE_YARP_AND_ICUB
00034 using namespace yarp::dev;
00035 using namespace yarp::os;
00036 #endif
00037 
00038 namespace farsa {
00039 
00040 wPID::wPID() {
00041     p_gain = 0;
00042     i_gain = 0;
00043     d_gain = 0;
00044     acc_ff = 0;
00045     fri_ff = 0;
00046     vel_ff = 0;
00047     bias = 0;
00048     accel_r = 0;
00049     setpt = 0;
00050     min = 0;
00051     max = 0;
00052     slew = 0;
00053     this_target = 0;
00054     next_target = 0;
00055     integral = 0;
00056     last_error = 0;
00057     last_output = 0;
00058 }
00059 
00060 double wPID::pidloop( double PV ) {
00061     double     this_error;
00062     double     this_output;
00063     double     accel;
00064     double     deriv;
00065     double     friction;
00066     /* the desired PV for this iteration is the value     */
00067     /* calculated as next_target during the last loop     */
00068     this_target = next_target;
00069     /* test for acceleration, compute new target PV for   */
00070     /* the next pass through the loop                     */
00071     if ( accel_r > 0 && this_target != setpt) {
00072         if ( this_target < setpt ) {
00073             next_target += accel_r;
00074             if ( next_target > setpt ) {
00075                 next_target = setpt;
00076             }
00077         } else { /* this_target > setpoint */
00078             next_target -= accel_r;
00079             if ( next_target < setpt ) {
00080                 next_target = setpt;
00081             }
00082         }
00083     } else {
00084         next_target = setpt;
00085     }
00086     /* acceleration is the difference between the PV      */
00087     /* target on this pass and the next pass through the  */
00088     /* loop                                               */
00089     accel = next_target - this_target;
00090     /* the error for the current pass is the difference   */
00091     /* between the current target and the current PV      */
00092     this_error = this_target - PV;
00093     /* the derivative is the difference between the error */
00094     /* for the current pass and the previous pass         */
00095     deriv = this_error - last_error;
00096     /* a very simple determination of whether there is    */
00097     /* special friction to be overcome on the next pass,  */
00098     /* if the current PV is 0 and the target for the next */
00099     /* pass is not 0, stiction could be a problem         */
00100     friction = ( PV == 0.0 && next_target != 0.0 );
00101     /* the new error is added to the integral             */
00102     integral += this_target - PV;
00103     /* now that all of the variable terms have been       */
00104     /* computed they can be multiplied by the appropriate */
00105     /* coefficients and the resulting products summed     */
00106     this_output = p_gain * this_error
00107                 + i_gain * integral
00108                 + d_gain * deriv
00109                 + acc_ff * accel
00110                 + vel_ff * next_target
00111                 + fri_ff * friction
00112                 + bias;
00113     last_error   = this_error;
00114     /* check for slew rate limiting on the output change  */
00115     if ( 0 != slew ) {
00116         if ( this_output - last_output > slew ) {
00117             this_output = last_output + slew;
00118         } else if ( last_output - this_output > slew ) {
00119             this_output = last_output - slew;
00120         }
00121     }
00122     /* now check the output value for absolute limits     */
00123     if ( this_output < min ) {
00124         this_output = min;
00125     } else if ( this_output > max ) {
00126         this_output = max;
00127     }
00128     /* store the new output value to be used as the old   */
00129     /* output value on the next loop pass                 */
00130     return last_output = this_output;
00131 }
00132 
00133 void wPID::reset() {
00134     // Resetting status variables
00135     this_target = 0;
00136     next_target = 0;
00137     integral = 0;
00138     last_error = 0;
00139     last_output = 0;
00140 }
00141 
00142 MotorController::MotorController( World* world ) {
00143     enabled = true;
00144     worldv = world;
00145 }
00146 
00147 MotorController::~MotorController() {
00148 }
00149 
00150 
00151 MultiMotorController::MultiMotorController( QVector<PhyDOF*> dofs, World* world ) :
00152     MotorController(world),
00153 #ifdef FARSA_USE_YARP_AND_ICUB
00154     IPositionControl(),
00155     IVelocityControl(),
00156 #endif
00157     motorsv(dofs)
00158 {
00159     //--- common control variable initialization
00160     controlModes.fill( 1, motorsv.size() );
00161     refsacc.fill( 1.0, motorsv.size() );
00162     //--- IPositionControl variable initialization
00163     refs.fill( 0.0, motorsv.size() );
00164     refsvel.fill( 1.0, motorsv.size() );
00165     xfx0.fill( 0.0, motorsv.size() );
00166     x0.fill( 0.0, motorsv.size() );
00167     dx0.fill( 0.0, motorsv.size() );
00168     t.fill( 0.0, motorsv.size() );
00169     T.fill( 0.0, motorsv.size() );
00170     stops.fill( true, motorsv.size() );
00171     lastErrors.fill( 0.0, motorsv.size() );
00172     lastIs.fill( 0.0, motorsv.size() );
00173     lastTorques.fill( 0.0, motorsv.size() );
00174     // create PIDs with default values
00175     pos_pids.resize( motorsv.size() );
00176     for( int i=0; i<motorsv.size(); i++ ) {
00177         pos_pids[i] = new wPID();
00178         pos_pids[i]->p_gain = 0.8;
00179         pos_pids[i]->i_gain = 0.05;
00180         pos_pids[i]->d_gain = 0.0;
00181         pos_pids[i]->accel_r = 0;
00182         pos_pids[i]->min = -PI_GRECO/2.0;
00183         pos_pids[i]->max = +PI_GRECO/2.0;
00184     }
00185     //--- IVelocityControl variable initialization
00186     desiredVel.fill( 0.0, motorsv.size() );
00187     // create PIDs with default values
00188     vel_pids.resize( motorsv.size() );
00189     for( int i=0; i<motorsv.size(); i++ ) {
00190         vel_pids[i] = new wPID();
00191         vel_pids[i]->p_gain = 0.8;
00192         vel_pids[i]->i_gain = 0.1;
00193         vel_pids[i]->d_gain = 0.0;
00194         //vel_pids[i]->accel_r = 3;
00195         //vel_pids[i]->acc_ff = 0.3;
00196         vel_pids[i]->min = -toRad( 120 ); // rads / second
00197         vel_pids[i]->max = +toRad( 120 ); // rads / second
00198     }
00199     //--- IControlLimits variable initialization
00200     loLimits.resize( motorsv.size() );
00201     hiLimits.resize( motorsv.size() );
00202     for( int i=0; i<motorsv.size(); i++ ) {
00203         real fmin, fmax;
00204         motorsv[i]->limits( fmin, fmax );
00205         loLimits[i] = fmin;
00206         hiLimits[i] = fmax;
00207     }
00208 }
00209 
00210 MultiMotorController::~MultiMotorController() {
00211     for( int i=0; i<motorsv.size(); i++ ) {
00212         delete (vel_pids[i]);
00213         delete (pos_pids[i]);
00214     }
00215 }
00216 
00217 void MultiMotorController::update() {
00218     real accum, /*wishangle,*/ wishvel;
00219     for( int i=0; i<motorsv.size(); i++ ) {
00220         switch( controlModes[i] ) {
00221         case 1: /* Position Controller */
00222             if ( ! stops[i] ) {
00223                 real tFracT = t[i] / T[i];
00224                 real tFracT3= tFracT * tFracT * tFracT;
00225                 real tFracT4= tFracT * tFracT3;
00226                 real tFracT5= tFracT * tFracT4;
00227 
00228                 //--- code from p5f code from iCub/src/controller4Dc/Code/trajectory.c
00229                 //float xfx0 = _xf[jj] - _x0[jj];  --- already computed when positionMove has been called
00230                 //float dx0  = _dx0[jj];           --- computed when positionMove has been called
00231                 accum = dx0[i] * tFracT;
00232                 accum = accum + tFracT3 * (10.0*xfx0[i] - 6.0*dx0[i]);
00233                 accum = accum - tFracT4 * (15.0*xfx0[i] - 8.0*dx0[i]);
00234                 accum = accum + tFracT5 * (6.0*xfx0[i] - 3.0*dx0[i]);
00235                 //--- in p5f code are missing x0 because it's added inside step_trajectory
00236                 accum += x0[i];
00237             } else {
00238                 accum = refs[i];
00239             }
00240             //--- accum is the angle at which the joint must be at current time
00241             pos_pids[i]->setpt = accum;
00242 //          wishangle = pos_pids[i]->pidloop( fromRawPosition(i) );
00243             motorsv[i]->setDesiredPosition( toRawPosition(accum, i) /*wishangle*/ );
00244             //--- advance t
00245             t[i] += world()->timeStep();
00246             //--- stop if necessary
00247             stops[i] = ( t[i] / T[i] > 1.0 );
00248         break;
00249         case 2: /* Velocity Controller */
00250             //--- the velocity at which the joint must be at current time
00251             vel_pids[i]->setpt = desiredVel[i];
00252             wishvel = vel_pids[i]->pidloop( motorsv[i]->velocity() );
00253             motorsv[i]->setDesiredVelocity( wishvel );
00254 //          motorsv[i]->setDesiredVelocity(desiredVel[i]); // This disables the PID
00255             break;
00256         default:
00257             break;
00258         }
00259     }
00260     return;
00261 }
00262 
00263 #ifdef FARSA_USE_YARP_AND_ICUB
00264 
00265 bool MultiMotorController::open( yarp::os::Searchable & ) {
00266     return true;
00267 }
00268 
00269 bool MultiMotorController::close( ) {
00270     return true;
00271 }
00272 
00273 bool MultiMotorController::configure( yarp::os::Searchable & ) {
00274     return true;
00275 }
00276 
00277 #endif
00278 
00279 bool MultiMotorController::getAxes( int *ax ) {
00280     *ax = motorsv.size();
00281     return true;
00282 }
00283 
00284 bool MultiMotorController::setPositionMode() {
00285     //controlMode = 1;
00286     return true;
00287 }
00288 
00289 bool MultiMotorController::positionMove(int j, double ref) {
00290     if ( j < 0 && j >= motorsv.size() ) {
00291         return false;
00292     }
00293     if ( motorsv[j]->translate() ) {
00294         refs[j] = ref;
00295     } else {
00296         refs[j] = toRad( ref );
00297     }
00298     if ( motorsv[j]->isLimited() ) {
00299         //--- check the limits
00300         //--- stay too near to the limits may create oscillation of the joint
00301         //--- about 0.5% of the range of the joint
00302         real offset = (fabs(hiLimits[j])-fabs(loLimits[j]))*0.005;
00303         refs[j] = ramp( loLimits[j]+offset, hiLimits[j]-offset, refs[j] );
00304     }
00305     //--- calculate xfx0, dx0, T
00306     x0[j] = fromRawPosition(j);
00307     xfx0[j] = refs[j] - x0[j];
00308     dx0[j] = motorsv[j]->velocity();
00309     T[j] = fabs( xfx0[j] ) / refsvel[j];
00310     //--- reset t to zero
00311     t[j] = 0.0;
00312     // if T[j] is less that 10 ms, then it simply stay there
00313     stops[j] = ( T[j] < 0.010 );
00314     controlModes[j] = 1;
00315     return true;
00316 }
00317 
00318 bool MultiMotorController::positionMove(const double *newrefs) {
00319     for( int i=0; i<refs.size(); i++ ) {
00320         if ( motorsv[i]->translate() ) {
00321             refs[i] = newrefs[i];
00322         } else {
00323             refs[i] = toRad( newrefs[i] );
00324         }
00325         if ( motorsv[i]->isLimited() ) {
00326             //--- check the limits
00327             //--- stay too near to the limits may create oscillation of the joint
00328             //--- about 0.5% of the range of the joint
00329             real offset = (fabs(hiLimits[i])-fabs(loLimits[i]))*0.005;
00330             refs[i] = ramp( loLimits[i]+offset, hiLimits[i]-offset, refs[i] );
00331         }
00332         //--- calculate xfx0, dx0, T
00333         x0[i] = fromRawPosition( i );
00334         xfx0[i] = refs[i] - x0[i];
00335         dx0[i] = motorsv[i]->velocity();
00336         T[i] = fabs( xfx0[i] ) / refsvel[i];
00337         //--- reset t to zero
00338         t[i] = 0.0;
00339         // if T[j] is less that 10 ms, then it simply stay there
00340         stops[i] = ( T[i] < 0.010 );
00341         controlModes[i] = 1;
00342     }
00343     return true;
00344 }
00345 
00346 bool MultiMotorController::relativeMove(int j, double delta) {
00347     if ( j < 0 && j >= motorsv.size() ) {
00348         return false;
00349     }
00350     if ( motorsv[j]->translate() ) {
00351         refs[j] += delta;
00352     } else {
00353         refs[j] += toRad( delta );
00354     }
00355     if ( motorsv[j]->isLimited() ) {
00356         //--- check the limits
00357         //--- stay too near to the limits may create oscillation of the joint
00358         //--- about 0.5% of the range of the joint
00359         real offset = (fabs(hiLimits[j])-fabs(loLimits[j]))*0.005;
00360         refs[j] = ramp( loLimits[j]+offset, hiLimits[j]-offset, refs[j] );
00361     }
00362     //--- calculate xfx0, dx0, T
00363     x0[j] = fromRawPosition(j);
00364     xfx0[j] = refs[j] - x0[j];
00365     dx0[j] = motorsv[j]->velocity();
00366     T[j] = fabs( xfx0[j] ) / refsvel[j];
00367     //--- reset t to zero
00368     t[j] = 0.0;
00369     stops[j] = false;
00370     controlModes[j] = 1;
00371     return true;
00372 }
00373 
00374 bool MultiMotorController::relativeMove(const double *deltas) {
00375     for( int i=0; i<refs.size(); i++ ) {
00376         if ( motorsv[i]->translate() ) {
00377             refs[i] += deltas[i];
00378         } else {
00379             refs[i] += toRad( deltas[i] );
00380         }
00381         if ( motorsv[i]->isLimited() ) {
00382             //--- check the limits
00383             //--- stay too near to the limits may create oscillation of the joint
00384             //--- about 0.5% of the range of the joint
00385             real offset = (fabs(hiLimits[i])-fabs(loLimits[i]))*0.005;
00386             refs[i] = ramp( loLimits[i]+offset, hiLimits[i]-offset, refs[i] );
00387         }
00388         //--- calculate xfx0, dx0, T
00389         x0[i] = fromRawPosition( i );
00390         xfx0[i] = refs[i] - x0[i];
00391         dx0[i] = motorsv[i]->velocity();
00392         T[i] = fabs( xfx0[i] ) / refsvel[i];
00393         //--- reset t to zero
00394         t[i] = 0.0;
00395         stops[i] = false;
00396         controlModes[i] = 1;
00397     }
00398     return true;
00399 }
00400 
00401 bool MultiMotorController::checkMotionDone(int j, bool *flag) {
00402     if ( j < 0 && j >= motorsv.size() ) {
00403         return false;
00404     }
00405     //--- I should check the actual position or just if stops[j] is true ??
00406     *flag = ( fabs(fromRawPosition(j) - refs[j]) < 0.01745329 );
00407     //*flag = stops[j];
00408     return true;
00409 }
00410 
00411 bool MultiMotorController::checkMotionDone(bool *flag) {
00412     bool ends = true;
00413     for( int i=0; i<refs.size(); i++ ) {
00414         //--- I should check the actual position or just if stops[j] is true ??
00415         ends &= ( fabs(fromRawPosition(i) - refs[i]) < 0.01745329 );
00416         //ends &= stops[i];
00417         if ( !ends ) break;
00418     }
00419     *flag = ends;
00420     return true;
00421 }
00422 
00423 bool MultiMotorController::setRefSpeed(int j, double sp) {
00424     if ( j < 0 && j >= motorsv.size() ) {
00425         return false;
00426     }
00427     if ( motorsv[j]->translate() ) {
00428         refsvel[j] = sp;
00429     } else {
00430         refsvel[j] = toRad(sp);
00431     }
00432     motorsv[j]->setMaxVelocity( refsvel[j] );
00433     return true;
00434 }
00435 
00436 bool MultiMotorController::setRefSpeeds(const double *spds) {
00437     for( int i=0; i<refs.size(); i++ ) {
00438         if ( motorsv[i]->translate() ) {
00439             refsvel[i] = spds[i];
00440         } else {
00441             refsvel[i] = toRad(spds[i]);
00442         }
00443         motorsv[i]->setMaxVelocity( refsvel[i] );
00444     }
00445     return true;
00446 }
00447 
00448 bool MultiMotorController::setRefAcceleration(int j, double acc) {
00449     if ( j < 0 && j >= motorsv.size() ) {
00450         return false;
00451     }
00452     if ( motorsv[j]->translate() ) {
00453         refsacc[j] = acc;
00454     } else {
00455         refsacc[j] = toRad(acc);
00456     }
00457     return true;
00458 }
00459 
00460 bool MultiMotorController::setRefAccelerations(const double *accs) {
00461     for( int i=0; i<refs.size(); i++ ) {
00462         if ( motorsv[i]->translate() ) {
00463             refsacc[i] = accs[i];
00464         } else {
00465             refsacc[i] = toRad(accs[i]);
00466         }
00467     }
00468     return true;
00469 }
00470 
00471 bool MultiMotorController::getRefSpeed(int j, double *ref) {
00472     if ( j < 0 && j >= motorsv.size() ) {
00473         return false;
00474     }
00475     if ( motorsv[j]->translate() ) {
00476         *ref = refsvel[j];
00477     } else {
00478         *ref = toDegree(refsvel[j]);
00479     }
00480     return true;
00481 }
00482 
00483 bool MultiMotorController::getRefSpeeds(double *spds) {
00484     for( int i=0; i<refsvel.size(); i++ ) {
00485         if ( motorsv[i]->translate() ) {
00486             spds[i] = refsvel[i];
00487         } else {
00488             spds[i] = toDegree(refsvel[i]);
00489         }
00490     }
00491     return true;
00492 }
00493 
00494 bool MultiMotorController::getRefAcceleration(int j, double *acc) {
00495     if ( j < 0 && j >= motorsv.size() ) {
00496         return false;
00497     }
00498     if ( motorsv[j]->translate() ) {
00499         *acc = refsacc[j];
00500     } else {
00501         *acc = toDegree(refsacc[j]);
00502     }
00503     return true;
00504 }
00505 
00506 bool MultiMotorController::getRefAccelerations(double *accs) {
00507     for( int i=0; i<refsvel.size(); i++ ) {
00508         if ( motorsv[i]->translate() ) {
00509             accs[i] = refsacc[i];
00510         } else {
00511             accs[i] = toDegree(refsacc[i]);
00512         }
00513     }
00514     return true;
00515 }
00516 
00517 bool MultiMotorController::stop(int j) {
00518     if ( j < 0 && j >= motorsv.size() ) {
00519         return false;
00520     }
00521     refs[j] = fromRawPosition(j);
00522     stops[j] = true;
00523     desiredVel[j] = 0;
00524     motorsv[j]->setVelocity(0.0);
00525     controlModes[j] = 1;
00526     vel_pids[j]->reset();
00527     return true;
00528 }
00529 
00530 bool MultiMotorController::stop() {
00531     for( int i=0; i<motorsv.size(); i++ ) {
00532         refs[i] = fromRawPosition(i);
00533         stops[i] = true;
00534         desiredVel[i] = 0;
00535         motorsv[i]->setVelocity(0.0);
00536         controlModes[i] = 1;
00537         vel_pids[i]->reset();
00538     }
00539     return true;
00540 }
00541 
00542 bool MultiMotorController::setVelocityMode() {
00543     //controlMode = 2;
00544     return true;
00545 }
00546 
00547 bool MultiMotorController::velocityMove(int j, double sp) {
00548     if ( j < 0 && j >= motorsv.size() ) {
00549         return false;
00550     }
00551     controlModes[j] = 2;
00552     desiredVel[j] = toRad(sp);
00553     return true;
00554 }
00555 
00556 bool MultiMotorController::velocityMove(const double *sp) {
00557     for( int i=0; i<desiredVel.size(); i++ ) {
00558         desiredVel[i] = toRad(sp[i]);
00559         controlModes[i] = 2;
00560     }
00561     return true;
00562 }
00563 
00564 bool MultiMotorController::setPositionMode( int j ) {
00565     if ( j < 0 && j >= motorsv.size() ) {
00566         return false;
00567     }
00568     //--- set the position to actual position and stop the joint
00569     refs[j] = fromRawPosition(j);
00570     stops[j] = true;
00571     controlModes[j] = 1;
00572     return true;
00573 }
00574 
00575 bool MultiMotorController::setVelocityMode(int j ) {
00576     if ( j < 0 && j >= motorsv.size() ) {
00577         return false;
00578     }
00579     //--- set the desired velocity to zero and stop the joint
00580     desiredVel[j] = 0;
00581     stops[j] = true;
00582     controlModes[j] = 2;
00583     return true;
00584 }
00585 
00586 bool MultiMotorController::setTorqueMode( int j ) {
00587     if ( j < 0 && j >= motorsv.size() ) {
00588         return false;
00589     }
00590     //--- torque mode not implemented yet
00591     return false;
00592 }
00593 
00594 bool MultiMotorController::getControlMode( int j, int* mode ) {
00595     if ( j < 0 && j >= motorsv.size() ) {
00596         return false;
00597     }
00598     *mode = controlModes[j];
00599     return true;
00600 }
00601 
00602 bool MultiMotorController::getControlModes( int* modes ) {
00603     for( int i=0; i<motorsv.size(); i++ ) {
00604         modes[i] = controlModes[i];
00605     }
00606     return true;
00607 }
00608 
00609 bool MultiMotorController::setOpenLoopMode( int ) {
00610     return false;
00611 }
00612 
00613 bool MultiMotorController::resetEncoder( int ) {
00614     return true;
00615 }
00616 
00617 bool MultiMotorController::resetEncoders() {
00618     return true;
00619 }
00620 
00621 bool MultiMotorController::setEncoder( int, double ) {
00622     return true;
00623 }
00624 
00625 bool MultiMotorController::setEncoders( const double* ) {
00626     return true;
00627 }
00628 
00629 bool MultiMotorController::getEncoder( int j, double *v ) {
00630     if ( j < 0 && j >= motorsv.size() ) {
00631         return false;
00632     }
00633     if ( motorsv[j]->translate() ) {
00634         (*v) = fromRawPosition(j);
00635     } else {
00636         (*v) = toDegree( fromRawPosition(j) );
00637     }
00638     return true;
00639 }
00640 
00641 bool MultiMotorController::getEncoders( double *encs ) {
00642     for( int i=0; i<motorsv.size(); i++ ) {
00643         if ( motorsv[i]->translate() ) {
00644             encs[i] = fromRawPosition(i);
00645         } else {
00646             encs[i] = toDegree( fromRawPosition(i) );
00647         }
00648     }
00649     return true;
00650 }
00651 
00652 bool MultiMotorController::getEncoderSpeed( int j, double *sp ) {
00653     if ( j < 0 && j >= motorsv.size() ) {
00654         return false;
00655     }
00656     if ( motorsv[j]->translate() ) {
00657         (*sp) = motorsv[j]->velocity();
00658     } else {
00659         (*sp) = toDegree(motorsv[j]->velocity());
00660     }
00661     return true;
00662 }
00663 
00664 bool MultiMotorController::getEncoderSpeeds( double *spds ) {
00665     for( int i=0; i<motorsv.size(); i++ ) {
00666         if ( motorsv[i]->translate() ) {
00667             spds[i] = motorsv[i]->velocity();
00668         } else {
00669             spds[i] = toDegree(motorsv[i]->velocity());
00670         }
00671     }
00672     return true;
00673 }
00674 
00675 bool MultiMotorController::getEncoderAcceleration( int, double * ) {
00676     return false;
00677 }
00678 
00679 bool MultiMotorController::getEncoderAccelerations( double * ) {
00680     return false;
00681 }
00682 
00683 bool MultiMotorController::setLimits( int axis, double min, double max ) {
00684     if ( axis < 0 && axis >= motorsv.size() ) {
00685         return false;
00686     }
00687     if ( motorsv[axis]->translate() ) {
00688         loLimits[axis] = min;
00689         hiLimits[axis] = max;
00690     } else {
00691         loLimits[axis] = toRad( min );
00692         hiLimits[axis] = toRad( max );
00693     }
00694     return true;
00695 }
00696     
00697 bool MultiMotorController::getLimits( int axis, double *min, double *max ) {
00698     if ( axis < 0 && axis >= motorsv.size() ) {
00699         return false;
00700     }
00701     if ( motorsv[axis]->translate() ) {
00702         *min = loLimits[axis];
00703         *max = hiLimits[axis];
00704     } else {
00705         *min = toDegree( loLimits[axis] );
00706         *max = toDegree( hiLimits[axis] );
00707     }
00708     return true;
00709 }
00710 
00711 bool MultiMotorController::setLimitsRaw( int axis, double min, double max ) {
00712     if ( axis < 0 && axis >= motorsv.size() ) {
00713         return false;
00714     }
00715     if ( motorsv[axis]->translate() ) {
00716         motorsv[axis]->setLimits( min, max );
00717     } else {
00718         motorsv[axis]->setLimits( toRad(min), toRad(max) );
00719     }
00720     return true;
00721 }
00722 
00723 bool MultiMotorController::getLimitsRaw( int axis, double *min, double *max ) {
00724     if ( axis < 0 && axis >= motorsv.size() ) {
00725         return false;
00726     }
00727     real fmin, fmax;
00728     motorsv[axis]->limits( fmin, fmax );
00729     if ( motorsv[axis]->translate() ) {
00730         *min = fmin;
00731         *max = fmax;
00732     } else {
00733         *min = toDegree( fmin );
00734         *max = toDegree( fmax );
00735     }
00736     return true;
00737 }
00738 
00739 bool MultiMotorController::setEnableLimitsRaw( int axis, bool enable ) {
00740     if ( axis < 0 && axis >= motorsv.size() ) {
00741         return false;
00742     }
00743     if ( enable ) {
00744         motorsv[axis]->enableLimits();
00745     } else {
00746         motorsv[axis]->disableLimits();
00747     }
00748     return true;
00749 }
00750 
00751 real MultiMotorController::fromRawPosition( int i ) {
00752     real rmin, rmax;
00753     motorsv[i]->limits( rmin, rmax );
00754     return linearMap( motorsv[i]->position(), rmin, rmax, loLimits[i], hiLimits[i] );
00755 }
00756 
00757 real MultiMotorController::toRawPosition( real norawpos, int i ) {
00758     real rmin, rmax;
00759     motorsv[i]->limits( rmin, rmax );
00760     return linearMap( norawpos, loLimits[i], hiLimits[i], rmin, rmax );
00761 }
00762 
00763 WheelMotorController::WheelMotorController( QVector<PhyDOF*> wheels, World* world ) :
00764     MotorController(world),
00765     motorsv(wheels) {
00766     desiredVel.fill( 0.0, motorsv.size() );
00767     minVel.fill( -1.0, motorsv.size() );
00768     maxVel.fill( 1.0, motorsv.size() );
00769 }
00770 
00771 WheelMotorController::~WheelMotorController() {
00772     /* nothing to do */
00773 }
00774 
00775 void WheelMotorController::update() {
00776     for( int i=0; i<motorsv.size(); i++ ) {
00777         motorsv[i]->setDesiredVelocity( desiredVel[i] );
00778     }
00779 }
00780 
00781 void WheelMotorController::setSpeeds( QVector<double> speeds ) {
00782     for( int i=0; i<qMin(speeds.size(), desiredVel.size()); i++ ) {
00783         if ( speeds[i] < minVel[i] ) {
00784             desiredVel[i] = minVel[i];
00785         } else if ( speeds[i] > maxVel[i] ) {
00786             desiredVel[i] = maxVel[i];
00787         } else {
00788             desiredVel[i] = speeds[i];
00789         }
00790     }
00791 }
00792 
00793 void WheelMotorController::setSpeeds( double sp1, double sp2 ) {
00794     if ( sp1 < minVel[0] ) {
00795         desiredVel[0] = minVel[0];
00796     } else if ( sp1 > maxVel[0] ) {
00797         desiredVel[0] = maxVel[0];
00798     } else {
00799         desiredVel[0] = sp1;
00800     }
00801 
00802     if ( sp2 < minVel[1] ) {
00803         desiredVel[1] = minVel[1];
00804     } else if ( sp2 > maxVel[0] ) {
00805         desiredVel[1] = maxVel[1];
00806     } else {
00807         desiredVel[1] = sp2;
00808     }
00809 }
00810 
00811 void WheelMotorController::getSpeeds( QVector<double>& speeds ) {
00812     speeds.clear();
00813     for( int i=0; i<motorsv.size(); i++ ) {
00814         speeds.append(motorsv[i]->velocity());
00815     }
00816 }
00817 
00818 void WheelMotorController::getSpeeds( double& sp1, double& sp2 ) {
00819     sp1 = motorsv[0]->velocity();
00820     sp2 = motorsv[1]->velocity();
00821 }
00822 
00823 void WheelMotorController::setSpeedLimits( QVector<double> minSpeeds, QVector<double> maxSpeeds ) {
00824     minVel = minSpeeds;
00825     maxVel = maxSpeeds;
00826 }
00827 
00828 void WheelMotorController::setSpeedLimits( double minSpeed1, double minSpeed2, double maxSpeed1, double maxSpeed2 ) {
00829     minVel[0] = minSpeed1;
00830     minVel[1] = minSpeed2;
00831     maxVel[0] = maxSpeed1;
00832     maxVel[1] = maxSpeed2;
00833 }
00834 
00835 void WheelMotorController::getSpeedLimits( QVector<double>& minSpeeds, QVector<double>& maxSpeeds ) {
00836     minSpeeds = minVel;
00837     maxSpeeds = maxVel;
00838 }
00839 
00840 void WheelMotorController::getSpeedLimits( double& minSpeed1, double& minSpeed2, double& maxSpeed1, double& maxSpeed2 ) {
00841     minSpeed1 = minVel[0];
00842     minSpeed2 = minVel[1];
00843     maxSpeed1 = maxVel[0];
00844     maxSpeed2 = maxVel[1];
00845 }
00846 
00847 } // end namespace farsa