Note
This repo serves as an educational tool to learn about IMU sensor fusion while also functioning as a sensor fusion toolbox for implementation on real devices. Please feel free to offer suggestions or comments about the functionality and documentation. Any feedback is greatly appreciated!
Background
Installation
Development
Usage
References
The following sections cover the necessary mathematical to cover the fusion process of the IMU data.
A general 3D rotation matrix can be obtained from these three matrices using matrix multiplication. For example, the product:
represents a rotation whose yaw, pitch, and roll angles are
Important
It is clear from looking at the last row of this matrix, that the yaw angle (
Warning
Gimbal Lock: when the pitch angle becomes +/- 90 degrees, the second and third elements of that row are always zero. This means that no change in roll will have an affect on the orientation.
When dealing with rotation matrices and angular velocities, we can find the updated rotation matrices by calculating the matrix exponential. 2
where
and
where
Since
where the exponential of a diagonal matrix is computed as:
Thus, the final result is:
To install the library run: pip install imu_fusion_py
- Install Poetry
make init
to create the virtual environment and install dependenciesmake format
to format the code and check for errorsmake test
to run the test suitemake clean
to delete the temporary files and directoriespoetry publish --build
to build and publish to https://pypi.org/project/lie_groups_py/
"""Basic docstring for my module."""
import matplotlib.pyplot as plt
import numpy as np
from loguru import logger
from se3_group import se3
def main() -> None:
"""Run a simple demonstration."""
pose_0 = se3.SE3(
xyz=np.array([0.0, 0.0, 0.0]),
rot=np.eye(3),
)
pose_1 = se3.SE3(
xyz=np.array([[2.0], [4.0], [8.0]]),
roll_pitch_yaw=np.array([np.pi / 2, np.pi / 4, np.pi / 8]),
)
logger.info(f"Pose 1: {pose_0}")
logger.info(f"Pose 2: {pose_1}")
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
pose_0.plot(ax)
pose_1.plot(ax)
for t in np.arange(0.0, 1.01, 0.1):
pose_interp = se3.interpolate(pose_1, pose_0, t=t)
pose_interp.plot(ax)
logger.info(f"Interpolated Pose at t={t:.2f}: {pose_interp}")
plt.axis("equal")
ax.set_xlabel("x-axis")
ax.set_ylabel("y-axis")
ax.set_zlabel("z-axis")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()