microbit: code scrub of MicroBitAccelerometer gesture recognition code
- updated acceleration threshold event names to reflect numeric values e.g. GESTURE_3G, GESTURE_6G, GESTURE_8G. - Add scoping to elements of SimpleGesture enum. - Code scrub of code layout caused by editor with incorrect configuration. - rename of internal state variables and functions to better reflect use. - added clarification to some comments.
This commit is contained in:
parent
1b18ac8641
commit
d3587d888c
2 changed files with 365 additions and 360 deletions
|
@ -5,8 +5,8 @@
|
|||
#include "MicroBitComponent.h"
|
||||
|
||||
/**
|
||||
* Relevant pin assignments
|
||||
*/
|
||||
* Relevant pin assignments
|
||||
*/
|
||||
#define MICROBIT_PIN_ACCEL_DATA_READY P0_28
|
||||
|
||||
/*
|
||||
|
@ -29,8 +29,8 @@
|
|||
|
||||
|
||||
/**
|
||||
* MMA8653 constants
|
||||
*/
|
||||
* MMA8653 constants
|
||||
*/
|
||||
#define MMA8653_WHOAMI_VAL 0x5A
|
||||
|
||||
#define MMA8653_SAMPLE_RANGES 3
|
||||
|
@ -39,42 +39,42 @@
|
|||
/*
|
||||
* Accelerometer events
|
||||
*/
|
||||
#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
|
||||
#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
|
||||
|
||||
/*
|
||||
* Gesture events
|
||||
*/
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_UP 1
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_DOWN 2
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_LEFT 3
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT 4
|
||||
#define MICROBIT_ACCELEROMETER_EVT_FACE_UP 5
|
||||
#define MICROBIT_ACCELEROMETER_EVT_FACE_DOWN 6
|
||||
#define MICROBIT_ACCELEROMETER_EVT_FREEFALL 7
|
||||
#define MICROBIT_ACCELEROMETER_EVT_WHEEE 8
|
||||
#define MICROBIT_ACCELEROMETER_EVT_SICK 9
|
||||
#define MICROBIT_ACCELEROMETER_EVT_UNCONSCIOUS 10
|
||||
#define MICROBIT_ACCELEROMETER_EVT_SHAKE 11
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_UP 1
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_DOWN 2
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_LEFT 3
|
||||
#define MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT 4
|
||||
#define MICROBIT_ACCELEROMETER_EVT_FACE_UP 5
|
||||
#define MICROBIT_ACCELEROMETER_EVT_FACE_DOWN 6
|
||||
#define MICROBIT_ACCELEROMETER_EVT_FREEFALL 7
|
||||
#define MICROBIT_ACCELEROMETER_EVT_3G 8
|
||||
#define MICROBIT_ACCELEROMETER_EVT_6G 9
|
||||
#define MICROBIT_ACCELEROMETER_EVT_8G 10
|
||||
#define MICROBIT_ACCELEROMETER_EVT_SHAKE 11
|
||||
|
||||
/*
|
||||
* Gesture recogniser constants
|
||||
*/
|
||||
#define MICROBIT_ACCELEROMETER_REST_TOLERANCE 200
|
||||
#define MICROBIT_ACCELEROMETER_TILT_TOLERANCE 200
|
||||
#define MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE 200
|
||||
#define MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE 1000
|
||||
#define MICROBIT_ACCELEROMETER_WHEEE_TOLERANCE 3000
|
||||
#define MICROBIT_ACCELEROMETER_SICK_TOLERANCE 5000
|
||||
#define MICROBIT_ACCELEROMETER_UNCONSCIOUS_TOLERANCE 8000
|
||||
#define MICROBIT_ACCELEROMETER_GESTURE_DAMPING 10
|
||||
#define MICROBIT_ACCELEROMETER_SHAKE_DAMPING 10
|
||||
#define MICROBIT_ACCELEROMETER_REST_TOLERANCE 200
|
||||
#define MICROBIT_ACCELEROMETER_TILT_TOLERANCE 200
|
||||
#define MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE 200
|
||||
#define MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE 1000
|
||||
#define MICROBIT_ACCELEROMETER_3G_TOLERANCE 3072
|
||||
#define MICROBIT_ACCELEROMETER_6G_TOLERANCE 6144
|
||||
#define MICROBIT_ACCELEROMETER_8G_TOLERANCE 8192
|
||||
#define MICROBIT_ACCELEROMETER_GESTURE_DAMPING 10
|
||||
#define MICROBIT_ACCELEROMETER_SHAKE_DAMPING 10
|
||||
|
||||
#define MICROBIT_ACCELEROMETER_REST_THRESHOLD (MICROBIT_ACCELEROMETER_REST_TOLERANCE * MICROBIT_ACCELEROMETER_REST_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD (MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE * MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_WHEEE_THRESHOLD (MICROBIT_ACCELEROMETER_WHEEE_TOLERANCE * MICROBIT_ACCELEROMETER_WHEEE_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_SICK_THRESHOLD (MICROBIT_ACCELEROMETER_SICK_TOLERANCE * MICROBIT_ACCELEROMETER_SICK_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_UNCONSCIOUS_THRESHOLD (MICROBIT_ACCELEROMETER_UNCONSCIOUS_TOLERANCE * MICROBIT_ACCELEROMETER_UNCONSCIOUS_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD 4
|
||||
#define MICROBIT_ACCELEROMETER_REST_THRESHOLD (MICROBIT_ACCELEROMETER_REST_TOLERANCE * MICROBIT_ACCELEROMETER_REST_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD (MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE * MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_3G_THRESHOLD (MICROBIT_ACCELEROMETER_3G_TOLERANCE * MICROBIT_ACCELEROMETER_3G_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_6G_THRESHOLD (MICROBIT_ACCELEROMETER_6G_TOLERANCE * MICROBIT_ACCELEROMETER_6G_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_8G_THRESHOLD (MICROBIT_ACCELEROMETER_8G_TOLERANCE * MICROBIT_ACCELEROMETER_8G_TOLERANCE)
|
||||
#define MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD 4
|
||||
|
||||
struct MMA8653Sample
|
||||
{
|
||||
|
@ -100,68 +100,68 @@ extern const MMA8653SampleRateConfig MMA8653SampleRate[];
|
|||
|
||||
enum BasicGesture
|
||||
{
|
||||
NONE,
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
FACE_UP,
|
||||
FACE_DOWN,
|
||||
FREEFALL,
|
||||
WHEEE,
|
||||
SICK,
|
||||
UNCONSCIOUS,
|
||||
SHAKE
|
||||
GESTURE_NONE,
|
||||
GESTURE_UP,
|
||||
GESTURE_DOWN,
|
||||
GESTURE_LEFT,
|
||||
GESTURE_RIGHT,
|
||||
GESTURE_FACE_UP,
|
||||
GESTURE_FACE_DOWN,
|
||||
GESTURE_FREEFALL,
|
||||
GESTURE_3G,
|
||||
GESTURE_6G,
|
||||
GESTURE_8G,
|
||||
GESTURE_SHAKE
|
||||
};
|
||||
|
||||
struct ShakeHistory
|
||||
{
|
||||
uint16_t shaken:1,
|
||||
x:1,
|
||||
y:1,
|
||||
z:1,
|
||||
count:4,
|
||||
timer:8;
|
||||
uint16_t shaken:1,
|
||||
x:1,
|
||||
y:1,
|
||||
z:1,
|
||||
count:4,
|
||||
timer:8;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition for MicroBit Accelerometer.
|
||||
*
|
||||
* Represents an implementation of the Freescale MMA8653 3 axis accelerometer
|
||||
* Also includes basic data caching and on demand activation.
|
||||
*/
|
||||
* Class definition for MicroBit Accelerometer.
|
||||
*
|
||||
* Represents an implementation of the Freescale MMA8653 3 axis accelerometer
|
||||
* Also includes basic data caching and on demand activation.
|
||||
*/
|
||||
class MicroBitAccelerometer : public MicroBitComponent
|
||||
{
|
||||
/**
|
||||
* Unique, enumerated ID for this component.
|
||||
* Used to track asynchronous events in the event bus.
|
||||
*/
|
||||
|
||||
MMA8653Sample sample; // The last sample read.
|
||||
DigitalIn int1; // Data ready interrupt.
|
||||
uint16_t address; // I2C address of this accelerometer.
|
||||
uint16_t samplePeriod; // The time between samples, in milliseconds.
|
||||
uint8_t sampleRange; // The sample range of the accelerometer in g.
|
||||
uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable.
|
||||
BasicGesture gesture; // the current, filtered orientation of the device.
|
||||
BasicGesture iGesture; // the last instantaneous orientation recorded.
|
||||
ShakeHistory shake; // State information needed to detect shake events.
|
||||
|
||||
* Unique, enumerated ID for this component.
|
||||
* Used to track asynchronous events in the event bus.
|
||||
*/
|
||||
|
||||
MMA8653Sample sample; // The last sample read.
|
||||
DigitalIn int1; // Data ready interrupt.
|
||||
uint16_t address; // I2C address of this accelerometer.
|
||||
uint16_t samplePeriod; // The time between samples, in milliseconds.
|
||||
uint8_t sampleRange; // The sample range of the accelerometer in g.
|
||||
uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable.
|
||||
BasicGesture lastGesture; // the last, stable gesture recorded.
|
||||
BasicGesture currentGesture; // the instantaneous, unfiltered gesture detected.
|
||||
ShakeHistory shake; // State information needed to detect shake events.
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create an accelerometer representation with the given ID.
|
||||
* @param id the ID of the new object.
|
||||
* @param address the default base address of the accelerometer.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
|
||||
* @endcode
|
||||
*/
|
||||
* Constructor.
|
||||
* Create an accelerometer representation with the given ID.
|
||||
* @param id the ID of the new object.
|
||||
* @param address the default base address of the accelerometer.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitAccelerometer(uint16_t id, uint16_t address);
|
||||
|
||||
|
||||
/**
|
||||
* Configures the accelerometer for G range and sample rate defined
|
||||
* in this object. The nearest values are chosen to those defined
|
||||
|
@ -173,26 +173,26 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
int configure();
|
||||
|
||||
/**
|
||||
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
|
||||
* This is called by the tick() member function, if the interrupt is set.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the read request fails.
|
||||
*/
|
||||
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
|
||||
* This is called by the tick() member function, if the interrupt is set.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the read request fails.
|
||||
*/
|
||||
int update();
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to set the sample rate of the accelerometer to the specified value (in ms).
|
||||
* n.b. the requested rate may not be possible on the hardware. In this case, the
|
||||
* nearest lower rate is chosen.
|
||||
* @param period the requested time between samples, in milliseconds.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
|
||||
*/
|
||||
* Attempts to set the sample rate of the accelerometer to the specified value (in ms).
|
||||
* n.b. the requested rate may not be possible on the hardware. In this case, the
|
||||
* nearest lower rate is chosen.
|
||||
* @param period the requested time between samples, in milliseconds.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
|
||||
*/
|
||||
int setPeriod(int period);
|
||||
|
||||
/**
|
||||
* Reads the currently configured sample rate of the accelerometer.
|
||||
* @return The time between samples, in milliseconds.
|
||||
*/
|
||||
* Reads the currently configured sample rate of the accelerometer.
|
||||
* @return The time between samples, in milliseconds.
|
||||
*/
|
||||
int getPeriod();
|
||||
|
||||
/**
|
||||
|
@ -211,116 +211,116 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
int getRange();
|
||||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the accelerometer.
|
||||
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.whoAmI();
|
||||
* @endcode
|
||||
*/
|
||||
* Attempts to determine the 8 bit ID from the accelerometer.
|
||||
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.whoAmI();
|
||||
* @endcode
|
||||
*/
|
||||
int whoAmI();
|
||||
|
||||
/**
|
||||
* Reads the X axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the X axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getX();
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the X axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the X axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getX();
|
||||
* @endcode
|
||||
*/
|
||||
int getX();
|
||||
|
||||
|
||||
/**
|
||||
* Reads the Y axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Y axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getY();
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the Y axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Y axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getY();
|
||||
* @endcode
|
||||
*/
|
||||
int getY();
|
||||
|
||||
|
||||
/**
|
||||
* Reads the Z axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Z axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getZ();
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the Z axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Z axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getZ();
|
||||
* @endcode
|
||||
*/
|
||||
int getZ();
|
||||
|
||||
/**
|
||||
* Reads the last recorded gesture detected.
|
||||
* @return The last gesture detected.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* if (uBit.accelerometer.getGesture() == SHAKE)
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the last recorded gesture detected.
|
||||
* @return The last gesture detected.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* if (uBit.accelerometer.getGesture() == SHAKE)
|
||||
* @endcode
|
||||
*/
|
||||
BasicGesture getGesture();
|
||||
|
||||
/**
|
||||
* periodic callback from MicroBit idle thread.
|
||||
* Check if any data is ready for reading by checking the interrupt flag on the accelerometer
|
||||
*/
|
||||
* periodic callback from MicroBit idle thread.
|
||||
* Check if any data is ready for reading by checking the interrupt flag on the accelerometer
|
||||
*/
|
||||
virtual void idleTick();
|
||||
|
||||
|
||||
/**
|
||||
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
|
||||
*/
|
||||
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
|
||||
*/
|
||||
virtual int isIdleCallbackNeeded();
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* Issues a standard, 2 byte I2C command write to the accelerometer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to write to.
|
||||
* @param value The value to write.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
|
||||
*/
|
||||
* Issues a standard, 2 byte I2C command write to the accelerometer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to write to.
|
||||
* @param value The value to write.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
|
||||
*/
|
||||
int writeCommand(uint8_t reg, uint8_t value);
|
||||
|
||||
|
||||
/**
|
||||
* Issues a read command into the specified buffer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to access.
|
||||
* @param buffer Memory area to read the data into.
|
||||
* @param length The number of bytes to read.
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
|
||||
*/
|
||||
* Issues a read command into the specified buffer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to access.
|
||||
* @param buffer Memory area to read the data into.
|
||||
* @param length The number of bytes to read.
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
|
||||
*/
|
||||
int readCommand(uint8_t reg, uint8_t* buffer, int length);
|
||||
|
||||
/**
|
||||
* Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
|
||||
* stability.
|
||||
*/
|
||||
void updateGesture();
|
||||
/**
|
||||
* Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
|
||||
* stability.
|
||||
*/
|
||||
void updateGesture();
|
||||
|
||||
/**
|
||||
* Service function. Calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
|
||||
* It does not, however, square root the result, as this is a relatively high cost operation.
|
||||
* This is left to application code should it be needed.
|
||||
* @return the sum of the square of the acceleration of the device across all axes.
|
||||
*/
|
||||
int instantaneousAcceleration2();
|
||||
/**
|
||||
* Service function. Calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
|
||||
* It does not, however, square root the result, as this is a relatively high cost operation.
|
||||
* This is left to application code should it be needed.
|
||||
* @return the sum of the square of the acceleration of the device across all axes.
|
||||
*/
|
||||
int instantaneousAccelerationSquared();
|
||||
|
||||
/**
|
||||
* Service function. Determines the best guess posture of the device based on instantaneous data.
|
||||
* This makes no use of historic data, and forms this input to th filter implemented in updateGesture().
|
||||
* @return A best guess of the curret posture of the device, based on instanataneous data.
|
||||
*/
|
||||
BasicGesture instantaneousPosture();
|
||||
/**
|
||||
* Service function. Determines the best guess posture of the device based on instantaneous data.
|
||||
* This makes no use of historic data, and forms this input to th filter implemented in updateGesture().
|
||||
* @return A best guess of the curret posture of the device, based on instanataneous data.
|
||||
*/
|
||||
BasicGesture instantaneousPosture();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
/**
|
||||
* Class definition for MicroBit Accelerometer.
|
||||
*
|
||||
* Represents an implementation of the Freescale MMA8653 3 axis accelerometer
|
||||
* Also includes basic data caching and on demand activation.
|
||||
*/
|
||||
|
||||
* Class definition for MicroBit Accelerometer.
|
||||
*
|
||||
* Represents an implementation of the Freescale MMA8653 3 axis accelerometer
|
||||
* Also includes basic data caching and on demand activation.
|
||||
*/
|
||||
|
||||
#include "MicroBit.h"
|
||||
|
||||
/**
|
||||
* Configures the accelerometer for G range and sample rate defined
|
||||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
|
||||
*/
|
||||
* Configures the accelerometer for G range and sample rate defined
|
||||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
|
||||
*/
|
||||
int MicroBitAccelerometer::configure()
|
||||
{
|
||||
const MMA8653SampleRangeConfig *actualSampleRange;
|
||||
|
@ -50,7 +50,7 @@ int MicroBitAccelerometer::configure()
|
|||
result = writeCommand(MMA8653_CTRL_REG1, 0x00);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
|
||||
// Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
|
||||
result = writeCommand(MMA8653_CTRL_REG2, 0x10);
|
||||
if (result != 0)
|
||||
|
@ -70,7 +70,7 @@ int MicroBitAccelerometer::configure()
|
|||
result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
|
||||
// Bring the device back online, with 10bit wide samples at the requested frequency.
|
||||
result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
|
||||
if (result != 0)
|
||||
|
@ -80,31 +80,31 @@ int MicroBitAccelerometer::configure()
|
|||
}
|
||||
|
||||
/**
|
||||
* Issues a standard, 2 byte I2C command write to the accelerometer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to write to.
|
||||
* @param value The value to write.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
|
||||
*/
|
||||
* Issues a standard, 2 byte I2C command write to the accelerometer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to write to.
|
||||
* @param value The value to write.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
|
||||
*/
|
||||
int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t command[2];
|
||||
command[0] = reg;
|
||||
command[1] = value;
|
||||
|
||||
|
||||
return uBit.i2c.write(address, (const char *)command, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a read command into the specified buffer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to access.
|
||||
* @param buffer Memory area to read the data into.
|
||||
* @param length The number of bytes to read.
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
|
||||
*/
|
||||
* Issues a read command into the specified buffer.
|
||||
* Blocks the calling thread until complete.
|
||||
*
|
||||
* @param reg The address of the register to access.
|
||||
* @param buffer Memory area to read the data into.
|
||||
* @param length The number of bytes to read.
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
|
||||
*/
|
||||
int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
||||
{
|
||||
int result;
|
||||
|
@ -124,16 +124,16 @@ int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create an accelerometer representation with the given ID.
|
||||
* @param id the ID of the new object.
|
||||
* @param address the default base address of the accelerometer.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
|
||||
* @endcode
|
||||
*/
|
||||
* Constructor.
|
||||
* Create an accelerometer representation with the given ID.
|
||||
* @param id the ID of the new object.
|
||||
* @param address the default base address of the accelerometer.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY)
|
||||
{
|
||||
// Store our identifiers.
|
||||
|
@ -144,15 +144,15 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
|
|||
this->samplePeriod = 20;
|
||||
this->sampleRange = 2;
|
||||
|
||||
// Initialise gesture history
|
||||
this->sigma = 0;
|
||||
this->gesture = NONE;
|
||||
this->iGesture = NONE;
|
||||
this->shake.x = 0;
|
||||
this->shake.y = 0;
|
||||
this->shake.z = 0;
|
||||
this->shake.count = 0;
|
||||
this->shake.timer = 0;
|
||||
// Initialise gesture history
|
||||
this->sigma = 0;
|
||||
this->lastGesture = GESTURE_NONE;
|
||||
this->currentGesture = GESTURE_NONE;
|
||||
this->shake.x = 0;
|
||||
this->shake.y = 0;
|
||||
this->shake.z = 0;
|
||||
this->shake.count = 0;
|
||||
this->shake.timer = 0;
|
||||
|
||||
// Configure and enable the accelerometer.
|
||||
if (this->configure() == MICROBIT_OK)
|
||||
|
@ -160,14 +160,14 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
|
|||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the accelerometer.
|
||||
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.whoAmI();
|
||||
* @endcode
|
||||
*/
|
||||
* Attempts to determine the 8 bit ID from the accelerometer.
|
||||
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.whoAmI();
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitAccelerometer::whoAmI()
|
||||
{
|
||||
uint8_t data;
|
||||
|
@ -181,11 +181,11 @@ int MicroBitAccelerometer::whoAmI()
|
|||
}
|
||||
|
||||
/**
|
||||
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
|
||||
* This is called by the tick() member function, if the interrupt is set!
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the read request fails.
|
||||
*/
|
||||
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
|
||||
* This is called by the tick() member function, if the interrupt is set!
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the read request fails.
|
||||
*/
|
||||
int MicroBitAccelerometer::update()
|
||||
{
|
||||
int8_t data[6];
|
||||
|
@ -199,7 +199,7 @@ int MicroBitAccelerometer::update()
|
|||
sample.x = data[0];
|
||||
sample.y = data[2];
|
||||
sample.z = data[4];
|
||||
|
||||
|
||||
// Normalize the data in the 0..1024 range.
|
||||
sample.x *= 8;
|
||||
sample.y *= 8;
|
||||
|
@ -221,8 +221,8 @@ int MicroBitAccelerometer::update()
|
|||
sample.y *= this->sampleRange;
|
||||
sample.z *= this->sampleRange;
|
||||
|
||||
// Update gesture tracking
|
||||
updateGesture();
|
||||
// Update gesture tracking
|
||||
updateGesture();
|
||||
|
||||
// Indicate that a new sample is available
|
||||
MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
|
||||
|
@ -237,11 +237,11 @@ int MicroBitAccelerometer::update()
|
|||
*
|
||||
* @return the sum of the square of the acceleration of the device across all axes.
|
||||
*/
|
||||
int
|
||||
MicroBitAccelerometer::instantaneousAcceleration2()
|
||||
int
|
||||
MicroBitAccelerometer::instantaneousAccelerationSquared()
|
||||
{
|
||||
// Use pythagoras theorem to determine the combined force acting on the device.
|
||||
return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
|
||||
// Use pythagoras theorem to determine the combined force acting on the device.
|
||||
return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,105 +250,110 @@ MicroBitAccelerometer::instantaneousAcceleration2()
|
|||
*
|
||||
* @return A best guess of the current posture of the device, based on instantaneous data.
|
||||
*/
|
||||
BasicGesture
|
||||
BasicGesture
|
||||
MicroBitAccelerometer::instantaneousPosture()
|
||||
{
|
||||
int force = instantaneousAcceleration2();
|
||||
bool shakeDetected = false;
|
||||
int force = instantaneousAccelerationSquared();
|
||||
bool shakeDetected = false;
|
||||
|
||||
// Test for shake events.
|
||||
if ((sample.x < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (sample.x > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
|
||||
{
|
||||
shakeDetected = true;
|
||||
shake.x = !shake.x;
|
||||
}
|
||||
// Test for shake events.
|
||||
// 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
|
||||
// a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out).
|
||||
//
|
||||
// If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device
|
||||
// has been shaken.
|
||||
if ((sample.x < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (sample.x > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
|
||||
{
|
||||
shakeDetected = true;
|
||||
shake.x = !shake.x;
|
||||
}
|
||||
|
||||
if ((sample.y < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (sample.y > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
|
||||
{
|
||||
shakeDetected = true;
|
||||
shake.y = !shake.y;
|
||||
}
|
||||
if ((sample.y < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (sample.y > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
|
||||
{
|
||||
shakeDetected = true;
|
||||
shake.y = !shake.y;
|
||||
}
|
||||
|
||||
if ((sample.z < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (sample.z > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
|
||||
{
|
||||
shakeDetected = true;
|
||||
shake.z = !shake.z;
|
||||
}
|
||||
if ((sample.z < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (sample.z > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
|
||||
{
|
||||
shakeDetected = true;
|
||||
shake.z = !shake.z;
|
||||
}
|
||||
|
||||
if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
|
||||
shake.shaken = 1;
|
||||
|
||||
if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
|
||||
{
|
||||
shake.timer = 0;
|
||||
if (shake.count > 0)
|
||||
{
|
||||
if(--shake.count == 0)
|
||||
shake.shaken = 0;
|
||||
}
|
||||
}
|
||||
if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
|
||||
shake.shaken = 1;
|
||||
|
||||
if (shake.shaken)
|
||||
return SHAKE;
|
||||
if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
|
||||
{
|
||||
shake.timer = 0;
|
||||
if (shake.count > 0)
|
||||
{
|
||||
if(--shake.count == 0)
|
||||
shake.shaken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (force < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
|
||||
return FREEFALL;
|
||||
if (shake.shaken)
|
||||
return GESTURE_SHAKE;
|
||||
|
||||
if (force > MICROBIT_ACCELEROMETER_UNCONSCIOUS_THRESHOLD)
|
||||
return UNCONSCIOUS;
|
||||
if (force < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
|
||||
return FREEFALL;
|
||||
|
||||
if (force > MICROBIT_ACCELEROMETER_SICK_THRESHOLD)
|
||||
return SICK;
|
||||
if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
|
||||
return GESTURE_3G;
|
||||
|
||||
if (force > MICROBIT_ACCELEROMETER_WHEEE_THRESHOLD)
|
||||
return WHEEE;
|
||||
if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD)
|
||||
return GESTURE_6G;
|
||||
|
||||
// Determine our posture.
|
||||
if (sample.x < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return LEFT;
|
||||
if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD)
|
||||
return GESTURE_8G;
|
||||
|
||||
if (sample.x > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return RIGHT;
|
||||
// Determine our posture.
|
||||
if (sample.x < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return GESTURE_LEFT;
|
||||
|
||||
if (sample.y < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return DOWN;
|
||||
if (sample.x > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return GESTURE_RIGHT;
|
||||
|
||||
if (sample.y > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return UP;
|
||||
if (sample.y < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return GESTURE_DOWN;
|
||||
|
||||
if (sample.z < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return FACE_UP;
|
||||
if (sample.y > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return GESTURE_UP;
|
||||
|
||||
if (sample.z > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return FACE_DOWN;
|
||||
if (sample.z < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return GESTURE_FACE_UP;
|
||||
|
||||
return NONE;
|
||||
if (sample.z > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return GESTURE_FACE_DOWN;
|
||||
|
||||
return GESTURE_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MicroBitAccelerometer::updateGesture()
|
||||
{
|
||||
// Determine what it looks like we're doing based on the latest sample...
|
||||
BasicGesture g = instantaneousPosture();
|
||||
// Determine what it looks like we're doing based on the latest sample...
|
||||
BasicGesture g = instantaneousPosture();
|
||||
|
||||
// Perform some low pass filtering to remove hysteresis (data flapping) effects
|
||||
if (g == iGesture)
|
||||
{
|
||||
if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
|
||||
sigma++;
|
||||
}
|
||||
else
|
||||
{
|
||||
iGesture = g;
|
||||
sigma = 0;
|
||||
}
|
||||
// Perform some low pass filtering to reduce jitter from any detected effects
|
||||
if (g == currentGesture)
|
||||
{
|
||||
if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
|
||||
sigma++;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentGesture = g;
|
||||
sigma = 0;
|
||||
}
|
||||
|
||||
// If we've reached threshold, update our record and raise the relevant event...
|
||||
if (iGesture != gesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
|
||||
{
|
||||
gesture = iGesture;
|
||||
MicroBitEvent e(MICROBIT_ID_GESTURE, gesture);
|
||||
}
|
||||
// If we've reached threshold, update our record and raise the relevant event...
|
||||
if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
|
||||
{
|
||||
lastGesture = currentGesture;
|
||||
MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -396,50 +401,50 @@ int MicroBitAccelerometer::getRange()
|
|||
}
|
||||
|
||||
/**
|
||||
* Reads the X axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the X axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getX();
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the X axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the X axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getX();
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitAccelerometer::getX()
|
||||
{
|
||||
return sample.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Y axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Y axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getY();
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the Y axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Y axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getY();
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitAccelerometer::getY()
|
||||
{
|
||||
return sample.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Z axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Z axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getZ();
|
||||
* @endcode
|
||||
*/
|
||||
* Reads the Z axis value of the latest update from the accelerometer.
|
||||
* Currently limited to +/- 2g
|
||||
* @return The force measured in the Z axis, in milli-g.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.accelerometer.getZ();
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitAccelerometer::getZ()
|
||||
{
|
||||
return sample.z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the last recorded gesture detected.
|
||||
* @return The last gesture detected.
|
||||
|
@ -451,13 +456,13 @@ int MicroBitAccelerometer::getZ()
|
|||
*/
|
||||
BasicGesture MicroBitAccelerometer::getGesture()
|
||||
{
|
||||
return gesture;
|
||||
return lastGesture;
|
||||
}
|
||||
|
||||
/**
|
||||
* periodic callback from MicroBit clock.
|
||||
* Check if any data is ready for reading by checking the interrupt flag on the accelerometer
|
||||
*/
|
||||
* periodic callback from MicroBit clock.
|
||||
* Check if any data is ready for reading by checking the interrupt flag on the accelerometer
|
||||
*/
|
||||
void MicroBitAccelerometer::idleTick()
|
||||
{
|
||||
// Poll interrupt line from accelerometer.
|
||||
|
@ -468,8 +473,8 @@ void MicroBitAccelerometer::idleTick()
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
|
||||
*/
|
||||
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
|
||||
*/
|
||||
int MicroBitAccelerometer::isIdleCallbackNeeded()
|
||||
{
|
||||
return !int1;
|
||||
|
|
Loading…
Reference in a new issue