Home | History | Annotate | Download | only in mllite
      1 /*
      2  $License:
      3     Copyright (C) 2011-2012 InvenSense Corporation, All Rights Reserved.
      4     See included License.txt for License information.
      5  $
      6  */
      7 
      8 /**
      9  *   @defgroup  HAL_Outputs hal_outputs
     10  *   @brief     Motion Library - HAL Outputs
     11  *              Sets up common outputs for HAL
     12  *
     13  *   @{
     14  *       @file  hal_outputs.c
     15  *       @brief HAL Outputs.
     16  */
     17 
     18 #include <string.h>
     19 
     20 #include "hal_outputs.h"
     21 #include "log.h"
     22 #include "ml_math_func.h"
     23 #include "mlmath.h"
     24 #include "start_manager.h"
     25 #include "data_builder.h"
     26 #include "results_holder.h"
     27 
     28 struct hal_output_t {
     29     int accuracy_mag;    /**< Compass accuracy */
     30 //    int accuracy_gyro;   /**< Gyro Accuracy */
     31 //    int accuracy_accel;  /**< Accel Accuracy */
     32     int accuracy_quat;   /**< quat Accuracy */
     33 
     34     inv_time_t nav_timestamp;
     35     inv_time_t gam_timestamp;
     36 //    inv_time_t accel_timestamp;
     37     inv_time_t mag_timestamp;
     38     long nav_quat[4];
     39     int gyro_status;
     40     int accel_status;
     41     int compass_status;
     42     int nine_axis_status;
     43     inv_biquad_filter_t lp_filter[3];
     44     float compass_float[3];
     45 };
     46 
     47 static struct hal_output_t hal_out;
     48 
     49 /** Acceleration (m/s^2) in body frame.
     50 * @param[out] values Acceleration in m/s^2 includes gravity. So while not in motion, it
     51 *             should return a vector of magnitude near 9.81 m/s^2
     52 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
     53 * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
     54 *             inv_build_accel().
     55 * @return     Returns 1 if the data was updated or 0 if it was not updated.
     56 */
     57 int inv_get_sensor_type_accelerometer(float *values, int8_t *accuracy,
     58                                        inv_time_t * timestamp)
     59 {
     60     int status;
     61     /* Converts fixed point to m/s^2. Fixed point has 1g = 2^16.
     62      * So this 9.80665 / 2^16 */
     63 #define ACCEL_CONVERSION 0.000149637603759766f
     64     long accel[3];
     65     inv_get_accel_set(accel, accuracy, timestamp);
     66     values[0] = accel[0] * ACCEL_CONVERSION;
     67     values[1] = accel[1] * ACCEL_CONVERSION;
     68     values[2] = accel[2] * ACCEL_CONVERSION;
     69     if (hal_out.accel_status & INV_NEW_DATA)
     70         status = 1;
     71     else
     72         status = 0;
     73     return status;
     74 }
     75 
     76 /** Linear Acceleration (m/s^2) in Body Frame.
     77 * @param[out] values Linear Acceleration in body frame, length 3, (m/s^2). May show
     78 *             accel biases while at rest.
     79 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
     80 * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
     81 *             inv_build_accel().
     82 * @return     Returns 1 if the data was updated or 0 if it was not updated.
     83 */
     84 int inv_get_sensor_type_linear_acceleration(float *values, int8_t *accuracy,
     85         inv_time_t * timestamp)
     86 {
     87     long gravity[3], accel[3];
     88 
     89     inv_get_accel_set(accel, accuracy, timestamp);
     90     inv_get_gravity(gravity);
     91     accel[0] -= gravity[0] >> 14;
     92     accel[1] -= gravity[1] >> 14;
     93     accel[2] -= gravity[2] >> 14;
     94     values[0] = accel[0] * ACCEL_CONVERSION;
     95     values[1] = accel[1] * ACCEL_CONVERSION;
     96     values[2] = accel[2] * ACCEL_CONVERSION;
     97 
     98     return hal_out.nine_axis_status;
     99 }
    100 
    101 /** Gravity vector (m/s^2) in Body Frame.
    102 * @param[out] values Gravity vector in body frame, length 3, (m/s^2)
    103 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
    104 * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
    105 *             inv_build_accel().
    106 * @return     Returns 1 if the data was updated or 0 if it was not updated.
    107 */
    108 int inv_get_sensor_type_gravity(float *values, int8_t *accuracy,
    109                                  inv_time_t * timestamp)
    110 {
    111     long gravity[3];
    112     int status;
    113 
    114     *accuracy = (int8_t) hal_out.accuracy_quat;
    115     *timestamp = hal_out.nav_timestamp;
    116     inv_get_gravity(gravity);
    117     values[0] = (gravity[0] >> 14) * ACCEL_CONVERSION;
    118     values[1] = (gravity[1] >> 14) * ACCEL_CONVERSION;
    119     values[2] = (gravity[2] >> 14) * ACCEL_CONVERSION;
    120     if ((hal_out.accel_status & INV_NEW_DATA) || (hal_out.gyro_status & INV_NEW_DATA))
    121         status = 1;
    122     else
    123         status = 0;
    124     return status;
    125 }
    126 
    127 /* Converts fixed point to rad/sec. Fixed point has 1 dps = 2^16.
    128  * So this is: pi / 2^16 / 180 */
    129 #define GYRO_CONVERSION 2.66316109007924e-007f
    130 
    131 /** Gyroscope calibrated data (rad/s) in body frame.
    132 * @param[out] values Rotation Rate in rad/sec.
    133 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
    134 * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
    135 *             inv_build_gyro().
    136 * @return     Returns 1 if the data was updated or 0 if it was not updated.
    137 */
    138 int inv_get_sensor_type_gyroscope(float *values, int8_t *accuracy,
    139                                    inv_time_t * timestamp)
    140 {
    141     long gyro[3];
    142     int status;
    143 
    144     inv_get_gyro_set(gyro, accuracy, timestamp);
    145     values[0] = gyro[0] * GYRO_CONVERSION;
    146     values[1] = gyro[1] * GYRO_CONVERSION;
    147     values[2] = gyro[2] * GYRO_CONVERSION;
    148     if (hal_out.gyro_status & INV_NEW_DATA)
    149         status = 1;
    150     else
    151         status = 0;
    152     return status;
    153 }
    154 
    155 /** Gyroscope raw data (rad/s) in body frame.
    156 * @param[out] values Rotation Rate in rad/sec.
    157 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
    158 * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
    159 *             inv_build_gyro().
    160 * @return     Returns 1 if the data was updated or 0 if it was not updated.
    161 */
    162 int inv_get_sensor_type_gyroscope_raw(float *values, int8_t *accuracy,
    163                                    inv_time_t * timestamp)
    164 {
    165     long gyro[3];
    166     int status;
    167 
    168     inv_get_gyro_set_raw(gyro, accuracy, timestamp);
    169     values[0] = gyro[0] * GYRO_CONVERSION;
    170     values[1] = gyro[1] * GYRO_CONVERSION;
    171     values[2] = gyro[2] * GYRO_CONVERSION;
    172     if (hal_out.gyro_status & INV_NEW_DATA)
    173         status = 1;
    174     else
    175         status = 0;
    176     return status;
    177 }
    178 
    179 /**
    180 * This corresponds to Sensor.TYPE_ROTATION_VECTOR.
    181 * The rotation vector represents the orientation of the device as a combination
    182 * of an angle and an axis, in which the device has rotated through an angle @f$\theta@f$
    183 * around an axis {x, y, z}. <br>
    184 * The three elements of the rotation vector are
    185 * {x*sin(@f$\theta@f$/2), y*sin(@f$\theta@f$/2), z*sin(@f$\theta@f$/2)}, such that the magnitude of the rotation
    186 * vector is equal to sin(@f$\theta@f$/2), and the direction of the rotation vector is
    187 * equal to the direction of the axis of rotation.
    188 *
    189 * The three elements of the rotation vector are equal to the last three components of a unit quaternion
    190 * {x*sin(@f$\theta@f$/2), y*sin(@f$\theta@f$/2), z*sin(@f$\theta@f$/2)>. The 4th element is cos(@f$\theta@f$/2).
    191 *
    192 * Elements of the rotation vector are unitless. The x,y and z axis are defined in the same way as the acceleration sensor.
    193 * The reference coordinate system is defined as a direct orthonormal basis, where:
    194 
    195     -X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points East).
    196     -Y is tangential to the ground at the device's current location and points towards the magnetic North Pole.
    197     -Z points towards the sky and is perpendicular to the ground.
    198 * @param[out] values Length 4.
    199 * @param[out] accuracy Accuracy 0 to 3, 3 = most accurate
    200 * @param[out] timestamp Timestamp. In (ns) for Android.
    201 * @return     Returns 1 if the data was updated or 0 if it was not updated.
    202 */
    203 int inv_get_sensor_type_rotation_vector(float *values, int8_t *accuracy,
    204         inv_time_t * timestamp)
    205 {
    206     *accuracy = (int8_t) hal_out.accuracy_quat;
    207     *timestamp = hal_out.nav_timestamp;
    208 
    209     if (hal_out.nav_quat[0] >= 0) {
    210         values[0] = hal_out.nav_quat[1] * INV_TWO_POWER_NEG_30;
    211         values[1] = hal_out.nav_quat[2] * INV_TWO_POWER_NEG_30;
    212         values[2] = hal_out.nav_quat[3] * INV_TWO_POWER_NEG_30;
    213         values[3] = hal_out.nav_quat[0] * INV_TWO_POWER_NEG_30;
    214     } else {
    215         values[0] = -hal_out.nav_quat[1] * INV_TWO_POWER_NEG_30;
    216         values[1] = -hal_out.nav_quat[2] * INV_TWO_POWER_NEG_30;
    217         values[2] = -hal_out.nav_quat[3] * INV_TWO_POWER_NEG_30;
    218         values[3] = -hal_out.nav_quat[0] * INV_TWO_POWER_NEG_30;
    219     }
    220     values[4] = inv_get_heading_confidence_interval();
    221 
    222     return hal_out.nine_axis_status;
    223 }
    224 
    225 
    226 /** Compass data (uT) in body frame.
    227 * @param[out] values Compass data in (uT), length 3. May be calibrated by having
    228 *             biases removed and sensitivity adjusted
    229 * @param[out] accuracy Accuracy 0 to 3, 3 = most accurate
    230 * @param[out] timestamp Timestamp. In (ns) for Android.
    231 * @return     Returns 1 if the data was updated or 0 if it was not updated.
    232 */
    233 int inv_get_sensor_type_magnetic_field(float *values, int8_t *accuracy,
    234                                         inv_time_t * timestamp)
    235 {
    236     int status;
    237     /* Converts fixed point to uT. Fixed point has 1 uT = 2^16.
    238      * So this is: 1 / 2^16*/
    239 //#define COMPASS_CONVERSION 1.52587890625e-005f
    240     int i;
    241 
    242     *timestamp = hal_out.mag_timestamp;
    243     *accuracy = (int8_t) hal_out.accuracy_mag;
    244 
    245     for (i=0; i<3; i++)  {
    246         values[i] = hal_out.compass_float[i];
    247     }
    248     if (hal_out.compass_status & INV_NEW_DATA)
    249         status = 1;
    250     else
    251         status = 0;
    252     return status;
    253 }
    254 
    255 static void inv_get_rotation(float r[3][3])
    256 {
    257     long rot[9];
    258     float conv = 1.f / (1L<<30);
    259 
    260     inv_quaternion_to_rotation(hal_out.nav_quat, rot);
    261     r[0][0] = rot[0]*conv;
    262     r[0][1] = rot[1]*conv;
    263     r[0][2] = rot[2]*conv;
    264     r[1][0] = rot[3]*conv;
    265     r[1][1] = rot[4]*conv;
    266     r[1][2] = rot[5]*conv;
    267     r[2][0] = rot[6]*conv;
    268     r[2][1] = rot[7]*conv;
    269     r[2][2] = rot[8]*conv;
    270 }
    271 
    272 static void google_orientation(float *g)
    273 {
    274     float rad2deg = (float)(180.0 / M_PI);
    275     float R[3][3];
    276 
    277     inv_get_rotation(R);
    278 
    279     g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg;
    280     g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg;
    281     g[2] = asinf ( R[2][0])          * rad2deg;
    282     if (g[0] < 0)
    283         g[0] += 360;
    284 }
    285 
    286 
    287 /** This corresponds to Sensor.TYPE_ORIENTATION. All values are angles in degrees.
    288 * @param[out] values Length 3, Degrees.<br>
    289 *        - values[0]: Azimuth, angle between the magnetic north direction
    290 *         and the y-axis, around the z-axis (0 to 359). 0=North, 90=East, 180=South, 270=West<br>
    291 *        - values[1]: Pitch, rotation around x-axis (-180 to 180), with positive values
    292 *         when the z-axis moves toward the y-axis.<br>
    293 *        - values[2]: Roll, rotation around y-axis (-90 to 90), with positive
    294 *          values when the x-axis moves toward the z-axis.<br>
    295 *
    296 * @note  This definition is different from yaw, pitch and roll used in aviation
    297 *        where the X axis is along the long side of the plane (tail to nose).
    298 *        Note: This sensor type exists for legacy reasons, please use getRotationMatrix()
    299 *        in conjunction with remapCoordinateSystem() and getOrientation() to compute
    300 *        these values instead.
    301 *        Important note: For historical reasons the roll angle is positive in the
    302 *        clockwise direction (mathematically speaking, it should be positive in
    303 *        the counter-clockwise direction).
    304 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
    305 * @param[out] timestamp The timestamp for this sensor.
    306 * @return     Returns 1 if the data was updated or 0 if it was not updated.
    307 */
    308 int inv_get_sensor_type_orientation(float *values, int8_t *accuracy,
    309                                      inv_time_t * timestamp)
    310 {
    311     *accuracy = (int8_t) hal_out.accuracy_quat;
    312     *timestamp = hal_out.nav_timestamp;
    313 
    314     google_orientation(values);
    315 
    316     return hal_out.nine_axis_status;
    317 }
    318 
    319 /** Main callback to generate HAL outputs. Typically not called by library users.
    320 * @param[in] sensor_cal Input variable to take sensor data whenever there is new
    321 * sensor data.
    322 * @return Returns INV_SUCCESS if successful or an error code if not.
    323 */
    324 inv_error_t inv_generate_hal_outputs(struct inv_sensor_cal_t *sensor_cal)
    325 {
    326     int use_sensor = 0;
    327     long sr = 1000;
    328     long compass[3];
    329     int8_t accuracy;
    330     int i;
    331     (void) sensor_cal;
    332 
    333     inv_get_quaternion_set(hal_out.nav_quat, &hal_out.accuracy_quat,
    334                            &hal_out.nav_timestamp);
    335     hal_out.gyro_status = sensor_cal->gyro.status;
    336     hal_out.accel_status = sensor_cal->accel.status;
    337     hal_out.compass_status = sensor_cal->compass.status;
    338 
    339     // Find the highest sample rate and tie generating 9-axis to that one.
    340     if (sensor_cal->gyro.status & INV_SENSOR_ON) {
    341         sr = sensor_cal->gyro.sample_rate_ms;
    342         use_sensor = 0;
    343     }
    344     if ((sensor_cal->accel.status & INV_SENSOR_ON) && (sr > sensor_cal->accel.sample_rate_ms)) {
    345         sr = sensor_cal->accel.sample_rate_ms;
    346         use_sensor = 1;
    347     }
    348     if ((sensor_cal->compass.status & INV_SENSOR_ON) && (sr > sensor_cal->compass.sample_rate_ms)) {
    349         sr = sensor_cal->compass.sample_rate_ms;
    350         use_sensor = 2;
    351     }
    352     if ((sensor_cal->quat.status & INV_SENSOR_ON) && (sr > sensor_cal->quat.sample_rate_ms)) {
    353         sr = sensor_cal->quat.sample_rate_ms;
    354         use_sensor = 3;
    355     }
    356 
    357     // Only output 9-axis if all 9 sensors are on.
    358     if (sensor_cal->quat.status & INV_SENSOR_ON) {
    359         // If quaternion sensor is on, gyros are not required as quaternion already has that part
    360         if ((sensor_cal->accel.status & sensor_cal->compass.status & INV_SENSOR_ON) == 0) {
    361             use_sensor = -1;
    362         }
    363     } else {
    364         if ((sensor_cal->gyro.status & sensor_cal->accel.status & sensor_cal->compass.status & INV_SENSOR_ON) == 0) {
    365             use_sensor = -1;
    366         }
    367     }
    368 
    369     switch (use_sensor) {
    370     case 0:
    371         hal_out.nine_axis_status = (sensor_cal->gyro.status & INV_NEW_DATA) ? 1 : 0;
    372         hal_out.nav_timestamp = sensor_cal->gyro.timestamp;
    373         break;
    374     case 1:
    375         hal_out.nine_axis_status = (sensor_cal->accel.status & INV_NEW_DATA) ? 1 : 0;
    376         hal_out.nav_timestamp = sensor_cal->accel.timestamp;
    377         break;
    378     case 2:
    379         hal_out.nine_axis_status = (sensor_cal->compass.status & INV_NEW_DATA) ? 1 : 0;
    380         hal_out.nav_timestamp = sensor_cal->compass.timestamp;
    381         break;
    382     case 3:
    383         hal_out.nine_axis_status = (sensor_cal->quat.status & INV_NEW_DATA) ? 1 : 0;
    384         hal_out.nav_timestamp = sensor_cal->quat.timestamp;
    385         break;
    386     default:
    387         hal_out.nine_axis_status = 0; // Don't output quaternion related info
    388         break;
    389     }
    390 
    391     /* Converts fixed point to uT. Fixed point has 1 uT = 2^16.
    392      * So this is: 1 / 2^16*/
    393     #define COMPASS_CONVERSION 1.52587890625e-005f
    394 
    395     inv_get_compass_set(compass, &accuracy, &(hal_out.mag_timestamp) );
    396     hal_out.accuracy_mag = (int ) accuracy;
    397 
    398     for (i=0; i<3; i++) {
    399         if ((sensor_cal->compass.status & (INV_NEW_DATA | INV_CONTIGUOUS)) ==
    400                                                              INV_NEW_DATA )  {
    401             // set the state variables to match output with input
    402             inv_calc_state_to_match_output(&hal_out.lp_filter[i], (float ) compass[i]);
    403         }
    404 
    405         if ((sensor_cal->compass.status & (INV_NEW_DATA | INV_RAW_DATA)) ==
    406                                          (INV_NEW_DATA | INV_RAW_DATA)   )  {
    407 
    408             hal_out.compass_float[i] = inv_biquad_filter_process(&hal_out.lp_filter[i],
    409                                            (float ) compass[i]) * COMPASS_CONVERSION;
    410 
    411         } else if ((sensor_cal->compass.status & INV_NEW_DATA) == INV_NEW_DATA )  {
    412             hal_out.compass_float[i] = (float ) compass[i] * COMPASS_CONVERSION;
    413         }
    414 
    415     }
    416     return INV_SUCCESS;
    417 }
    418 
    419 /** Turns off generation of HAL outputs.
    420 * @return Returns INV_SUCCESS if successful or an error code if not.
    421  */
    422 inv_error_t inv_stop_hal_outputs(void)
    423 {
    424     inv_error_t result;
    425     result = inv_unregister_data_cb(inv_generate_hal_outputs);
    426     return result;
    427 }
    428 
    429 /** Turns on generation of HAL outputs. This should be called after inv_stop_hal_outputs()
    430 * to turn generation of HAL outputs back on. It is automatically called by inv_enable_hal_outputs().
    431 * @return Returns INV_SUCCESS if successful or an error code if not.
    432 */
    433 inv_error_t inv_start_hal_outputs(void)
    434 {
    435     inv_error_t result;
    436     result =
    437         inv_register_data_cb(inv_generate_hal_outputs,
    438                              INV_PRIORITY_HAL_OUTPUTS,
    439                              INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);
    440     return result;
    441 }
    442 /* file name: lowPassFilterCoeff_1_6.c */
    443 float compass_low_pass_filter_coeff[5] =
    444 {+2.000000000000f, +1.000000000000f, -1.279632424998f, +0.477592250073f, +0.049489956269f};
    445 
    446 /** Initializes hal outputs class. This is called automatically by the
    447 * enable function. It may be called any time the feature is enabled, but
    448 * is typically not needed to be called by outside callers.
    449 * @return Returns INV_SUCCESS if successful or an error code if not.
    450 */
    451 inv_error_t inv_init_hal_outputs(void)
    452 {
    453     int i;
    454     memset(&hal_out, 0, sizeof(hal_out));
    455     for (i=0; i<3; i++)  {
    456         inv_init_biquad_filter(&hal_out.lp_filter[i], compass_low_pass_filter_coeff);
    457     }
    458 
    459     return INV_SUCCESS;
    460 }
    461 
    462 /** Turns on creation and storage of HAL type results.
    463 * @return Returns INV_SUCCESS if successful or an error code if not.
    464 */
    465 inv_error_t inv_enable_hal_outputs(void)
    466 {
    467     inv_error_t result;
    468 
    469 	// don't need to check the result for inv_init_hal_outputs
    470 	// since it's always INV_SUCCESS
    471 	inv_init_hal_outputs();
    472 
    473     result = inv_register_mpl_start_notification(inv_start_hal_outputs);
    474     return result;
    475 }
    476 
    477 /** Turns off creation and storage of HAL type results.
    478 */
    479 inv_error_t inv_disable_hal_outputs(void)
    480 {
    481     inv_error_t result;
    482 
    483     inv_stop_hal_outputs(); // Ignore error if we have already stopped this
    484     result = inv_unregister_mpl_start_notification(inv_start_hal_outputs);
    485     return result;
    486 }
    487 
    488 /**
    489  * @}
    490  */
    491