Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

TeRKDriver.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_TeRKDriver_h_
00003 #define INCLUDED_TeRKDriver_h_
00004 
00005 #include "local/DeviceDriver.h"
00006 #include "local/MotionHook.h"
00007 
00008 #include "local/terk/ObjectPingThread.h"
00009 #include "local/terk/QwerkBot.h"
00010 
00011 #include "IceUtil/UUID.h"
00012 #include "Ice/ProxyHandle.h"
00013 #include "Ice/Identity.h"
00014 
00015 //! Provides access to the Telepresence Robotics Kit, which specifies an ICE (Internet Communications Engine) based protocol for robotics control
00016 /*!
00017  *  TeRK information:http://www.terk.ri.cmu.edu/
00018  *  ICE information: http://www.zeroc.com/
00019  *
00020  *  To use this driver, you must install ICE, and cause the HAVE_ICE compiler flag to be set.
00021  *  This is most easily done by the Tekkotsu Environment.conf, set the ICE_ROOT parameter to
00022  *  the location of the Ice libraries.  This will automatically cause HAVE_ICE to be set by the
00023  *  Makefiles whenever ICE_ROOT is a valid filesystem path.
00024  */
00025 class TeRKDriver : public virtual DeviceDriver, public MotionHook, public virtual plist::PrimitiveListener {
00026 public:
00027   //! constructor
00028   explicit TeRKDriver(const std::string& name)
00029     : DeviceDriver(autoRegisterTeRKDriver,name), MotionHook(), 
00030     host(), uuid("direct_connect_client|"+IceUtil::generateUUID()), properties(), ic(), 
00031       ping(), qwerk(NULL), idcount(0)
00032   {
00033     for(unsigned int i=0; i<NumLEDs; ++i)
00034       ledActivation[i]=0;
00035     TeRKProperties* tprop = new TeRKProperties;
00036     addEntry("Host",host,"Hostname of the robot");
00037     //addEntry("Port",port,"Port number of the robot's ICE server");
00038     addEntry("IceConfig",*tprop,"Settings for ICE protocol");
00039     Ice::InitializationData iceData;
00040     iceData.properties = properties = tprop;
00041     ic = Ice::initialize(iceData);
00042     host.addPrimitiveListener(this);
00043   }
00044   
00045   //! destructor
00046   virtual ~TeRKDriver() {
00047     host.removePrimitiveListener(this);
00048     close();
00049     if(ic)
00050       ic->destroy();
00051     // don't need to delete properties, smart pointer
00052   }
00053 
00054   virtual std::string getClassName() const { return autoRegisterTeRKDriver; }
00055 
00056   virtual MotionHook* getMotionSink() { return dynamic_cast<MotionHook*>(this); }
00057   virtual void getSensorSources(std::map<std::string,DataSource*>& sources) {
00058     sources.clear();
00059     if(qwerk!=NULL && qwerk->dataCache!=NULL)
00060       sources["Sensors"]=qwerk->dataCache;
00061   }
00062   virtual void getImageSources(std::map<std::string,DataSource*>& sources) {
00063     sources.clear();
00064     if(qwerk!=NULL && qwerk->imageCache!=NULL)
00065       sources["Camera"]=qwerk->imageCache;
00066   }
00067   
00068   virtual void motionStarting() {}
00069   virtual void motionUpdated(const std::vector<size_t>& changedIndices, const float outputs[][NumOutputs]);
00070   virtual void motionStopping() {}
00071   
00072   virtual void plistValueChanged(const plist::PrimitiveBase& pl);
00073 
00074   //! creates a proxy for a specified service
00075   /*! @todo import QwerkBot and make this protected?) */
00076   Ice::ObjectPrx getPeerProxy(Ice::Identity proxyIdentity) const;
00077   
00078   //! hostname of the qwerk we are connecting to.
00079   plist::Primitive<std::string> host;
00080   
00081 protected:
00082   //! connect to qwerk
00083   virtual void connect();
00084 
00085   //! initializes a connection to #host
00086   QwerkBot* connectToPeer();
00087   
00088   //! closes the current proxies (reuses the communicator instance though)
00089   virtual void close() {
00090     if(ping){
00091       ping->destroy();
00092       ping=NULL;
00093     }
00094     delete qwerk;
00095     qwerk=NULL;
00096   }
00097   
00098   //! allows LEDs to flicker at various frequencies to emulate having linear brightness control instead of boolean control
00099   inline ::TeRK::LEDMode calcLEDValue(unsigned int i,float x) {
00100     if(x<=0.0) {
00101       ledActivation[i]*=.9; //decay activation... resets to keeps LEDs in sync, looks a little better
00102       return ::TeRK::LEDOff;
00103     } else if(x>=1.0) {
00104       return ::TeRK::LEDOn;
00105     } else {
00106       x*=x; // squared to "gamma correct" - we can see a single pulse better than a single flicker - after image and all that
00107       ledActivation[i]+=x;
00108       if(ledActivation[i]>=1.0) {
00109         ledActivation[i]-=1.0;
00110         return ::TeRK::LEDOn;
00111       } else {
00112         return ::TeRK::LEDOff;
00113       }
00114     }
00115   }
00116   float ledActivation[NumLEDs]; //!< used to track partial LED activation (see calcLEDValue
00117   
00118   //! unique identifier, should be different for every active connection
00119   /*! This will be constant for the lifetime of the TeRKDriver, as we only ever have one
00120    *  active connection per driver instance.  (If more than one instance, each will have
00121    *  its own uuid however!) */
00122   std::string uuid;
00123   
00124   //! TeRKProperties instance provides Ice configuration values, default values for which are in TeRKDriver.cc.
00125   /*! These aren't really user-configurable settings, but are exposed via a Tekkotsu plist entry. */
00126   Ice::PropertiesPtr properties;
00127   
00128   //! The core Ice object, which manages connections, proxies, adapters, etc.
00129   /*! We create one instance and reuse it over the life of the driver.
00130    *  (In other words, we shouldn't need to delete/reallocate it every time we
00131    *  switch hosts, although if that winds up being easier, we could certainly
00132    *  do that instead) */
00133   Ice::CommunicatorPtr ic;
00134   
00135   //! tests to make sure the remote host is still alive
00136   /*! @todo do we do anything if the remote host goes down? */
00137   ObjectPingThreadPtr ping;
00138   
00139   //! storage class holds proxies for various TeRK services.
00140   /*! @todo should be imported and stored directly in driver? */
00141   QwerkBot* qwerk;
00142     
00143   int idcount;
00144   //! Grafts a Ice::Properties interface on a plist::Dictionary so we can use the Tekkotsu configuration system to control ICE
00145   /*! The constructor assigns various default values to #defaults - these will be used
00146    * unless a value is found in the plist::Dictionary storage.  We keep these values
00147    * separate because they shouldn't be written to persistent storage unless explicitly
00148    * set.  (Default values may change in the future, could break things if the defaults
00149    * were written to file... most of these values are not really configurable by end user) */
00150   class TeRKProperties : public virtual ::Ice::Properties, public virtual plist::Dictionary {
00151   public:
00152     typedef ::Ice::PropertiesPtr PointerType; //!< forwarding typedef for good form
00153     typedef plist::Dictionary::iterator iterator; //!< forwarding typedef for good form
00154     typedef plist::Dictionary::const_iterator const_iterator; //!< forwarding typedef for good form
00155     
00156     //! constructor, initialize #defaults from #defaultValues (C++0x will make this much more elegant!)
00157     TeRKProperties() : defaults(defaultValues, defaultValues+NUM_DEFAULT_VALUES) {}
00158     
00159     //! These provide the TeRK configuration parameters for ICE communication, unless overridden by a setting in the class itself (see class notes)
00160     /*! These may be changed from the initial #defaultValues settings if a corresponding
00161      *  TeRKDriver setting (e.g. port) is modified.  This is to avoid user confusion with having
00162      *  settings appear twice (once in the more human-readable driver settings, and again
00163      *  in this dictionary.)  So settings stored in TeRKProperties itself is reserved for explicit
00164      *  overrides from the user */
00165     ::Ice::PropertyDict defaults;
00166     
00167     //! returns value associated with @a key, or empty string if not found
00168     virtual ::std::string getProperty(const ::std::string& key) { return getPropertyWithDefault(key,""); }
00169     //! returns value associated with @a key, or @a def if not found
00170     virtual ::std::string getPropertyWithDefault(const ::std::string& key, const ::std::string& def);
00171     //! returns value associated with @a key, or 0 if not found
00172     virtual ::Ice::Int getPropertyAsInt(const ::std::string& key) { return getPropertyAsIntWithDefault(key,0); }
00173     //! returns value associated with @a key, or @a def if not found
00174     virtual ::Ice::Int getPropertyAsIntWithDefault(const ::std::string& key, ::Ice::Int def);
00175     //! returns a sub-map, selecting keys which match the specified prefix
00176     virtual ::Ice::PropertyDict getPropertiesForPrefix(const ::std::string& prefix);
00177     //! assigns a new value to a @a key
00178     virtual void setProperty(const ::std::string& key, const ::std::string& val) { setEntry(key,new plist::Primitive<std::string>(val)); }
00179     //! returns an empty sequence
00180     virtual ::Ice::StringSeq getCommandLineOptions() { return ::Ice::StringSeq(); }
00181     //! returns the same sequence it is passed (doesn't handle parsing command line options, we're not using that interface)
00182     virtual ::Ice::StringSeq parseCommandLineOptions(const ::std::string&, const ::Ice::StringSeq& options) { return options; }
00183     //! returns the same sequence it is passed (doesn't handle parsing command line options, we're not using that interface)
00184     virtual ::Ice::StringSeq parseIceCommandLineOptions(const ::Ice::StringSeq& options) { return options; }
00185     //! tries to load the specified file name (assumes plist format, not the ICE format!)
00186     virtual void load(const ::std::string& filename);
00187     //! makes a copy of the current property list
00188     virtual ::Ice::PropertiesPtr clone() { return new TeRKProperties(*this); }
00189     virtual TeRKProperties* clone() const { return new TeRKProperties(*this); }
00190     
00191   protected:
00192     static const unsigned int NUM_DEFAULT_VALUES=14;
00193     static std::pair<std::string,std::string> defaultValues[NUM_DEFAULT_VALUES];
00194   };
00195   
00196 private:
00197   //! holds the class name, set via registration with the DeviceDriver registry
00198   static const std::string autoRegisterTeRKDriver;
00199 
00200   TeRKDriver(const TeRKDriver&); //!< do not call
00201   TeRKDriver& operator=(const TeRKDriver&); //!< do not call
00202 };
00203 
00204 /*! @file
00205  * @brief 
00206  * @author Ethan Tira-Thompson (ejt) (Creator)
00207  *
00208  * $Author: ejt $
00209  * $Name: tekkotsu-4_0 $
00210  * $Revision: 1.13 $
00211  * $State: Exp $
00212  * $Date: 2007/11/11 23:57:29 $
00213  */
00214 
00215 #endif

Tekkotsu Hardware Abstraction Layer 4.0
Generated Thu Nov 22 01:00:53 2007 by Doxygen 1.5.4