Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
hardwareSensorAbstract.hpp
Go to the documentation of this file.
00001 
00012 #ifndef HARDWARE_SENSOR_HPP_
00013 #define HARDWARE_SENSOR_HPP_
00014 
00015 #include <typeinfo>
00016 
00017 #include <boost/thread/condition_variable.hpp>
00018 
00019 #include <jafarConfig.h>
00020 
00021 #ifdef HAVE_POSTERLIB
00022 #include "posterLib.h"
00023 #endif
00024 
00025 #include "kernel/threads.hpp"
00026 #include "kernel/dataLog.hpp"
00027 
00028 #include "jmath/indirectArray.hpp"
00029 #include "jmath/ublasExtra.hpp"
00030 
00031 #include "rtslam/rawAbstract.hpp"
00032 
00033 namespace jafar {
00034 namespace rtslam {
00035 
00036 struct RawInfo
00037 { unsigned id; double timestamp; double arrival;
00038   RawInfo(unsigned id, double timestamp, double arrival): id(id), timestamp(timestamp), arrival(arrival) {}
00039   RawInfo() {}
00040 };
00041 struct RawInfos
00042   { std::vector<RawInfo> available; RawInfo next; double process_time; bool integrate_all; };
00043 
00044 struct RawVec
00045 {
00046   jblas::vec data;
00047   double arrival;
00048   RawVec(unsigned n): data(n), arrival(0.) {}
00049   void resize(unsigned n) { data.resize(n); }
00050   RawVec() {}
00051 };
00052 
00053 // TODO use kernel version when released
00054 class LoggableClose: public kernel::Loggable
00055 {
00056  private:
00057   std::fstream *logStream;
00058   std::ofstream *logoStream;
00059  public:
00060   LoggableClose(std::fstream & logStream): logStream(&logStream), logoStream(NULL) {}
00061   LoggableClose(std::ofstream & logoStream): logStream(NULL), logoStream(&logoStream) {}
00062   virtual void log() {
00063     if (logStream && logStream->is_open()) logStream->close();
00064     if (logoStream && logoStream->is_open()) logoStream->close();
00065   }
00066 };
00067 
00068 
00069 namespace hardware {
00070 
00071 //namespace ublas = boost::numeric::ublas;
00072 
00073 #ifdef HAVE_POSTERLIB
00074 extern STATUS reentrantPosterIoctl(POSTER_ID posterId, int code, void *parg);
00075 extern int reentrantPosterRead(POSTER_ID posterId, int offset, void *buf, int nbytes);
00076 #endif
00077 
00078 
00079 inline double extractRawTimestamp(raw_ptr_t &raw) { return raw->timestamp; }
00080 inline double extractRawTimestamp(RawVec &raw) { return raw.data(0); }
00081 inline double extractRawArrival(raw_ptr_t &raw) { return raw->arrival; }
00082 inline double extractRawArrival(RawVec &raw) { return raw.arrival; }
00083 
00084 enum Mode { mOnline, mOnlineDump, mOffline };
00085 
00086 #define narrival_delays 2
00087 
00100 template<typename T>
00101 class HardwareSensorAbstract
00102 {
00103   public:
00104     typedef ublas::vector<T> VecT;
00105     typedef ublas::vector_indirect<VecT> VecIndT;
00106   
00107   private:
00108     int write_pos; 
00109     int read_pos;  
00110     bool buffer_full; 
00111     bool read_pos_used;  
00112     
00113   protected:
00114     kernel::VariableCondition<int> *condition; 
00115     kernel::VariableCondition<int> index; 
00116     boost::mutex mutex_data; 
00117     boost::condition_variable cond_offline_full;
00118     boost::condition_variable cond_offline_freed;
00119     int data_count; 
00120     int last_sent_pos; 
00121     bool no_more_data;
00122     double timestamps_correction;
00123     double data_period;
00124     double arrival_delays[narrival_delays];
00125     int iarrival_delay;
00126     double arrival_delay;
00127     bool started; 
00128 
00134     bool stopping;
00135     bool enabled; 
00136     bool initialized_; 
00137     Mode mode;
00138 
00139     int bufferSize; 
00140     VecT buffer; 
00141 
00142     int getWritePos(bool locked = false) {
00143       if (isFull(locked)) JFR_ERROR(RtslamException, RtslamException::GENERIC_ERROR, "HardwareSensor " << typeid(this).name() << ": buffer is full"); // FIXME chose policty when full
00144       // don't need to lock, because will only be used and modified by writer
00145       return write_pos;
00146     }
00147     void incWritePos(bool locked = false) {
00148       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00149       ++write_pos;
00150       if (write_pos >= bufferSize) write_pos = 0;
00151       if (write_pos == read_pos) buffer_full = true; // full
00152       ++data_count;
00153     }
00154     int getFirstUnreadPos() {
00156       // don't need to lock, because will only be used and modified by reader
00157       if (!read_pos_used) return read_pos;
00158       if (read_pos != bufferSize-1) return read_pos+1; else return 0;
00159     }
00160     int getLastUnreadPos(bool locked = false) {
00162       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00163       return (write_pos == 0 ? bufferSize-1 : write_pos-1);
00164     }
00166     void releaseUntil(unsigned id, bool locked = false) {
00167       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00168       read_pos = id;
00169       read_pos_used = true;
00170       if (getFirstUnreadPos() == write_pos) buffer_full = false;
00171       l.unlock();
00172       cond_offline_freed.notify_all();
00173       // cannot be full as id is not released
00174     }
00176     void release(unsigned id, bool locked = false) {
00177       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00178       if (id != (unsigned)(bufferSize-1)) read_pos = id+1; else read_pos = 0;
00179       if (write_pos == read_pos) buffer_full = false; // empty
00180       read_pos_used = false;
00181       l.unlock();
00182       cond_offline_freed.notify_all();
00183     }
00184     bool isFull(bool locked = false)
00185     {
00186       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00187       return (read_pos == write_pos && buffer_full);
00188     }
00189     bool isEmpty(bool locked = false)
00190     {
00191       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00192       return (getFirstUnreadPos() == write_pos && !buffer_full);
00193     }
00194 
00195     void update_arrival_delay(double delay)
00196     {
00197       // find min of current and past narrival_delays
00198       arrival_delay = delay;
00199       for(int i = 0; i < narrival_delays; ++i) if (arrival_delays[i] < arrival_delay) arrival_delay = arrival_delays[i];
00200       // write current
00201       ++iarrival_delay; if (iarrival_delay >= narrival_delays) iarrival_delay = 0;
00202       arrival_delays[iarrival_delay] = delay;
00203     }
00204 
00205   public:
00209     HardwareSensorAbstract(kernel::VariableCondition<int> *condition, Mode mode, unsigned bufferSize):
00210       write_pos(0), read_pos(0), buffer_full(false), read_pos_used(false),
00211       condition(condition), index(-1),
00212       data_count(0), no_more_data(false), timestamps_correction(0.0), iarrival_delay(0), started(false), stopping(false), enabled(true), initialized_(true), mode(mode),
00213       bufferSize(bufferSize), buffer(bufferSize)
00214     { for(int i = 0; i < narrival_delays; ++i) arrival_delays[i] = 0.0; }
00215     virtual void start() = 0; 
00216     virtual void stop() = 0; 
00217     virtual bool join(int timed_ms = -1) = 0; 
00218     bool stopped() { return no_more_data || stopping; }
00219     bool initialized() { return initialized_; }
00220 
00221     void setSyncConfig(double timestamps_correction = 0.0)
00222       { this->timestamps_correction = timestamps_correction; }
00230     virtual void getTimingInfos(double &data_period, double &arrival_delay, bool locked = false)
00231     {
00232       boost::unique_lock<boost::mutex> l(mutex_data, boost::defer_lock_t()); if (!locked) l.lock();
00233       data_period = this->data_period; arrival_delay = this->arrival_delay;
00234     }
00235     virtual void setTimingInfos(double data_period, double arrival_delay)
00236       { this->data_period = data_period; this->arrival_delay = arrival_delay; for(int i = 0; i < narrival_delays; ++i) arrival_delays[i] = arrival_delay; }
00237     
00238     
00239     virtual double getLastTimestamp() = 0;
00240     virtual void showInfos() {}
00241     
00242     virtual VecIndT getRaws(double t1, double t2, bool release = true); 
00243     virtual int getUnreadRawInfos(RawInfos &infos); 
00244     virtual int getNextRawInfo(RawInfo &info); 
00245     virtual void getRaw(unsigned id, T& raw); 
00246     virtual void observeRaw(unsigned id, T& raw); 
00247     virtual double getRawTimestamp(unsigned id);
00248     virtual int getLastUnreadRaw(T& raw); 
00249     virtual void getLastProcessedRaw(T& raw) { raw = buffer(last_sent_pos); } 
00250     virtual void release() { release(read_pos); }
00251     virtual void enable(bool enabled = true) { this->enabled = enabled; }
00252     void stopDumping() { if (this->mode == mOnlineDump) this->mode = mOnline; }
00253 
00254     friend class rtslam::SensorProprioAbstract;
00255     friend class rtslam::SensorExteroAbstract;
00256 };
00257 
00258 
00259 bool checkStream(std::istream &f, std::string const & owner);
00260 
00261 
00262 class LoggableProprio: public kernel::Loggable
00263 {
00264  private:
00265   std::fstream &fl;
00266   std::fstream &fb;
00267   jblas::vec data;
00268 
00269  public:
00270   LoggableProprio(std::fstream &fl, std::fstream &fb, jblas::vec & data):
00271     fl(fl), fb(fb), data(data) {}
00272   virtual void log();
00273 };
00274 
00275 
00276 class ProprioLog
00277 {
00278   protected:
00279     std::fstream fl;
00280     std::fstream fb;
00281     bool binary; // binary format available
00282     bool old; // old log format
00283     int size; // if !binary, 0 means old text format, -1 means unknown
00284     kernel::LoggerTask *loggerTask;
00285     std::string name;
00286 
00287   public:
00288     ProprioLog(): binary(true), old(false), size(-1), loggerTask(NULL) {}
00289     void openWrite(std::string name, std::string dump_path, int format, int size, kernel::LoggerTask *loggerTask);
00290     void write(jblas::vec &v) { loggerTask->push(new LoggableProprio(fl, fb, v)); }
00291     void openRead(std::string name, std::string dump_path, int &format, int &size);
00292     bool read(jblas::vec &v);
00293     void close();
00294 };
00295 
00296 
00297 
00298 
00299 
00300 class HardwareSensorProprioAbstract: public HardwareSensorAbstract<RawVec>
00301 {
00302   public:
00319     enum Quantity { qPos, qOriQuat, qOriEuler, qVel, qAbsVel, qNormVel, qAngVel, qAbsAngVel, qAcc, qAbsAcc, qBundleobs, qMag, qNQuantity };
00320     static const int QuantityDataSizes[qNQuantity];
00321     static const int QuantityObsSizes[qNQuantity];
00322     enum CovType { ctNone, ctVar, ctFull };
00323   private:
00324     int quantities[qNQuantity];
00325     size_t data_size;
00326     size_t obs_size;
00327     CovType cov_type;
00328   protected:
00329     RawVec reading;
00330     ProprioLog log;
00331     void addQuantity(Quantity quantity) { quantities[quantity] = data_size+1; data_size += QuantityDataSizes[quantity]; obs_size += QuantityObsSizes[quantity]; }
00332     void addDataQuantities(int n) { data_size += n; }
00333     void clearQuantities() { for(int i = 0; i < qNQuantity; ++i) quantities[i] = -1; data_size = obs_size = 0; }
00334   public:
00335     HardwareSensorProprioAbstract(kernel::VariableCondition<int> *condition, Mode mode, unsigned bufferSize, CovType covType):
00336       HardwareSensorAbstract<RawVec>(condition, mode, bufferSize), cov_type(covType) { clearQuantities(); }
00337     size_t dataSize() { return data_size; } 
00338     size_t obsSize() { return obs_size; } 
00339     size_t readingSize() { switch (cov_type) { case ctNone: return 1+data_size; case ctVar: return 1+data_size*2; case ctFull: return 1+data_size*(data_size+3)/2; default: return 0; } } 
00340     size_t getQuantity(Quantity quantity) { return quantities[quantity]; } 
00341     CovType covType() { return cov_type; } 
00342     jblas::sym_mat extractDataCovBlock(size_t pos, size_t size)
00343     {
00344       switch (cov_type) {
00345         case ctNone: { jblas::sym_mat res(size,size); res.clear(); return res; }
00346         case ctVar : { jblas::sym_mat res(size,size); for(size_t i = 0; i < size; ++i) res(i,i) = reading.data(data_size+pos+i); return res; }
00347         case ctFull: { return jmath::ublasExtra::createSymMat(reading.data, data_size+1, data_size, pos, size); }
00348         default: return jblas::sym_mat(0,0);
00349       }
00350     }
00351 
00352     void initData() {
00353       int size = readingSize();
00354       for(int i = 0; i < bufferSize; ++i) { buffer[i].resize(size); buffer(i).data(0) = -99.; }
00355       reading.resize(size);
00356     }
00362     virtual jblas::ind_array instantValues() = 0;
00367     virtual jblas::ind_array incrementValues() = 0;
00368 };
00369 
00370 class HardwareSensorExteroAbstract: public HardwareSensorAbstract<raw_ptr_t>
00371 {
00372   public:
00373     HardwareSensorExteroAbstract(kernel::VariableCondition<int> *condition, Mode mode, unsigned bufferSize):
00374       HardwareSensorAbstract<raw_ptr_t>(condition, mode, bufferSize) {}
00375   
00376   
00377 };
00378 
00379 typedef boost::shared_ptr<hardware::HardwareSensorExteroAbstract> hardware_sensorext_ptr_t;
00380 typedef boost::shared_ptr<hardware::HardwareSensorProprioAbstract> hardware_sensorprop_ptr_t;
00381 
00382 
00386 // Template implementations
00387 
00388 
00389 template<typename T>
00390 typename HardwareSensorAbstract<T>::VecIndT HardwareSensorAbstract<T>::getRaws(double t1, double t2, bool release)
00391 {
00392   JFR_ASSERT(t1 <= t2, "");
00393   boost::unique_lock<boost::mutex> l(mutex_data);
00394   int i1, i2;
00395   int i, j;
00396 
00397   // find first by dichotomy
00398   int i_left = write_pos, i_right = write_pos + bufferSize-1;
00399   while(i_left != i_right)
00400   {
00401     j = (i_left+i_right)/2;
00402     i = j % bufferSize;
00403     if (extractRawTimestamp(buffer(i)) >= t1) i_right = j; else i_left = j+1;
00404   }
00405   i = i_left % bufferSize;
00406   i1 = (i-1 + bufferSize) % bufferSize; // get the one before for interpolation
00407   if (t1 <= -0.1) i1 = i; // or not if we explicitly asked for the first one
00408   bool no_larger = (extractRawTimestamp(buffer(i)) < t1);
00409   bool no_smaller = (i == write_pos);
00410   if (no_larger && extractRawTimestamp(buffer(i1)) < 0.0)  // no data at all
00411     return ublas::project(buffer, jmath::ublasExtra::ia_set(ublas::range(0,0)));
00412   if (no_smaller && t1 > 0) JFR_ERROR(RtslamException, RtslamException::BUFFER_OVERFLOW, "HardwareSensor " << typeid(this).name() << ": missing data (increase buffer size !)");
00413 
00414   // find last by dichotomy
00415   if (no_larger)
00416     i2 = i1;
00417   else
00418   {
00419     i_right = write_pos + bufferSize-1;
00420     while(i_left != i_right)
00421     {
00422       j = (i_left+i_right)/2;
00423       i = j % bufferSize;
00424       if (extractRawTimestamp(buffer(i)) >= t2) i_right = j; else i_left = j+1;
00425     }
00426     i = i_left % bufferSize;
00427     i2 = i; // this is already the one after for interpolation, or the last one if there is none after
00428   }
00429 
00430   // return mat_indirect
00431   if (release) read_pos = i1;
00432   l.unlock();
00433   if (release) cond_offline_freed.notify_all();
00434 
00435   if (i1 <= i2)
00436   {
00437     return ublas::project(buffer,
00438       jmath::ublasExtra::ia_set(ublas::range(i1,i2+1)));
00439   } else
00440   {
00441     return ublas::project(buffer,
00442       jmath::ublasExtra::ia_concat(jmath::ublasExtra::ia_set(ublas::range(i1,buffer.size())),
00443                                    jmath::ublasExtra::ia_set(ublas::range(0,i2+1))));
00444   }
00445 }
00446 
00447 
00448 template<typename T>
00449 int HardwareSensorAbstract<T>::getUnreadRawInfos(RawInfos &infos)
00450 {
00451   infos.available.clear();
00452   if (!isEmpty())
00453   {
00454     int first_stop, second_stop;
00455     int first = getFirstUnreadPos(), last = getLastUnreadPos();
00456     JFR_DEBUG("getUnreadRawInfos: first " << first << " last " << last);
00457 
00458     if (first <= last)
00459     {
00460       first_stop = last;
00461       second_stop = -1;
00462     } else
00463     {
00464       first_stop = bufferSize-1;
00465       second_stop = last;
00466     }
00467     
00468     for(int pos = first; pos <= first_stop; ++pos)
00469       infos.available.push_back(RawInfo(pos,extractRawTimestamp(buffer(pos)),extractRawArrival(buffer(pos))));
00470     for(int pos = 0; pos <= second_stop; ++pos)
00471       infos.available.push_back(RawInfo(pos,extractRawTimestamp(buffer(pos)),extractRawArrival(buffer(pos))));
00472   }
00473   
00474   double data_period, arrival_delay;
00475   getTimingInfos(data_period, arrival_delay); // use the accessor for mutex protection
00476   double next_date = getLastTimestamp() + data_period;
00477   infos.next = RawInfo(0,next_date,next_date+arrival_delay);
00478   infos.process_time = 0.;
00479   
00480   if (infos.available.size() == 0)
00481   {
00482     if (no_more_data) return -2; else return -1;
00483   }
00484   return 0;
00485 }
00486 
00487 template<typename T>
00488 int HardwareSensorAbstract<T>::getNextRawInfo(RawInfo &info)
00489 {
00490   if (!isEmpty())
00491   {
00492     int first = getFirstUnreadPos();
00493     info = RawInfo(first,extractRawTimestamp(buffer(first)),0.0);
00494     return 0;
00495   } else
00496   {
00497     if (no_more_data) return -2; else return -1;
00498   }
00499 }
00500 
00501 template<typename T>
00502 double HardwareSensorAbstract<T>::getRawTimestamp(unsigned id)
00503 {
00504   return extractRawTimestamp(buffer[id]);
00505 }
00506 
00507 template<typename T>
00508 void HardwareSensorAbstract<T>::observeRaw(unsigned id, T& raw)
00509 {
00510   raw = buffer[id];
00511 }
00512 
00513 template<typename T>
00514 void HardwareSensorAbstract<T>::getRaw(unsigned id, T& raw)
00515 {
00516   releaseUntil(id);
00517   raw = buffer[id];
00518   last_sent_pos = id;
00519   index.applyAndNotify(boost::lambda::_1++);
00520 }
00521 
00522 template<typename T>
00523 int HardwareSensorAbstract<T>::getLastUnreadRaw(T& raw)
00524 {
00525   boost::unique_lock<boost::mutex> l(mutex_data);
00526   int missed_count = data_count-1;
00527   if (data_count > 0)
00528   {
00529     unsigned id = getLastUnreadPos(true);
00530     releaseUntil(id, true);
00531     raw = buffer[id];
00532     last_sent_pos = id;
00533     boost::unique_lock<boost::mutex> l(mutex_data);
00534     data_count = 0;
00535     l.unlock();
00536     index.applyAndNotify(boost::lambda::_1++);
00537   }
00538   if (no_more_data && missed_count == -1) return -2; else return missed_count;
00539 }
00540 
00541 
00542 
00543 }}}
00544 
00545 #endif
00546 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Wed Oct 15 2014 00:37:26 for Jafar by doxygen 1.7.6.1
LAAS-CNRS