00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "KNI/kmlExt.h"
00023 #include "KNI/kmlFactories.h"
00024
00025 #include "common/MathHelperFunctions.h"
00026 #include "common/Timer.h"
00027
00028 #include <iostream>
00029 #include <algorithm>
00030 #include <vector>
00031
00032 #define max(a,b) (((a)>(b))?(a):(b))
00033 KNI::Timer kni_timer;
00034
00036 const int POLLFREQUENCY = 300;
00037
00038 void CKatana::inc(long idx, int dif, bool wait, int tolerance, long timeout) {
00039 base->GetMOT()->arr[idx].inc(dif,wait,tolerance,timeout);
00040 }
00041
00042 void CKatana::dec(long idx, int dif, bool wait, int tolerance, long timeout) {
00043 base->GetMOT()->arr[idx].dec(dif,wait,tolerance,timeout);
00044 }
00045
00046 void CKatana::mov(long idx, int tar, bool wait, int tolerance, long timeout) {
00047 base->GetMOT()->arr[idx].mov(tar, wait,tolerance,timeout);
00048 }
00049
00050
00051
00052 void CKatana::incDegrees(long idx, double dif, bool wait, int tolerance, long timeout) {
00053 base->GetMOT()->arr[idx].incDegrees(dif,wait,tolerance,timeout);
00054 }
00055
00056 void CKatana::decDegrees(long idx, double dif, bool wait, int tolerance, long timeout) {
00057 base->GetMOT()->arr[idx].decDegrees(dif,wait,tolerance,timeout);
00058 }
00059
00060 void CKatana::movDegrees(long idx, double tar, bool wait, int tolerance, long timeout) {
00061 base->GetMOT()->arr[idx].movDegrees(tar,wait,tolerance,timeout);
00062 }
00063
00064
00065 void CKatana::create(const char* configurationFile, CCplBase* protocol) {
00066 KNI::kmlFactory infos;
00067 if(!infos.openFile(configurationFile)) {
00068 throw ConfigFileOpenException(configurationFile);
00069 }
00070 create(&infos, protocol);
00071 }
00072
00073 void CKatana::create(KNI::kmlFactory* infos, CCplBase* protocol) {
00074 base->init( infos->getGNL(), infos->getMOT(), infos->getSCT(), infos->getEFF(), protocol);
00075
00076 for(int i=0; i<getNumberOfMotors(); ++i) {
00077 TMotInit init = infos->getMotInit(i);
00078
00079 base->GetMOT()->arr[i].setInitialParameters(KNI_MHF::deg2rad(init.angleOffset), KNI_MHF::deg2rad(init.angleRange), init.encodersPerCycle, init.encoderOffset, init.rotationDirection);
00080
00081 TMotCLB clb = infos->getMotCLB(i);
00082 base->GetMOT()->arr[i].setCalibrationParameters( clb.enable, clb.order, clb.dir, clb.mcf, clb.encoderPositionAfter );
00083
00084 base->GetMOT()->arr[i].setDYL( infos->getMotDYL(i) );
00085 base->GetMOT()->arr[i].setSCP( infos->getMotSCP(i) );
00086 }
00087 mKatanaType = infos->getType();
00088 if (mKatanaType == 450) {
00089 mKinematics = infos->getKinematics();
00090 if (protocol != NULL)
00091 base->flushMoveBuffers();
00092 } else {
00093 mKinematics = 0;
00094 }
00095 if(base->checkKatanaType(mKatanaType) < 0){
00096
00097 std::cout << "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
00098 std::cout << "Exit: Incompatible Config File!\n";
00099 std::cout << "Check whether you have a Katana 400 or 300 and choose the config file accordingly\n";
00100 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n.";
00101 exit(0);
00102 }
00103 bool gripperIsPresent;
00104 int gripperOpenEncoders, gripperCloseEncoders;
00105 infos->getGripperParameters(gripperIsPresent, gripperOpenEncoders, gripperCloseEncoders);
00106 setGripperParameters(gripperIsPresent, gripperOpenEncoders, gripperCloseEncoders);
00107
00108 }
00109
00110 void CKatana::create(TKatGNL& gnl, TKatMOT& mot, TKatSCT& sct, TKatEFF& eff, CCplBase* protocol) {
00111 base->init(gnl, mot, sct, eff, protocol);
00112 }
00113
00114
00115 void CKatana::calibrate() {
00116 if(mKatanaType >= 400){
00117 std::cout << "Katana4xx calibration started\n";
00118
00119 TMotCmdFlg cflg = MCF_CALIB;
00120 TMotTPS tps;
00121 tps.tarpos = 32000;
00122 tps.mcfTPS = cflg;
00123 for(int i=0; i < getNumberOfMotors(); ++i){
00124 base->GetMOT()->arr[i].setCalibrated(false);
00125 }
00127
00128 byte p[32];
00129 byte buf[256];
00130 byte sz = 10;
00131 p[0] = 'C';
00132 p[1] = 0;
00133 p[2] = 4;
00134 p[3] = (byte)(tps.tarpos >> 8);
00135 p[4] = (byte)(tps.tarpos);
00136 base->getProtocol()->comm(p,buf,&sz);
00138 for (int i=0; i < getNumberOfMotors(); ++i) {
00139 base->GetMOT()->arr[i].setCalibrated(true);
00140 }
00141
00142 p[0] = 'D';
00143 p[1] = 1;
00144 do{
00145 KNI::sleep(1000);
00146 base->getProtocol()->comm(p,buf,&sz);
00147 }
00148 while(buf[2] == 4);
00149 std::cout << "...done with calibration.\n";
00150
00151 }
00152 else if(mKatanaType == 300){
00153 std::cout << "Katana300 calibration started\n";
00154 KNI::sleep(500);
00155
00156
00157
00158
00159
00160 TMotAPS aps;
00161 for (int i=0; i<getNumberOfMotors(); i++) {
00162 aps.actpos = 0;
00163 aps.mcfAPS = MCF_ON;
00164 base->GetMOT()->arr[i].sendAPS(&aps);
00165 }
00166 for (int i=0; i < getNumberOfMotors(); ++i) {
00167 for(int j=0; j < getNumberOfMotors(); ++j) {
00168 if(base->GetMOT()->arr[j].GetCLB()->order == i) {
00169 base->GetMOT()->arr[j].setCalibrated(false);
00170 calibrate( j, *base->GetMOT()->arr[j].GetCLB(), *base->GetMOT()->arr[j].GetSCP(), *base->GetMOT()->arr[j].GetDYL() );
00171 base->GetMOT()->arr[j].setCalibrated(true);
00172 break;
00173 }
00174 }
00175 }
00176 }
00177 }
00178
00179
00180
00181 void CKatana::calibrate(long idx, TMotCLB clb, TMotSCP scp, TMotDYL dyl) {
00182
00183 if (!clb.enable)
00184 return;
00185
00186 searchMechStop(idx,clb.dir,scp,dyl);
00187
00188 TMotAPS aps = { clb.mcf, base->GetMOT()->arr[idx].GetInitialParameters()->encoderOffset };
00189 base->GetMOT()->arr[idx].sendAPS(&aps);
00190
00191 mov(idx, clb.encoderPositionAfter, true);
00192 }
00193
00194
00195 void CKatana::searchMechStop(long idx, TSearchDir dir,
00196 TMotSCP _scp, TMotDYL _dyl ) {
00197
00198 base->GetMOT()->arr[idx].setPwmLimits(_scp.maxppwm_nmp, _scp.maxnpwm_nmp);
00199 base->GetMOT()->arr[idx].setControllerParameters(_scp.kspeed_nmp, _scp.kpos_nmp, _scp.kI_nmp);
00200 base->GetMOT()->arr[idx].setCrashLimit(_scp.crash_limit_nmp);
00201 base->GetMOT()->arr[idx].setCrashLimitLinear(_scp.crash_limit_lin_nmp);
00202 base->GetMOT()->arr[idx].setAccelerationLimit(1);
00203 base->GetMOT()->arr[idx].setSpeedLimits(25, 25);
00204
00205 TMotAPS aps;
00206 switch (dir) {
00207 case DIR_POSITIVE:
00208 aps.actpos = -31000;
00209 aps.mcfAPS = MCF_FREEZE;
00210 base->GetMOT()->arr[idx].sendAPS(&aps);
00211 break;
00212 case DIR_NEGATIVE:
00213 aps.actpos = 31000;
00214 aps.mcfAPS = MCF_FREEZE;
00215 base->GetMOT()->arr[idx].sendAPS(&aps);
00216 break;
00217 };
00218
00219 TMotTPS tps;
00220 switch (dir) {
00221 case DIR_POSITIVE:
00222 tps.tarpos = 32000;
00223 tps.mcfTPS = MCF_ON;
00224 base->GetMOT()->arr[idx].sendTPS(&tps);
00225
00226 break;
00227 case DIR_NEGATIVE:
00228 tps.tarpos = -32000;
00229 tps.mcfTPS = MCF_ON;
00230 base->GetMOT()->arr[idx].sendTPS(&tps);
00231
00232
00233 break;
00234 };
00235
00236 double firstSpeedSample = 100, secondSpeedSample = 100;
00237
00238 KNI::Timer poll_t(POLLFREQUENCY);
00239 while(true) {
00240 poll_t.Start();
00241 base->GetMOT()->arr[idx].recvPVP();
00242 firstSpeedSample = base->GetMOT()->arr[idx].GetPVP()->vel;
00243
00244 if( (firstSpeedSample + secondSpeedSample) == 0.0 ) {
00245 break;
00246 }
00247 secondSpeedSample = firstSpeedSample;
00248 poll_t.WaitUntilElapsed();
00249 }
00250
00251
00252
00253
00254 aps.actpos = 0;
00255 aps.mcfAPS = MCF_FREEZE;
00256
00257 base->GetMOT()->arr[idx].sendAPS(&aps);
00258
00259
00260
00261 base->GetMOT()->arr[idx].setPwmLimits(_scp.maxppwm_nmp, _scp.maxnpwm_nmp);
00262 base->GetMOT()->arr[idx].setControllerParameters(_scp.kspeed_nmp, _scp.kpos_nmp, _scp.kI_nmp);
00263 base->GetMOT()->arr[idx].setCrashLimit(_scp.crash_limit_nmp);
00264 base->GetMOT()->arr[idx].setCrashLimitLinear(_scp.crash_limit_lin_nmp);
00265 base->GetMOT()->arr[idx].setAccelerationLimit((short) _dyl.maxaccel_nmp);
00266 base->GetMOT()->arr[idx].setSpeedLimits(_dyl.maxpspeed_nmp, _dyl.maxnspeed_nmp);
00267
00268 }
00269
00270
00271 void CKatana::setTolerance(long idx, int enc_tolerance) {
00272 base->GetMOT()->arr[idx].setTolerance(enc_tolerance);
00273 }
00274
00275
00276 bool CKatana::checkENLD(long idx, double degrees) {
00277 return base->GetMOT()->arr[idx].checkAngleInRange(degrees);
00278 }
00279
00280
00281 void CKatana::enableCrashLimits() {
00282 base->enableCrashLimits();
00283 }
00284
00285
00286 void CKatana::disableCrashLimits() {
00287 base->disableCrashLimits();
00288 }
00289
00290
00291 void CKatana::unBlock() {
00292 base->unBlock();
00293 }
00294
00295
00296 void CKatana::flushMoveBuffers() {
00297 base->flushMoveBuffers();
00298 }
00299
00300
00301 void CKatana::setCrashLimit(long idx, int limit) {
00302 base->setCrashLimit(idx, limit);
00303 }
00304
00306 void CKatana::setPositionCollisionLimit(long idx, int limit){
00307 base->GetMOT()->arr[idx].setPositionCollisionLimit(limit);
00308 }
00310 void CKatana::setSpeedCollisionLimit(long idx, int limit){
00311 base->GetMOT()->arr[idx].setSpeedCollisionLimit(limit);
00312 }
00314 void CKatana::setForceLimit(int axis, int limit){
00315 if(axis == 0){
00316 for (int i=1; i <= getNumberOfMotors(); i++) {
00317 setForceLimit(i, limit);
00318 }
00319 }
00320
00321
00322 if (axis < 1) return;
00323 if (axis > getNumberOfMotors()) return;
00324
00325
00326 if (base->GetMOT()->arr[axis-1].GetSFW()->type == 0) return;
00327
00328 int force = abs(limit);
00329 if (force > 100)
00330 force = 100;
00331
00332 byte p[32];
00333 byte buf[256];
00334 byte sz = 0;
00335 p[0] = 'S';
00336 p[1] = axis;
00337 p[2] = 10;
00338 p[3] = (char)(force >> 8);
00339 p[4] = (char)(force);
00340 p[5] = 0;
00341 base->getProtocol()->comm(p,buf,&sz);
00342 }
00344 short CKatana::getForce(int axis){
00345 byte r1, r2, r3;
00346 base->GetMOT()->arr[axis-1].getParameterOrLimit(244, &r1, &r2, &r3);
00347 char force = (char)r2;
00348 return (short)force;
00349 }
00351 int CKatana::getCurrentControllerType(int axis){
00352 base->GetMOT()->arr[axis-1].recvSFW();
00353 return (int) base->GetMOT()->arr[axis-1].GetSFW()->type;
00354 }
00356 short
00357 CKatana::getNumberOfMotors() const {
00358 return base->GetMOT()->cnt;
00359 }
00360
00361 int
00362 CKatana::getMotorEncoders(short number, bool refreshEncoders) const {
00363 if(refreshEncoders)
00364 base->GetMOT()->arr[number].recvPVP();
00365 return base->GetMOT()->arr[number].GetPVP()->pos;
00366 }
00367
00368 std::vector<int>::iterator
00369 CKatana::getRobotEncoders(std::vector<int>::iterator start, std::vector<int>::const_iterator end, bool refreshEncoders) const {
00370 if(refreshEncoders)
00371 base->recvMPS();
00372 std::vector<int>::iterator iter = start;
00373 for(int i = 0; i < getNumberOfMotors(); ++i) {
00374 if(iter == end)
00375 return iter;
00376 (*iter) = getMotorEncoders(i, false);
00377 ++iter;
00378 }
00379 return iter;
00380 }
00381
00382 std::vector<int>
00383 CKatana::getRobotEncoders(bool refreshEncoders) const {
00384 std::vector<int> temp(getNumberOfMotors());
00385 getRobotEncoders(temp.begin(),temp.end(), refreshEncoders);
00386 return temp;
00387 }
00388
00389 short
00390 CKatana::getMotorVelocityLimit(short number) const {
00391 return base->GetMOT()->arr[number].GetDYL()->maxpspeed_nmp;
00392 }
00393 short
00394 CKatana::getMotorAccelerationLimit(short number) const {
00395 return base->GetMOT()->arr[number].GetDYL()->maxaccel_nmp;
00396 }
00397
00398 void
00399 CKatana::setMotorVelocityLimit(short number, short velocity) {
00400 base->GetMOT()->arr[number].setSpeedLimit(velocity);
00401 }
00402
00403 void
00404 CKatana::setRobotVelocityLimit(short velocity) {
00405 for(short c = 0; c < getNumberOfMotors(); ++c) {
00406 base->GetMOT()->arr[c].setSpeedLimit( velocity );
00407 }
00408 }
00409
00410 void
00411 CKatana::setMotorAccelerationLimit(short number, short acceleration) {
00412 base->GetMOT()->arr[number].setAccelerationLimit(acceleration);
00413 }
00414
00415 void
00416 CKatana::setRobotAccelerationLimit(short acceleration) {
00417 for(short c = 0; c < getNumberOfMotors(); ++c) {
00418 base->GetMOT()->arr[c].setAccelerationLimit(acceleration);
00419 }
00420 }
00421
00422 void
00423 CKatana::moveMotorByEnc(short number, int encoders, bool waitUntilReached, int waitTimeout) {
00424 if(encoders >= 0) {
00425 inc(number, encoders, waitUntilReached, waitTimeout);
00426 } else {
00427 dec(number, abs(encoders), waitUntilReached, 100, waitTimeout);
00428 }
00429 }
00430
00431 void
00432 CKatana::moveMotorBy(short number, double radianAngle, bool waitUntilReached, int waitTimeout) {
00433 double degree = radianAngle/M_PI*180;
00434 base->GetMOT()->arr[number].incDegrees(degree, waitUntilReached, 100, waitTimeout);
00435 }
00436
00437 void
00438 CKatana::moveMotorToEnc(short number, int encoders, bool waitUntilReached, int encTolerance, int waitTimeout) {
00439 mov(number, encoders, waitUntilReached, encTolerance, waitTimeout);
00440 }
00441
00442 void
00443 CKatana::moveMotorTo(short number, double radianAngle, bool waitUntilReached, int waitTimeout) {
00444 int encoders = KNI_MHF::rad2enc( radianAngle,
00445 base->GetMOT()->arr[number].GetInitialParameters()->angleOffset,
00446 base->GetMOT()->arr[number].GetInitialParameters()->encodersPerCycle,
00447 base->GetMOT()->arr[number].GetInitialParameters()->encoderOffset,
00448 base->GetMOT()->arr[number].GetInitialParameters()->rotationDirection);
00449 mov(number, encoders, waitUntilReached, 100, waitTimeout);
00450 }
00451
00452 void
00453 CKatana::waitForMotor( short number, int encoders, int encTolerance, short mode, int waitTimeout){
00454 base->GetMOT()->arr[number].waitForMotor(encoders,encTolerance, mode, waitTimeout);
00455 }
00456
00457 void
00458 CKatana::waitFor(TMotStsFlg status, int waitTimeout) {
00459 base->waitFor(status, waitTimeout, _gripperIsPresent);
00460 }
00461
00462 void
00463 CKatana::moveRobotToEnc(std::vector<int>::const_iterator start, std::vector<int>::const_iterator end, bool waitUntilReached, int encTolerance, int waitTimeout) {
00464
00465
00466
00467
00468
00469
00470
00471 int i = 0;
00472 std::vector<int>::const_iterator iter = start;
00473 while( (iter != end) && (i < getNumberOfMotors()) ) {
00474
00475
00476
00477 mov(i, *iter, false, encTolerance, waitTimeout);
00478 ++i;
00479 ++iter;
00480 }
00481
00482
00483 if(!waitUntilReached)
00484 return;
00485
00486 const TKatMOT* mot = base->GetMOT();
00487 bool pos_reached;
00488 KNI::Timer t(waitTimeout), poll_t(POLLFREQUENCY);
00489 t.Start();
00490 while (true) {
00491 if (t.Elapsed())
00492 throw MotorTimeoutException();
00493 pos_reached = true;
00494 poll_t.Start();
00495 base->recvMPS();
00496 base->recvGMS();
00497 for (int idx=0; idx<getNumberOfMotors(); idx++) {
00498 if (mot->arr[idx].GetPVP()->msf == 40)
00499 throw MotorCrashException();
00500 pos_reached &= std::abs(mot->arr[idx].GetTPS()->tarpos - mot->arr[idx].GetPVP()->pos) < 100;
00501 }
00502 if (pos_reached)
00503 break;
00504 poll_t.WaitUntilElapsed();
00505 }
00506 }
00507
00508 void
00509 CKatana::moveRobotToEnc(std::vector<int> encoders, bool waitUntilReached, int encTolerance, int waitTimeout) {
00510 moveRobotToEnc(encoders.begin(), encoders.end(), waitUntilReached, encTolerance, waitTimeout);
00511 }
00512
00513 void
00514 CKatana::moveRobotToEnc4D(std::vector<int> target, int velocity, int acceleration, int encTolerance){
00515
00516 int n, maxDistance = 0;
00517 short numberOfMotors = getNumberOfMotors();
00518 std::vector<int> diffMot,speed,oldSpeed;
00519
00520
00521 for (n=0;n<numberOfMotors;n++){
00522 diffMot.push_back(std::abs(getMotorEncoders(n,true)-target.at(n)));
00523 maxDistance=max(diffMot.at(n),maxDistance);
00524 }
00525
00526
00527 for (n=0;n<numberOfMotors;n++){
00528 oldSpeed.push_back(getMotorVelocityLimit(n));
00529 speed.push_back(max(static_cast<int>((static_cast<double>(diffMot.at(n))/maxDistance) * velocity),10));
00530 setMotorVelocityLimit(n,speed.at(n));
00531 setMotorAccelerationLimit(n,acceleration);
00532 }
00533
00534
00535 for (n=0;n<numberOfMotors;n++){
00536 moveMotorToEnc(n,target.at(n));
00537 }
00538
00539
00540 for (n=0;n<numberOfMotors;n++){
00541 waitForMotor(n,target.at(n),encTolerance);
00542 }
00543
00544
00545 for (n=0;n<numberOfMotors;n++){
00546 setMotorVelocityLimit(n,oldSpeed.at(n));
00547 }
00548 }
00549
00550 void
00551 CKatana::openGripper(bool waitUntilReached, int waitTimeout) {
00552 if(!_gripperIsPresent)
00553 return;
00554 moveMotorToEnc( getNumberOfMotors()-1, _gripperOpenEncoders, waitUntilReached, waitTimeout );
00555 }
00556
00557 void
00558 CKatana::closeGripper(bool waitUntilReached, int waitTimeout) {
00559 if(!_gripperIsPresent)
00560 return;
00561 moveMotorToEnc( getNumberOfMotors()-1, _gripperCloseEncoders, waitUntilReached, waitTimeout );
00562 }
00563
00564
00565 void
00566 CKatana::freezeRobot() {
00567 for(int i = 0; i < getNumberOfMotors(); ++i)
00568 freezeMotor(i);
00569 }
00570 void
00571 CKatana::freezeMotor(short number) {
00572 base->GetMOT()->arr[number].recvPVP();
00573 const TMotPVP *pvp = base->GetMOT()->arr[number].GetPVP();
00574 TMotTPS tps = { MCF_FREEZE, pvp->pos };
00575 base->GetMOT()->arr[number].sendTPS(&tps);
00576 }
00577 void
00578 CKatana::switchRobotOn() {
00579 for(int i = 0; i < getNumberOfMotors(); ++i)
00580
00581 freezeMotor(i);
00582 }
00583 void
00584 CKatana::switchRobotOff() {
00585 for(int i = 0; i < getNumberOfMotors(); ++i)
00586 switchMotorOff(i);
00587 }
00588 void
00589 CKatana::switchMotorOn(short number) {
00590 base->GetMOT()->arr[number].recvPVP();
00591 const TMotPVP *pvp = base->GetMOT()->arr[number].GetPVP();
00592 TMotTPS tps = { MCF_FREEZE, pvp->pos };
00593 base->GetMOT()->arr[number].sendTPS(&tps);
00594 }
00595 void
00596 CKatana::switchMotorOff(short number) {
00597 base->GetMOT()->arr[number].recvPVP();
00598 const TMotPVP *pvp = base->GetMOT()->arr[number].GetPVP();
00599 TMotTPS tps = { MCF_OFF, pvp->pos };
00600 base->GetMOT()->arr[number].sendTPS(&tps);
00601 }
00602
00603 void
00604 CKatana::setGripperParameters(bool isPresent, int openEncoders, int closeEncoders) {
00605 _gripperIsPresent = isPresent;
00606 _gripperOpenEncoders = openEncoders;
00607 _gripperCloseEncoders = closeEncoders;
00608 }
00609
00610 void
00611 CKatana::getGripperParameters(bool &isPresent, int &openEncoders, int &closeEncoders) {
00612 isPresent = _gripperIsPresent;
00613 openEncoders = _gripperOpenEncoders;
00614 closeEncoders = _gripperCloseEncoders;
00615 }
00616
00617 void
00618 CKatana::startSplineMovement(bool exactflag, int moreflag) {
00619 int exact = 0;
00620 if (exactflag) {
00621 exact = 1;
00622 }
00623 if (!_gripperIsPresent) {
00624 exact += 2;
00625 }
00626 base->startSplineMovement(exact, moreflag);
00627 }
00628
00629
00630 void
00631 CKatana::sendSplineToMotor(short number, short targetPosition, short duration, short p1, short p2, short p3, short p4) {
00632 base->GetMOT()->arr[number].sendSpline(targetPosition, duration, p1, p2, p3, p4);
00633 }
00634
00635 void
00636 CKatana::setAndStartPolyMovement(std::vector<short> polynomial, bool exactflag, int moreflag) {
00637 int exact = 0;
00638 if (exactflag) {
00639 exact = 1;
00640 }
00641 if (!_gripperIsPresent) {
00642 exact += 2;
00643 }
00644 base->setAndStartPolyMovement(polynomial, exact, moreflag);
00645 }
00646
00647 int CKatana::readDigitalIO(){
00648 return base->readDigitalIO();
00649 }