mbed.org local branch of microbit-dal. The real version lives in git at https://github.com/lancaster-university/microbit-dal
Dependencies: BLE_API nRF51822 mbed-dev-bin
Dependents: microbit Microbit IoTChallenge1 microbit ... more
MicroBitAccelerometer.cpp
00001 /* 00002 The MIT License (MIT) 00003 00004 Copyright (c) 2016 British Broadcasting Corporation. 00005 This software is provided by Lancaster University by arrangement with the BBC. 00006 00007 Permission is hereby granted, free of charge, to any person obtaining a 00008 copy of this software and associated documentation files (the "Software"), 00009 to deal in the Software without restriction, including without limitation 00010 the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 and/or sell copies of the Software, and to permit persons to whom the 00012 Software is furnished to do so, subject to the following conditions: 00013 00014 The above copyright notice and this permission notice shall be included in 00015 all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00023 DEALINGS IN THE SOFTWARE. 00024 */ 00025 00026 /** 00027 * Class definition for MicroBit Accelerometer. 00028 * 00029 * Represents an implementation of the Freescale MMA8653 3 axis accelerometer 00030 * Also includes basic data caching and on demand activation. 00031 */ 00032 #include "MicroBitConfig.h" 00033 #include "MicroBitAccelerometer.h" 00034 #include "ErrorNo.h" 00035 #include "MicroBitConfig.h" 00036 #include "MicroBitEvent.h" 00037 #include "MicroBitCompat.h" 00038 #include "MicroBitFiber.h" 00039 00040 /** 00041 * Configures the accelerometer for G range and sample rate defined 00042 * in this object. The nearest values are chosen to those defined 00043 * that are supported by the hardware. The instance variables are then 00044 * updated to reflect reality. 00045 * 00046 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured. 00047 */ 00048 int MicroBitAccelerometer::configure() 00049 { 00050 const MMA8653SampleRangeConfig *actualSampleRange; 00051 const MMA8653SampleRateConfig *actualSampleRate; 00052 int result; 00053 00054 // First find the nearest sample rate to that specified. 00055 actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1]; 00056 for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--) 00057 { 00058 if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000) 00059 break; 00060 00061 actualSampleRate = &MMA8653SampleRate[i]; 00062 } 00063 00064 // Now find the nearest sample range to that specified. 00065 actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1]; 00066 for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--) 00067 { 00068 if(MMA8653SampleRange[i].sample_range < this->sampleRange) 00069 break; 00070 00071 actualSampleRange = &MMA8653SampleRange[i]; 00072 } 00073 00074 // OK, we have the correct data. Update our local state. 00075 this->samplePeriod = actualSampleRate->sample_period / 1000; 00076 this->sampleRange = actualSampleRange->sample_range; 00077 00078 // Now configure the accelerometer accordingly. 00079 // First place the device into standby mode, so it can be configured. 00080 result = writeCommand(MMA8653_CTRL_REG1, 0x00); 00081 if (result != 0) 00082 return MICROBIT_I2C_ERROR; 00083 00084 // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA! 00085 result = writeCommand(MMA8653_CTRL_REG2, 0x10); 00086 if (result != 0) 00087 return MICROBIT_I2C_ERROR; 00088 00089 // Enable the INT1 interrupt pin. 00090 result = writeCommand(MMA8653_CTRL_REG4, 0x01); 00091 if (result != 0) 00092 return MICROBIT_I2C_ERROR; 00093 00094 // Select the DATA_READY event source to be routed to INT1 00095 result = writeCommand(MMA8653_CTRL_REG5, 0x01); 00096 if (result != 0) 00097 return MICROBIT_I2C_ERROR; 00098 00099 // Configure for the selected g range. 00100 result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg); 00101 if (result != 0) 00102 return MICROBIT_I2C_ERROR; 00103 00104 // Bring the device back online, with 10bit wide samples at the requested frequency. 00105 result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); 00106 if (result != 0) 00107 return MICROBIT_I2C_ERROR; 00108 00109 return MICROBIT_OK; 00110 } 00111 00112 /** 00113 * Issues a standard, 2 byte I2C command write to the accelerometer. 00114 * 00115 * Blocks the calling thread until complete. 00116 * 00117 * @param reg The address of the register to write to. 00118 * 00119 * @param value The value to write. 00120 * 00121 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed. 00122 */ 00123 int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value) 00124 { 00125 uint8_t command[2]; 00126 command[0] = reg; 00127 command[1] = value; 00128 00129 return i2c.write(address, (const char *)command, 2); 00130 } 00131 00132 /** 00133 * Issues a read command, copying data into the specified buffer. 00134 * 00135 * Blocks the calling thread until complete. 00136 * 00137 * @param reg The address of the register to access. 00138 * 00139 * @param buffer Memory area to read the data into. 00140 * 00141 * @param length The number of bytes to read. 00142 * 00143 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed. 00144 */ 00145 int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length) 00146 { 00147 int result; 00148 00149 if (buffer == NULL || length <= 0 ) 00150 return MICROBIT_INVALID_PARAMETER; 00151 00152 result = i2c.write(address, (const char *)®, 1, true); 00153 if (result !=0) 00154 return MICROBIT_I2C_ERROR; 00155 00156 result = i2c.read(address, (char *)buffer, length); 00157 if (result !=0) 00158 return MICROBIT_I2C_ERROR; 00159 00160 return MICROBIT_OK; 00161 } 00162 00163 /** 00164 * Constructor. 00165 * Create a software abstraction of an accelerometer. 00166 * 00167 * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer. 00168 * 00169 * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. 00170 * 00171 * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER 00172 * 00173 * @code 00174 * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0); 00175 * 00176 * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c); 00177 * @endcode 00178 */ 00179 MicroBitAccelerometer::MicroBitAccelerometer(MicroBitI2C& _i2c, uint16_t address, uint16_t id) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c) 00180 { 00181 // Store our identifiers. 00182 this->id = id; 00183 this->status = 0; 00184 this->address = address; 00185 00186 // Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms). 00187 this->samplePeriod = 20; 00188 this->sampleRange = 2; 00189 00190 // Initialise gesture history 00191 this->sigma = 0; 00192 this->impulseSigma = 0; 00193 this->lastGesture = MICROBIT_ACCELEROMETER_EVT_NONE; 00194 this->currentGesture = MICROBIT_ACCELEROMETER_EVT_NONE; 00195 this->shake.x = 0; 00196 this->shake.y = 0; 00197 this->shake.z = 0; 00198 this->shake.count = 0; 00199 this->shake.timer = 0; 00200 this->shake.impulse_3 = 1; 00201 this->shake.impulse_6 = 1; 00202 this->shake.impulse_8 = 1; 00203 00204 // Configure and enable the accelerometer. 00205 if (this->configure() == MICROBIT_OK) 00206 status |= MICROBIT_COMPONENT_RUNNING; 00207 } 00208 00209 /** 00210 * Attempts to read the 8 bit ID from the accelerometer, this can be used for 00211 * validation purposes. 00212 * 00213 * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails. 00214 * 00215 * @code 00216 * accelerometer.whoAmI(); 00217 * @endcode 00218 */ 00219 int MicroBitAccelerometer::whoAmI() 00220 { 00221 uint8_t data; 00222 int result; 00223 00224 result = readCommand(MMA8653_WHOAMI, &data, 1); 00225 if (result !=0) 00226 return MICROBIT_I2C_ERROR; 00227 00228 return (int)data; 00229 } 00230 00231 /** 00232 * Reads the acceleration data from the accelerometer, and stores it in our buffer. 00233 * This only happens if the accelerometer indicates that it has new data via int1. 00234 * 00235 * On first use, this member function will attempt to add this component to the 00236 * list of fiber components in order to constantly update the values stored 00237 * by this object. 00238 * 00239 * This technique is called lazy instantiation, and it means that we do not 00240 * obtain the overhead from non-chalantly adding this component to fiber components. 00241 * 00242 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails. 00243 */ 00244 int MicroBitAccelerometer::updateSample() 00245 { 00246 if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE)) 00247 { 00248 fiber_add_idle_component(this); 00249 status |= MICROBIT_ACCEL_ADDED_TO_IDLE; 00250 } 00251 00252 // Poll interrupt line from accelerometer. 00253 // n.b. Default is Active LO. Interrupt is cleared in data read. 00254 if(!int1) 00255 { 00256 int8_t data[6]; 00257 int result; 00258 00259 result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6); 00260 if (result !=0) 00261 return MICROBIT_I2C_ERROR; 00262 00263 // read MSB values... 00264 sample.x = data[0]; 00265 sample.y = data[2]; 00266 sample.z = data[4]; 00267 00268 // Normalize the data in the 0..1024 range. 00269 sample.x *= 8; 00270 sample.y *= 8; 00271 sample.z *= 8; 00272 00273 #if CONFIG_ENABLED(USE_ACCEL_LSB) 00274 // Add in LSB values. 00275 sample.x += (data[1] / 64); 00276 sample.y += (data[3] / 64); 00277 sample.z += (data[5] / 64); 00278 #endif 00279 00280 // Scale into millig (approx!) 00281 sample.x *= this->sampleRange; 00282 sample.y *= this->sampleRange; 00283 sample.z *= this->sampleRange; 00284 00285 // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed. 00286 status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID; 00287 00288 // Update gesture tracking 00289 updateGesture(); 00290 00291 // Indicate that a new sample is available 00292 MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE); 00293 } 00294 00295 return MICROBIT_OK; 00296 }; 00297 00298 /** 00299 * A service function. 00300 * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). 00301 * It does not, however, square root the result, as this is a relatively high cost operation. 00302 * 00303 * This is left to application code should it be needed. 00304 * 00305 * @return the sum of the square of the acceleration of the device across all axes. 00306 */ 00307 int MicroBitAccelerometer::instantaneousAccelerationSquared() 00308 { 00309 updateSample(); 00310 00311 // Use pythagoras theorem to determine the combined force acting on the device. 00312 return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z; 00313 } 00314 00315 /** 00316 * Service function. 00317 * Determines a 'best guess' posture of the device based on instantaneous data. 00318 * 00319 * This makes no use of historic data, and forms the input to the filter implemented in updateGesture(). 00320 * 00321 * @return A 'best guess' of the current posture of the device, based on instanataneous data. 00322 */ 00323 uint16_t MicroBitAccelerometer::instantaneousPosture() 00324 { 00325 bool shakeDetected = false; 00326 00327 // Test for shake events. 00328 // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by 00329 // a strong acceleration to the right, then we can infer a shake. Similarly, we can do this for each axis (left/right, up/down, in/out). 00330 // 00331 // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device 00332 // has been shaken. 00333 if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x)) 00334 { 00335 shakeDetected = true; 00336 shake.x = !shake.x; 00337 } 00338 00339 if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y)) 00340 { 00341 shakeDetected = true; 00342 shake.y = !shake.y; 00343 } 00344 00345 if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z)) 00346 { 00347 shakeDetected = true; 00348 shake.z = !shake.z; 00349 } 00350 00351 // If we detected a zero crossing in this sample period, count this. 00352 if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD) 00353 { 00354 shake.count++; 00355 00356 if (shake.count == 1) 00357 shake.timer = 0; 00358 00359 if (shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD) 00360 { 00361 shake.shaken = 1; 00362 shake.timer = 0; 00363 return MICROBIT_ACCELEROMETER_EVT_SHAKE; 00364 } 00365 } 00366 00367 // measure how long we have been detecting a SHAKE event. 00368 if (shake.count > 0) 00369 { 00370 shake.timer++; 00371 00372 // If we've issued a SHAKE event already, and sufficient time has assed, allow another SHAKE event to be issued. 00373 if (shake.shaken && shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_RTX) 00374 { 00375 shake.shaken = 0; 00376 shake.timer = 0; 00377 shake.count = 0; 00378 } 00379 00380 // Decay our count of zero crossings over time. We don't want them to accumulate if the user performs slow moving motions. 00381 else if (!shake.shaken && shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING) 00382 { 00383 shake.timer = 0; 00384 if (shake.count > 0) 00385 shake.count--; 00386 } 00387 } 00388 00389 if (instantaneousAccelerationSquared() < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD) 00390 return MICROBIT_ACCELEROMETER_EVT_FREEFALL; 00391 00392 // Determine our posture. 00393 if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) 00394 return MICROBIT_ACCELEROMETER_EVT_TILT_LEFT; 00395 00396 if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) 00397 return MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT; 00398 00399 if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) 00400 return MICROBIT_ACCELEROMETER_EVT_TILT_DOWN; 00401 00402 if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) 00403 return MICROBIT_ACCELEROMETER_EVT_TILT_UP; 00404 00405 if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) 00406 return MICROBIT_ACCELEROMETER_EVT_FACE_UP; 00407 00408 if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) 00409 return MICROBIT_ACCELEROMETER_EVT_FACE_DOWN; 00410 00411 return MICROBIT_ACCELEROMETER_EVT_NONE; 00412 } 00413 00414 /** 00415 * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote 00416 * stability. 00417 */ 00418 void MicroBitAccelerometer::updateGesture() 00419 { 00420 // Check for High/Low G force events - typically impulses, impacts etc. 00421 // Again, during such spikes, these event take priority of the posture of the device. 00422 // For these events, we don't perform any low pass filtering. 00423 int force = instantaneousAccelerationSquared(); 00424 00425 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD) 00426 { 00427 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD && !shake.impulse_3) 00428 { 00429 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_3G); 00430 shake.impulse_3 = 1; 00431 } 00432 if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD && !shake.impulse_6) 00433 { 00434 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_6G); 00435 shake.impulse_6 = 1; 00436 } 00437 if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD && !shake.impulse_8) 00438 { 00439 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_8G); 00440 shake.impulse_8 = 1; 00441 } 00442 00443 impulseSigma = 0; 00444 } 00445 00446 // Reset the impulse event onve the acceleration has subsided. 00447 if (impulseSigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING) 00448 impulseSigma++; 00449 else 00450 shake.impulse_3 = shake.impulse_6 = shake.impulse_8 = 0; 00451 00452 00453 // Determine what it looks like we're doing based on the latest sample... 00454 uint16_t g = instantaneousPosture(); 00455 00456 if (g == MICROBIT_ACCELEROMETER_EVT_SHAKE) 00457 { 00458 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_SHAKE); 00459 return; 00460 } 00461 00462 // Perform some low pass filtering to reduce jitter from any detected effects 00463 if (g == currentGesture) 00464 { 00465 if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING) 00466 sigma++; 00467 } 00468 else 00469 { 00470 currentGesture = g; 00471 sigma = 0; 00472 } 00473 00474 // If we've reached threshold, update our record and raise the relevant event... 00475 if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING) 00476 { 00477 lastGesture = currentGesture; 00478 MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture); 00479 } 00480 } 00481 00482 /** 00483 * Attempts to set the sample rate of the accelerometer to the specified value (in ms). 00484 * 00485 * @param period the requested time between samples, in milliseconds. 00486 * 00487 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails. 00488 * 00489 * @code 00490 * // sample rate is now 20 ms. 00491 * accelerometer.setPeriod(20); 00492 * @endcode 00493 * 00494 * @note The requested rate may not be possible on the hardware. In this case, the 00495 * nearest lower rate is chosen. 00496 */ 00497 int MicroBitAccelerometer::setPeriod(int period) 00498 { 00499 this->samplePeriod = period; 00500 return this->configure(); 00501 } 00502 00503 /** 00504 * Reads the currently configured sample rate of the accelerometer. 00505 * 00506 * @return The time between samples, in milliseconds. 00507 */ 00508 int MicroBitAccelerometer::getPeriod() 00509 { 00510 return (int)samplePeriod; 00511 } 00512 00513 /** 00514 * Attempts to set the sample range of the accelerometer to the specified value (in g). 00515 * 00516 * @param range The requested sample range of samples, in g. 00517 * 00518 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails. 00519 * 00520 * @code 00521 * // the sample range of the accelerometer is now 8G. 00522 * accelerometer.setRange(8); 00523 * @endcode 00524 * 00525 * @note The requested range may not be possible on the hardware. In this case, the 00526 * nearest lower range is chosen. 00527 */ 00528 int MicroBitAccelerometer::setRange(int range) 00529 { 00530 this->sampleRange = range; 00531 return this->configure(); 00532 } 00533 00534 /** 00535 * Reads the currently configured sample range of the accelerometer. 00536 * 00537 * @return The sample range, in g. 00538 */ 00539 int MicroBitAccelerometer::getRange() 00540 { 00541 return (int)sampleRange; 00542 } 00543 00544 /** 00545 * Reads the value of the X axis from the latest update retrieved from the accelerometer. 00546 * 00547 * @param system The coordinate system to use. By default, a simple cartesian system is provided. 00548 * 00549 * @return The force measured in the X axis, in milli-g. 00550 * 00551 * @code 00552 * accelerometer.getX(); 00553 * @endcode 00554 */ 00555 int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system) 00556 { 00557 updateSample(); 00558 00559 switch (system) 00560 { 00561 case SIMPLE_CARTESIAN: 00562 return -sample.x; 00563 00564 case NORTH_EAST_DOWN: 00565 return sample.y; 00566 00567 case RAW: 00568 default: 00569 return sample.x; 00570 } 00571 } 00572 00573 /** 00574 * Reads the value of the Y axis from the latest update retrieved from the accelerometer. 00575 * 00576 * @return The force measured in the Y axis, in milli-g. 00577 * 00578 * @code 00579 * accelerometer.getY(); 00580 * @endcode 00581 */ 00582 int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system) 00583 { 00584 updateSample(); 00585 00586 switch (system) 00587 { 00588 case SIMPLE_CARTESIAN: 00589 return -sample.y; 00590 00591 case NORTH_EAST_DOWN: 00592 return -sample.x; 00593 00594 case RAW: 00595 default: 00596 return sample.y; 00597 } 00598 } 00599 00600 /** 00601 * Reads the value of the Z axis from the latest update retrieved from the accelerometer. 00602 * 00603 * @return The force measured in the Z axis, in milli-g. 00604 * 00605 * @code 00606 * accelerometer.getZ(); 00607 * @endcode 00608 */ 00609 int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system) 00610 { 00611 updateSample(); 00612 00613 switch (system) 00614 { 00615 case NORTH_EAST_DOWN: 00616 return -sample.z; 00617 00618 case SIMPLE_CARTESIAN: 00619 case RAW: 00620 default: 00621 return sample.z; 00622 } 00623 } 00624 00625 /** 00626 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. 00627 * 00628 * @return The pitch of the device, in degrees. 00629 * 00630 * @code 00631 * accelerometer.getPitch(); 00632 * @endcode 00633 */ 00634 int MicroBitAccelerometer::getPitch() 00635 { 00636 return (int) ((360*getPitchRadians()) / (2*PI)); 00637 } 00638 00639 /** 00640 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. 00641 * 00642 * @return The pitch of the device, in radians. 00643 * 00644 * @code 00645 * accelerometer.getPitchRadians(); 00646 * @endcode 00647 */ 00648 float MicroBitAccelerometer::getPitchRadians() 00649 { 00650 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID)) 00651 recalculatePitchRoll(); 00652 00653 return pitch; 00654 } 00655 00656 /** 00657 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. 00658 * 00659 * @return The roll of the device, in degrees. 00660 * 00661 * @code 00662 * accelerometer.getRoll(); 00663 * @endcode 00664 */ 00665 int MicroBitAccelerometer::getRoll() 00666 { 00667 return (int) ((360*getRollRadians()) / (2*PI)); 00668 } 00669 00670 /** 00671 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. 00672 * 00673 * @return The roll of the device, in radians. 00674 * 00675 * @code 00676 * accelerometer.getRollRadians(); 00677 * @endcode 00678 */ 00679 float MicroBitAccelerometer::getRollRadians() 00680 { 00681 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID)) 00682 recalculatePitchRoll(); 00683 00684 return roll; 00685 } 00686 00687 /** 00688 * Recalculate roll and pitch values for the current sample. 00689 * 00690 * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather 00691 * heavyweight for a CPU without a floating point unit. 00692 */ 00693 void MicroBitAccelerometer::recalculatePitchRoll() 00694 { 00695 double x = (double) getX(NORTH_EAST_DOWN); 00696 double y = (double) getY(NORTH_EAST_DOWN); 00697 double z = (double) getZ(NORTH_EAST_DOWN); 00698 00699 roll = atan2(y, z); 00700 pitch = atan(-x / (y*sin(roll) + z*cos(roll))); 00701 00702 status |= MICROBIT_ACCEL_PITCH_ROLL_VALID; 00703 } 00704 00705 /** 00706 * Retrieves the last recorded gesture. 00707 * 00708 * @return The last gesture that was detected. 00709 * 00710 * Example: 00711 * @code 00712 * MicroBitDisplay display; 00713 * 00714 * if (accelerometer.getGesture() == SHAKE) 00715 * display.scroll("SHAKE!"); 00716 * @endcode 00717 */ 00718 uint16_t MicroBitAccelerometer::getGesture() 00719 { 00720 return lastGesture; 00721 } 00722 00723 /** 00724 * A periodic callback invoked by the fiber scheduler idle thread. 00725 * 00726 * Internally calls updateSample(). 00727 */ 00728 void MicroBitAccelerometer::idleTick() 00729 { 00730 updateSample(); 00731 } 00732 00733 /** 00734 * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components. 00735 */ 00736 MicroBitAccelerometer::~MicroBitAccelerometer() 00737 { 00738 fiber_remove_idle_component(this); 00739 } 00740 00741 const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = { 00742 {2, 0}, 00743 {4, 1}, 00744 {8, 2} 00745 }; 00746 00747 const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = { 00748 {1250, 0x00}, 00749 {2500, 0x08}, 00750 {5000, 0x10}, 00751 {10000, 0x18}, 00752 {20000, 0x20}, 00753 {80000, 0x28}, 00754 {160000, 0x30}, 00755 {640000, 0x38} 00756 };
Generated on Tue Jul 12 2022 15:22:55 by 1.7.2