Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
MirageComm.hGo 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 |