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
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
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");
00144
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;
00152 ++data_count;
00153 }
00154 int getFirstUnreadPos() {
00156
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
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;
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
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
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;
00282 bool old;
00283 int size;
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
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
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;
00407 if (t1 <= -0.1) i1 = i;
00408 bool no_larger = (extractRawTimestamp(buffer(i)) < t1);
00409 bool no_smaller = (i == write_pos);
00410 if (no_larger && extractRawTimestamp(buffer(i1)) < 0.0)
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
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;
00428 }
00429
00430
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);
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