In this installment, I’d like to touch upon the new sensor API. This is only available in the NDK 2.0 and later and it replaced the old accelerometer API. Through this API, a developer would be able to query for the accelerometer, magnetometer, gyroscope (if there is one), temperature, light, etc. The list of supported hardware deceives is rather extensive and may not be supported on every BlackBerry device that is produced. This post will only deal with a few of these sensors.
Initialization is similar to that of the previous examples in this series. Request sensor events by calling sensor_request_events() and stop by calling sensor_stop_events().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
int main(int argc, char ** argv) { // Initialize BPS bps_initialize(); bps_set_verbosity(100); // Initialize events navigator_request_events(0); // Verify sensor availability bool accSup = sensor_is_supported(SENSOR_TYPE_ACCELEROMETER); bool magSup = sensor_is_supported(SENSOR_TYPE_MAGNETOMETER); bool gyrSup = sensor_is_supported(SENSOR_TYPE_GYROSCOPE); bool tmpSup = sensor_is_supported(SENSOR_TYPE_TEMPERATURE); bool litSup = sensor_is_supported(SENSOR_TYPE_LIGHT); sensor_request_events(SENSOR_TYPE_ACCELEROMETER); sensor_request_events(SENSOR_TYPE_MAGNETOMETER); // ... etc ... return 0; } |
Following initialization and verification of sensor availability, you would start the main event loop. To request events from a specific sensor, call sensor_request_events(). Once a BPS event is received, you can call sensor_get_domain() to determine whether it was a sensor event and bps_event_get_code() to determine the type of sensor event.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
while (true) { bps_event_t *ev = NULL; bps_get_event(&ev, -1); int iDomain = bps_event_get_domain(ev); uint16_t iCode = bps_event_get_code(ev); // Check for if (iDomain == sensor_get_domain()) { switch (iCode) { // .... handle event code here .... } } } |
The sensor event codes seem to be missing from the NDK reference webpage. However, they are available in the sensor.h header. The Magnetometer, Accelerometer, Gyroscope, Gravity and Linear Acceleration are all described in values of x, y, and z. However, in the case of the accelerometer and linear acceleration events, those values measure G forces. For the magnetometer, it is a magnetic field along a vector of [x, y, z]. For the gyroscope, the value is in radians per second. Lastly, for gravity, it’s the direction measured in meters per second squared.
1 2 3 4 5 6 7 8 9 |
float x, y, z; case SENSOR_ACCELEROMETER_READING: case SENSOR_MAGNETOMETER_READING: case SENSOR_GYROSCOPE_READING: case SENSOR_GRAVITY_READING: case SENSOR_LINEAR_ACCEL_READING: sensor_event_get_xyz(ev, &x, &y, &z); break; |
Similar to the above is the azimuth/pitch/roll sensor. Azimuth refers to the angle between magnetic north (not true north) and the y-axis, around the z-axis. If you require the azimuth relative to true north, you must apply magnetic declination manually. Pitch refers to the rotation around the x-axis, with positive values indicating that the z-axis is moving towards the y-axis. Roll refers to the rotation around the y-axis, with positive values indicating that the x-axis is moving toward the z-axis.
1 2 3 |
case SENSOR_AZIMUTH_PITCH_ROLL_READING: sensor_event_get_apr(event, &x, &y, &z); break; |
Probably the most useful sensor API are the two that generate a matrix and vector based on the physical rotations of the device. Both easily plug into OpenGL.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Vector is a struct of float[4] sensor_rotation_vector_t vector; // Matrix is a struct of float[3 * 3] sensor_rotation_matrix_t matrix; switch (iCode) { case SENSOR_ROTATION_VECTOR_READING: sensor_event_get_rotation_vector(event, &vector); break; case SENSOR_ROTATION_MATRIX_READING: sensor_event_get_rotation_matrix(event, &matrix); break; } |
There are more sensors that could be polled but, to keep this post brief, I’ll stop here. Before sensors can be used with any degree with accuracy, they need to be calibrated to a relative point. The relative point can change and so can the accuracy of the sensors due to floating point calculation errors and other factors. During the development of your application, consider writing a calibration step if you require a high degree of accuracy from these sensors. For most applications, this shouldn’t be a problem. According to the BPS reference documents, the device relies on background calibration during the use of the device to keep sensors calibrated.
Jeanniton Monero
Thank for sharing those codes.
I will appreciate a link for download them.