📜 ⬆️ ⬇️

Pebble: accelerometer, example of use

The accelerometer, which is used in Pebble is calibrated to measure acceleration within ± 4G, using API it is possible to obtain acceleration on three axes x, y and z in thousandths of G. Thus, the range of possible values ​​for each axis is from -4000 to 4000.
It is possible to set the frequency of data updating with the accelerometer in: 10, 25 (default), 50 and 100 Hz.

Below is about how to get data from the Pebble-built accelerometer and the extreme application of acquired knowledge.

The developers offer three separate ways to use the accelerometer [1] :


Tap Event Service


Using when the application needs to track down the fact that the user has shaken for hours or tapped them.
The event handler will generally look like:
')
static void tap_handler(AccelAxisType axis, int32_t direction) { } 

AccelAxisType axis - the axis along which the “tychek” occurred, the possible values ​​are ACCEL_AXIS_X , ACCEL_AXIS_Y , ACCEL_AXIS_Z .
int32_t direction - the direction of "poke" (-1 or +1). For the X axis, the positive direction is towards the right side of the clock, for Y it is the movement towards the top, for Z it is vertically up.

Subscribing to events, the tap_handler handler is called at every tap:

 accel_tap_service_subscribe(tap_handler); 


Data Event Service


Used to accumulate and analyze accelerometer data, the definition of a specific gesture or movement of the user.

The event handler will generally look like:

 static void data_handler(AccelData *data, uint32_t num_samples) { } 

AccelData * data - a set of data for all axes, plus a time stamp and a sign if the vibrator worked when receiving a set.
uint32_t num_samples - the number of sets in the buffer, from 0 to 25.

Subscribing to events, the data_handler handler is called each time a dataset is received.

 uint32_t num_samples = 3; accel_data_service_subscribe(num_samples, data_handler); 

And an example from the data processing documentation:

 static void data_handler(AccelData *data, uint32_t num_samples) { // Long lived buffer static char s_buffer[128]; // Compose string of all data for 3 samples snprintf(s_buffer, sizeof(s_buffer), "NX,Y,Z\n0 %d,%d,%d\n1 %d,%d,%d\n2 %d,%d,%d", data[0].x, data[0].y, data[0].z, data[1].x, data[1].y, data[1].z, data[2].x, data[2].y, data[2].z ); //Show the data text_layer_set_text(s_output_layer, s_buffer); } 


Service peek


Getting the latest saved values ​​of accelerometer indicators.

NB Cannot be used when subscribing to the Data Event Service .

At any given time, the call accel_service_peek allows you to read the latest data saved by the accelerometer.

Typical use:
 AccelData accel = (AccelData) { .x = 0, .y = 0, .z = 0 }; accel_service_peek(&accel); 


Determining the height of throwing hours


And, as a result, an example of an application that will determine how high the user does not mind throwing a clock.

The idea is not new at all, the first time I came across a similar one on the Nokia n900 [5] - the n900Fly toy. Then SMTH (Send Me To Heaven) appeared .

Application functionality:

In this case, neither the definition of tapes nor the analysis of data sets is used.
Without inventing a new one, to determine the moments of throwing and landing from the n900Fly:

We initialize the accelerometer, set the refresh rate to 25Hz and subscribe to a timer with an update interval of 20 milliseconds:
 #define ACCEL_STEP_MS 20 static void init(void) { /* ... */ accel_service_set_sampling_rate(ACCEL_SAMPLING_25HZ); accel_data_service_subscribe(0, NULL); timer = app_timer_register(ACCEL_STEP_MS, accel_callback, NULL); } 


Every 20 milliseconds, an accelerometer is polled, the average acceleration value is calculated and the state of the clock is determined:
 static void accel_callback(void *data) { AccelData accel = (AccelData) { .x = 0, .y = 0, .z = 0 }; accel_service_peek(&accel); //  if (( accel_abs(accel) < 400 ) && ( !iFlying)) { time_ms(&start.sec, &start.ms); iFlying = true; }; //  if ( (accel_abs(accel) > 500) && (iFlying) ) { time_ms(&end.sec, &end.ms); flightTime = flight_time(start, end); flightHeight = flight_height(flightTime); iFlying = false; layer_mark_dirty(s_layer); timer = app_timer_register(1000, accel_callback, NULL); return; } timer = app_timer_register(ACCEL_STEP_MS, accel_callback, NULL); } 

If we fix a touchdown, then we redraw the layer and delay the following access to the accelerometer data by 1 second, otherwise even a small bounce will be considered as a new throw.

Mathematical functions in the Pebble SDK are presented poorly. Therefore, to calculate the square root, an integer algorithm for calculating the inverse square root [6] , found on the Internet, is used:
 #define SQRT_MAGIC_F 0x5f3759df float my_sqrt(const float x) { const float xhalf = 0.5f*x; union { float x; int i; } u; ux = x; ui = SQRT_MAGIC_F - (ui >> 1); return x*ux*(1.5f - xhalf*ux*ux); } 


For the accuracy of the calculation of flight time, it is necessary to take into account milliseconds
 typedef struct time_with_ms { time_t sec; uint16_t ms; } time_with_ms; static time_with_ms start; static time_with_ms end; /* ... */ time_ms(&end.sec, &end.ms); /* ... */ time_ms(&start.sec, &start.ms); /* ... */ //     static uint32_t flight_time(time_with_ms start, time_with_ms end) { return ( (end.sec - start.sec)*1000 + end.ms - start.ms ); } 


And we consider the height at which the clock flies by the formula G * t ^ 2/2, where g = 9.8 m / s ^ 2:
 //     static uint32_t flight_height(uint32_t flightTime) { return (uint32_t)( 9.8 * ((flightTime/2)*(flightTime/2))/2 / 100 ); } 


Calculated flightTime and flightHeight, you can show them in any convenient way for the user:


Who is higher?

Full code of the application bitbucket / icanfly

Pebble App Store: I can fly

1. Pebble Developers // Detection Acceleration
2. Pebble Developers // Tap Event Service
3. Pebble Developers // Data Event Service
4. Pebble Developers // AccelerometerService
5. maemo.org - package overview for n900Fly
6. Wikipedia - Quick reverse square root

Source: https://habr.com/ru/post/250823/


All Articles