Skip to content

Commit c5118de

Browse files
feat: cold start (initial roll and pitch calibration) (#94)
1 parent 6a2083c commit c5118de

7 files changed

Lines changed: 415 additions & 446 deletions

File tree

docs/user_guide/quickstart.rst

Lines changed: 63 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -14,42 +14,15 @@ long-term stable aiding measurements to ensure convergence and stability of the
1414
The aiding measurements are typically provided by a `global navigation satellite system`
1515
(GNSS) and a compass, providing absolute position, velocity, and heading information.
1616

17-
In scenarios where only compass aiding (but no GNSS) is available, the INS cannot provide
18-
reliable position and velocity information but still deliver stable attitude estimates.
19-
When the AINS is operated in this mode, we call it an `Attitude and Heading Reference System`
20-
(AHRS).
21-
22-
In aiding-denied scenarios, where no aiding measurements are available, the INS
23-
must rely solely on the IMU's measurements to estimate the body's motion. In such
24-
scenarios, only the roll and pitch degrees of freedom are observable, as they can
25-
still be corrected using the IMU's accelerometer data and the known direction of
26-
the gravitational field. When operated in this mode, the AINS is referred to as
27-
a `Vertical Reference Unit` (VRU).
28-
29-
``smsfusion`` provides Python implementations of a few INS algorithms, including:
30-
31-
* :class:`~smsfusion.AidedINS`: Aided INS (AINS) algorithm. Used to estimate position,
32-
velocity and attitude (PVA) using IMU data, GNSS data and compass data.
33-
* :class:`~smsfusion.AHRS`: AHRS wrapper around :class:`~smsfusion.AidedINS` with sane defaults.
34-
Used to estimate attitude only using IMU data and compass data.
35-
* :class:`~smsfusion.VRU`: VRU wrapper around :class:`~smsfusion.AidedINS` with sane defaults.
36-
Used to estimate roll and pitch only using IMU data.
37-
* :class:`~smsfusion.StrapdownINS`: Simple strapdown INS algorithm, where the
38-
IMU measurements are integrated without incorporating any additional aiding measurements.
39-
The state estimates will therefore drift over time and quickly diverge from their true values.
40-
This class is primarily used for PVA propagation in other aided INS algorithms.
41-
42-
All AINS algorithms in ``smsfusion`` are based on a fusion filtering technique known
43-
as the `multiplicative extended Kalman filter` (MEKF).
44-
45-
In this quickstart guide, we will demonstrate how to use the AINS algorithms
46-
available in ``smsfusion`` to estimate PVA of a moving body using IMU measurements
47-
and aiding measurements.
17+
``smsfusion`` provides Python implementations of a few AINS algorithms, including
18+
:class:`~smsfusion.AidedINS`, :class:`~smsfusion.AHRS` and :class:`~smsfusion.VRU`.
19+
In this quickstart guide we will demonstrate how to use these AINS algorithms to
20+
estimate PVA of a moving body using IMU measurements and aiding measurements.
4821

4922
Measurement data
5023
----------------
5124
This quickstart guide assumes that you have access to accelerometer and gyroscope
52-
data from an IMU sensor, and maybe position and heading data from other aiding
25+
data from an IMU sensor, and ideally position and heading data from other aiding
5326
sensors. If you do not have access to such data, you can generate synthetic
5427
measurements using the code provided here.
5528

@@ -108,8 +81,26 @@ For simpler cases where only compass or no aiding is available, consider using
10881
:func:`~smsfusion.benchmark.benchmark_pure_attitude_beat_202311A` instead to
10982
generate synthetic data.
11083

111-
Aided INS: Estimate position, velocity and attitude (PVA)
112-
---------------------------------------------------------
84+
INS algorithms
85+
--------------
86+
The following INS algorithms are provided by ``smsfusion``:
87+
88+
* :class:`~smsfusion.AidedINS`: Aided INS (AINS) algorithm. Used to estimate position,
89+
velocity and attitude (PVA) using IMU data, GNSS data and compass data.
90+
* :class:`~smsfusion.AHRS`: AHRS wrapper around :class:`~smsfusion.AidedINS` with sane defaults.
91+
Used to estimate attitude only using IMU data and compass data.
92+
* :class:`~smsfusion.VRU`: VRU wrapper around :class:`~smsfusion.AidedINS` with sane defaults.
93+
Used to estimate roll and pitch only using IMU data.
94+
* :class:`~smsfusion.StrapdownINS`: Simple strapdown INS algorithm, where the
95+
IMU measurements are integrated without incorporating any additional aiding measurements.
96+
The state estimates will therefore drift over time and quickly diverge from their true values.
97+
This class is primarily used for PVA propagation in other aided INS algorithms.
98+
99+
All AINS algorithms provided by ``smsfusion`` are based on a fusion filtering technique
100+
known as the `multiplicative extended Kalman filter` (MEKF).
101+
102+
AidedINS - IMU + heading and position aiding
103+
............................................
113104
If you have access to accelerometer and gyroscope data from an IMU sensor, as well
114105
as position and heading data from other aiding sensors, you can estimate the position,
115106
velocity and attitude (PVA) of a moving body using the :func:`~smsfusion.AidedINS` class:
@@ -120,16 +111,9 @@ velocity and attitude (PVA) of a moving body using the :func:`~smsfusion.AidedIN
120111
import smsfusion as sf
121112
122113
123-
# Initial (a priori) state
124-
p0 = pos[0] # position [m]
125-
v0 = vel[0] # velocity [m/s]
126-
q0 = sf.quaternion_from_euler(euler[0], degrees=False) # attitude as unit quaternion
127-
ba0 = np.zeros(3) # accelerometer bias [m/s^2]
128-
bg0 = np.zeros(3) # gyroscope bias [rad/s]
129-
x0 = np.concatenate((p0, v0, q0, ba0, bg0))
130-
131114
# Initialize AINS
132-
ains = sf.AidedINS(fs, x0)
115+
fs = 10.24 # sampling rate in Hz
116+
ains = sf.AidedINS(fs)
133117
134118
# Estimate PVA states sequentially using AINS
135119
pos_est, vel_est, euler_est = [], [], []
@@ -152,8 +136,13 @@ velocity and attitude (PVA) of a moving body using the :func:`~smsfusion.AidedIN
152136
vel_est = np.array(vel_est)
153137
euler_est = np.array(euler_est)
154138
155-
AHRS: Estimate attitude with compass-aiding
156-
-------------------------------------------
139+
AHRS - IMU + heading aiding
140+
...........................
141+
In scenarios where only compass aiding is available (i.e., no GNSS), the INS is
142+
unable to provide reliable position and velocity information, but it can still
143+
deliver stable attitude estimates. When the AINS is operated in this mode, we call
144+
it an `Attitude and Heading Reference System` (AHRS).
145+
157146
To limit integration drift in AHRS mode, we must assume that the sensor on average
158147
is stationary. The static assumtion is incorporated as so-called pseudo aiding measurements
159148
of zero with corresponding error variances. For most applications, the following pseudo
@@ -163,25 +152,18 @@ aiding is sufficient:
163152
* Velocity: 0 m/s with 10 m/s standard deviation
164153

165154
If you have access to accelerometer and gyroscope data from an IMU sensor and
166-
compass measurements, you can estimate the attitude of a moving body using
167-
the :func:`~smsfusion.AHRS` class:
155+
heading measurements from a compass, you can estimate the attitude of a moving body
156+
using the :func:`~smsfusion.AHRS` class:
168157

169158
.. code-block:: python
170159
171160
import numpy as np
172161
import smsfusion as sf
173162
174163
175-
# Initial (a priori) state
176-
p0 = np.zeros(3) # position [m]
177-
v0 = np.zeros(3) # velocity [m/s]
178-
q0 = sf.quaternion_from_euler(euler[0], degrees=False) # attitude as unit quaternion
179-
ba0 = np.zeros(3) # accelerometer bias [m/s^2]
180-
bg0 = np.zeros(3) # gyroscope bias [rad/s]
181-
x0 = np.concatenate((p0, v0, q0, ba0, bg0))
182-
183164
# Initialize AHRS
184-
ahrs = sf.AHRS(fs, x0)
165+
fs = 10.24 # sampling rate in Hz
166+
ahrs = sf.AHRS(fs)
185167
186168
# Estimate attitude sequentially using AHRS
187169
euler_est = []
@@ -198,8 +180,15 @@ the :func:`~smsfusion.AHRS` class:
198180
199181
euler_est = np.array(euler_est)
200182
201-
VRU: Estimate partial attitude in aiding-denied scenarios
202-
---------------------------------------------------------
183+
VRU - IMU only (aiding-denied)
184+
..............................
185+
In aiding-denied scenarios, where no aiding measurements are available, the INS
186+
must rely solely on the IMU's measurements to estimate the body's motion. In such
187+
scenarios only the roll and pitch degrees of freedom are observable, as they can
188+
still be corrected using the IMU's accelerometer data and the known direction of
189+
the gravitational field. When operated in this mode, the AINS is referred to as
190+
a `Vertical Reference Unit` (VRU).
191+
203192
To limit integration drift in VRU mode, we must assume that the sensor on average
204193
is stationary. The static assumption is incorporated as so-called pseudo aiding measurements
205194
of zero with corresponding error variances. For most applications, the following pseudo
@@ -221,25 +210,14 @@ estimate the roll and pitch degrees of freedom of a moving body using the
221210
import smsfusion as sf
222211
223212
224-
# Initial (a priori) state
225-
p0 = np.zeros(3) # position [m]
226-
v0 = np.zeros(3) # velocity [m/s]
227-
q0 = sf.quaternion_from_euler(euler[0], degrees=False) # attitude as unit quaternion
228-
ba0 = np.zeros(3) # accelerometer bias [m/s^2]
229-
bg0 = np.zeros(3) # gyroscope bias [rad/s]
230-
x0 = np.concatenate((p0, v0, q0, ba0, bg0))
231-
232213
# Initialize VRU
233-
vru = sf.VRU(fs, x0)
214+
fs = 10.24 # sampling rate in Hz
215+
vru = sf.VRU(fs)
234216
235217
# Estimate roll and pitch sequentially using VRU
236218
roll_pitch_est = []
237219
for f_i, w_i in zip(acc_imu, gyro_imu):
238-
vru.update(
239-
f_i,
240-
w_i,
241-
degrees=False
242-
)
220+
vru.update(f_i, w_i, degrees=False)
243221
roll_pitch_est.append(vru.euler(degrees=False)[:2])
244222
245223
roll_pitch_est = np.array(roll_pitch_est)
@@ -249,17 +227,17 @@ Smoothing
249227
---------
250228
Smoothing refers to post-processing techniques that enhance the accuracy of a Kalman
251229
filter's state and covariance estimates by incorporating both past and future measurements.
252-
In contrast, standard forward filtering (as implemented in :class:`~smsfusion.AidedINS`)
253-
relies only on past and current measurements, leading to suboptimal estimates when
254-
future data is available.
230+
In contrast, standard forward filtering (as provided by :class:`~smsfusion.AidedINS`,
231+
:class:`~smsfusion.AHRS` and :class:`~smsfusion.VRU`) relies only on past and current
232+
measurements, leading to suboptimal estimates when future data is available.
255233

256234
Fixed-interval smoothing
257235
........................
258236
The :class:`~smsfusion.FixedIntervalSmoother` class implements fixed-interval smoothing
259237
for an :class:`~smsfusion.AidedINS` instance or one of its subclasses (:class:`~smsfusion.AHRS`
260-
or :class:`~smsfusion.VRU`). After a complete forward pass using the AINS algorithm,
261-
a backward sweep with a smoothing algorithm is performed to refine the state
262-
and covariance estimates. Fixed-interval smoothing is particularly useful
238+
or :class:`~smsfusion.VRU`). After a complete forward pass using the given AINS
239+
algorithm, a backward sweep with a smoothing algorithm is performed to refine the
240+
state and covariance estimates. Fixed-interval smoothing is particularly useful
263241
when the entire measurement sequence is available, as it allows for optimal state
264242
estimation by considering all measurements in the sequence.
265243

@@ -274,13 +252,13 @@ additional aiding parameters depending on the type of AINS instance used.
274252
import smsfusion as sf
275253
276254
277-
vru_smoother = sf.FixedIntervalSmoother(vru)
255+
# Initialize VRU-based fixed-interval smoother
256+
fs = 10.24 # sampling rate in Hz
257+
smoother = sf.FixedIntervalSmoother(sf.VRU(fs))
278258
259+
# Update with accelerometer and gyroscope measurements
279260
for f_i, w_i in zip(acc_imu, gyro_imu):
280-
vru_smoother.update(
281-
f_i,
282-
w_i,
283-
degrees=False
284-
)
261+
smoother.update(f_i, w_i, degrees=False)
285262
286-
roll_pitch_est = vru_smoother.euler(degrees=False)[:, :2]
263+
# Get smoothed roll and pitch estimates
264+
roll_pitch_est = smoother.euler(degrees=False)[:, :2]

0 commit comments

Comments
 (0)