bma180s.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Robert Bosch LLC
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of Robert Bosch LLC nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 /*********************************************************************
00031  *
00032  * Disclaimer
00033  *
00034  * This source code is not officially released or supported by Bosch Sensortec.
00035  * Please contact the listed authors with bugs or other modifications.
00036  * If you would like the official Bosch Sensortec drivers, please contact:
00037  * contact@bosch-sensortec.com
00038  *
00039  *********************************************************************/
00040 
00041 
00042 /*
00043  * bma180.cpp
00044  *
00045  *  Created on: Jul 26, 2011
00046  *      Author: Lucas Marti, Nikhil Deshpande, Philip Roan, Robert Bosch LLC
00047  */
00048 #include <iostream>
00049 #include <string>
00050 #include <ros/ros.h>
00051 #include "bma180/bma180s.h"
00052 #include <sstream>
00053 #include <ros/time.h>
00054 #include <math.h>
00055 #include <vector>
00056 
00057 #define ROS_INFO printf
00058 #define ROS_WARN printf
00059 #define ROS_ERROR printf
00060 
00061 Bma180::Bma180( double max_acceleration_g, double dBandwidth_Hz, bool bCalibrate, double dRate_Hz, std::string sSub20Serial ):
00062   bSubDeviceOpen       (false),
00063   bSubDeviceConfigured (false)
00064 {
00065   int               error_code; // Sub20 error code
00066   int               iSPI_cfg_set; //Set SPI config
00067   int               iSPI_cfg_get; //Get SPI config
00068   int               iNumOfRanges;
00069   int               iElCount;
00070   std::stringstream ss_errmsg;
00071   std::string       ss_config, sub20Serial;
00072   sub_device        sub20dev;
00073   sub_handle        sub20handle;
00074   OneSub20Config    OneSub20Configuration;
00075 
00076   printf("Max acceleration entered: %f [g].\n", max_acceleration_g);
00077   printf("Sensor bandwidth entered: %f [Hz].\n", dBandwidth_Hz);
00078   printf("Sensor Reading Rate entered: %f [Hz].\n", dRate_Hz);
00079 
00080   //Retrieve calibration data from user
00081   set_calibstatus( bCalibrate );
00082 
00083   // Evaluate the accelerometer range  to be selected
00084   iNumOfRanges = sizeof(bma180_cmd::COMMAND_FULLSCALE_G) / sizeof(char);
00085   iElCount = 0;
00086   while( (max_acceleration_g > bma180_cmd::dFULLRANGELOOKUP[iElCount]) && (iElCount < iNumOfRanges) )
00087   {
00088     iElCount++;
00089   };
00090   printf("Range chosen: %f [g].\n", bma180_cmd::dFULLRANGELOOKUP[iElCount]);
00091 
00092   chMaxAccRange_selected = bma180_cmd::COMMAND_FULLSCALE_G[iElCount];
00093   
00094   // Evaluate the bandwidth to be selected
00095   iNumOfRanges = sizeof(bma180_cmd::COMMAND_BANDWIDTH_HZ) / sizeof(char);
00096   iElCount = 0;
00097   while( (dBandwidth_Hz > bma180_cmd::dBWLOOKUP[iElCount]) && (iElCount < iNumOfRanges) )
00098   {
00099     iElCount++;
00100   };
00101   printf("Range chosen BW: %f.\n", bma180_cmd::dBWLOOKUP[iElCount]);
00102 
00103   chBW_selected = bma180_cmd::COMMAND_BANDWIDTH_HZ[iElCount];
00104 
00105   // Open connected Sub20 Devices
00106   sub20dev = 0;
00107   sub20dev = sub_find_devices(sub20dev);
00108   while( sub20dev != 0 )
00109   {
00110     sub20handle = sub_open( sub20dev );
00111     // on success, sub_open returns non-zero handle
00112     if( sub20handle > 0 )
00113     {
00114       sub20Serial.clear();
00115       sub20Serial.resize( bma180_cmd::uSERIALNUMLENGTH );
00116       sub_get_serial_number( sub20handle, const_cast<char*>(sub20Serial.c_str()), sub20Serial.size() );
00117       printf( "Serial Number: %s.\n", sub20Serial.c_str() );
00118       if( strcmp(sub20Serial.c_str(), sSub20Serial.c_str()) == 0 )
00119       {
00120         subhndl = sub20handle;
00121 
00122         // Configure Sub20 device
00123         std::cout << "---Initializing SPI Interface---" << std::endl;;
00124         // Read current SPI configuration
00125         error_code = sub_spi_config( sub20handle, 0, &iSPI_cfg_get );
00126         std::cout << "Sub SPI config  : " << iSPI_cfg_get << std::endl;
00127         
00128         // Important: The SPI interface does not work properly at higher frequencies, i.e. > 2MHz
00129         // SET: Polarity Fall, SetupSmpl,  MSB first, 2MHZ
00130         iSPI_cfg_set = SPI_ENABLE | SPI_CPOL_FALL | SPI_SETUP_SMPL | SPI_MSB_FIRST | SPI_CLK_2MHZ;
00131         // Configure SPI
00132         error_code = sub_spi_config( sub20handle, iSPI_cfg_set, 0 );
00133         // Read current SPI configuration
00134         error_code = sub_spi_config( sub20handle, 0, &iSPI_cfg_get );
00135         // verify if sub20 device has accepted the configuration
00136         if( iSPI_cfg_get == iSPI_cfg_set )
00137         {
00138           std::cout<< "SPI Configuration: " << iSPI_cfg_set << " successfully stored." << std::endl;
00139 
00140           // Subdevice has been configured successfully
00141           OneSub20Configuration.bSubSPIConfigured = true;
00142           OneSub20Configuration.handle_subdev     = sub20handle;
00143 
00144           // Configure Sensors on Sub20
00145           confsens_on_sub20( &OneSub20Configuration, chMaxAccRange_selected, chBW_selected);
00146         }
00147         else
00148         {
00149           ROS_INFO("ERROR! SPI Configuration %d not accepted by device.\n", iSPI_cfg_set);
00150 
00151           // Subdevice could not be configured
00152           OneSub20Configuration.bSubSPIConfigured = false;
00153         }
00154         if( OneSub20Configuration.bSubSPIConfigured )
00155         {
00156           // string needs to be cleared otherwise conversion is going wrong
00157           serial_number.clear();
00158           serial_number.resize( bma180_cmd::uSERIALNUMLENGTH );
00159           sub_get_serial_number( sub20handle, const_cast<char*>(serial_number.c_str()), serial_number.size() );
00160           OneSub20Configuration.strSub20Serial = serial_number;
00161           OneSub20Configuration.subdev = sub20dev;
00162           std::cout << "Device Handle: " << OneSub20Configuration.handle_subdev << std::endl;
00163           std::cout << "Serial Number: " << OneSub20Configuration.strSub20Serial << std::endl;
00164 
00165           // Push element onto list of subdevices
00166           Sub20Device_list.push_back( OneSub20Configuration );
00167           std::cout << "Publishing to topic /bma180." << std::endl;
00168         }
00169         break;
00170       }
00171       else
00172       {
00173         sub_close( sub20handle );
00174       }
00175     }
00176     // find next device, sub_find_devices using current provides next
00177     sub20dev = sub_find_devices( sub20dev );
00178   }
00179 };
00180 
00181 Bma180::~Bma180()
00182 {
00183   int error_code;
00184   OneSub20Config OneSub20Configuration;
00185 
00186   // close opened subdevices
00187 
00188   // Disable SPI
00189   error_code = sub_spi_config( subhndl, 0, 0 );
00190 
00191   // Close USB device
00192   sub_close( subhndl );
00193   while( !Sub20Device_list.empty() )
00194   {
00195     OneSub20Configuration = Sub20Device_list.back();
00196     std::cout << "Sub device removed " << OneSub20Configuration.strSub20Serial << std::endl;
00197     Sub20Device_list.pop_back();
00198   }
00199 };
00200 
00201 void Bma180::GetMeasurements( std::list<OneBma180Meas> &list_meas )
00202 {
00203   char              chACC_XYZ[7]; //Containing
00204   double            dAccX, dAccY, dAccZ;
00205   double            dEstBiasX, dEstBiasY, dEstBiasZ;
00206   int               uiBcorrX, uiBcorrY, uiBcorrZ, uiRawX, uiRawY, uiRawZ;
00207   double            dTemp;
00208   int               error_code, dummy, j = 0;
00209   bool              SPIMeas = false;
00210   OneBma180Meas     sMeas;
00211   //ros::Time         dtomeas;
00212   char              chCMD;
00213   std::stringstream ss_errmsg;
00214   int               chip_select;
00215   std::list<OneSub20Config>::iterator iterat;
00216   
00217   // verify that a subdevice is connected
00218   if( 1 > (int)Sub20Device_list.size() )
00219   {
00220     throw std::string( "No SubDevice connected OR access rights to USB not given" );
00221   }
00222 
00223   // Trace sub20 list
00224   for( iterat = Sub20Device_list.begin(); iterat != Sub20Device_list.end(); iterat++ )
00225   {
00226     // verify if the sub20 device is configured (which should be the case as only configured sub20ies are pushed on list)
00227     if( iterat->bSubSPIConfigured == true)
00228     {
00229       // Trace through cluster
00230       for( chip_select = 0; chip_select < bma180_cmd::MAX_NUM_SENSORS; chip_select++ )
00231       {
00232       // verify if sensor is available on respective chipselect
00233         if( iterat->Bma180Cluster[chip_select].bConfigured == true )
00234         {
00235           error_code = 0;
00236           // NOTE: Not executed in order to save one SPI transfer
00237           // //ensure CS is high
00238           // //error_code = sub_spi_transfer( iterat->handle_subdev, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00239           // //send read command
00240           chCMD = bma180_cmd::ADDRESS_ACCLXYZ | bma180_cmd::FLAG_R;
00241           error_code += sub_spi_transfer( iterat->handle_subdev, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00242           error_code += sub_spi_transfer( iterat->handle_subdev, 0, chACC_XYZ, 7, SS_CONF(chip_select,SS_L) );
00243           // ensure CS is high
00244           error_code += sub_spi_transfer( iterat->handle_subdev, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00245 
00246           if( error_code == 0 )
00247           {
00248             SPIMeas = true;
00249             dAccX = bma180data_to_double(chACC_XYZ[1], chACC_XYZ[0], bma180_cmd::eACCEL, &uiRawX, iterat->Bma180Cluster[chip_select].dFullScaleRange );
00250             dAccY = bma180data_to_double(chACC_XYZ[3], chACC_XYZ[2], bma180_cmd::eACCEL, &uiRawY, iterat->Bma180Cluster[chip_select].dFullScaleRange );
00251             dAccZ = bma180data_to_double(chACC_XYZ[5], chACC_XYZ[4], bma180_cmd::eACCEL, &uiRawZ, iterat->Bma180Cluster[chip_select].dFullScaleRange );
00252             dTemp = bma180data_to_double(chACC_XYZ[6], chACC_XYZ[6], bma180_cmd::eTEMP,  &dummy, iterat->Bma180Cluster[chip_select].dFullScaleRange );
00253 
00254             // Collect data for all chipSelects
00255             sMeas.dAccX[j] = dAccX;
00256             sMeas.dAccY[j] = dAccY;
00257             sMeas.dAccZ[j] = dAccZ;
00258             sMeas.dTemp    = dTemp;
00259             sMeas.chip_select[j] = chip_select;
00260             j++;
00261             sMeas.iNumAccels = j;
00262 
00263             // Execute calibration if desired
00264             // Note: For calibration procedure, only one XDIMAX box is allowed to be connected
00265             if( bExecuteCalibration == true && 2 > (int)Sub20Device_list.size() )  
00266             {
00267               if( chip_select == iCalib_CS ) 
00268               {
00269                 if( calib_bma180.calibsens_completed() == false && calib_bma180.calibsens_set() == false )
00270                 {
00271                   std::cout << " Bias read from image: " << iterat->Bma180Cluster[chip_select].uiBiasImageX << " " << iterat->Bma180Cluster[chip_select].uiBiasImageY << " " << iterat->Bma180Cluster[chip_select].uiBiasImageZ << std::endl;
00272                   // set the sensor to be calibrated
00273                   calib_bma180.setcalibsens( sMeas );
00274                 }
00275                 else
00276                 {
00277                   calib_bma180.setdata_bma180( sMeas );
00278                 }
00279                 if( calib_bma180.calibsens_completed() && !calib_bma180.verification_active() )
00280                 {
00281                   // Get estimated sensor biases
00282 
00283                   calib_bma180.get_estbiases(&dEstBiasX, &dEstBiasY, &dEstBiasZ);
00284                   std::cout << "estimated biases : " << dEstBiasX << " " << dEstBiasY << " " << dEstBiasZ << std::endl;
00285 
00286                   // calculate adjustment
00287                   // +0.5 for typecast to get propper rounding
00288                   // 2048: Bias has 12 bit, thus halfrange is 2^11 where as bias corr scales by range
00289                   int iBcorrX, iBcorrY, iBcorrZ;
00290                   iBcorrX = (short)( dEstBiasX / iterat->Bma180Cluster[chip_select].dFullScaleRange * 2048 + 0.5 );
00291                   iBcorrY = (short)( dEstBiasY / iterat->Bma180Cluster[chip_select].dFullScaleRange * 2048 + 0.5 ) ;
00292                   iBcorrZ = (short)( (dEstBiasZ - 1) / iterat->Bma180Cluster[chip_select].dFullScaleRange * 2048 + 0.5 ) ;
00293                   
00294                   std::cout << "Bias adjustments [X Y Z] " << iBcorrX << " " << iBcorrY << " " << iBcorrZ << std::endl;
00295                   std::cout << "Image values before adjustments " << iterat->Bma180Cluster[chip_select].uiBiasImageX << " " << iterat->Bma180Cluster[chip_select].uiBiasImageY << " " << iterat->Bma180Cluster[chip_select].uiBiasImageZ << std::endl;
00296                   uiBcorrX = (unsigned short)( iterat->Bma180Cluster[chip_select].uiBiasImageX - ((short)( dEstBiasX / bma180_cmd::dFULLRANGELOOKUP[6] * 2048 )) );
00297                   uiBcorrY = (unsigned short)( iterat->Bma180Cluster[chip_select].uiBiasImageY - ((short)( dEstBiasY / bma180_cmd::dFULLRANGELOOKUP[6] * 2048 )) );
00298                   uiBcorrZ = (unsigned short)( iterat->Bma180Cluster[chip_select].uiBiasImageZ - ((short)( (dEstBiasZ - 1) / bma180_cmd::dFULLRANGELOOKUP[6] * 2048 )) );
00299 
00300                   std::cout << "corrected biases " << uiBcorrX << " " << uiBcorrY << " " << uiBcorrZ << std::endl;
00301 
00302                   // Write to image
00303                   if( !set_biassettings( iterat->handle_subdev, chip_select, uiBcorrX, uiBcorrY, uiBcorrZ, false) )
00304                   {
00305                     bExecuteCalibration = false;
00306                     throw std::string( "Bias corrections cannot be written to image. Calibration procedure aborted." );
00307                   }
00308 
00309                   // Activate verification
00310                   if( !calib_bma180.biasverify() )
00311                   {
00312                     bExecuteCalibration = false;
00313                     throw std::string( "Bias verification cannot be executed. Calibration procedure aborted." );
00314                   }
00315                 }
00316 
00317                 if( calib_bma180.calibsens_completed() && calib_bma180.verification_active() && calib_bma180.verification_completed() )
00318                 {
00319                   std::cout << "Verifying biases..." << std::endl;
00320 
00321                   // Get verified biases after image write
00322                   if( !calib_bma180.get_verifiedbiases( &dEstBiasX, &dEstBiasY, &dEstBiasZ ) )
00323                   {
00324                     bExecuteCalibration = false;
00325                     throw std::string( "Verified biases cannot be retrieved. Calibration procedure aborted." );
00326                   };
00327 
00328                   if( bma180_cmd::dCALIB_ACCURACY > fabs(dEstBiasX) && bma180_cmd::dCALIB_ACCURACY > fabs(dEstBiasY) && bma180_cmd::dCALIB_ACCURACY > fabs( dEstBiasZ - 1 ) )
00329                   {
00330                     // Writing EEPROM
00331                     uiBcorrX = 0;
00332                     uiBcorrY = 0;
00333                     uiBcorrZ = 0;
00334                     std::string myAnswer;
00335                     std::cin.ignore();
00336                     std::cout << "Really write EEPROM <Y/N>? ";
00337                     std::getline( std::cin, myAnswer );
00338                     if( 0 == myAnswer.find('Y') || 0 == myAnswer.find('y') )
00339                     {
00340                       if( !set_biassettings( iterat->handle_subdev, chip_select, uiBcorrX, uiBcorrY, uiBcorrZ, true ) )
00341                       {
00342                         bExecuteCalibration = false;
00343                         throw std::string( "Biases cannot be written into EEPROM. Calibration procedure aborted.");
00344                       };
00345                       ROS_INFO("EEPROM has been written.\n");
00346 
00347                     }
00348                     else
00349                     {
00350                       ROS_INFO("EEPROM write aborted.\n");
00351                     }
00352                   }
00353                   else
00354                   {
00355                     std::cout << "Error values " << fabs(dEstBiasX) << " " << fabs(dEstBiasY) << " " << fabs(dEstBiasZ-1) << std::endl;
00356                     bExecuteCalibration = false;
00357                     throw std::string( "Bias verification failed because the calibration values are too large. Calibration procedure aborted.");
00358                   }
00359                   // We are done with calibration
00360                   bExecuteCalibration = false;
00361                   std::cout << "Calibration completed successfully." << std::endl;
00362                 }
00363               }
00364             }
00365             else
00366             {
00367               if( bExecuteCalibration == true && 1 < (int)Sub20Device_list.size() )
00368               {
00369                 throw std::string( "As a pre-caution, please connect only one Sub20 device during calibration.");
00370               }
00371             }
00372           }
00373           else
00374           {
00375             throw std::string( "There has been an SPI communication error. Continuing attempts to communicate with the device will be made." );
00376           }
00377         } // config verify
00378       } // scanning through all the chipselects
00379     }
00380 
00381     // Only publish data after all data for all chipSelects is collected
00382     if( SPIMeas )
00383     {
00384       //sMeas.dtomeas = ros::Time::now();
00385       sMeas.bMeasAvailable = true;
00386       sMeas.serial_number = iterat->strSub20Serial;
00387       
00388       // Push measurement onto heap
00389       list_meas.push_back( sMeas );
00390     }
00391     else
00392     {
00393       throw std::string( "SUB20 connected but not configured. A restart of the ROS node is suggested.");
00394     }
00395   } // sub20 for loop
00396 };
00397 
00398 double Bma180::bma180data_to_double( char chMSB, char chLSB, bma180_cmd::eSensorType eSensor, int *raw, double dAccScale )
00399 {
00400   short s16int;       // 2 byte int to build message
00401   double dSensorMeas; // Scaled sensor measurement
00402 
00403   switch( eSensor )
00404   {
00405     // Retrieve Accel Data
00406     case bma180_cmd::eACCEL:
00407       // verify if pos or neg
00408       if( (chMSB & 0x80) == 0 )
00409       {
00410         // positive number
00411         s16int = (short)( (((unsigned short)chMSB) & 0xFF) << 6) + ((((unsigned short)chLSB) & 0xFC) >> 2 );
00412       }
00413       else
00414       {
00415         // negative number
00416         // set MSB (sign) to zero and build 2 complement unsigned; offset 8192 for 2^13
00417         s16int = (short)( ((((unsigned short)chMSB) & 0x7F ) << 6 ) + ((((unsigned short)chLSB) & 0xFC) >> 2 ) - 8192 );
00418       }
00419       dSensorMeas = ( ((double)s16int) / 8192 ) * dAccScale;
00420       break;
00421 
00422       // Convert Temperature Data
00423   case bma180_cmd::eTEMP:
00424     // verify if pos or neg
00425     if( (chLSB & 0x80) == 0 )
00426     {
00427       // positive number
00428       s16int = (short)( ((unsigned short)chLSB) & 0xFF );
00429     }
00430     else
00431     {
00432       // negative number
00433       // set MSB (sign) to zero and build 2 complement unsigned; offset 128 for 2^7
00434       s16int = (short)( (((unsigned short)chLSB) & 0x7F ) - 128 );
00435     };
00436     dSensorMeas = ( ( (double)s16int) / 8192 ) * 2;
00437     break;
00438 
00439   default :
00440     dSensorMeas = 0;
00441   }
00442   *raw = s16int;
00443   return (dSensorMeas);
00444 };
00445 
00446 unsigned short Bma180::bma180data_to_uint( char chMSB, char chLSB, bma180_cmd::eSensorType eSensor )
00447 {
00448   unsigned short u16int_bias; // 2 byte int to build message
00449   switch( eSensor )
00450   {
00451   // Bias X axis data
00452   case bma180_cmd::eBIAS_X:
00453     u16int_bias = (short) ((((unsigned short)chMSB)&0xFF)<<4)+((((unsigned short)chLSB)&0xF0)>>4);
00454     break;
00455 
00456   // Bias Y axis data
00457   case bma180_cmd::eBIAS_Y:
00458     u16int_bias = (short) ((((unsigned short)chMSB)&0xFF)<<4)+((((unsigned short)chLSB)&0x0F));
00459     break;
00460 
00461   // Bias Z axis data
00462   case bma180_cmd::eBIAS_Z:
00463     u16int_bias = (short) ((((unsigned short)chMSB)&0xFF)<<4)+((((unsigned short)chLSB)&0xF0)>>4);
00464     break;
00465   default :
00466     u16int_bias = 0;
00467   }
00468   return (u16int_bias);
00469 };
00470 
00471 bool Bma180::read_byte_eeprom_sub20( char chADR, char* pchREGISTER, unsigned short chip_select, sub_handle sub_h )
00472 {
00473   int     error_code = 0;
00474   bool    bSuccess;
00475   char    chCMD;
00476 
00477   // Read register at specified adderss chADR
00478 
00479   // ensure CS is high
00480   error_code += sub_spi_transfer( sub_h, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00481   // send read command
00482   chCMD         = chADR | bma180_cmd::FLAG_R;
00483   error_code += sub_spi_transfer( sub_h, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00484   error_code += sub_spi_transfer( sub_h, 0, pchREGISTER, 1, SS_CONF(chip_select,SS_L) );
00485   // ensure CS is high
00486   error_code += sub_spi_transfer( sub_h, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00487 
00488   if (error_code == 0)
00489   {
00490     // successful operation
00491     bSuccess = true;
00492   }
00493   else
00494   {
00495     // SPI error
00496     bSuccess = false;
00497   }
00498   return (bSuccess);
00499 };
00500 
00501 bool Bma180::write_bit_eeprom_sub20( char chADR, unsigned short iLSBOfByte, unsigned short iNumOfBits, char chBitSeq, unsigned short chip_select, sub_handle sub_h )
00502 {
00503   char chCMD;      // temporary character for building commands
00504   char chREGISTER; // temporary read status of register
00505   char chREGISTER_MODIFIED;
00506   int  error_code;
00507   char chMask;
00508   bool bSuccess;
00509   bool bEEReadSuccess;
00510 
00511   // only one byte will be handled, thus iLSBOfByte + iNumOfBits > 8 means out of range
00512   if ( iLSBOfByte + iNumOfBits <= 8 )
00513   {
00514     error_code = 0;
00515     bEEReadSuccess = true;
00516  
00517     // Read register at specified address chADR
00518     chCMD = chADR | bma180_cmd::FLAG_R;
00519     bEEReadSuccess &= read_byte_eeprom_sub20(chCMD, &chREGISTER, chip_select, sub_h );
00520 
00521     // Write the specified bit into register
00522     // Build mask, i.e. zero pad the respective points where we need to have
00523     if ( iNumOfBits < 8 )
00524     {
00525       chMask = ~( ((1 << iNumOfBits) - 1) << iLSBOfByte );
00526     }
00527     else
00528     {
00529       // as function of the range check above, it can only be 8
00530       chMask = 0x00;
00531     }
00532     // write specific register
00533     chREGISTER_MODIFIED = ( chREGISTER & chMask ) | ( chBitSeq << iLSBOfByte );
00534     // build up command to be written to register (note read flag is not set
00535     chCMD  = chADR;
00536     error_code += sub_spi_transfer( sub_h, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00537     error_code += sub_spi_transfer( sub_h, &chREGISTER_MODIFIED, 0, 1, SS_CONF(chip_select,SS_L) );
00538     // ensure CS is high
00539     error_code += sub_spi_transfer( sub_h, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00540 
00541     // Check if register has been set (only verification)
00542 
00543     // send read command
00544     chCMD = chADR | bma180_cmd::FLAG_R;
00545     bEEReadSuccess &= read_byte_eeprom_sub20(chCMD, &chREGISTER, chip_select, sub_h);
00546 
00547     if( (error_code == 0) && (bEEReadSuccess) )
00548     {
00549       bSuccess = true;
00550     }
00551     else
00552     {
00553       // SPI communication error
00554       bSuccess = false;
00555     }
00556   }
00557   else
00558   {
00559     // out of range
00560     bSuccess = false;
00561   }
00562   return bSuccess;
00563 };
00564 
00565 void Bma180::confsens_on_sub20( OneSub20Config *pOneSub20Conf, char chFullscale, char chBandwidth )
00566  {
00567   int               error_code;
00568   int               chip_select;
00569   bool              bSuccess;
00570   char              chCHIP_ID;
00571   char              chALML_VER;
00572   char              chCMD;
00573   char              chREGSTATUS;
00574   unsigned short    uiBiasX;
00575   unsigned short    uiBiasY;
00576   unsigned short    uiBiasZ;
00577   std::stringstream ss_errmsg;
00578   sub_handle        handle_sub20;
00579   bool              bEE_RWsuccess;
00580 
00581   // retrieve handle for sub20 device
00582   handle_sub20 = pOneSub20Conf->handle_subdev;
00583   for( chip_select = 0; chip_select < bma180_cmd::MAX_NUM_SENSORS; chip_select++ )
00584   {
00585     pOneSub20Conf->Bma180Cluster[chip_select].iNumOfCalibMeas = 0;
00586     error_code = 0;
00587     bEE_RWsuccess = true;
00588     // ensure CS is high
00589     error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00590     // send read command
00591     chCMD = bma180_cmd::ADDRESS_VER | bma180_cmd::FLAG_R;
00592     error_code += sub_spi_transfer( handle_sub20, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00593     error_code += sub_spi_transfer( handle_sub20, 0, &chCHIP_ID, 1, SS_CONF(chip_select,SS_L) );
00594     error_code += sub_spi_transfer( handle_sub20, 0, &chALML_VER, 1, SS_CONF(chip_select,SS_L) );
00595     // ensure CS is high
00596     error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00597 
00598     // Verify if a BMA180 is connected on the respective ChipSelect
00599     if( error_code == 0 && 0 < (unsigned short)chCHIP_ID && 0 < (unsigned short)chALML_VER )
00600     {
00601       ROS_INFO("BMA 180 - Chip Select %d\n", chip_select);
00602       ROS_INFO("CHIP ID: %u\n", (unsigned short)chCHIP_ID);
00603       ROS_INFO("ALML Ver: %u\n", (unsigned short)chALML_VER);
00604 
00605       // call method to set ee_write flag
00606       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_CTRLREG0, 4, 1, bma180_cmd::COMMAND_SET_EEW, chip_select, handle_sub20 );
00607       // issue soft reset
00608       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_SOFTRESET, 0, 8, bma180_cmd::COMMAND_SOFTRESET, chip_select, handle_sub20 );
00609       // call method to set ee_write flag
00610       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_CTRLREG0, 4, 1, bma180_cmd::COMMAND_SET_EEW, chip_select, handle_sub20 );
00611       // change maxrange of sensor
00612       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_RANGE, 1, 3, chFullscale, chip_select, handle_sub20 );
00613       bEE_RWsuccess &= read_byte_eeprom_sub20( bma180_cmd::ADDRESS_RANGE, &chREGSTATUS, chip_select, handle_sub20 );
00614       // Extract range
00615       pOneSub20Conf->Bma180Cluster[chip_select].dFullScaleRange = bma180_cmd::dFULLRANGELOOKUP[((unsigned short)((chREGSTATUS & 0x0E)>>1))];
00616       // change sensor bandwidth
00617       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_BWTCS, 4, 4, chBandwidth, chip_select, handle_sub20 );
00618       bEE_RWsuccess &= read_byte_eeprom_sub20( bma180_cmd::ADDRESS_BWTCS, &chREGSTATUS, chip_select, handle_sub20 );
00619       // Extract range
00620       pOneSub20Conf->Bma180Cluster[chip_select].dSensorBandwidth = bma180_cmd::dBWLOOKUP[((unsigned short)((chREGSTATUS & 0xF0)>>4))];
00621       ROS_INFO("EEPROM stored Fullrange: %f [g]\n", pOneSub20Conf->Bma180Cluster[chip_select].dFullScaleRange);
00622       ROS_INFO("EEPROM stored Bandwidth: %f [Hz]\n", pOneSub20Conf->Bma180Cluster[chip_select].dSensorBandwidth);
00623 
00624       // Read bias that are currently stored in image
00625       bEE_RWsuccess &= read_biassettings( handle_sub20, chip_select, &uiBiasX, &uiBiasY, &uiBiasZ );
00626       pOneSub20Conf->Bma180Cluster[chip_select].uiBiasImageX = uiBiasX;
00627       pOneSub20Conf->Bma180Cluster[chip_select].uiBiasImageY = uiBiasY;
00628       pOneSub20Conf->Bma180Cluster[chip_select].uiBiasImageZ = uiBiasZ;
00629 
00630       if( bEE_RWsuccess )
00631       {
00632         // Set flag that sensor has been initialized
00633         pOneSub20Conf->Bma180Cluster[chip_select].bConfigured = true;
00634         // successful operation
00635         bSuccess = true;
00636       }
00637       else
00638       {
00639         // Set flag that sensor has been initialized
00640         pOneSub20Conf->Bma180Cluster[chip_select].bConfigured = false;
00641         // unsuccessful operation
00642         bSuccess = false;
00643       }
00644     }
00645     else
00646     {
00647       ROS_INFO("BMA 180 %d: No sensor detected\n", chip_select);
00648 
00649       // Set flag that sensor hasn't been initialized
00650       pOneSub20Conf->Bma180Cluster[chip_select].bConfigured = false;
00651       pOneSub20Conf->Bma180Cluster[chip_select].dFullScaleRange = 0;
00652       pOneSub20Conf->Bma180Cluster[chip_select].dSensorBandwidth = 0;
00653       pOneSub20Conf->Bma180Cluster[chip_select].uiBiasImageX = 0;
00654       pOneSub20Conf->Bma180Cluster[chip_select].uiBiasImageY = 0;
00655       pOneSub20Conf->Bma180Cluster[chip_select].uiBiasImageZ = 0;
00656       // unsuccessful operation
00657       bSuccess = false;
00658     }
00659   }
00660 };
00661 
00662 bool Bma180::read_biassettings( sub_handle handle_sub20, int chip_select, unsigned short* uiBiasX, unsigned short* uiBiasY, unsigned short* uiBiasZ )
00663 {
00664   int  error_code;
00665   char chBiasXYZT[6];
00666   bool bSuccess;
00667   char chCMD;
00668   char chCHIP_ID;
00669   char chALML_VER;
00670 
00671   // Ensure BMA180 is connected
00672 
00673   // ensure CS is high
00674   error_code = 0;
00675   error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00676   // send read command
00677   chCMD   = bma180_cmd::ADDRESS_VER|bma180_cmd::FLAG_R;
00678   error_code += sub_spi_transfer( handle_sub20, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00679   error_code += sub_spi_transfer( handle_sub20, 0, &chCHIP_ID, 1, SS_CONF(chip_select,SS_L) );
00680   error_code += sub_spi_transfer( handle_sub20, 0, &chALML_VER, 1, SS_CONF(chip_select,SS_L) );
00681   // ensure CS is high
00682   error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00683 
00684   // Verify if a BMA180 is connected on the respective chip select line
00685   if( (error_code == 0) && ( 0 < (unsigned short)chCHIP_ID) && ( 0 < (unsigned short)chALML_VER) ) 
00686   {
00687     // ensure CS is high
00688     // NOTE: Not executed in order to save one SPI transfer
00689     //error_code = sub_spi_transfer( iterat->handle_subdev, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00690     // send read command
00691     chCMD = bma180_cmd::ADDRESS_OFFSET_LSB1 | bma180_cmd::FLAG_R;
00692     error_code += sub_spi_transfer( handle_sub20, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00693     error_code += sub_spi_transfer( handle_sub20, 0, chBiasXYZT, 6, SS_CONF(chip_select,SS_L) );
00694     // ensure CS is high
00695     error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00696 
00697     if( error_code == 0 )
00698     {
00699       (*uiBiasX) = bma180data_to_uint( chBiasXYZT[3], chBiasXYZT[0], bma180_cmd::eBIAS_X );
00700       (*uiBiasY) = bma180data_to_uint( chBiasXYZT[4], chBiasXYZT[1], bma180_cmd::eBIAS_Y );
00701       (*uiBiasZ) = bma180data_to_uint( chBiasXYZT[5], chBiasXYZT[1], bma180_cmd::eBIAS_Z );
00702       bSuccess = true;
00703     }
00704     else
00705     {
00706       (*uiBiasX) = 0;
00707       (*uiBiasY) = 0;
00708       (*uiBiasZ) = 0;
00709       bSuccess = false;
00710     }
00711   }
00712   else
00713   {
00714     (*uiBiasX) = 0;
00715     (*uiBiasY) = 0;
00716     (*uiBiasZ) = 0;
00717     bSuccess = false;
00718   }
00719   return bSuccess;
00720 };
00721 
00722 bool Bma180::set_biassettings( sub_handle handle_sub20, int chip_select, unsigned short uiBiasX, unsigned short uiBiasY, unsigned short uiBiasZ, bool bWriteEEPROM )
00723 {
00724   int  error_code;              //Error code for Sub20 API
00725   bool bSuccess;
00726   char chCMD;
00727   char chCHIP_ID;
00728   char chALML_VER;
00729   char chMSB;
00730   char chLSB;
00731   bool bEE_RWsuccess;
00732 
00733   // Ensure BMA180 is connected
00734 
00735   // ensure CS is high
00736   error_code = 0;
00737   bEE_RWsuccess = true;
00738   error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00739   
00740   // send read command
00741   chCMD = bma180_cmd::ADDRESS_VER | bma180_cmd::FLAG_R;
00742   error_code += sub_spi_transfer( handle_sub20, &chCMD, 0, 1, SS_CONF(chip_select,SS_L) );
00743   error_code += sub_spi_transfer( handle_sub20, 0, &chCHIP_ID, 1, SS_CONF(chip_select,SS_L) );
00744   error_code += sub_spi_transfer( handle_sub20, 0, &chALML_VER, 1, SS_CONF(chip_select,SS_L) );
00745 
00746   // ensure CS is high
00747   error_code += sub_spi_transfer( handle_sub20, 0, &chCMD, 1, SS_CONF(chip_select,SS_H) );
00748 
00749   // Verify if a BMA180 is connected on the respective ChipSelect
00750   if( error_code == 0 && ( 0 < (unsigned short) chCHIP_ID) && ( 0 < (unsigned short)chALML_VER) )
00751   {
00752     if( !bWriteEEPROM == true)
00753     {
00754       // Write X axis offset
00755       chMSB = (char)( (uiBiasX&0xFF0) >> 4 );
00756       chLSB = (char)( (uiBiasX&0x0F) );
00757       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_OFFSET_X, 0, 8, chMSB, chip_select, handle_sub20 );
00758       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_OFFSET_LSB1, 4, 4, chLSB, chip_select, handle_sub20 );
00759 
00760       // Write Y axis offset
00761       chMSB = (char)( (uiBiasY&0xFF0) >> 4 );
00762       chLSB = (char)( (uiBiasY&0x0F));
00763       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_OFFSET_Y, 0, 8, chMSB, chip_select, handle_sub20 );
00764       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_OFFSET_LSB2, 0, 4, chLSB, chip_select, handle_sub20 );
00765 
00766       // Write Z axis offset
00767       chMSB = (char)( (uiBiasZ&0xFF0) >> 4 );
00768       chLSB = (char)( (uiBiasZ&0x0F) );
00769       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_OFFSET_Z, 0, 8, chMSB, chip_select, handle_sub20 );
00770       bEE_RWsuccess &= write_bit_eeprom_sub20( bma180_cmd::ADDRESS_OFFSET_LSB2, 4, 4, chLSB, chip_select, handle_sub20 );
00771 
00772       if( bEE_RWsuccess )
00773       {
00774         std::cout << "Writing to image " << std::endl;
00775         bSuccess = true;
00776       }
00777       else
00778       {
00779         bSuccess = false;
00780         ROS_WARN("Cannot write BMA180 image.\n");
00781       }
00782     }
00783     else
00784     {
00785       // Writing to the EEPROM is done by indirect write, i.e. setting values to image register
00786       // and then writing to the eeprom, which in fact reads the image register
00787       // Per write 16 bit from image to eeprom are written and only even addresses can used (see docu)
00788       bEE_RWsuccess &= write_bit_eeprom_sub20(bma180_cmd::ADDRESS_EE_GAIN_Z, 0, 8, 0x00, chip_select, handle_sub20 );
00789       bEE_RWsuccess &= write_bit_eeprom_sub20(bma180_cmd::ADDRESS_EE_OFFSET_LSB2, 0, 8, 0x00, chip_select, handle_sub20 );
00790       bEE_RWsuccess &= write_bit_eeprom_sub20(bma180_cmd::ADDRESS_EE_OFFSET_X, 0, 8, 0x00, chip_select, handle_sub20 );
00791       bEE_RWsuccess &= write_bit_eeprom_sub20(bma180_cmd::ADDRESS_EE_OFFSET_Z, 0, 8, 0x00, chip_select, handle_sub20 );
00792 
00793       if( bEE_RWsuccess )
00794       {
00795         ROS_INFO("BMA180 EEPROM written.\n");
00796         bSuccess = true;
00797       }
00798       else
00799       {
00800         bSuccess = false;
00801       }
00802     }
00803   }
00804   else 
00805   {
00806     // unsuccessful operation
00807     bSuccess = false;
00808   }
00809   return bSuccess;
00810 };
00811 
00812 
00813 void Bma180::set_calibstatus( bool bCalibrate)
00814 {
00815   if( bCalibrate == true )
00816   {
00817     std::string myAnswer;
00818     std::cout << "Sensors shall be calibrated <Y/N>? ";
00819     std::getline( std::cin, myAnswer );
00820     if( (0 == myAnswer.find('Y')) || (0 == myAnswer.find('y')) )
00821     {
00822       unsigned short myCS;
00823       std::cout << "Specify ChipSelect <0..4>? ";
00824       if( std::cin >> myCS )
00825       {
00826         if( myCS < bma180_cmd::MAX_NUM_SENSORS )
00827         {
00828           bExecuteCalibration = true;
00829           bCalibrationCompleted = false;
00830           iCalib_CS = myCS;
00831         }
00832         else
00833         {
00834           bExecuteCalibration = false;
00835           bCalibrationCompleted = true;
00836         }
00837       }
00838       else
00839       {
00840         bExecuteCalibration = false;
00841         bCalibrationCompleted = true;
00842         std::cin.clear();
00843       }
00844     }
00845     else
00846     {
00847       bExecuteCalibration = false;
00848       bCalibrationCompleted = true;
00849     }
00850   }
00851   else
00852   {
00853     bExecuteCalibration = false;
00854     bCalibrationCompleted = true;
00855   }
00856 };
00857 
00858 
00859 
00860 
00861 // main loop
00862 
00863 int main(int argc, char **argv)
00864 {
00865   int count = 1;
00866   int i = 0;
00867 
00868 
00869   // Parameter Server values
00870   double        max_acceleration_g, dRate_Hz, dBandwidth_Hz;
00871   bool          bCalibrate;
00872   std::string   sSub20Serial;
00873 
00874   // Set initialization values
00875   max_acceleration_g = 2.0;
00876   dBandwidth_Hz = 100; 
00877   dRate_Hz = 100;
00878   bCalibrate = false;
00879   sSub20Serial = "0651";
00880 
00881   Bma180 bma180_attached( max_acceleration_g, dBandwidth_Hz, bCalibrate, dRate_Hz, sSub20Serial );
00882   OneBma180Meas sOneMeas;
00883   bma180::bma180meas msg;
00884   std::list<OneBma180Meas> measurements_list;
00885 
00886 
00887   // Run sensor node
00888   // some sort of rate setup here
00889   while( true )
00890   {
00891     // initiate a measurement
00892     try
00893     {
00894       bma180_attached.GetMeasurements(measurements_list);
00895     }
00896 
00897     catch( std::string e )
00898     {
00899       ROS_ERROR( "An exception occurred: %s\n", e.c_str() );
00900       std::exit(1);
00901     }
00902 
00903     while( !measurements_list.empty() ) 
00904     {
00905       sOneMeas = measurements_list.back();
00906       measurements_list.pop_back();
00907 
00908       // only publish if a successful measurement was received
00909       if( sOneMeas.bMeasAvailable == true )
00910       {
00911         msg.strIdSubDev = sOneMeas.serial_number;
00912 
00913         // Print results to screen
00914         for( i = 0; i < sOneMeas.iNumAccels; i++ )
00915         {
00916           printf("BMA180 %d\tx: %1.4f\ty: %1.4f\tz: %1.4f\n", sOneMeas.chip_select[i], sOneMeas.dAccX[i], sOneMeas.dAccY[i], sOneMeas.dAccZ[i] );
00917         }
00918       }
00919     }
00920 
00921     //loop_rate.sleep();
00922     usleep( 1e6 / dRate_Hz );
00923 
00924     ++count;
00925   }
00926 }
00927 
00928 


bma180
Author(s): Lukas Marti, Nikhil Deshpande, Philip Roan (Maintained by Philip Roan)
autogenerated on Mon Oct 6 2014 10:10:49