Library Integration for IMU - Measurement Integration
Integration Process
Gyroscopes measure the angular velocities in the three dimensions, meaning they provide the rate of change of the angle in time (radians/second). The integral of the velocity is the position; in this case, the position is the rotation angle at a specific time.
Along with the techniques, the research community has proposed work where the accelerometer can improve the angular measurements, reducing gyroscope biasing. Our library uses complementary integration as one of the integration techniques that allows the use of the accelerometer measurements if present.
The angular velocities coming from the gyroscope can be seen in the following plot:
The integration process leads to the quaternion representation of the angles. Transforming the resulting quaternions into the Euler angles leads to the following plot:
With this, we have all the angular data softened (filtered from high-frequency noise) and ready to use by the quaternion algorithms. The jump from negative to positive in the plot is just that the angle reached more than -180 degrees and changes sign given that is represented from -180 to 180 degrees. The angle represents the position of the entire system along the 3D space. It is convenient given that it does not require any special consideration about the physical environment.
Using the Integrator
Using the integrator involves having the sensor data as a vector of SensorPayload (more information in Preparing the IMU Measurements). Moreover, it involves having an initial position where the integration will start.
To create a new integrator, you can use the factory from IIntegrator.
// Load the Settings: auto settings = std::make_shared<IntegratorSettings>(); settings->enable_gyroscope = true; settings->enable_accelerometer = false; settings->enable_complementary = false; // Create the integrator auto integrator = IIntegrator::Build(kSimpleComplementaryIntegrator, settings);
The IntegrationSettings indicate the integrator the available data from the vector of SensorPayload.
Once the integrator is created, the starting time and the initial orientation are given to indicate where and when the integration starts.
// Initial orientation: In this case, it is 90 degrees in Y rvs::Quaternion<double> initial_orientation{0.70710678, 0, 0.70710678, 0}; // The time starts from 0: this assumption depends on the system and the temporal reference // It is recommended to use the first datum from the sensor uint64_t initial_time = 0; // Create the integrator integrator->Reset(initial_orientation, initial_time);
Once set the initial conditions, you can start using the integrator:
// Assume that the data arrives in packets of various elements // It depends on the system std::vector<SensorPayload> sensor_data; // Integrate std::vector<std::pair<Quaternion<Double>, uint64_t>> integrated; integrator->Apply(integrated, sensor_data);
The size of the vector integrated
will match the size of the input data sensor_data
. Moreover, the output is a vector of quaternions with a timestamp associated with it, which matches the timestamp of the sensor_data
.