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

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