Page Example

Pedometer Sample Overview

Mobile native

The Pedometer sample demonstrates how to implement a simple pedometer (step counting) application using the Sensor and Location APIs. The data from the acceleration sensor is used to detect when the user takes a step, whereas the location position data is used to track the user movement and measure the walked distance as well as the average step length. If the feature is supported by the device, the application also uses the Activity Recognition API to detect when the user walks or runs and displays the activity type.

The following figure illustrates the application view.

Figure: Pedometer view

Pedometer view

The main window consists of the following areas:

  • GPS status area

    A label in the top left corner of the screen where the current GPS status is displayed.

  • Activity type area

    Displays the name of detected activity, which can be:

    • STATIONARY: when the user is not moving
    • WALK: when the user is walking
    • RUN: when the user is running
    • N/A: when such information is not available
  • Steps count area

    Displays the number of steps detected in the current session.

  • Steps length area

    Displays the average step length calculated based on the total walked distance and step count, in meters.

  • Total distance area

    Displays the total walked distance acquired from the GPS data, in meters.

  • Buttons area

    Consists of 2 buttons used to start and stop (pause) the application features.

If GPS is not enabled, the total distance and average step length are not calculated.

Prerequisites

  • To ensure proper application execution, the following privilege must be set:
    • http://tizen.org/privilege/location
  • To ensure proper application execution, the following features must be enabled:
    • http://tizen.org/feature/location
    • http://tizen.org/feature/location.gps
    • http://tizen.org/feature/sensor.accelerometer
    • http://tizen.org/feature/sensor.activity_recognition

Implementation

Activity Recognition Module

To check whether the activity recognition feature is supported on the current device, the activity_is_supported() function is invoked. If support is available, an activity_h handle is initialized and a callback function is registered by calling the activity_start_recognition() function. The function takes the activity_type_e enumerator as an argument (the STATIONARY, WALK and RUN values are supported). A new handle has to be created for each of them.

The registered callback function is invoked when a given activity type is detected.

activity_h *handle = NULL;
bool supported = false;

if (activity_is_supported(type, &supported) != ACTIVITY_ERROR_NONE || !supported) 
{
   // Error handling
}

if (activity_create(handle) != ACTIVITY_ERROR_NONE) 
{
   // Error handling
}

if (activity_start_recognition(*handle, type, activity_cb, NULL) != ACTIVITY_ERROR_NONE) 
{
   // Error handling
}

The same function is registered as a callback for each activity. It sets the activity type label based on the given type.

static void
activity_cb(activity_type_e type, const activity_data_h data, double timestamp, activity_error_e error, void *user_data)
{
   s_pedometer_info.activity_type = type;

   if (type == ACTIVITY_WALK) 
   {
      view_activity_type_set(WALK_STR);
   } 
   else if (type == ACTIVITY_RUN) 
   {
      view_activity_type_set(RUN_STR);
   } 
   else if (type == ACTIVITY_STATIONARY) 
   {
      view_activity_type_set(STATIONARY_STR);
   }
}

When the activity handles are no longer needed, they have to be stopped using the activity_stop_recognition() function and released using the activity_release() function.

if (s_pedometer_info.stationary_handle) 
{
   activity_stop_recognition(*s_pedometer_info.stationary_handle);
   activity_release(*s_pedometer_info.stationary_handle);
}

if (s_pedometer_info.walk_handle) 
{
   activity_stop_recognition(*s_pedometer_info.walk_handle);
   activity_release(*s_pedometer_info.walk_handle);
}

if (s_pedometer_info.run_handle) 
{
   activity_stop_recognition(*s_pedometer_info.run_handle);
   activity_release(*s_pedometer_info.run_handle);
}

Step Detection Module

The acceleration data from the accelerometer sensor is used in the step detection method. The method uses the average value of the accelerations on all 3 axes so that it does not matter how the device is oriented during the measurement.

