Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SSC32Driver.cc

Go to the documentation of this file.
00001 #include "SSC32Driver.h"
00002 #include "Shared/MarkScope.h"
00003 #include "Shared/get_time.h"
00004 #include "Shared/debuget.h"
00005 
00006 using namespace std; 
00007 
00008 const unsigned int SSC32Driver::NUM_SERVO;
00009 const int SSC32Driver::UNUSED;
00010 const std::string SSC32Driver::autoRegisterSSC32Driver = DeviceDriver::getRegistry().registerType<SSC32Driver>("SSC32");
00011 
00012 void SSC32Driver::motionStarting() {
00013   ASSERTRET(!motionActive,"SSC32Driver::motionStarting, but motionActive is true");
00014   MotionHook::motionStarting();
00015   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00016   if(comm==NULL)
00017     std::cerr << "SSC32Driver \"" << instanceName << "\": could not find CommPort \"" << commName << "\"" << std::endl;
00018   else
00019     comm->open();
00020   motionActive=true;
00021   commName.addPrimitiveListener(this);
00022   
00023   for(unsigned i = 0; i < NUM_SERVO; i++) {
00024     if(killSignalDelayed[i]) {
00025       sparse=true;
00026       queryServos=true;
00027     }
00028   }
00029 }
00030 
00031 bool SSC32Driver::isConnected() {
00032   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00033   return (comm!=NULL && comm->isWriteable());
00034 }
00035 
00036 void SSC32Driver::motionStopping() {
00037   ASSERTRET(motionActive,"SSC32Driver::motionStopping, but motionActive is false");
00038   motionActive=false;
00039   if(!sensorsActive) // listener count is not recursive, so only remove if we're the last one
00040     commName.removePrimitiveListener(this);
00041   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00042   if(comm!=NULL)
00043     comm->close(); // this *is* recursive, so we always close it to match our open() in motionStarting()
00044   MotionHook::motionStopping();
00045 }
00046 
00047 void SSC32Driver::motionCheck(const float outputs[][NumOutputs]) {
00048   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00049   if(comm==NULL || !comm->isWriteable())
00050     return;
00051   
00052   stringstream ss;
00053   for(unsigned int i=0; i<NUM_SERVO; i++) {
00054     int idx=servos[i];
00055     if(idx<0 || static_cast<unsigned int>(idx)>=NumOutputs) {
00056       if(idx!=UNUSED)
00057         std::cerr << "Warning: SSC32 driver mapping servo " << i << " to invalid output index " << idx << std::endl;
00058       continue; // invalid/unused servo
00059     }
00060     
00061     //std::cout << "Test : " << i << " , " << outputs[NumFrames-1][idx] << std::endl;
00062     
00063     //int mode = modeCheck(outputs); || ((mode == 1) && (idx == 10))
00064     if(isFirstCheck || !sparse || lastOutputs[idx]!=outputs[NumFrames-1][idx] ) {
00065       /*std::cout << "Mode : " <<  mode << ", Servo: " << i << ", " << outputs[NumFrames-1][idx] << ", " << angleCalibration(i, mode, outputs[NumFrames-1][idx]) << ", " << lastOutputs[idx] << std::endl;*/
00066       setServo(ss, i, outputs[NumFrames-1][idx]);
00067     }
00068   }
00069   string s=ss.str();
00070   if(s.size()>0) { // if sparse and no changes, skip update altogether
00071     Thread::Lock& l = comm->getLock();
00072     unsigned int t=get_time();
00073     // keep trying to get the lock, sleeping 1 ms each time, until 3/4 the frame time is gone (then give up)
00074     unsigned int dt = static_cast<unsigned int>(NumFrames*FrameTime/((getTimeScale()>0)?getTimeScale():1.f));
00075     unsigned int giveup = t+dt*3/4;
00076     t+=dt;
00077     while(!l.trylock()) {
00078       if(get_time()>=giveup) {
00079         if(MotionHook::verbose>0)
00080           cerr << "Dropping SSC32 motion update: couldn't get lock on comm port" << endl;
00081         return;
00082       }
00083       usleep(1000);
00084     }
00085     MarkScope autolock(l); l.unlock(); //transfer lock to MarkScope
00086     std::ostream os(&comm->getWriteStreambuf());
00087 
00088     // request exception on badbit so we can thread_cancel read under linux
00089     // (otherwise we get FATAL: exception not rethrown / Abort error)
00090     os.exceptions(ios_base::badbit);
00091   
00092     unsigned int curt = get_time();
00093     if(curt>=t) // too late!
00094       os << s << '\r' << flush;
00095     else {
00096       dt=t-curt;
00097       os << s << 'T' << dt << '\r' << flush; // indicate time until next update
00098     }
00099   }
00100   
00101   MotionHook::motionCheck(outputs); // updates lastOutputs and isFirstCheck, we ignore its motionUpdated() call
00102 }
00103 
00104 
00105 unsigned int SSC32Driver::nextTimestamp() {
00106   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00107   if(comm==NULL || !comm->isReadable())
00108     return -1U;
00109   return static_cast<unsigned int>(lastSensorTime + 1000.f/(*sensorFramerate) + .5f);
00110 }
00111 
00112 void SSC32Driver::registerSource() {
00113   ASSERTRET(!sensorsActive,"SSC32Driver::registerSource, but sensorsActive is true");
00114   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00115   if(comm!=NULL)
00116     comm->open();
00117   queryServos.addPrimitiveListener(this);
00118   if(queryServos) {
00119     for(unsigned int i=0; i<NUM_SERVO; i++) {
00120       provideOutput(servos[i]);
00121       servos[i].addPrimitiveListener(this);
00122     }
00123   }
00124   sensorsActive=true;
00125   commName.addPrimitiveListener(this);
00126 }
00127 void SSC32Driver::deregisterSource() {
00128   ASSERTRET(sensorsActive,"SSC32Driver::deregisterSource, but sensorsActive is false");
00129   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00130   if(comm!=NULL)
00131     comm->close();
00132   if(queryServos) {
00133     for(unsigned int i=0; i<NUM_SERVO; ++i) {
00134       servos[i].removePrimitiveListener(this);
00135       ignoreOutput(servos[i]);
00136     }
00137   }
00138   queryServos.removePrimitiveListener(this);
00139   sensorsActive=false;
00140   if(!motionActive) // listener count is not recursive, so only remove if we're the last one
00141     commName.removePrimitiveListener(this);
00142 }
00143 void SSC32Driver::doUnfreeze() {
00144   MarkScope sl(poller.getStartLock());
00145   if(!poller.isStarted()) {
00146     poller.resetPeriod(1.0/(*sensorFramerate));
00147     poller.start();
00148   }
00149   sensorFramerate->addPrimitiveListener(this);
00150 }
00151 void SSC32Driver::doFreeze() {
00152   MarkScope sl(poller.getStartLock());
00153   if(poller.isStarted())
00154     poller.stop().join();
00155   sensorFramerate->removePrimitiveListener(this);
00156 }
00157 
00158 
00159 bool SSC32Driver::advance() {
00160   CommPort * comm = CommPort::getRegistry().getInstance(commName);
00161   if(comm==NULL || !comm->isReadable() || !comm->isWriteable())
00162     return false;
00163   
00164   MarkScope commlock(comm->getLock());
00165   std::ostream os(&comm->getWriteStreambuf());
00166   std::istream is(&comm->getReadStreambuf());
00167   
00168   // request exception on badbit so we can thread_cancel read under linux
00169   // (otherwise we get FATAL: exception not rethrown / Abort error)
00170   os.exceptions(ios_base::badbit);
00171   is.exceptions(ios_base::badbit);
00172   
00173   unsigned T = get_time();
00174   
00175   MarkScope writelock(getSensorWriteLock());
00176   // generally, bad idea to request servo position before position has been sent
00177   // But if the arm is still powered, it'll know it's position.  If the user has set WaitForSensors,
00178   // then DataSource::requiresFirstSensor will be set, otherwise we skip queries until we've sent
00179   // a servo position (and thus set the isFirstCheck flag
00180   if((!isFirstCheck || DataSource::requiresFirstSensor) && queryServos) {
00181     // check joint positions
00182     stringstream q;
00183     for(unsigned int i=0; i<NUM_SERVO; i++) {
00184       int idx=servos[i];
00185       if(idx<0 || static_cast<unsigned int>(idx)>=NumOutputs)
00186         continue; // invalid/unused servo
00187       q << "QP " << i << ' ';
00188     }
00189     try {
00190       os << q.rdbuf() << '\r' << flush;
00191     } catch(const std::exception&) {}
00192     if(!os) {
00193       std::cerr << "SSC32 position query failed (bad write)" << std::endl;
00194       return false;
00195     }
00196     for(unsigned int i=0; i<NUM_SERVO; i++) {
00197       int idx=servos[i];
00198       if(idx<0 || static_cast<unsigned int>(idx)>=NumOutputs)
00199         continue; // invalid/unused servo
00200       int check=is.get();
00201       if(check==-1) {
00202         cerr << "SSC32Driver: bad read!" << endl;
00203         return false;
00204       }
00205       unsigned int v=(unsigned char)check;
00206       if(killSignalDelayed[i]) {
00207         float val = getServo(i,v*10);
00208         float prev = getOutputValue(idx);
00209         
00210         if(val != prev) {
00211           timeLastChanged[i] = T;
00212         } else if(timeLastChanged[i] != 0 && T - timeLastChanged[i] > 1000) {
00213           os<<"#"<<i<<"L\r";
00214           os.flush();
00215           timeLastChanged[i] = 0;
00216         }
00217       }
00218       setOutputValue(idx, getServo(i,v*10));
00219     }
00220   }
00221   stringstream aq,dq;
00222   bool acnt=false,dcnt=false;
00223   for(unsigned int i=0; i<NUM_INPUT; i++) {
00224     int idx=inputs[i];
00225     if(!buttonMode[i]) {
00226       if(idx<0 || static_cast<unsigned int>(idx)>=NumSensors) {
00227         if(idx!=UNUSED)
00228           std::cerr << "Warning: SSC32 driver mapping input " << i << " to invalid sensor index " << idx << std::endl;
00229         continue; // invalid/unused servo
00230       }
00231       acnt=true;
00232       aq << 'V' << char('A'+i) << ' ';
00233     } else {
00234       if(idx<0 || static_cast<unsigned int>(idx)>=NumButtons) {
00235         if(idx!=UNUSED)
00236           std::cerr << "Warning: SSC32 driver mapping input " << i << " to invalid button index " << idx << std::endl;
00237         continue; // invalid/unused servo
00238       }
00239       dcnt=true;
00240       dq << char('A'+i) << ' ' << char('A'+i) << "L ";
00241     }
00242   }
00243   
00244   // send both queries now, we can process first response while SSC is processing second query
00245   try {
00246     if(dcnt)
00247       os << dq.str() << '\r';
00248     if(acnt)
00249       os << aq.str() << '\r';
00250     if(dcnt || acnt)
00251       os << flush;
00252   } catch(const std::exception&) {}
00253   if(!os) {
00254     std::cerr << "SSC32 sensor query failed (bad write)" << std::endl;
00255     return false;
00256   }
00257   
00258   // store responses
00259   if(dcnt) {
00260     for(unsigned int i=0; i<NUM_INPUT; i++) {
00261       int idx=inputs[i];
00262       if(idx>=0 && static_cast<unsigned int>(idx)<NumButtons && buttonMode[i]) {
00263         int check=is.get();
00264         if(check==-1) {
00265           cerr << "SSC32Driver: bad read!" << endl;
00266           return false;
00267         }
00268         unsigned char cur=check;
00269         check=is.get();
00270         if(check==-1) {
00271           cerr << "SSC32Driver: bad read!" << endl;
00272           return false;
00273         }
00274         unsigned char latch=check;
00275         setButtonValue(idx, getDigital(i,cur,latch));
00276       }
00277     }
00278   }
00279   if(acnt) {
00280     for(unsigned int i=0; i<NUM_INPUT; i++) {
00281       int idx=inputs[i];
00282       if(idx>=0 && static_cast<unsigned int>(idx)<NumSensors && !buttonMode[i]) {
00283         int check=is.get();
00284         if(check==-1) {
00285           cerr << "SSC32Driver: bad read!" << endl;
00286           return false;
00287         }
00288         setSensorValue(idx, getAnalog(i,check));
00289       }
00290     }
00291   }
00292   lastSensorTime=get_time();
00293   ++frameNumber;
00294   return true;
00295 }
00296 
00297 void SSC32Driver::plistValueChanged(const plist::PrimitiveBase& pl) {
00298   if(&pl==&commName) {
00299     // if here, then motionStarted or setDataSourceThread has been called, thus when commName changes,
00300     // need to close old one and reopen new one
00301     if(poller.isStarted())
00302       poller.stop().join();
00303     
00304     CommPort * comm = CommPort::getRegistry().getInstance(commName.getPreviousValue());
00305     if(comm!=NULL) {
00306       // close each of our old references
00307       if(sensorsActive)
00308         comm->close();
00309       if(motionActive)
00310         comm->close();
00311     }
00312     comm = CommPort::getRegistry().getInstance(commName);
00313     if(comm==NULL) {
00314       std::cerr << "SSC32Driver \"" << instanceName << "\": could not find CommPort \"" << commName << "\"" << std::endl;
00315     } else {
00316       // open each of our new references
00317       if(sensorsActive)
00318         comm->open();
00319       if(motionActive)
00320         comm->open();
00321     }
00322     
00323     if(getTimeScale()>0) {
00324       poller.resetPeriod(1.0/(*sensorFramerate));
00325       poller.start();
00326     }     
00327   } else if(&pl==&queryServos) {
00328     // if here, LoadDataThread has been assigned, need to update providing/ignoring outputs
00329     // (and maintain listeners for individual servos while providing)
00330     if(queryServos) {
00331       for(unsigned int i=0; i<NUM_SERVO; i++) {
00332         provideOutput(servos[i]);
00333         servos[i].addPrimitiveListener(this);
00334       }
00335     } else {
00336       for(unsigned int i=0; i<NUM_SERVO; ++i) {
00337         servos[i].removePrimitiveListener(this);
00338         ignoreOutput(servos[i]);
00339       }
00340     }
00341   } else if(&pl==sensorFramerate) {
00342     poller.resetPeriod(1.0/(*sensorFramerate));
00343   } else {
00344     // check if it's one of the individual servos... if it is, means we're providing servo feedback,
00345     // need to call providingOutput/ignoringOutput as appropriate
00346     for(unsigned int i=0; i<NUM_SERVO; ++i) {
00347       if(&pl==&servos[i]) {
00348         ignoreOutput(servos[i].getPreviousValue());
00349         provideOutput(servos[i]);
00350         return; // found it, DON'T fall through to error message below...
00351       }
00352     }
00353     std::cerr << "Unhandled value change in " << getClassName() << ": " << pl.get() << std::endl;
00354   }
00355 }
00356 
00357 void SSC32Driver::setServo(std::ostream& ss, unsigned int servoIdx, float v) {
00358   
00359     unsigned int outputIdx = servos[servoIdx];
00360   // get output's range in radians
00361   float outRange = outputRanges[outputIdx][MaxRange]-outputRanges[outputIdx][MinRange];
00362   // get servo's range in pulse width (ms)
00363   unsigned int servoRange = maxPW[servoIdx]-minPW[servoIdx];
00364   // get commanded position as percent of range of motion
00365   float cmd = (v-outputRanges[outputIdx][MinRange])/outRange;
00366   // flip commanded position -- map positive (high) rotation to low pulse width
00367   // this is so if you mount a servo "up", coordinate system will work correctly
00368 #ifdef TGT_HAS_LEDS
00369   if(outputIdx<LEDOffset || outputIdx>=LEDOffset+NumLEDs) // only flip non-LEDs though
00370     cmd=1-cmd;
00371 #endif
00372   // do conversion from radians (output domain) to pulse width (servo domain)
00373   float pw = cmd*servoRange+minPW[servoIdx];
00374   if(pw<0)
00375     pw=0;
00376   // round to int
00377   unsigned int bpw = static_cast<unsigned int>(pw+0.5);
00378   // check bounds
00379   if(bpw<minPW[servoIdx])
00380     bpw=minPW[servoIdx];
00381   if(bpw>maxPW[servoIdx])
00382     bpw=maxPW[servoIdx];
00383   // send to output buffer
00384   ss << '#' << servoIdx << " P" << bpw << ' ';
00385 }
00386 
00387 float SSC32Driver::getServo(unsigned int servoIdx, unsigned int pw) {
00388   unsigned int outputIdx = servos[servoIdx];
00389   // get output's range in radians
00390   float outRange = outputRanges[outputIdx][MaxRange]-outputRanges[outputIdx][MinRange];
00391   // get servo's range in pulse width (ms)
00392   unsigned int servoRange = maxPW[servoIdx]-minPW[servoIdx];
00393   // do conversion from pulse width (servo domain) to radians (output domain)
00394   return (pw-minPW[servoIdx])*outRange/servoRange + outputRanges[outputIdx][MinRange];
00395 }
00396 
00397 float SSC32Driver::getAnalog(unsigned int /*inputIdx*/, unsigned char s) {
00398   return s*5.f/256;
00399 }
00400 
00401 float SSC32Driver::getDigital(unsigned int /*inputIdx*/, unsigned char cur, unsigned char latch) {
00402   // The SSC-32 only  latches on 1->0 transitions, so switches should be wired with NC to +5V and NO to GND.
00403   if (cur=='1')  // switch hasn't been pressed since last query
00404     return 0;
00405   // switch has been pressed, so...
00406   return (latch=='1') ? 0.5f : 1;
00407 }
00408 
00409 /*! @file
00410  * @brief 
00411  * @author Ethan Tira-Thompson (ejt) (Creator)
00412  */

Tekkotsu Hardware Abstraction Layer 5.1CVS
Generated Mon May 9 05:01:39 2016 by Doxygen 1.6.3