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: */