When the application is launched, the acceleration sensor and listener are initialized:

  1. The sensor_is_supported() function is called to check whether the specified sensor is available on the currently used device.
  2. The default specific sensor handle is acquired using the sensor_get_default_sensor() function with SENSOR_ACCELEROMETER as the sensor type.
  3. A sensor listener is created with the acquired handle. Using the listener, a callback function is registered to be invoked when an acceleration sensor event occurs. The callback function is invoked every 200 milliseconds.
  4. To ensure that steps are detected and counted even if the screen is off or the power save mode is on, the sensor_listener_set_option() function is called to set the SENSOR_OPTION_ALWAYS_ON option for the created sensor listener.
bool
acceleration_sensor_handle_init(void)
{
   sensor_h sensor;
   bool supported = false;

   if (sensor_is_supported(SENSOR_ACCELEROMETER, &supported) != SENSOR_ERROR_NONE || !supported) 
   {
      // Error handling
   }

   if (sensor_get_default_sensor(SENSOR_ACCELEROMETER, &sensor) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }

   if (sensor_create_listener(sensor, &s_acc_data.acceleration_listener) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }

   if (sensor_listener_set_event_cb(s_acc_data.acceleration_listener, 200, accel_cb, NULL) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }

   if (sensor_listener_set_option(s_acc_data.acceleration_listener, SENSOR_OPTION_ALWAYS_ON) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }

   return true;
}

The acceleration sensor listener starts receiving acceleration events after the application start button is clicked and the sensor_listener_start() function is invoked.

When the stop button is clicked, step detection must be paused with the sensor_listener_stop() function. It stops the sensor server for the acceleration listener so that acceleration sensor events no longer occur. To restart the service, the sensor_listener_start() function must be called again.

if (s_acc_data.acceleration_listener) 
{
   if (sensor_listener_start(s_acc_data.acceleration_listener) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }
}

if (s_acc_data.acceleration_listener) 
{
   if (sensor_listener_stop(s_acc_data.acceleration_listener) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }
}

The actual step detection takes place in the accel_cb() callback function. To simplify the step detection regardless of the device orientation, the average acceleration value of the accelerations in all 3 dimensions is used.

When the service is started, the application registers the initial average acceleration value, which is used as a baseline for later measurements. This method is based on the assumption that the user is relatively stationary when starting the pedometer.

A step is registered when a significant change in the average acceleration value is detected, including sign inversion. The following figure shows a sample of average acceleration data together with the initial average acceleration value for reference. This data was acquired during a 10-step walk.

Figure: Average acceleration values during a 10-step walk

Average acceleration values during a 10-step walk

A step is registered when the average acceleration value "drop" occurs. In order to detect these drops, the initial average acceleration value is preserved together with the average acceleration value registered when the function was previously called. The initial value is reset every time the service is stopped.

A drop occurs when the previous value was greater than the initial value and the current value is smaller than the initial value by at least THRESHOLD m/s². When a step is detected, the step count is incremented and the GUI is updated.

static void
accel_cb(sensor_h sensor, sensor_event_s *event, void *data)
{
   // Get current average value of acceleration on 3 axes
   double current_acc_av = (event->values[1] + event->values[2] + event->values[3])/3;

   // If initial average acceleration value is not set, do it now
   if (s_acc_data.init_acc_av == MAX_ACCEL_INIT_VALUE) 
   {
      s_acc_data.init_acc_av = s_acc_data.prev_acc_av = current_acc_av;
		
      return;
   }

   // Register a drop of acceleration average value
   if ((s_acc_data.prev_acc_av > s_acc_data.init_acc_av && s_acc_data.init_acc_av - current_acc_av > THRESHOLD))
      view_steps_count_set(++s_acc_data.steps_count);

   s_acc_data.prev_acc_av = current_acc_av;
}

When the acceleration sensor listener is no longer needed, the sensor_destroy_listener() function is called to destroy the sensor handle and release all its resources.

