Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Dynamixel.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_Dynamixel_h_
00003 #define INCLUDED_Dynamixel_h_
00004 
00005 #include "local/DeviceDriver.h"
00006 #include "local/MotionHook.h"
00007 #include "local/DataSource.h"
00008 #include "local/CommPort.h"
00009 #include "Shared/plist.h"
00010 #include "Shared/plistSpecialty.h"
00011 #include "Shared/get_time.h"
00012 #include "IPC/Thread.h"
00013 #include "IPC/FailsafeThread.h"
00014 #include "IPC/DriverMessaging.h"
00015 #include "DynamixelProtocol.h"
00016 #include <iostream>
00017 #include <sstream>
00018 #include <iomanip>
00019 
00020 //! description of Dynamixel
00021 class DynamixelDriver : public virtual DeviceDriver, public virtual DriverMessaging::Listener, public MotionHook, public DataSource, public virtual plist::PrimitiveListener {
00022 public:
00023   static const int START_SERVO_ID = 1; //!< bioloid kits start the id count at 1
00024   static const unsigned int UNUSED = plist::OutputSelector::UNUSED;
00025   
00026   //! Offsets into OuputPIDs, since Dynamixel servos don't actually use PID control, but a different set of parameters
00027   enum ServoParam_t {
00028     DYNAMIXEL_SLOPE=0, //!< compliance slope, the proportional control (P in PID) 
00029     DYNAMIXEL_PUNCH, //!< punch, a constant added to the slope once error exceeds compliance margin
00030     DYNAMIXEL_MARGIN //!< compliance margin, the amount of error to tolerate before triggering a torque response
00031   };
00032 
00033   explicit DynamixelDriver(const std::string& name)
00034     : DeviceDriver(autoRegisterDynamixelDriver,name), DriverMessaging::Listener(), MotionHook(), DataSource(),
00035     servos(), commName(), loadCompensation(28.f), commLatency(16), numPoll(3), responseTime(4000), servoIDSync(), 
00036     commThread(servos,commName,*this), motionActive(false), sensorsActive(false), lastSensor()
00037   {
00038     // redo these lookups, they aren't set reliably otherwise due to static initialization order issues
00039     VOLTAGE_SENSOR_OFFSET = capabilities.findSensorOffset("PowerVoltage");
00040     TEMP_SENSOR_OFFSET = capabilities.findSensorOffset("PowerThermo");
00041     
00042     addEntry("Servos",servos,"Maps servo IDs to Tekkotsu output offsets, use command line new/delete commands to add/remove mappings.");
00043     addEntry("CommPort",commName,"Name of the CommPort to use, generally a SerialCommPort with direct binary TTL communication with the servos");
00044     addEntry("LoadCompensation",loadCompensation,"Ratio of load to deflection, if non-zero will use LoadPrediction messages and attempt to counter anticipated loads");
00045     addEntry("CommLatency",commLatency,"The delay (in MILLIseconds, ms) to get a response from the servos due to buffering in the USB-to-TTL interface.");
00046     addEntry("NumPoll",numPoll,"Number of sensor queries to send before reading responses.  This lets us front-load the queries so we can get multiple responses per read buffer flush period");
00047     addEntry("ResponseTime",responseTime,"The amount of time (in MICROseconds, µs) to wait between sending a sensor query and sending another when front-loading the buffer.\nIf this is too short, the next query will collide with the previous response.");
00048     
00049     for(unsigned int i=0; i<NumPIDJoints; ++i) {
00050       std::stringstream bio_id;
00051       bio_id << std::setw(3) << std::setfill('0') << (i+START_SERVO_ID);
00052       servos[bio_id.str()]=ServoInfo(i+START_SERVO_ID);
00053     }
00054     servos.addCollectionListener(&servoIDSync);
00055     DriverMessaging::addListener(this,DriverMessaging::LoadPrediction::NAME);
00056     DriverMessaging::addListener(this,DriverMessaging::SensorPriority::NAME);
00057   }
00058   virtual ~DynamixelDriver() {
00059     servos.removeCollectionListener(&servoIDSync);
00060     DriverMessaging::removeListener(this,DriverMessaging::SensorPriority::NAME);
00061     DriverMessaging::removeListener(this,DriverMessaging::LoadPrediction::NAME);
00062   }
00063   
00064   virtual std::string getClassName() const { return autoRegisterDynamixelDriver; }
00065   
00066   virtual MotionHook* getMotionSink() { return dynamic_cast<MotionHook*>(this); }
00067   virtual void getSensorSources(std::map<std::string,DataSource*>& sources) {
00068     sources.clear();
00069     sources["Sensors"]=dynamic_cast<DataSource*>(this);
00070   }
00071   
00072   virtual void motionStarting();
00073   virtual bool isConnected();
00074   virtual void motionStopping();
00075   virtual void motionCheck(const float outputs[][NumOutputs]);
00076   virtual void updatePIDs(const std::vector<MotionHook::PIDUpdate>& pids);
00077   virtual void registerSource();
00078   virtual void deregisterSource();
00079   virtual void enteringRealtime(const plist::Primitive<double>& simTimeScale) { DataSource::enteringRealtime(simTimeScale); }
00080   virtual void leavingRealtime(bool isFullSpeed) { DataSource::leavingRealtime(isFullSpeed); }
00081   
00082   virtual unsigned int nextTimestamp();
00083   virtual const std::string& nextName() { return instanceName; }
00084   virtual bool advance();
00085   
00086   virtual void plistValueChanged(const plist::PrimitiveBase& pl);
00087 
00088   virtual void processDriverMessage(const DriverMessaging::Message& d);
00089   
00090   struct ServoInfo : public virtual plist::Dictionary {
00091     ServoInfo(unsigned int i=DynamixelProtocol::INVALID_ID)
00092       : plist::Dictionary(false), detected(false), output(), led(), freeSpinOutput(), /*maxSpeed(0),*/ invertRotation(false), zeroAngle(0), maxTic(0), maxAngle(0),
00093       cmdSpeedSlopeP(0.6575f), cmdSpeedOffsetP(0.1557f), cmdSpeedSlopeN(0.6554f), cmdSpeedOffsetN(-0.1256f),
00094       repSpeedSlope(0.111f / 60 * 2 * (float)M_PI), // from Dynamixel documentation, rpm = reported speed * 0.111 (114rpm ≈ 1023) ... rpm / value / 60 seconds per minute * 2π radians = 0.011623892818282 rad/s per value
00095       leftIRDistOffset(), centerIRDistOffset(), rightIRDistOffset(),
00096       leftLuminosityOffset(), centerLuminosityOffset(), rightLuminosityOffset(), 
00097       micVolumeOffset(), micSpikeCountOffset(), 
00098       servoID(i), slope(0), punch(0), margin(0), curRotationMode(UNKNOWN), lastCmd(), recentCmdMotion(0), failures(0), 
00099       predictedLoad(0), sensorPriority(-1), sensorActivation(1), micSpikeFrameNumber(-1U), model(DynamixelProtocol::MODEL_UNKNOWN), modelName()
00100     {
00101       i-=START_SERVO_ID;
00102 #ifdef TGT_HAS_WHEELS
00103       if(WheelOffset<PIDJointOffset || WheelOffset>=PIDJointOffset+NumPIDJoints) {
00104         // wheels are not a subset of PIDJoints, so we'll default map the first NumWheel servos to wheels, and the rest to PIDJoints
00105         if(i<(int)NumWheels) {
00106           output = ( i+WheelOffset );
00107           freeSpinOutput = ( i+WheelOffset );
00108         } else {
00109           output = ( (i-NumWheels<(int)NumPIDJoints) ? i-NumWheels+PIDJointOffset : UNUSED );
00110         }
00111       } else {
00112         // wheels are a subset of PIDJoints, don't subtract NumWheels...
00113         output = ( (i<NumPIDJoints) ? i+PIDJointOffset : UNUSED);
00114         if(i>=(int)WheelOffset && i<(int)(WheelOffset+NumWheels)) {
00115           freeSpinOutput = ( i+PIDJointOffset );
00116         }
00117       }
00118 #else
00119       output = ( (i<NumPIDJoints) ? i+PIDJointOffset : UNUSED);
00120 #endif
00121 #ifdef TGT_HAS_LEDS
00122       led = (i<NumLEDs ? i+LEDOffset : UNUSED);
00123 #endif
00124       
00125       plist::NamedEnumeration<SensorOffset_t>::setNames(sensorNames);
00126       plist::NamedEnumeration<SensorOffset_t>::addNameForVal("UNUSED",static_cast<SensorOffset_t>(-1));
00127       leftIRDistOffset.set(capabilities.findSensorOffset("LeftIRDist"));
00128       centerIRDistOffset.set(capabilities.findSensorOffset("CenterIRDist"));
00129       rightIRDistOffset.set(capabilities.findSensorOffset("RightIRDist"));
00130       leftLuminosityOffset.set(capabilities.findSensorOffset("LeftLuminosity"));
00131       centerLuminosityOffset.set(capabilities.findSensorOffset("CenterLuminosity"));
00132       rightLuminosityOffset.set(capabilities.findSensorOffset("RightLuminosity"));
00133       micVolumeOffset.set(capabilities.findSensorOffset("MicVolume"));
00134       micSpikeCountOffset.set(capabilities.findSensorOffset("MicSpikeCount"));
00135       
00136       setLoadSavePolicy(FIXED,SYNC);
00137       initEntries();
00138     }
00139     
00140     void setModel(DynamixelProtocol::ModelID_t m) { if(model!=m) { model=m; initEntries(); } }
00141     DynamixelProtocol::ModelID_t getModel() const { return model; }
00142     void setModelName(const std::string m) { modelName=m; }
00143     const std::string& getModelName() const { return modelName; }
00144     
00145     //! returns true if any of the AX-S1 sensor offsets are in use
00146     bool hasSensorOffset() const {
00147       const SensorOffset_t US = static_cast<SensorOffset_t>(-1);
00148       return leftIRDistOffset!=US || centerIRDistOffset!=US || rightIRDistOffset!=US
00149         || leftLuminosityOffset!=US || centerLuminosityOffset!=US || rightLuminosityOffset!=US
00150         || micVolumeOffset!=US || micSpikeCountOffset!=US;
00151     }
00152     
00153     plist::Primitive<bool> detected;
00154     
00155     // Servo stuff
00156     plist::OutputSelector output;
00157     plist::OutputSelector led;
00158     plist::OutputSelector freeSpinOutput;
00159     //plist::Primitive<float> maxSpeed;
00160     plist::Primitive<bool> invertRotation;
00161     plist::Angle zeroAngle;
00162     plist::Primitive<unsigned int> maxTic;
00163     plist::Angle maxAngle;
00164     plist::Primitive<float> cmdSpeedSlopeP;
00165     plist::Primitive<float> cmdSpeedOffsetP;
00166     plist::Primitive<float> cmdSpeedSlopeN;
00167     plist::Primitive<float> cmdSpeedOffsetN;
00168     plist::Primitive<float> repSpeedSlope;
00169     
00170     // Sensor (AX-S1) stuff
00171     plist::NamedEnumeration<SensorOffset_t> leftIRDistOffset;
00172     plist::NamedEnumeration<SensorOffset_t> centerIRDistOffset;
00173     plist::NamedEnumeration<SensorOffset_t> rightIRDistOffset;
00174     plist::NamedEnumeration<SensorOffset_t> leftLuminosityOffset;
00175     plist::NamedEnumeration<SensorOffset_t> centerLuminosityOffset;
00176     plist::NamedEnumeration<SensorOffset_t> rightLuminosityOffset;
00177     plist::NamedEnumeration<SensorOffset_t> micVolumeOffset;
00178     plist::NamedEnumeration<SensorOffset_t> micSpikeCountOffset;
00179     
00180     unsigned int servoID;
00181     float slope;
00182     float punch;
00183     float margin;
00184     enum RotationMode { POSITION, CONTINUOUS, UNKNOWN } curRotationMode;
00185     unsigned short lastCmd;
00186     float recentCmdMotion;
00187     unsigned short failures;
00188     float predictedLoad;
00189     float sensorPriority; //!< amount to add to sensor activation each sensor check, negative values indicate "auto" mode based on movement speed with decay
00190     float sensorActivation; //!< the accumulated "energy" for polling this servo, the servos with highest activation are polled as avaiable
00191     unsigned int micSpikeFrameNumber; //!< stores the frame number when the micSpike occurred, so we can tell when the system has received it
00192     
00193     DynamixelProtocol::ModelID_t model;
00194     plist::Primitive<std::string> modelName; // assigned during pingServos to string name so we can include numeric value of unknown servo model IDs
00195   protected:
00196     void initEntries() {
00197       using namespace DynamixelProtocol;
00198       clear();
00199       
00200       addEntry("Model",modelName,"Model name for this device; set automatically via pingServos");
00201       addEntry("Detected",detected,"If true, servo is detected and functioning.  If a servo is reconnected, set back to true to attempt to re-enable communication.");
00202       
00203       if(model!=MODEL_AXS1 || model==MODEL_UNKNOWN) {
00204         addEntry("Output",output,"Tekkotsu offset to pull servo positions from; -1 or empty string to mark unused\n"
00205                  "(May still rotate via FreeSpinOutput if position control by Output is unused...)");
00206         addEntry("LED",led,"Tekkotsu offset to pull LED values from; -1 or empty string to mark unused");
00207         addEntry("FreeSpinOutput",freeSpinOutput,"Tekkotsu output to control the 'continuous rotation mode'. If specified output's\n"
00208                  "value is non-zero, the value from Output is ignored, and the servo is rotated at the\n"
00209                  "specified speed.  If Output and FreeSpinOutput are equal, then the servo is permanently\n"
00210                  "in continuous rotation mode.");
00211         //addEntry("MaxSpeed",maxSpeed,"Indicates maximum joint speed in rad/s, 0 for no maximum");
00212         addEntry("InvertRotation",invertRotation,"If true, the servo moves in the reverse direction.  Calibration parameters are always applied relative to the 'native' orientation.");
00213         addEntry("ZeroAngle",zeroAngle,"Specifies the angle to which the zero point of the output will be mapped.\n"
00214                  "For an AX or RX servo, this must be in the range ±2.618 radians (i.e. ±150°), such that\n"
00215                  "a value of zero is centered in the range of motion.");
00216         maxTic = IS_MXEX(model) ? 4095 : 1023 ;
00217         maxAngle = IS_MXEX(model) ? (360*(float)M_PI/180) : (300*(float)M_PI/180);
00218         addEntry("MaxTic",maxTic,"The maximum servo tic value (e.g. 1023 for AX and RX, 4095 for EX-106 and MX series)");
00219         addEntry("MaxAngle",maxAngle,"The maximum servo angle (e.g. 300° for AX and RX, 280.6° for EX-106, 360° for MX series )");
00220         addEntry("CmdSpeedSlopePos",cmdSpeedSlopeP,"Calibration parameter for converting desired physical positive speeds to speed command for the servo.");
00221         addEntry("CmdSpeedOffsetPos",cmdSpeedOffsetP,"Calibration parameter for converting desired physical positive speeds to speed command for the servo.");
00222         addEntry("CmdSpeedSlopeNeg",cmdSpeedSlopeN,"Calibration parameter for converting desired physical negative speeds to speed command for the servo.");
00223         addEntry("CmdSpeedOffsetNeg",cmdSpeedOffsetN,"Calibration parameter for converting desired physical negative speeds to speed command for the servo.");
00224         addEntry("ReportedSpeedSlope",repSpeedSlope,"Calibration parameter for converting speed feedback from servo to actual physical speed.");
00225       }
00226       
00227       if(model==MODEL_AXS1 || model==MODEL_UNKNOWN) {
00228         addEntry("LeftIRDistOffset",leftIRDistOffset,"Tekkotsu sensor offset where the left IR distance reading should be stored.");
00229         addEntry("CenterIRDistOffset",centerIRDistOffset,"Tekkotsu sensor offset where the center IR distance reading should be stored.");
00230         addEntry("RightIRDistOffset",rightIRDistOffset,"Tekkotsu sensor offset where the right IR distance reading should be stored.");
00231         addEntry("LeftLuminosityOffset",leftLuminosityOffset,"Tekkotsu sensor offset where the left luminosity reading should be stored.");
00232         addEntry("CenterLuminosityOffset",centerLuminosityOffset,"Tekkotsu sensor offset where the center luminosity reading should be stored.");
00233         addEntry("RightLuminosityOffset",rightLuminosityOffset,"Tekkotsu sensor offset where the right luminosity reading should be stored.");
00234         addEntry("MicVolumeOffset",micVolumeOffset,"Tekkotsu sensor offset where the volume magnitude reading should be stored.");
00235         addEntry("MicSpikeCountOffset",micSpikeCountOffset,"Tekkotsu sensor offset where the volume spike count should be stored.");
00236       }
00237     }
00238     
00239   };
00240   
00241   plist::DictionaryOf< ServoInfo > servos; //!< Maps servo IDs to Tekkotsu output offsets, use command line new/delete commands to add/remove mappings.
00242   typedef plist::DictionaryOf< ServoInfo >::const_iterator servo_iterator;
00243   
00244   plist::Primitive<std::string> commName; //!< Name of the CommPort to use, generally a SerialCommPort with direct binary TTL communication with the servos
00245   plist::Primitive<float> loadCompensation; //!< Ratio of load to deflection, if non-zero will use LoadPrediction messages and attempt to counter anticipated loads
00246   plist::Primitive<unsigned int> commLatency; //!< The delay (in MILLIseconds, ms) to get a response from the servos due to buffering in the USB-to-TTL interface.
00247   plist::Primitive<unsigned int> numPoll; //!< Number of sensor queries to send before reading responses.  This lets us front-load the queries so we can get multiple responses per read buffer flush period
00248   plist::Primitive<unsigned int> responseTime; //!< The amount of time (in MICROseconds, µs) to wait between sending a sensor query and sending another when front-loading the buffer.  If this is too short, the next query will collide with the previous response.
00249   
00250 protected:  
00251   static unsigned int VOLTAGE_SENSOR_OFFSET; //!< index of the voltage sensor
00252   static unsigned int TEMP_SENSOR_OFFSET; //!< index of the temperature sensor
00253   
00254   struct ServoInfoIDSync : plist::CollectionListener {
00255     virtual void plistCollectionEntryAdded(plist::Collection& col, ObjectBase&) { plistCollectionEntriesChanged(col); }
00256     virtual void plistCollectionEntriesChanged(plist::Collection& col) {
00257       plist::DictionaryOf< ServoInfo >& s = dynamic_cast<plist::DictionaryOf<ServoInfo>& > (col);
00258       for(servo_iterator it=s.begin(); it!=s.end(); ++it)
00259         it->second->servoID = atoi(it->first.c_str());
00260     }
00261   } servoIDSync;
00262   
00263   class CommThread : public Thread, public plist::CollectionListener {
00264   public:
00265     CommThread(plist::DictionaryOf< ServoInfo >& servoList, const plist::Primitive<std::string>& comm, DynamixelDriver& parent)
00266       : Thread(), pidLock(), dirtyPIDs(0), commName(comm), servos(servoList), driver(parent), servoPollQueue(),
00267       failsafe(*this,FrameTime*NumFrames*3/2000.0,false), continuousUpdates(), updated(false), responsePending(false), lastSensorTime(0), 
00268       servoDeflection(0), isFirstCheck(true), timestampBufA(0), timestampBufB(0), timestampBufC(0), curBuf(NULL)
00269     {
00270       failsafe.restartFlag=true;
00271       for(unsigned int i=0; i<NumLEDs; ++i)
00272         lastLEDState[i]=LED_UNKNOWN;
00273       servos.addCollectionListener(this);
00274       plistCollectionEntriesChanged(servos);
00275     }
00276     ~CommThread() { servos.removeCollectionListener(this); }
00277     
00278     virtual void plistCollectionEntryAdded(Collection& /*col*/, ObjectBase& primitive) {
00279       if(ServoInfo* si = dynamic_cast<ServoInfo*>(&primitive)) {
00280         servoPollQueue.push_back(si);
00281         si->detected=true;
00282         if(isStarted())
00283           driver.pingServos(true);
00284       }
00285     }
00286     virtual void plistCollectionEntryRemoved(Collection& /*col*/, ObjectBase& primitive) {
00287       ServoInfo* si = dynamic_cast<ServoInfo*>(&primitive);
00288       std::vector<ServoInfo*>::iterator it = std::find(servoPollQueue.begin(),servoPollQueue.end(),si);
00289       if(it!=servoPollQueue.end())
00290         servoPollQueue.erase(it);
00291     }
00292     virtual void plistCollectionEntriesChanged(Collection& /*col*/) {
00293       servoPollQueue.resize(servos.size());
00294       unsigned int i=0;
00295       for(plist::DictionaryOf< ServoInfo >::const_iterator it=servos.begin(); it!=servos.end(); ++it) {
00296         servoPollQueue[i++] = it->second;
00297         if(isStarted())
00298           it->second->detected=true;
00299       }
00300       if(isStarted())
00301         driver.pingServos(true);
00302     }
00303     
00304     virtual void start() { updated=false; continuousUpdates=true; Thread::start(); }
00305     virtual void startOneUpdate() { updated=false; continuousUpdates=false; Thread::start(); }
00306     virtual Thread& stop();
00307     virtual void waitForUpdate();
00308     virtual bool isStarted() const { return Thread::isStarted() || failsafe.isStarted(); }
00309     bool takeUpdate() { if(!updated) { return false; } else { updated=false; return true; } }
00310     
00311     //! find the oldest of the output buffers that isn't currently in use
00312     float* getWriteBuffer();
00313     //! sets the timestamp on the indicated buffer (indicates you're done writing)
00314     void setWriteBufferTimestamp(float * buf);
00315     
00316     unsigned int nextTimestamp() const { return lastSensorTime + driver.commLatency; }
00317     
00318     Thread::Lock pidLock;
00319     PIDUpdate pidValues[NumOutputs];
00320     unsigned int dirtyPIDs;
00321     
00322   protected:
00323     virtual bool launched();
00324     virtual void cancelled();
00325     void clearBuffer();
00326     virtual unsigned int runloop();
00327     template<class T> void readResponse(T& response, std::istream& is, ServoInfo& module);
00328     virtual void updateCommands(std::istream& is, std::ostream& os);
00329     
00330     //! converts the value @a v from radians into the specified servo's range, with expected speed (rad/s)
00331     DynamixelProtocol::SyncWritePosSpeedEntry setServo(const servo_iterator& servo, ServoInfo::RotationMode rm, float v, float speed);
00332     
00333     const plist::Primitive<std::string>& commName;
00334     plist::DictionaryOf< ServoInfo >& servos;
00335     DynamixelDriver& driver;
00336     std::vector<ServoInfo*> servoPollQueue; //!< priority queue of servos waiting to be polled for sensor information
00337     FailsafeThread failsafe;
00338     bool continuousUpdates;
00339     bool updated;
00340     bool responsePending;
00341     unsigned int lastSensorTime;
00342     float servoDeflection; //!< 'tics' of servo deflection from target per newton·meter of torque applied
00343     
00344     bool isFirstCheck;
00345     float outputBufA[NumOutputs];
00346     unsigned int timestampBufA;
00347     float outputBufB[NumOutputs];
00348     unsigned int timestampBufB;
00349     float outputBufC[NumOutputs];
00350     unsigned int timestampBufC;
00351     float lastOutputs[NumOutputs];
00352     float * curBuf;
00353     
00354     //! allows LEDs to flicker at various frequencies to emulate having linear brightness control instead of boolean control
00355     inline bool calcLEDValue(unsigned int i,float x) {
00356       if(x<=0.0) {
00357         ledActivation[i]*=.9f; //decay activation... resets to keeps LEDs in sync, looks a little better
00358         return false;
00359       } else if(x>=1.0) {
00360         return true;
00361       } else {
00362         float x3 = x*x*x;
00363         x = .25f*x3*x3 + .75f*x; // fancy but unscientific equation to "gamma correct" - we can see a single pulse better than a single flicker - after image and all that
00364         ledActivation[i]+=x;
00365         if(ledActivation[i]>=1) {
00366           ledActivation[i]-=1;
00367           return true;
00368         } else {
00369           return false;
00370         }
00371       }
00372     }
00373     float ledActivation[NumLEDs]; //!< used to track partial LED activation (see calcLEDValue())
00374     enum LedState { LED_OFF=0, LED_ON, LED_UNKNOWN } lastLEDState[NumLEDs]; //!< keeps track of the last full activation value sent to servo
00375     
00376   private:
00377     CommThread(const CommThread&); //!< don't copy
00378     CommThread& operator=(const CommThread&); //!< don't assign
00379   } commThread;
00380   
00381   void doFreeze();
00382   void doUnfreeze();
00383   
00384   //! sends servo feedback values into the framework
00385   static void provideValues(const ServoInfo& info, const DynamixelProtocol::ServoSensorsResponse& response);
00386   //! sends AX-S1 sensor values into the framework
00387   static void provideValues(ServoInfo& info, const DynamixelProtocol::AXS1SensorsResponse& response);
00388   
00389   //! forwards call to DataSource::providingOutput() if the index is valid
00390   void provideOutput(unsigned int idx) { if(idx<NumOutputs) providingOutput(idx); }
00391   //! forwards call to DataSource::ignoringOutput() if the index is valid
00392   void ignoreOutput(unsigned int idx) { if(idx<NumOutputs) ignoringOutput(idx); }
00393   
00394   //! tests each servo to see if it is connected
00395   void pingServos(bool detectedOnly=false);
00396   
00397   //! broadcasts a "relax" command to all servos
00398   void sendZeroTorqueCmd(CommPort& comm);
00399   
00400   //! sends a series of sync write entries into a stream (adding appropriate header and checksum)
00401   template<class T> static void writeSyncEntries(std::ostream& os, const std::vector<T>& entries) {
00402     if(entries.size()==0)
00403       return;
00404     unsigned char checksum=0;
00405     DynamixelProtocol::write(os, DynamixelProtocol::SyncWriteHeader<T>(entries.size()), checksum);
00406     os.write(entries[0],entries.size()*sizeof(T));
00407     checksum+=DynamixelProtocol::nchecksum(entries[0],entries.size()*sizeof(T));
00408     os.put(~checksum);
00409   }
00410   
00411   bool motionActive;
00412   bool sensorsActive;
00413   std::string lastSensor;
00414 
00415 private:
00416   //! holds the class name, set via registration with the DeviceDriver registry
00417   static const std::string autoRegisterDynamixelDriver;
00418 };
00419 
00420 template<class T> void DynamixelDriver::CommThread::readResponse(T& response, std::istream& is, ServoInfo& module) {
00421   do {
00422     testCancel();
00423     while(!DynamixelProtocol::readResponse(is,response,module.output)) {
00424       /*std::cerr << "DynamixelDriver got an invalid response from " << (int)response.servoid << " to sensor query of " << module.servoID << ", re-reading." << std::endl;
00425        if(response.servoid!=module.servoID)
00426          std::cerr << "DynamixelDriver got an unexpected response from " << (int)response.servoid << " to sensor query of " << module.servoID << ", re-reading." << std::endl;*/
00427       failsafe.progressFlag=true;
00428       testCancel();
00429     }
00430   } while(response.servoid!=module.servoID);
00431     
00432   module.failures=0;
00433   module.sensorActivation=0;
00434   // LOW LEVEL LOGGING:
00435   //cout << get_time() << '\t' << response.getPosition() << '\t' << response.getLoad() << '\t' << servoPollQueue[i]->lastCmd << endl;
00436   //cout << servoPollQueue[i]->servoID << ": " << get_time() << /*" = " <<  TimeET() <<*/ ' ' << validate(response) << ' ' << response.getPosition() << ' ' << response.getSpeed() << ' ' << response.getLoad() << ' ' << (int)response.voltage << ' ' << (int)response.temp << endl;
00437   
00438   provideValues(module, response);
00439 }
00440 
00441 
00442 /*! @file
00443  * @brief 
00444  * @author Ethan Tira-Thompson (ejt) (Creator)
00445  */
00446 
00447 #endif

Tekkotsu Hardware Abstraction Layer 5.1CVS
Generated Sat May 4 06:37:21 2013 by Doxygen 1.6.3