Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MirageComm.h

Go to the documentation of this file.
00001 #include "Motion/KinematicJoint.h"
00002 #include "Wireless/netstream.h"
00003 #include "Shared/plist.h"
00004 #include "Shared/plistSpecialty.h"
00005 #include "Shared/debuget.h"
00006 
00007 //! Handles communication with Mirage to place and control an object in the environment
00008 /*! The MirageComm constructor will open a connection to Mirage (if not already open).
00009  *  Then call setName() to register a name for your object.  Finally, assign a KinematicJoint via
00010  *  setKinematics() to provide information to configure and display your object.
00011  *
00012  *  You can reuse the MirageComm instance for multiple objects in Mirage, simply call setName()
00013  *  to change the name of the object being controlled.  Alternatively, you can use multiple
00014  *  MirageComms with a single shared network connection.  Each MirageComm tracks the
00015  *  name of the object is controlling and sends this state in each update to Mirage.
00016  *
00017  *  Parameters assigned by MirageComm are buffered until MirageComm
00018  *  hits its destructor, setName(), or flush() is called.
00019  *
00020  *  Objects are kept in the Mirage simulation until all network connections associated
00021  *  with that object are closed.  However, if setPersist(true) is called, the object will be kept
00022  *  active even if all associated network connections are closed.
00023  *
00024  *  @code
00025  *  #include "local/DeviceDrivers/MirageComm.h"
00026  *  #include "Wireless/netstream.h"
00027  *  ionetstream net;
00028  *  MirageComm mirage(net); // without arguments, makes connection to "localhost"
00029  *  mirage.setName("target");
00030  *  mirage.setPersist(true); // so we can close net without removing object
00031  *  KinematicJoint * k = new KinematicJoint; // this will hold object description
00032  *  k->model="Sphere";
00033  *  k->material="Pink";
00034  *  k->modelScale=plist::Point(15,15,15);
00035  *  mirage.setKinematics(k); // mirage will delete k after the flush
00036  *  mirage.setPosition(500,0,0); // place object at (500,0,0) mm
00037  *  // mirage destructor will automatically flush assigned attributes
00038  *  //   at end of scope, or you can call mirage.flush()
00039  *  @endcode
00040  *
00041  *  When you want to close the connection (e.g. remove the object "target" from previous example)
00042  *  just close the ionetstream connection.  If you want to be "nice" about this, let MirageComm do it:
00043  *  @code
00044  *  ionetstream net; // or continue 'net' scope from above to avoid connection overhead
00045  *  MirageComm mirage(net);
00046  *  mirage.setName("target");
00047  *  mirage.setPersist(false); // disable persistance, object will be removed when 'net' is closed
00048  *  mirage.close(); // sends XML closing tags to make Mirage's parser feel warm and fuzzy
00049  *  @endcode
00050  *
00051  *  Note that if you can match the network connection scope to the desired lifetime of the
00052  *  object in Mirage (e.g. make 'net' a class member of your object's controller), then you don't need to call setPersist(),
00053  *  and can simply rely on objects being "garbage collected" when you eventually close the connection.
00054  */
00055 class MirageComm {
00056 public:
00057   //! Constructor, if @a io is not already connected, it will reconnect to @a host and @a port
00058   /*! If the connection fails, no status is returned, check io.is_open() or the MirageComm bool cast */
00059   MirageComm(ionetstream& io, const std::string& host="localhost", unsigned short port=19785) : comm(io), name(), msg() {
00060     if(!comm.is_open())
00061       connect(host,port);
00062   }
00063   
00064   //! destructor
00065   ~MirageComm() { if(msg.size()>0) flush(); }
00066   
00067   //! opens connection to Mirage
00068   bool connect(const std::string& host, unsigned short port=19785) {
00069     if(!comm.open(IPaddr(host,port)))
00070       return false;
00071     comm.clear();
00072     comm << "<messages>" << std::endl;
00073     return comm;
00074   }
00075   
00076   //! Closes connection to Mirage.
00077   /*! Any objects which have not had setPersist(true) and have not been "touched"
00078    *  by other connections will be removed from the environment. */
00079   void close() {
00080     if(comm.is_open()) {
00081       flush();
00082       comm << "</messages>" << std::endl;
00083       comm.close();
00084     }
00085   }
00086   
00087   //! Indicates which object is being controlled.
00088   /*! If an object with this name already exists, subsequent 'set' calls will control that object.
00089    *  If no such object exists, a new one will be created.
00090    *  This implies a flush if any parameters have been set under the old name. */
00091   MirageComm& setName(const std::string& n) {
00092     if(name.size()>0) //! If no name has been set yet, inherit parameters (i.e. doesn't flush parameters without a name)
00093       flush();
00094     name = n;
00095     return *this;
00096   }
00097   
00098   //! If passed 'true', this will prevent the current object from being removed when the connection is closed.
00099   MirageComm& setPersist(bool persist) {
00100     msg.addValue("Persist",persist);
00101     return *this;
00102   }
00103   
00104   //! Assigns kinematic information to define the display and movement of the object, will delete @a kj after flush!
00105   /*! This will delete @a kj after the next flush, so pass the result of kj->clone() if you don't want to lose your instance */
00106   MirageComm& setKinematics(KinematicJoint* kj) {
00107     KinematicJointSaver * kinSaver = new KinematicJointSaver(*kj,true);
00108     msg.addEntry("Model",kinSaver);
00109     return *this;
00110   }
00111   
00112   //! Assigns a value to a specific field of the root kinematic object
00113   /*! Many times no joints are in use, and you only want to modify a subset of fields, 
00114    *  without respecifying the kinematic description—this will let you do it. */
00115   template<class T>
00116   MirageComm& setKinematicProperty(const std::string& paramName, const T& val) {
00117     plist::Dictionary::const_iterator it = msg.findEntry("Model");
00118     if(it!=msg.end()) {
00119       // TODO there should be an array wrapping this I think?
00120       plist::Dictionary& kd = dynamic_cast<plist::Dictionary&>(*it->second);
00121       plist::Dictionary::const_iterator it2 = kd.findEntry(paramName);
00122       if(it2!=kd.end()) {
00123         std::stringstream ss;
00124         ss << val;
00125         plist::PrimitiveBase& prim = dynamic_cast<plist::PrimitiveBase&>(*it2->second);
00126         prim.set(ss.str());
00127       } else {
00128         kd.addValue(paramName,val);
00129       }
00130     } else {
00131       // TODO should this dict be wrapped in an array?!?
00132       plist::Dictionary * kd = new plist::Dictionary;
00133       kd->addValue(paramName,val);
00134       msg.addEntry("Model",kd);
00135     }
00136     return *this;
00137   }
00138   
00139   //! Controls position of the object
00140   MirageComm& setPosition(float x, float y, float z) { 
00141     msg.addEntry("Location",new plist::Point(x,y,z));
00142     return *this;
00143   }
00144   //! Controls position of the object
00145   MirageComm& setPosition(const fmat::Column<3>& x) {
00146     msg.addEntry("Location",new plist::Point(x[0],x[1],x[2]));
00147     return *this;
00148   }
00149   //! Controls position of the object
00150   MirageComm& setPosition(const fmat::SubVector<3>& x) {
00151     msg.addEntry("Location",new plist::Point(x[0],x[1],x[2]));
00152     return *this;
00153   }
00154   //! Controls position of the object
00155   MirageComm& setPosition(const fmat::SubVector<3,const fmat::fmatReal>& x) {
00156     msg.addEntry("Location",new plist::Point(x[0],x[1],x[2]));
00157     return *this;
00158   }
00159   //! Controls position of the object
00160   MirageComm& setPosition(const plist::Point& x) {
00161     msg.addEntry("Location",x.clone());
00162     return *this;
00163   }
00164   
00165   //! Controls orientation of the object
00166   MirageComm& setOrientation(const fmat::Quaternion& q) {
00167     plist::Point* pq = new plist::Point;
00168     q.exportTo((*pq)[0],(*pq)[1],(*pq)[2]);
00169     msg.addEntry("Orientation",pq);
00170     return *this;
00171   }
00172   
00173   //! Will cause previous 'set' calls to be transmitted to Mirage
00174   bool flush() {
00175     if(msg.size()==0)
00176       return true;
00177     ASSERTRETVAL(name.size()>0,"flushing without name",false);
00178     msg.addEntry("ID",name);
00179     msg.saveStream(comm,true);
00180     msg.clear();
00181     return comm.flush();
00182   }
00183   
00184   //! returns true if the communication socket is still good
00185   operator bool() const { return comm; }
00186   
00187 protected:
00188   ionetstream& comm; //!< connection to Mirage
00189   plist::Primitive<std::string> name; //!< name ("ID") of the current object in Mirage
00190   plist::Dictionary msg; //!< buffers settings to Mirage until flush();
00191 };

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