EKF and UKF implementations for 2D robot localization using simulated IMU and RTK data, written in C++ with Eigen library.
A robotic lawn mower running on a predefined path. Two sensors are available:
- IMU : acceleration and angular velocity.
- RTK-GPS (lower freq.): high accuracy position, but signal lost at corner
The goal is to fuse these two sensors to get accurate position estimates, especially during GPS outages.
State vector:
where
Motion model:
Observation model (GPS measures position directly):
Linearizes the motion model using the Jacobian.
State propagation — apply nonlinear function f(x, u):
Jacobian
Covariance matrix:
Innovation:
Covariance:
Kalman gain:
State update:
Covariance update:
Instead of linearizing the function, the UKF approximates the probability distribution using sigma points.
Step 1 — Generate 2n+1 = 9 sigma points:
L is the lower triangular matrix from Cholesky decomposition. Each column of L defines the direction and distance of sigma points from the mean.
Step 2 — Propagate each sigma point through the nonlinear model:
Each sigma point goes through the same motion model (with its own yaw value), so different points experience different cos/sin transformations.
Step 3 — Recover predicted mean and covariance:
Since the GPS observation model is linear (H just selects x and y from the state), the update step is the same as EKF. If the observation model were nonlinear, sigma points would also be used in the update step.
The data generator creates a ground truth trajectory and simulates sensor readings:
- Trajectory: straight 5m → right turn 90° (3s, ω = π/6 rad/s) → straight 5m
- IMU noise: white noise on acceleration (σ = 0.1 m/s²) and gyroscope (σ = 0.01 rad/s)
- GPS noise: Gaussian noise on position (σ = 0.03 m, simulating RTK-GPS)
- GPS dropout: configurable time window where GPS signal is lost (default: 4–9 seconds)
- Blue: ground truth trajectory
- Red dots: GPS measurements (absent during dropout period)
- Green dashed: EKF estimate
- Purple dotted: UKF estimate
During normal operation, both filters closely track the true trajectory. During GPS dropout, the filters rely on IMU, which drifts due to sensor noise. When GPS signal recovers, both filters quickly converge back to the true position.
- C++17 compiler
- CMake ≥ 3.14
- Eigen3
- Python 3 with numpy and matplotlib (for visualization)
mkdir build && cd build
cmake .. && make
cd ..
mkdir -p data
./build/kalman-mower
python3 scripts/plot.py data/ekf_output.csv data/ukf_output.csvOr simply:
./run.shkalman-mower/
├── CMakeLists.txt
├── README.md
├── run.sh
├── src/
│ ├── main.cpp
│ ├── data_generator.h/cpp
│ ├── ekf.h/cpp
│ └── ukf.h/cpp
├── scripts/
│ └── plot.py
└── data/
