Акселорометр, который используется в Pebble откалиброван для измерения ускорения в пределах ± 4G, через API возможно получение ускорения по трем осям x, y и z в тысячных долях G. Таким образом диапазон возможных значений для каждой оси от -4000 до 4000.
Есть возможность установить частоту обновления данных акселерометром в: 10, 25 (по умолчанию), 50 и 100 Hz.
Ниже о том, как получать данные встроенного в Pebble акселерометра и экстремальное применение приобретенных знаний.
Разработчики предлагают три обособленных способа использования акселерометра [1]:
- Tap Event Service — реакция приложения на резкое движение часов. [2]
- Data Event Service — получение всех данных акселерометра. [3]
- Service Peek — интерактивное получение данных.[4]
Tap Event Service
Используетя когда приложению нужно отследить факт того, что пользователь потряс часами или постучал по ним.
Обработчик события в общем случае будет выглядеть, как:
static void tap_handler(AccelAxisType axis, int32_t direction) {
}
AccelAxisType axis — ось по которой произошел «тычек», возможные значения ACCEL_AXIS_X, ACCEL_AXIS_Y, ACCEL_AXIS_Z.
int32_t direction — направление «тычка» (-1 или +1). Для оси X положительное направление к правой части часов, для Y — движение к верхней части, для Z — вертикально вверх.
Подписка на события, обработчик tap_handler вызывается при каждом tap'е:
accel_tap_service_subscribe(tap_handler);
Data Event Service
Используется для накопления и анализа данных акселерометра, определение конкретного жеста или движения пользователя.
Обработчик события в общем случае будет выглядеть, как:
static void data_handler(AccelData *data, uint32_t num_samples) {
}
AccelData *data — набор данных для всех осей, плюс таймштамп и признак работал ли вибродвигатель при получении набора.
uint32_t num_samples — количество наборов в буфере, от 0 до 25.
Подписка на события, обработчик data_handler вызывается каждый раз при получении набора данных.
uint32_t num_samples = 3;
accel_data_service_subscribe(num_samples, data_handler);
И пример из документации обработки данных:
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),
"N X,Y,Zn0 %d,%d,%dn1 %d,%d,%dn2 %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
Получение последних сохраненных значений показателей акселерометра.
N.B. Использование невозможно при подписке на Data Event Service.
В любой момент времени вызов accel_service_peek позволяет прочитать последние данные сохраненные акселерометром.
Типовое использование:
AccelData accel = (AccelData) { .x = 0, .y = 0, .z = 0 };
accel_service_peek(&accel);
Определение высоты подбрасывания часов
И, как результат, пример приложения, которое определят насколько высоко пользователю не жалко подбросить часы.
Идея совершенно не новая, в первый раз я столкнулся с подобным на Nokia n900 [5] — игрушка n900Fly. Потом появилось S.M.T.H (Send Me To Heaven).
Функциональность приложения:
- определение состояние полета часов;
- определение времени полета и расчет высоты;
- отображение последнего результата подкидывания
В данном случае ни определение тапа, ни анализ наборов данных не используем.
Не выдумывая нового, спооб определения моментов бросания и приземления из n900Fly:
- расчитывается средний вектор ускорения, как sqrt(x^2+y^2+z^2);
- если вектор становится меньше 400 — момент отрыва;
- если вектор становится больше 500 — момент приземления.
Инициализируем акселерометр, устанавливаем частоту обновления в 25Hz и подписываемся на таймер с интервалом обновления 20 милисекунд:
#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);
}
Раз в 20 милисекунд проходит опрос акселерометра, расчитывается среднее значение ускорения и определяется состояние часов:
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);
}
Если фиксируем приземление, то перерисовываем слой и задерживаем следующие обращение к данным акселерометра на 1 с, иначе даже маленький отскок посчитается как новый бросок.
Математические функции в Pebble SDK представлены скудно. Поэтому для вычисления квадратного корня используется целочисленный алгоритм вычисления обратного квадратного корня [6], найденный на просторах Интернета:
#define SQRT_MAGIC_F 0x5f3759df
float my_sqrt(const float x) {
const float xhalf = 0.5f*x;
union {
float x;
int i;
} u;
u.x = x;
u.i = SQRT_MAGIC_F - (u.i >> 1);
return x*u.x*(1.5f - xhalf*u.x*u.x);
}
Для точности расчета времени полета необходимо учитывать милисекунды:
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 );
}
А высоту на которую подлетают часы считаем по формуле G*t^2/2, где g=9.8 м/с^2:
// Высота полета в мм
static uint32_t flight_height(uint32_t flightTime) {
return (uint32_t)( 9.8 * ((flightTime/2)*(flightTime/2))/2 / 100 );
}
Посчитаны flightTime и flightHeight, можно их показать любым удобным для пользователя способом:
Кто выше?
Полный код приложения bitbucket/icanfly
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. Википедия — Быстрый обратный квадратный корень
Автор: tmnhy