IMU_MicroStrain_3DM_GX2.C

00001 /*!@file Devices/IMU_MicroStrain_3DM-GX2.C class for interfacing with the
00002   MicroStrain 3DM-GX2 IMU */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00006 // by the University of Southern California (USC) and the iLab at USC.  //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/IMU_MicroStrain_3DM_GX2.C $
00036 // $Id: IMU_MicroStrain_3DM_GX2.C 14295 2010-12-02 20:02:32Z itti $
00037 //
00038 // NOTE: This IMU has 2 reporting mode. One is a continuous mode and another
00039 //       is a polled mode. Current default mode is polled mode.
00040 //
00041 //       Continuous mode is setting a continuous command address to
00042 //       the desired command (this is done using test-serial) and it
00043 //       will do it continuously with a specified interval (can be
00044 //       changed by writing to the EEPROM address OxFCA2. Read pg. 29
00045 //       of the manual). Default 100Hz.
00046 //
00047 //       Polled mode allow the user to inquire a one time data.
00048 //       If both modes are running, there will be two data being sent, the
00049 //       first one from the continuous mode, the the polled command.
00050 
00051 // TODO:
00052 //  Get the orientation Matrix M and change matrix C
00053 //    (Euler Angle can be calculated with this)
00054 //          Magnetometer
00055 //          ACC bias/ gyro bias <- to zero out stuff
00056 //  OPENGL setup for other information?
00057 //  temperature?
00058 
00059 #include "Devices/IMU_MicroStrain_3DM_GX2.H"
00060 #include "Util/BinaryConversion.H"
00061 #include "Util/Timer.H"
00062 #include <GL/gl.h>
00063 #undef APIENTRY // otherwise it gets redefined between gl.h and glut.h???
00064 #include <GL/glut.h>
00065 
00066 // A static pointer to the IMU
00067 static IMU_MicroStrain_3DM_GX2* theIMU = NULL;
00068 
00069 void *IMU_MicroStrain_3DM_GX2_run(void *c);
00070 
00071 // ######################################################################
00072 void *IMU_MicroStrain_3DM_GX2_run(void *c)
00073 {
00074   IMU_MicroStrain_3DM_GX2 *d = (IMU_MicroStrain_3DM_GX2 *) c;
00075   d ->run();
00076   return NULL;
00077 }
00078 
00079 // ######################################################################
00080 void renderScene(void)
00081 {
00082   // get IMU attitude
00083   RollPitchYawRecord rpyRecord;
00084   theIMU->getRollPitchYaw(rpyRecord);
00085   LDEBUG("Euler Angle  r:%15.6f p:%15.6f y:%15.6f",
00086          rpyRecord.roll, rpyRecord.pitch, rpyRecord.yaw);
00087 
00088   // visualize the IMU attitude
00089 
00090   // notice that we're now clearing the depth buffer
00091   // as well this is required, otherwise the depth buffer
00092   // gets filled and nothing gets rendered.
00093   // Try it out, remove the depth buffer part.
00094   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00095 
00096   // Reset The Current Modelview Matrix
00097   glLoadIdentity();
00098 
00099   // save the previous settings, in this case save
00100   // we're refering to the camera settings.
00101   //glPushMatrix();
00102 
00103   float sz = 0.25;
00104   glRotatef( rpyRecord.pitch/M_PI * 180.0,  1.0f,0.0f,0.0f);
00105   glRotatef( rpyRecord.yaw  /M_PI * 180.0,  0.0f,1.0f,0.0f);
00106   glRotatef( rpyRecord.roll /M_PI * 180.0,  0.0f,0.0f,1.0f);
00107 
00108   glBegin(GL_QUADS);
00109   glColor3f(0.0f, 0.0f, 1.0f);        // Color Blue
00110   glVertex3f(-sz, -sz, -sz);
00111   glVertex3f(-sz,  sz, -sz);
00112   glVertex3f( sz,  sz, -sz);
00113   glVertex3f( sz, -sz, -sz);
00114 
00115   glColor3f(1.0f, 1.0f, 0.0f);        // Color Yellow
00116   glVertex3f(-sz, -sz,  sz);
00117   glVertex3f(-sz,  sz,  sz);
00118   glVertex3f( sz,  sz,  sz);
00119   glVertex3f( sz, -sz,  sz);
00120 
00121   glColor3f(1.0f, 0.0f, 0.0f);        // Color Red
00122   glVertex3f(-sz, -sz, -sz);
00123   glVertex3f(-sz, -sz,  sz);
00124   glVertex3f(-sz,  sz,  sz);
00125   glVertex3f(-sz,  sz, -sz);
00126 
00127   glColor3f(0.0f, 1.0f,1.0f);        // Color Cyan
00128   glVertex3f( sz, -sz, -sz);
00129   glVertex3f( sz, -sz,  sz);
00130   glVertex3f( sz,  sz,  sz);
00131   glVertex3f( sz,  sz, -sz);
00132 
00133   glColor3f(0.0f, 1.0f, 0.0f);        // Color Green
00134   glVertex3f(-sz, -sz, -sz);
00135   glVertex3f(-sz, -sz,  sz);
00136   glVertex3f( sz, -sz,  sz);
00137   glVertex3f( sz, -sz, -sz);
00138 
00139   glColor3f(1.0f,0.0f,1.0f);        // Color Magenta
00140   glVertex3f(-sz,  sz, -sz);
00141   glVertex3f(-sz,  sz,  sz);
00142   glVertex3f( sz,  sz,  sz);
00143   glVertex3f( sz,  sz, -sz);
00144 
00145   glEnd();
00146 
00147   //  glPopMatrix();
00148 
00149   // swapping the buffers causes the rendering above to be shown
00150   glutSwapBuffers();
00151 }
00152 
00153 // ######################################################################
00154 void *display_thread_function(void *ptr)
00155 {
00156   //Initialize the GLUT runtime with some bogus command line args
00157   int argc = 1;
00158   char** argv = new char*[1];
00159   argv[0] = new char[4];
00160   glutInit(&argc, argv);
00161 
00162   // This is where we say that we want a double buffer
00163   glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
00164 
00165   glutInitWindowPosition(100,100);
00166   glutInitWindowSize(320,320);
00167   glutCreateWindow("IMU Visualization");
00168   glutDisplayFunc(renderScene);
00169 
00170   // here is the setting of the idle function
00171   glutIdleFunc(renderScene);
00172 
00173   //glutReshapeFunc(changeSize);
00174 
00175   // enable depth testing
00176   glEnable(GL_DEPTH_TEST);
00177   glutMainLoop();
00178   return NULL;
00179 }
00180 
00181 // ######################################################################
00182 IMU_MicroStrain_3DM_GX2::IMU_MicroStrain_3DM_GX2
00183 (OptionManager& mgr,
00184  const std::string& descrName,
00185  const std::string& tagName,
00186  const std::string& dev) :
00187   ModelComponent(mgr, descrName, tagName),
00188   itsSerial(new Serial(mgr))
00189 {
00190   addSubComponent(itsSerial);
00191   pthread_mutex_init(&itsResLock, NULL);
00192   pthread_mutex_init(&itsDataRequestedLock, NULL);
00193   itsRunDataUpdateThread = true;
00194   itsNewData = false;
00195 
00196   // Default Data requested is roll, pitch, yaw
00197   itsDataRequested = MAGNETOMETER;
00198   //itsDataRequested = ROLL_PITCH_YAW;
00199 }
00200 
00201 // ######################################################################
00202 void IMU_MicroStrain_3DM_GX2::configureSerial(std::string dev)
00203 {
00204   itsSerialDev = dev;
00205   itsSerial->configure(itsSerialDev.c_str(), 115200);
00206 }
00207 
00208 // ######################################################################
00209 void IMU_MicroStrain_3DM_GX2::start1()
00210 {
00211   // thread to update the IMU data
00212   pthread_create(&itsDataUpdateThread, NULL,
00213                  &IMU_MicroStrain_3DM_GX2_run, (void *) this);
00214 
00215   if(theIMU != NULL)
00216     {
00217       LINFO("Trying to create a duplicate IMU!!!");
00218       exit(-1);
00219     }
00220   theIMU = this;
00221 
00222   // thread to make OpenGL rendering
00223   pthread_create(&itsDataDisplayThread, NULL,
00224                  display_thread_function, NULL);
00225 
00226   itsRollPitchYawRecord.roll  = 0.0;
00227   itsRollPitchYawRecord.pitch = 0.0;
00228   itsRollPitchYawRecord.yaw   = 0.0;
00229 }
00230 
00231 // ######################################################################
00232 void IMU_MicroStrain_3DM_GX2::stop1()
00233 {
00234   itsRunDataUpdateThread = false;
00235   usleep(300000); // make sure thread has exited
00236 }
00237 
00238 // ######################################################################
00239 IMU_MicroStrain_3DM_GX2::~IMU_MicroStrain_3DM_GX2()
00240 {
00241   pthread_mutex_destroy(&itsResLock);
00242   pthread_mutex_destroy(&itsDataRequestedLock);
00243 }
00244 
00245 // ######################################################################
00246 bool IMU_MicroStrain_3DM_GX2::setDataRequested(DataRequested dataRequested)
00247 {
00248   // double check if it's a valid dataRequested
00249   switch(dataRequested)
00250     {
00251     case ACCEL_AND_ANG_RATE: break;
00252     case DELTA_ANG_AND_VEL:  break;
00253     case MAGNETOMETER:       break;
00254     case ORIENTATION_MATRIX: break;
00255     case ROLL_PITCH_YAW:     break;
00256     case TEMPERATURE:        break;
00257 
00258     default: LERROR("Unknown data requested: %d", dataRequested);
00259       return false;
00260     }
00261 
00262   pthread_mutex_lock(&itsDataRequestedLock);
00263   itsDataRequested = dataRequested;
00264   pthread_mutex_unlock(&itsDataRequestedLock);
00265 
00266   return true;
00267 }
00268 
00269 // ######################################################################
00270 DataRequested IMU_MicroStrain_3DM_GX2::getDataRequested()
00271 {
00272   pthread_mutex_lock(&itsDataRequestedLock);
00273   DataRequested dataRequested = itsDataRequested;
00274   pthread_mutex_unlock(&itsDataRequestedLock);
00275 
00276   return dataRequested;
00277 }
00278 
00279 // ######################################################################
00280 bool IMU_MicroStrain_3DM_GX2::newData()
00281 {
00282   bool ret;
00283   pthread_mutex_lock(&itsResLock);
00284   ret = itsNewData;
00285   pthread_mutex_unlock(&itsResLock);
00286   return ret;
00287 }
00288 
00289 // ######################################################################
00290 void IMU_MicroStrain_3DM_GX2::getAccelerationAndAngularRate()
00291 {
00292   // 0xC2 for acceleration and angular rate
00293   unsigned char cmd = char(0xC2);
00294   itsSerial->write(&cmd, 1);
00295 
00296   unsigned char buffer[256];
00297   itsSerial->read(&buffer,31);
00298 
00299   std::vector<unsigned char> response(buffer, buffer+31);
00300 
00301   //if(dwBytesRead != 31){ return SERIAL_READ_ERROR; }
00302   if(response[0] == 0xC2) LDEBUG("Angular ACC");
00303   else                    LINFO("NOT Angular ACC");
00304 
00305   pthread_mutex_lock(&itsResLock);
00306 
00307   // acceleration
00308   itsAccelAndAngRateRecord.accelX =
00309     binaryconversion::FloatFromBytes(&response[1], true); //bytes 1.. 4
00310   itsAccelAndAngRateRecord.accelY =
00311     binaryconversion::FloatFromBytes(&response[5], true); //bytes 5.. 8
00312   itsAccelAndAngRateRecord.accelZ =
00313     binaryconversion::FloatFromBytes(&response[9], true); //bytes 9..12
00314 
00315 
00316   // Angular Rate
00317   itsAccelAndAngRateRecord.angRateX =
00318     binaryconversion::FloatFromBytes(&response[13], true); //bytes 13.. 16
00319   itsAccelAndAngRateRecord.angRateY =
00320     binaryconversion::FloatFromBytes(&response[17], true); //bytes 17.. 20
00321   itsAccelAndAngRateRecord.angRateZ =
00322     binaryconversion::FloatFromBytes(&response[21], true); //bytes 21.. 24
00323 
00324   // Timer
00325   // record->timer = response[25, 26, 27, 28];
00326 
00327   //wChecksum = MAKEWORD(response[30], response[29]);
00328   //calculate the checkusm, 29 = 31-2 don't include the checksum bytes
00329   //wCalculatedCheckSum = Checksum(&response[0], 29);
00330   //if(wChecksum != wCalculatedCheckSum)  CHECKSUM_ERROR;
00331 
00332   itsNewData = true;
00333   pthread_mutex_unlock(&itsResLock);
00334 }
00335 
00336 // ######################################################################
00337 void IMU_MicroStrain_3DM_GX2::
00338 getAccelerationAndAngularRate(AccelAndAngRateRecord &record)
00339 {
00340   pthread_mutex_lock(&itsResLock);
00341 
00342   // acceleration
00343   record.accelX = itsAccelAndAngRateRecord.accelX;
00344   record.accelY = itsAccelAndAngRateRecord.accelY;
00345   record.accelZ = itsAccelAndAngRateRecord.accelZ;
00346 
00347   // Angular Rate
00348   record.angRateX = itsAccelAndAngRateRecord.angRateX;
00349   record.angRateY = itsAccelAndAngRateRecord.angRateY;
00350   record.angRateZ = itsAccelAndAngRateRecord.angRateZ;
00351 
00352   itsNewData = false;
00353   pthread_mutex_unlock(&itsResLock);
00354 }
00355 
00356 // ######################################################################
00357 void IMU_MicroStrain_3DM_GX2::getMagnetometer()
00358 {
00359   // 0xC7 for magnetometer direction and magnitude
00360   unsigned char cmd = char(0xC7);
00361   itsSerial->write(&cmd, 1);
00362 
00363   unsigned char buffer[256];
00364   itsSerial->read(&buffer,19);
00365 
00366   std::vector<unsigned char> response(buffer, buffer+31);
00367 
00368   if(response[0] == 0xC7) LDEBUG("Magnetometer");
00369   else                    LINFO("NOT Magnetometer");
00370 
00371   pthread_mutex_lock(&itsResLock);
00372 
00373   // magnetometer
00374   itsMagnetometerRecord.magX =
00375     binaryconversion::FloatFromBytes(&response[1], true); //bytes 1.. 4
00376   itsMagnetometerRecord.magY =
00377     binaryconversion::FloatFromBytes(&response[5], true); //bytes 5.. 8
00378   itsMagnetometerRecord.magZ =
00379     binaryconversion::FloatFromBytes(&response[9], true); //bytes 9..12
00380 
00381   itsNewData = true;
00382   pthread_mutex_unlock(&itsResLock);
00383 }
00384 
00385 // ######################################################################
00386 void IMU_MicroStrain_3DM_GX2::getMagnetometer(MagnetometerRecord &record)
00387 {
00388   pthread_mutex_lock(&itsResLock);
00389 
00390   record.magX = itsMagnetometerRecord.magX;
00391   record.magY = itsMagnetometerRecord.magY;
00392   record.magZ = itsMagnetometerRecord.magZ;
00393 
00394   itsNewData = false;
00395   pthread_mutex_unlock(&itsResLock);
00396 }
00397 
00398 // ######################################################################
00399 void IMU_MicroStrain_3DM_GX2::getRollPitchYaw()
00400 {
00401   // 0xCE for roll, pitch, yaw
00402   unsigned char cmd = char(0xCE);
00403   itsSerial->write(&cmd, 1);
00404 
00405   unsigned char buffer[256];
00406   itsSerial->read(&buffer,19);
00407 
00408   std::vector<unsigned char> response(buffer, buffer+31);
00409 
00410   if(response[0] == 0xCE) LDEBUG("Roll, pitch, yaw");
00411   else                    LINFO("NOT roll, pitch, yaw");
00412 
00413   pthread_mutex_lock(&itsResLock);
00414 
00415   // acceleration
00416   itsRollPitchYawRecord.roll  =
00417     binaryconversion::FloatFromBytes(&response[1], true); //bytes 1.. 4
00418   itsRollPitchYawRecord.pitch =
00419     binaryconversion::FloatFromBytes(&response[5], true); //bytes 5.. 8
00420   itsRollPitchYawRecord.yaw   =
00421     binaryconversion::FloatFromBytes(&response[9], true); //bytes 9..12
00422 
00423   itsNewData = true;
00424   pthread_mutex_unlock(&itsResLock);
00425 }
00426 
00427 // ######################################################################
00428 void IMU_MicroStrain_3DM_GX2::getRollPitchYaw(RollPitchYawRecord &record)
00429 {
00430   pthread_mutex_lock(&itsResLock);
00431 
00432   record.roll  = itsRollPitchYawRecord.roll;
00433   record.pitch = itsRollPitchYawRecord.pitch;
00434   record.yaw   = itsRollPitchYawRecord.yaw;
00435 
00436   itsNewData = false;
00437   pthread_mutex_unlock(&itsResLock);
00438 }
00439 
00440 // ######################################################################
00441 void IMU_MicroStrain_3DM_GX2::run()
00442 {
00443   Timer t(1000000);
00444   t.reset();
00445 
00446   while(itsRunDataUpdateThread)
00447     {
00448 //       do {
00449 //       } while ((checksum & 0x0000FFFF)); // exit iff checksum correct
00450 
00451       // if continuous mode is also set
00452       // then we have to read those data first before processing
00453       // polling mode data
00454 
00455       pthread_mutex_lock(&itsDataRequestedLock);
00456       DataRequested dr = itsDataRequested;
00457       pthread_mutex_unlock(&itsDataRequestedLock);
00458 
00459       // data requested for polling mode
00460       switch(dr)
00461         {
00462         case ACCEL_AND_ANG_RATE:
00463           getAccelerationAndAngularRate();
00464           break;
00465 
00466         case DELTA_ANG_AND_VEL:
00467           // FIX: getDeltaAngleAndVelocity();
00468           break;
00469 
00470         case MAGNETOMETER:
00471           getMagnetometer();
00472           break;
00473 
00474         case ORIENTATION_MATRIX:
00475           // FIX: getOrientationMatrix();
00476           break;
00477 
00478         case ROLL_PITCH_YAW:
00479           getRollPitchYaw();
00480           break;
00481 
00482         case TEMPERATURE:
00483           // FIX: getTemperature();
00484           break;
00485 
00486         default: LERROR("Unknown data requested: %d",
00487                         itsDataRequested);
00488         }
00489 
00490       usleep(1000);
00491       LDEBUG("time %11.5f", t.get()/1000.0F);
00492       t.reset();
00493     }
00494 
00495   pthread_exit(0);
00496 }
00497 
00498 // ######################################################################
00499 /* So things look consistent in everyone's emacs... */
00500 /* Local Variables: */
00501 /* indent-tabs-mode: nil */
00502 /* End: */
Generated on Sun May 8 08:40:37 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3