pebble/devsite/source/_guides/events-and-services/compass.md
2025-02-24 18:58:29 -08:00

7 KiB
Raw Permalink Blame History

title description guide_group order related_docs related_examples
Compass How to use data from the Compass API to determine direction. events-and-services 3
CompassService
title url
Feature Compass https://github.com/pebble-examples/feature-compass
title url
Official Compass Watchapp https://github.com/pebble-hacks/pebble-compass

The CompassService combines data from Pebble's accelerometer and magnetometer to automatically calibrate the compass and produce a CompassHeading, containing an angle measured relative to magnetic north.

The compass service provides magnetic north and information about its status and accuracy through the CompassHeadingData structure.

Calibration

The compass service requires an initial calibration before it can return accurate results. Calibration is performed automatically by the system when first required. The compass_status field indicates whether the compass service is calibrating. To help the calibration process, the app should show a message to the user asking them to move their wrists in different directions.

Refer to the compass example for an example of how to implement this screen.

Magnetic North and True North

Depending on the user's location on Earth, the measured heading towards magnetic north and true north can significantly differ. This is due to magnetic variation, also known as 'declination'.

Pebble does not automatically correct the magnetic heading to return a true heading, but the API is designed so that this feature can be added in the future and the app will be able to automatically take advantage of it.

For a more precise heading, use the magnetic_heading field of CompassHeadingData and use a webservice to retrieve the declination at the user's current location. Otherwise, use the true_heading field. This field will contain the magnetic_heading if declination is not available, or the true heading if declination is available. The field is_declination_valid will be true when declination is available. Use this information to tell the user whether the app is showing magnetic north or true north.

Declination illustrated

To see the true extent of declination, see how declination has changed over time.

Battery Considerations

Using the compass will turn on both Pebble's magnetometer and accelerometer. Those two devices will have a slight impact on battery life. A much more significant battery impact will be caused by redrawing the screen too often or performing CPU-intensive work every time the compass heading is updated.

Use compass_service_subscribe() if the app only needs to update its UI when new compass data is available, or else use compass_service_peek() if this happens much less frequently.

Defining "Up" on Pebble

Compass readings are always relative to the current orientation of Pebble. Using the accelerometer, the compass service figures out which direction the user is facing.

Compass Orientation

The best orientation to encourage users to adopt while using a compass-enabled watchapp is with the top of the watch parallel to the ground. If the watch is raised so that the screen is facing the user, the plane will now be perpedicular to the screen, but still parallel to the ground.

Angles and Degrees

The magnetic heading value is presented as a number between 0 and TRIG_MAX_ANGLE (65536). This range is used to give a higher level of precision for drawing commands, which is preferable to using only 360 degrees.

If you imagine an analogue clock face on your Pebble, the angle 0 is always at the 12 o'clock position, and the magnetic heading angle is calculated in a counter clockwise direction from 0.

This can be confusing to grasp at first, as its opposite of how direction is measured on a compass, but it's simple to convert the values into a clockwise direction:

int clockwise_angle = TRIG_MAX_ANGLE - heading_data.magnetic_heading;

Once you have an angle relative to North, you can convert that to degrees using the helper function TRIGANGLE_TO_DEG():

int degrees = TRIGANGLE_TO_DEG(TRIG_MAX_ANGLE - heading_data.magnetic_heading);

Subscribing to Compass Data

Compass heading events can be received in a watchapp by subscribing to the CompassService:

// Subscribe to compass heading updates
compass_service_subscribe(compass_heading_handler);

The provided CompassHeadingHandler function (called compass_heading_handler above) can be used to read the state of the compass, and the current heading if it is available. This value is given in the range of 0 to TRIG_MAX_ANGLE to preserve precision, and so it can be converted using the TRIGANGLE_TO_DEG() macro:

static void compass_heading_handler(CompassHeadingData heading_data) {
  // Is the compass calibrated?
  switch(heading_data.compass_status) {
    case CompassStatusDataInvalid:
      APP_LOG(APP_LOG_LEVEL_INFO, "Not yet calibrated.");
      break;
    case CompassStatusCalibrating:
      APP_LOG(APP_LOG_LEVEL_INFO, "Calibration in progress. Heading is %ld",
                TRIGANGLE_TO_DEG(TRIG_MAX_ANGLE - heading_data.magnetic_heading));
      break;
    case CompassStatusCalibrated:
      APP_LOG(APP_LOG_LEVEL_INFO, "Calibrated! Heading is %ld",
                TRIGANGLE_TO_DEG(TRIG_MAX_ANGLE - heading_data.magnetic_heading));
      break;
  }
}

By default, the callback will be triggered whenever the heading changes by one degree. To reduce the frequency of updates, change the threshold for heading changes by setting a heading filter:

// Only notify me when the heading has changed by more than 5 degrees.
compass_service_set_heading_filter(DEG_TO_TRIGANGLE(5));

Unsubscribing From Compass Data

When the app is done using the compass, stop receiving callbacks by unsubscribing:

compass_service_unsubscribe();

Peeking at Compass Data

To fetch a compass heading without subscribing, simply peek to get a single sample:

// Peek to get data
CompassHeadingData data;
compass_service_peek(&data);

Similar to the subscription-provided data, the app should examine the peeked CompassHeadingData to determine if it is valid (i.e. the compass is calibrated).