if (s_acc_data.acceleration_listener) 
{
   if (sensor_destroy_listener(s_acc_data.acceleration_listener) != SENSOR_ERROR_NONE) 
   {
      // Error handling
   }

Distance Tracker Module

The distance tracker is initialized when the application is launched. It uses the location manager to receive position updates. In order to do so, a location manager is created using the location_manager_create() function with LOCATION_METHOD_GPS specified. The newly created location manager handle is then used to set a callback function for position updates. The pos_updated_cb() callback is invoked every 4 seconds.

// Create location manager and set callback for position updates
if (location_manager_create(LOCATIONS_METHOD_GPS, &s_tracker_data.location_manager) != LOCATIONS_ERROR_NONE) 
{
   // Error handling
}

if (location_manager_set_position_updated_cb(s_tracker_data.location_manager, pos_updated_cb, 4, NULL) != LOCATIONS_ERROR_NONE) 
{
   // Error handling
}

To start the location manager, the location_manager_start() function is used. It takes the location manager handle as an argument.

Similarly, to stop the location manager, the location_manager_stop() function is called.

void
distance_tracker_start(void)
{
   if (!s_tracker_data.location_manager && !distance_tracker_init()) 
   {
      // Error handling
   }

   if (location_manager_start(s_tracker_data.location_manager) != LOCATIONS_ERROR_NONE) 
   {
      // Error handling
   }
}

void
distance_tracker_stop(void)
{
   if (s_tracker_data.location_manager) 
   {
      if (location_manager_stop(s_tracker_data.location_manager) != LOCATIONS_ERROR_NONE) 
      {
         // Error handling
      }
   }
}

Before the location manager handle is initialized, the GPS status must be checked using the location_manager_is_enabled_method() function with LOCATION_METHOD_GPS as the first argument. A callback function is also set for GPS status changes so that the distance tracker can react properly and stop or start the service when necessary.

bool
distance_tracker_gps_check(void)
{
   bool gps_enabled = false;

   // Check whether GPS is enabled and set callback for GPS status updates
   if (location_manager_is_enabled_method(LOCATIONS_METHOD_GPS, &gps_enabled) != LOCATIONS_ERROR_NONE) 
   {
      // Error handling
   }

   if (location_manager_set_setting_changed_cb(LOCATIONS_METHOD_GPS, gps_status_changed_cb, NULL) != LOCATIONS_ERROR_NONE) 
   {
      // Error handling
   }

   if (!gps_enabled) 
   {
      // Error handling
   }

   view_gps_ok_text_set(gps_enabled);

   return true;
}

The total distance is calculated by comparing the newly received coordinates with the previously received ones. When the pos_updated_cb() function is called for the first time, the initial latitude and longitude are preserved so that the next time it is invoked, the distance can be calculated based on former and current location coordinates.

The location_manager_get_distance() function is used to calculate the distance between 2 sets of coordinates. The total distance is then incremented by the obtained value. After that, the current coordinates are saved as the previous values so the next time the callback function is invoked, only the distance between previous and currently registered position is added to the total distance. Also, the average step length is calculated based on the total distance value and steps count - a simple division to get the average value.

static void
pos_updated_cb(double latitude, double longitude, double altitude, time_t timestamp, void *data)
{
   int steps_count;
   double distance = 0;

   // If callback is called for the first time, set prev values
   if (s_tracker_data.prev_latitude == LAT_UNINITIATED && s_tracker_data.prev_longitude == LONG_UNINITIATED) 
   {
      s_tracker_data.prev_latitude = latitude;
      s_tracker_data.prev_longitude = longitude;
		
      return;
   }

   // Calculate distance between previous and current location data and update view
   if (location_manager_get_distance(latitude, longitude, s_tracker_data.prev_latitude,
                                     s_tracker_data.prev_longitude, &distance) != LOCATIONS_ERROR_NONE) 
   {
      // Error handling
   }

   s_tracker_data.total_distance += distance;
   view_total_distance_set(s_tracker_data.total_distance);

   // Set new prev values
   s_tracker_data.prev_latitude = latitude;
   s_tracker_data.prev_longitude = longitude;

   // Calculate and set step length if number of steps is greater than 0
   steps_count = acceleration_sensor_steps_count_get();

   if (steps_count)
      view_step_length_set(s_tracker_data.total_distance/steps_count);
}

When the location manager is no longer needed, it has to be released using the location_manager_destroy() function.

if (s_tracker_data.location_manager) 
{
   if (location_manager_destroy(s_tracker_data.location_manager) != LOCATIONS_ERROR_NONE) 
   {
      // Error handling
   }
}