Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SkewlZoneDriver.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_SkewlZoneDriver_h_
00003 #define INCLUDED_SkewlZoneDriver_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 "IPC/CallbackThread.h"
00012 #include "Shared/RobotInfo.h"
00013 #include <iostream>
00014 
00015 ////////////////////////////////////////////////////////////////////////////////
00016 // Files and declarations needed by Botsense
00017 
00018 #include <stdio.h>
00019 #include <unistd.h>
00020 #include <stdlib.h>
00021 #include <libgen.h>
00022 
00023 #include "rnr/rnrconfig.h"
00024 #include "rnr/new.h"
00025 #include "rnr/opts.h"
00026 #include "rnr/log.h"
00027 
00028 #include "rnr/i2c.h"
00029 #include "rnr/serdev.h"
00030 
00031 #include "rcb3/rcb3prot.h"
00032 #include "rcb3/rcb3lib.h"
00033 
00034 #include "botsense/szFoot.h"
00035 #include "botsense/szIMU.h"
00036 #include "botsense/BotSense.h"
00037 #include "botsense/libBotSense.h"
00038 
00039 //#include "version.h"
00040 
00041 //
00042 // Simple SkewlZone BotSense Application Exit Codes
00043 //
00044 #define SK_EC_OK        0                 ///< success exit code
00045 #define SK_EC_USAGE     2                 ///< usage error exit code
00046 #define SK_EC_EXEC      4                 ///< execution error exit code
00047 
00048 //
00049 // The command and command-line options.
00050 //
00051 //static char *OptsIFSz         = "/dev/i2c-0";       ///< SkewlZone \h_i2c device
00052 
00053 //
00054 // State
00055 //
00056 // TODO should this be a configuration parameter?
00057 static char    *SKProxyIPAddr     = "localhost";
00058 static int      SKProxyIPPort     = BSPROXY_LISTEN_PORT_DFT;
00059 
00060 // End of Botsense declarations
00061 ////////////////////////////////////////////////////////////////////////////////
00062 
00063 //! description of SkewlZoneDriver
00064 class SkewlZoneDriver : public virtual DeviceDriver, public MotionHook, public DataSource, public virtual plist::PrimitiveListener {
00065 public:
00066   static const unsigned int NUM_SERVO=NumOutputs;
00067   static const unsigned int NUM_INPUT=NumSensors;
00068   static const int UNUSED=plist::OutputSelector::UNUSED;
00069 
00070   ////////////////////////////////////////////////////////////////////////////////
00071   // more botsense stuff
00072 
00073   BsLibClient_P           pClient;      // client instance
00074   int                     h;            // proxied device handle
00075   BsBotMotorPosVec_T      vecMotorPos;  // vector of motor positions
00076   BsBotMotorSpeedPosVec_T vecMotorMove; // vector of motor speed-position tuples
00077   int                     index;        // working index
00078   int                     rc;           // return code
00079 
00080   // End of more botsense stuff
00081   ////////////////////////////////////////////////////////////////////////////////
00082 
00083   
00084   explicit SkewlZoneDriver(const std::string& name)
00085     : DeviceDriver(autoRegisterSkewlZoneDriver,name), MotionHook(), DataSource(),
00086     serialPath("/dev/ttyUSB0"), servos(NUM_SERVO,UNUSED), inputs(NUM_INPUT,UNUSED),
00087     minPW(NUM_SERVO,500), maxPW(NUM_SERVO,2500), buttonMode(NUM_INPUT,false),
00088   sparse(false), commName(), queryServos(false), poller(&SkewlZoneDriver::advance,*this,TimeET(0L),TimeET(1.0/(*sensorFramerate)),true,CallbackPollThread::IGNORE_RETURN),
00089     motionActive(false), sensorsActive(false), lastSensorTime(), frameNumber(0)
00090   {
00091     for(unsigned int i=0; i<NumOutputs && i<NUM_SERVO; ++i)
00092       servos[i]=i;
00093     for(unsigned int i=0; i<NumSensors && i<NUM_INPUT; ++i)
00094       inputs[i]=i;
00095     addEntry("SerialPath",serialPath,"Path to connect to botsense using a serial device");
00096     addEntry("OutputMap",servos,"For each of the SkewlZone's servo pins, lists the output index it should take its values from; -1 to mark unused");
00097     addEntry("InputMap",inputs,"For each of the SkewlZone's input pins, lists the sensor index it should send its value to; -1 to mark unused");
00098     addEntry("MinPulseWidth",minPW,"The low end of the servo's legal pulse width range (may correspond to unreachable position, use RobotInfo's outputRange[] to limit motion, not this)"); 
00099     addEntry("MaxPulseWidth",maxPW,"The high end of the servo's legal pulse width range (may correspond to unreachable position, use RobotInfo's outputRange[] to limit motion, not this)");  
00100     addEntry("ButtonMode",buttonMode,"Controls interpretation of the input pin.\nFalse means directly measure voltage, true means test for high (1),\nhigh now but low was detected in interval (0.5), or low (0).\nButton mode implies interpreting inputMap value as a button index instead of sensor index.");
00101     addEntry("SparseUpdates",sparse,"If true, only send servo positions to SkewlZone when they change, instead of all servos on every update (don't use a lossy transport like UDP if you turn this on!)");
00102     addEntry("CommPort",commName,"The name of the comm port where output will be sent");
00103     addEntry("QueryServos",queryServos,"If set to true, will attempt to query the servo positions with each sensor update.\nThis may decrease the sampling frequency");
00104 
00105 
00106 
00107     ////////////////////////////////////////////////////////////////////
00108     // call the SZ initialization functions
00109     
00110     // TODO this should probably be moved to an init function which is called
00111     //   by the first of motionStarting or registerSource, and then set a flag
00112     //   so the second doesn't re-initialize.  Then to be matched by de-initialization
00113     //   in the last called of motionStopping and deregisterSource.  See
00114     //   look how the commport stuff is handled and replace that since
00115     //   this driver internalizes its communication.
00116 
00117     // create the SZ client
00118           if(createSZclient() != SK_EC_EXEC) {
00119       // if that is successful, connect it
00120       if(connectSZserver() != SK_EC_EXEC) {
00121         // if that is successful, open an RCB3 connection
00122         if(openRCB3() != SK_EC_EXEC) {
00123           // if that is successful, attach the RCB3, set units, apply E-stop, and print initial positions
00124           attachRCB3();
00125           setSZunits();
00126           if(RCB3EStop() != SK_EC_EXEC) {
00127             printf("E Stop Applied to SkewlZone!\n");
00128           }
00129           printServos();
00130           initMotorVec();
00131         }
00132       }
00133     }
00134 
00135     // initialize the motor move vector with what was read into the position vector
00136     for (unsigned int i=0; i<vecMotorPos.m_uCount; i++) {
00137       vecMotorMove.m_fBufSpeed[i] = 0.0;
00138       vecMotorMove.m_fBufPos[i] = vecMotorPos.m_fBuf[i];
00139     }
00140       
00141     // end of SZ initialization
00142     ////////////////////////////////////////////////////////////////////
00143 
00144   }
00145   virtual ~SkewlZoneDriver() {}
00146   
00147   virtual std::string getClassName() const { return autoRegisterSkewlZoneDriver; }
00148   
00149   virtual MotionHook* getMotionSink() { return dynamic_cast<MotionHook*>(this); }
00150   virtual void getSensorSources(std::map<std::string,DataSource*>& sources) {
00151     sources.clear();
00152     sources["Sensors"]=dynamic_cast<DataSource*>(this);
00153   }
00154   
00155   virtual void motionStarting();
00156   virtual bool isConnected();
00157   virtual void motionStopping();
00158   virtual void motionCheck(const float outputs[][NumOutputs]);
00159   
00160   virtual unsigned int nextTimestamp();
00161   virtual const std::string& nextName() { return instanceName; }
00162   virtual void registerSource();
00163   virtual void deregisterSource();
00164   virtual void enteringRealtime(const plist::Primitive<double>& simTimeScale) { DataSource::enteringRealtime(simTimeScale); }
00165   virtual void leavingRealtime(bool isFullSpeed) { DataSource::leavingRealtime(isFullSpeed); }
00166   virtual bool advance();
00167   
00168   virtual void plistValueChanged(const plist::PrimitiveBase& pl);
00169   
00170   plist::Primitive<std::string> serialPath; //! TODO this should replace commName (see where commName is used to allow runtime reconfiguration)
00171   plist::ArrayOf<plist::OutputSelector> servos;
00172   plist::ArrayOf<plist::Primitive<int> > inputs;
00173   plist::ArrayOf<plist::Primitive<unsigned int> > minPW;
00174   plist::ArrayOf<plist::Primitive<unsigned int> > maxPW;
00175   plist::ArrayOf<plist::Primitive<bool> > buttonMode;
00176   plist::Primitive<bool> sparse;
00177   plist::Primitive<std::string> commName; //!< TODO this should be replaced by serialPath
00178   plist::Primitive<bool> queryServos; //!< TODO this might not make sense for this driver?
00179 
00180   ///////////////////////////////////////////////////////////////////////////////////
00181   // Botsense function declarations
00182 
00183   // prints a character prefix followed by a vector, typically used for current motor position readings
00184   virtual void simplePrintVec(const char *sPrefix, double fBuf[], size_t uCount);
00185   // creates a new SkewlZone client
00186   virtual int createSZclient();
00187   // attaches a SkewlZone client to the botsense server
00188   virtual int connectSZserver();
00189   // opens a connection to the RCB3 controller board
00190   virtual int openRCB3();
00191   // attach the RCB3 connection
00192   virtual void attachRCB3();
00193   // emergency stop for the RCB3 controller board
00194   virtual int RCB3EStop();
00195   // converts the Tekkotsu index of the servo to the corresponding RCB3 port
00196   virtual int convertIndex(int index);
00197   // returns 0 or 1 to check whether or not the passed index value should have its angle
00198   // inverted to maintain mirrored movement about the center of the robot
00199   virtual int indexInverted(int index);
00200   // defines units of operation (radians, degrees, percent, m/s2)
00201   virtual void setSZunits();
00202   // uses the vector print function to print the last servo position sent
00203   virtual void printServos();
00204   // initializes the motor vector to a NOOP
00205   virtual void initMotorVec();
00206 
00207   // End of Botsense function declarations
00208   ///////////////////////////////////////////////////////////////////////////////////
00209 
00210 protected:
00211   void doFreeze();
00212   void doUnfreeze();
00213   
00214   //! forwards call to DataSource::providingOutput() if the index is valid
00215   void provideOutput(unsigned int idx) { if(idx<NumOutputs) providingOutput(idx); }
00216   //! forwards call to DataSource::ignoringOutput() if the index is valid
00217   void ignoreOutput(unsigned int idx) { if(idx<NumOutputs) ignoringOutput(idx); }
00218   
00219   //! converts the value @a v from radians into the specified servo's pulse width range
00220   virtual void setServo(std::ostream& ss, unsigned int servoIdx, float v);
00221   //! converts the value @a pw from specified servo's pulse width range into radians
00222   virtual float getServo(unsigned int servoIdx, unsigned int pw);
00223   //! converts the value @a s from specified input's signal to voltage
00224   virtual float getAnalog(unsigned int inputIdx, unsigned char s);
00225   //! converts the value @a cur and @a latch to the output format (0 if low, 0.5 if high but has been low, 1 if consistent high)
00226   virtual float getDigital(unsigned int inputIdx, unsigned char cur, unsigned char latch);
00227   //int modeCheck(const float outputs[][NumOutputs]);
00228   float angleCalibration(unsigned int servoIdx, int mode, float v);
00229     
00230   CallbackPollThread poller;
00231         
00232   
00233   bool motionActive;
00234   bool sensorsActive;
00235   unsigned int lastSensorTime;
00236   unsigned int frameNumber;
00237   
00238 private:
00239   //! holds the class name, set via registration with the DeviceDriver registry
00240   static const std::string autoRegisterSkewlZoneDriver;
00241 };
00242 
00243 /*! @file
00244  * @brief Implements SkewlZoneDriver, based on SSC32Driver, ported to support SkewlZone interface by Jason Tennyson and Aaron Parker
00245  */
00246 
00247 #endif

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