Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MirageDriver.cc

Go to the documentation of this file.
00001 #include "MirageDriver.h"
00002 #include "local/CommPort.h"
00003 #include "Motion/KinematicJoint.h"
00004 #include "Shared/Config.h"
00005 #include "Shared/debuget.h"
00006 #include "Shared/get_time.h"
00007 #include <libxml/tree.h>
00008 
00009 //better to put this here instead of the header
00010 using namespace std; 
00011 
00012 const std::string MirageDriver::autoRegisterDriver = DeviceDriver::getRegistry().registerType<MirageDriver>("Mirage");
00013 
00014 const char* MirageDriver::encodingNames[] = { "YUV", "PNG", "JPG", NULL };
00015 INSTANTIATE_NAMEDENUMERATION_STATICS(MirageDriver::Encoding);
00016 
00017 
00018 void MirageDriver::ImageSubscription::registerSource() {
00019   DataStreamDriver::registerSource();
00020 #if defined(TGT_HAS_CAMERA)
00021   CameraName = "Mirage";
00022 #endif
00023 }
00024 
00025 void MirageDriver::ImageSubscription::deregisterSource() {
00026 #if defined(TGT_HAS_CAMERA)
00027   CameraName = CameraModelName;
00028 #endif
00029   DataStreamDriver::deregisterSource();
00030 }
00031 
00032 void MirageDriver::motionStarting() {
00033   MotionHook::motionStarting();
00034   opener.start();
00035   imgsrc.host.addPrimitiveListener(this);
00036   imgsrc.port.addPrimitiveListener(this);
00037   sensrc.host=imgsrc.host;
00038   sensrc.port=imgsrc.port;
00039   for(unsigned int i=0; i<NumOutputs; ++i)
00040     positions[i] = DataSource::getOutputValue(i);
00041 }
00042 
00043 bool MirageDriver::isConnected() {
00044   return comm.is_open() || comm.is_connecting();
00045 }
00046 
00047 void MirageDriver::motionStopping() {
00048   persist.removePrimitiveListener(this);
00049   imgsrc.host.removePrimitiveListener(this);
00050   imgsrc.port.removePrimitiveListener(this);
00051   if(opener.isStarted())
00052     opener.stop().join();
00053   MotionHook::motionStopping();
00054 }
00055 
00056 void MirageDriver::motionUpdated(const std::vector<size_t>& changedIndices, const float outputs[][NumOutputs]) {
00057   MotionHook::motionUpdated(changedIndices,outputs);
00058   if(changedIndices.size()==0 || !comm.is_open() || !comm) {
00059     // just copy values, don't send update
00060     for(std::vector<size_t>::const_iterator it=changedIndices.begin(); it!=changedIndices.end(); ++it)
00061       positions[*it]=outputs[NumFrames-1][*it];
00062   } else {
00063     plist::Dictionary d;
00064     plist::Dictionary pos;
00065     for(std::vector<size_t>::const_iterator it=changedIndices.begin(); it!=changedIndices.end(); ++it) {
00066       positions[*it]=outputs[NumFrames-1][*it];
00067       pos.addEntry(capabilities.getOutputName(*it),positions[*it]);
00068     }
00069     d.addEntry("Positions",pos);
00070     sendUpdate(d);
00071   }
00072 }
00073 
00074 
00075 void MirageDriver::plistValueChanged(const plist::PrimitiveBase& pl) {
00076   if(&pl==&imgsrc.host || &pl==&imgsrc.port) {
00077     // if here, then motionStarted or setDataSourceThread has been called, thus when host changes,
00078     // need to close old one and reopen new one
00079     if(opener.isStarted())
00080       opener.stop().join();
00081     sensrc.host=imgsrc.host;
00082     sensrc.port=imgsrc.port;
00083     opener.start();
00084   } else if(&pl==&persist) {
00085     plist::Dictionary d;
00086     d.addEntry("Persist",persist);
00087     sendUpdate(d);
00088   } else if(&pl==&highres) {
00089     if(highres && imgsrc.encoding==ENCODE_YUV) {
00090       std::cerr << "MirageDriver: YUV encoding does not support highres mode (try PNG)" << std::endl;
00091       highres=false;
00092       return;
00093     }
00094     if(!comm.is_open())
00095       return;
00096 #ifdef TGT_HAS_CAMERA
00097     plist::Dictionary cam;
00098     cam.addEntry("Width",new plist::Primitive<unsigned int>(highres ? CameraResolutionX*2 : CameraResolutionX));
00099     cam.addEntry("Height",new plist::Primitive<unsigned int>(highres ? CameraResolutionY*2 : CameraResolutionY));
00100     plist::Array cameras;
00101     cameras.addEntry(cam);
00102     plist::Dictionary d;
00103     d.addEntry("Cameras",cameras);
00104     sendUpdate(d);
00105 #endif
00106   } else if(&pl==&imgsrc.encoding) {
00107     if(highres && imgsrc.encoding==ENCODE_YUV) {
00108       std::cerr << "MirageDriver: YUV encoding does not support highres mode" << std::endl;
00109       highres=false;
00110       return;
00111     }
00112   } else if(&pl==&physicsWalk) {
00113     if(!physicsWalk) {
00114       DriverMessaging::addListener(this,DriverMessaging::FixedPoints::NAME);
00115     } else {
00116       std::cout << "removing fixed points" << std::endl;
00117       DriverMessaging::removeListener(this,DriverMessaging::FixedPoints::NAME);
00118       // send empty FixedPoints list to clear them out
00119       plist::Array arr;
00120       plist::Dictionary msg;
00121       msg.addEntry("FixedPoints",arr);
00122       sendUpdate(msg);
00123     }
00124   } else if(&pl==&physicsWheels) {
00125     plist::Dictionary msg;
00126     msg.addEntry("PhysicsWheels",physicsWheels);
00127     sendUpdate(msg);
00128   } else {
00129     std::cerr << "Unhandled value change in " << getClassName() << ": " << pl.get() << std::endl;
00130   }
00131 }
00132 
00133 void MirageDriver::openConnection() {
00134   IPaddr addr(imgsrc.host,imgsrc.port);
00135   if(!addr.is_valid()) {
00136     std::cerr << instanceName << " could not open connection to " << imgsrc.host << ":" << imgsrc.port << std::endl;
00137     return;
00138   }
00139 
00140   try {
00141     if(!physicsWalk)
00142       DriverMessaging::addListener(this,DriverMessaging::FixedPoints::NAME);
00143     physicsWalk.addPrimitiveListener(this);
00144     physicsWheels.addPrimitiveListener(this);
00145     while(true) {
00146       { // scope limiting
00147         MarkScope autolock(commLock);
00148         
00149         comm.clear(); // clear out iostream state bits... new connection, try again
00150         comm.seekp(0); // clear out any old unflushed messages (e.g. what we were trying to write when received notification of closure)
00151         while(!comm.open(addr)) {
00152           Thread::testCurrentCancel();
00153           usleep(1000*1000);
00154           Thread::testCurrentCancel();
00155           //std::cout << "attempt open to " << addr.get_name() << " on " << addr.get_port() << std::endl;
00156         }
00157         comm << "<messages>\n";
00158         
00159         KinematicJoint kin;
00160         if(kin.loadFile(::config->makePath(::config->motion.kinematics).c_str())==0) {
00161           std::cerr << "MirageDriver unable to find/parse kinematics file '" << ::config->motion.kinematics << "'" << std::endl;
00162           return;
00163         }
00164         
00165         plist::Dictionary d;
00166         d.addEntry("Persist",persist);
00167         if(!persist) {
00168           d.addEntry("Location",initLocation);
00169           d.addEntry("Orientation",initOrientation);
00170         }
00171         KinematicJointSaver kinSaver(kin);
00172         d.addEntry("Model",kinSaver);
00173         plist::Dictionary pos;
00174         for(unsigned int i=0; i<NumOutputs; ++i)
00175           pos.addEntry(outputNames[i],positions[i]);
00176         d.addEntry("Positions",pos);
00177         d.addEntry("PhysicsWheels",physicsWheels);
00178 #ifdef TGT_HAS_CAMERA
00179         plist::Dictionary cam;
00180         cam.addValue("FrameName",outputNames[CameraFrameOffset]);
00181         cam.addValue("Width",highres ? CameraResolutionX*2 : CameraResolutionX);
00182         cam.addValue("Height",highres ? CameraResolutionY*2 : CameraResolutionY);
00183         /* Mirage (or really Ogre) does not support rendering non-square pixels.
00184          * Ogre specifies camera by Y FOV.  We pass CameraVertFOV below, which will
00185          * maintain the vertical FOV for accurate distance estimates, but note
00186          * in the case of non-square pixels this sacrifies heading measurements.
00187          *
00188          * If you want to reverse this trade-off, recompute 'square' Y field of view:
00189          *   yfov = 2 * std::atan( std::tan(CameraHorizFOV/2) * CameraResolutionY / CameraResolutionX );
00190          */
00191         cam.addValue("FOV_Y",CameraVertFOV);
00192         plist::Array cameras;
00193         cameras.addEntry(cam);
00194         d.addEntry("Cameras",cameras);
00195         highres.addPrimitiveListener(this);
00196 #endif
00197         
00198         sendUpdate(d);
00199         
00200         // these aren't recursive, so just do every time:
00201         persist.addPrimitiveListener(this);
00202       } // release lock while we block on connection to close
00203       
00204       comm.get(); // either remote closes first and we get an error here ...
00205       if(comm.is_open()) {
00206         // try to close the connection now
00207         MarkScope autolock(commLock);
00208         comm.clear(); // breaking out of the comm.get causes an error bit, but connection may be fine
00209         comm << "</messages>" << std::endl;
00210         comm.close();
00211       }
00212       Thread::testCurrentCancel(); // ... or we close first and get a thread cancellation from the destructor
00213       ASSERT(!comm,"comm closed, but still active?");
00214     }
00215   } catch(...) { // thread cancellation?
00216     physicsWalk.removePrimitiveListener(this);
00217     physicsWheels.removePrimitiveListener(this);
00218     DriverMessaging::removeListener(this);
00219     if(comm.is_open()) {
00220       // try to close the connection now
00221       MarkScope autolock(commLock);
00222       comm.clear(); // breaking out of the comm.get causes an error bit, but connection may be fine
00223       comm << "</messages>" << std::endl;
00224       comm.close();
00225     }
00226     throw;
00227   }
00228 }
00229 
00230 void MirageDriver::sendUpdate(plist::Dictionary& msg) {
00231   std::stringstream ss;
00232   ss << "RobotID-" << ::config->wireless.id;
00233   plist::Primitive<std::string> wid(ss.str());
00234   msg.addEntry("ID",wid);
00235   MarkScope autolock(commLock);
00236   msg.saveStream(comm,true);
00237   if(bufferedMsg.size()>0) {
00238     comm << bufferedMsg;
00239     bufferedMsg.clear();
00240   }
00241   comm.flush();
00242 }
00243 
00244 void MirageDriver::SensorSubscription::opened() {
00245   NetworkCommPort::opened();
00246   
00247   plist::Dictionary msg;
00248   
00249   std::stringstream ss;
00250   ss << "RobotID-" << ::config->wireless.id;
00251   plist::Primitive<std::string> wid(ss.str());
00252   msg.addEntry("ID",wid);
00253   
00254   plist::Primitive<bool> sendSensors(true);
00255   msg.addEntry("SendSensors",sendSensors);
00256   
00257   MarkScope autolock(*this);
00258   std::ostream os(&getWriteStreambuf());
00259   os << "<subscription>\n";
00260   msg.saveStream(os,true);
00261   os.flush();
00262 }
00263 
00264 void MirageDriver::ImageSubscription::opened() {
00265   NetworkCommPort::opened();
00266   
00267   plist::Dictionary msg;
00268   
00269   std::stringstream ss;
00270   ss << "RobotID-" << ::config->wireless.id;
00271   plist::Primitive<std::string> wid(ss.str());
00272   msg.addEntry("ID",wid);
00273   
00274   plist::Primitive<unsigned int> camIdx(0);
00275   msg.addEntry("CameraIndex",camIdx);
00276   
00277   msg.addEntry("Encoding",encoding);
00278   msg.addEntry("PNGLevel",pngCompressionLevel);
00279   msg.addEntry("JPGQuality",jpgQualityLevel);
00280   
00281   MarkScope autolock(*this);
00282   std::ostream os(&getWriteStreambuf());
00283   os << "<subscription>\n";
00284   msg.saveStream(os,true);
00285   os.flush();
00286 }
00287 
00288 void MirageDriver::ImageSubscription::plistValueChanged(const plist::PrimitiveBase& pl) {
00289   if(&pl==&encoding) {
00290     format.set(encoding.get());
00291   } else if(&pl==&pngCompressionLevel || &pl==&jpgQualityLevel) {
00292     if(!isWriteable())
00293       return;
00294     plist::Dictionary d;
00295     // just send them both every time because I'm lazy
00296     d.addEntry("PNGLevel",pngCompressionLevel);
00297     d.addEntry("JPGQuality",jpgQualityLevel);
00298     MarkScope autolock(*this);
00299     std::ostream os(&getWriteStreambuf());
00300     d.saveStream(os,true);
00301     os.flush();
00302   } else
00303     Subscription<ImageStreamDriver>::plistValueChanged(pl);
00304 }
00305 
00306 void MirageDriver::processDriverMessage(const DriverMessaging::Message& dmsg) {
00307   if(!comm.is_open() || !comm)
00308     return;
00309   if(dmsg.CLASS_NAME==DriverMessaging::FixedPoints::NAME) {
00310     plist::Dictionary msg;
00311     const DriverMessaging::FixedPoints& fpmsg = dynamic_cast<const DriverMessaging::FixedPoints&>(dmsg);
00312     msg.addEntry("FixedPoints",const_cast<DriverMessaging::FixedPoints&>(fpmsg));
00313     if(!fpmsg.flushOnMotionUpdate)
00314       sendUpdate(msg);
00315     else {
00316       std::stringstream ss;
00317       ss << "RobotID-" << ::config->wireless.id;
00318       plist::Primitive<std::string> wid(ss.str());
00319       msg.addEntry("ID",wid);
00320       ss.str(std::string());
00321       msg.saveStream(ss,true);
00322       bufferedMsg = ss.str();
00323     }
00324   }
00325 }
00326 
00327 /*! @file
00328  * @brief 
00329  * @author Ethan Tira-Thompson (ejt) (Creator)
00330  */

Tekkotsu Hardware Abstraction Layer 5.1CVS
Generated Fri Mar 16 05:30:34 2012 by Doxygen 1.6.3