Skip to content

TUMRT/steering_ff_control

Repository files navigation

Steering Feedforward Control for Autonomous Racing

Onboard cockpit view of the Dallara EAV24 at the Abu Dhabi circuit with the two feedforward steering angles annotated
Onboard of the Dallara EAV24 at the Abu Dhabi circuit. The feedforward controllers in this repo compute the feedforward steering command δff to track the desired trajectory provided by a high-level MPC.

Code accompanying the paper

Benchmarking Empirical and Learning-Based Approaches for Feedforward Steering Control in Autonomous Racing G. Jank, M. Piccinini, S. Wenk, P. Pitschi, J. Betz, B. Lohmann.

The repo contains the Python implementations used to fit / train the four feedforward steering controllers benchmarked in the paper, the open-loop evaluation harness, and a reference C++ port of the same controllers for ROS 2 deployment.

Name Type Python module C++ class
TAM baseline empirical (linear) tam_baseline_empirical_ff TamBaselineEmpiricalFF
EHD (proposed) empirical (polynomial surface) empirical_handling_diagram_ff EmpiricalHandlingDiagramFF
MS-NN model-structured neural network nnodely_ff NNodelyFF
LSTM recurrent neural network lstm_ff LstmFF

The C++ side builds standalone — its dependencies (tum_types_cpp, tum_helpers_cpp, param_management_cpp, tsl_logger_cpp, controller_helpers_cpp) are vendored under external/tam_common/. A ready-made ff_emulator CLI replays the paper test lap through any of the four FFs and writes per-sample predictions next to the measured steering, so users can verify the C++ matches the Python end-to-end without needing the closed-loop ROS 2 stack. See lat_acc_feedforward_cpp/README.md for the exact invocations.

Hierarchical control architecture: high-level MPC outputs acceleration targets that are tracked by decoupled longitudinal and lateral low-level controllers. The lateral controller has a feedforward-feedback structure; the FF block is what this repo replaces.
Where the feedforward block sits in the control stack; the four FFs in this repo are drop-in replacements for the highlighted block in this diagram.

Repository layout

.
├── config/                              # public ROS-style parameter YAMLs
├── data_analysis/                       # fitting / training / evaluation (Python)
│   ├── evaluate_ff_algorithms.py        # open-loop benchmark (paper Fig. 5–7)
│   ├── delay_estimation.py              # cross-correlation (paper Fig. 7 top)
│   ├── pyproject.toml
│   └── src/
│       ├── common/                      # PT1 filter
│       ├── interface/                   # FeedforwardBase + LearningFF base
│       ├── tam_baseline_empirical_ff/   # baseline
│       ├── empirical_handling_diagram_ff/  # EHD (proposed)
│       ├── nnodely_ff/                  # MS-NN
│       └── lstm_ff/                     # LSTM
├── lat_acc_feedforward_cpp/             # reference C++ port (ROS 2)
│   └── (incl. ff_emulator CLI for end-to-end replay)
├── external/tam_common/                 # vendored C++ dependencies
├── trained_models/                      # checkpoints + ONNX exports
├── data/example/                        # CSV laps used in the paper (training/test)
├── docs/images/                         # paper figures used by this README
└── LICENSE

Installation

Python 3.11 is required. The analysis stack uses PyTorch and nnodely.

cd data_analysis/src/lstm_ff && ./setup.sh && cd ../../..

setup.sh auto-detects an NVIDIA GPU via lspci and installs a matching PyTorch wheel; CPU-only is supported. Set CUDA_OVERRIDE=none|cu124|cu128 to skip autodetect.

After install, activate with:

source data_analysis/src/lstm_ff/venv/bin/activate

Usage

All commands below assume the venv is active and the working directory is data_analysis/.

1. Fit / train the feedforward controllers

Each script accepts one or more processed-CSV paths via --data.

# EHD — polynomial surface fit (a few seconds)
python -m src.empirical_handling_diagram_ff.empirical_handling_diagram_ff \
    --data ../data/example/training/*.csv

# MS-NN — nnodely-based model-structured NN
python -m src.nnodely_ff.nnodely_ff --data ../data/example/training/*.csv

# LSTM
python -m src.lstm_ff.lstm_ff --data ../data/example/training/*.csv

Each model writes a timestamped folder under trained_models/<ModelClass>/YYYY_MM_DD/HH_MM_SS/ containing the checkpoint, exported ONNX, loss curves, and (for EHD) a ROS 2 parameter YAML.

The TAM baseline has no training step — it reads its parameters directly from config/baseline_ff_config.yml together with config/vehicle_config.yml.

2. Open-loop benchmark

python evaluate_ff_algorithms.py \
    --data_path ../data/example/test/EAV24_A2RL_2026-02-12_15-20_lap_8.csv

Loads the checkpoints under trained_models/<…>/example/, computes RMSE / MAE / FVU for all four controllers, and writes the per-sample prediction plot, prediction-error plot, and the sign-corrected error vs. longitudinal acceleration (median + IQR) to --save_dir (default: data_analysis/logs/). A combined CSV with measured and predicted steering for every algorithm is saved alongside as model_comparison_results.csv.

Override --ehd_model_path, --msnn_model_path, --lstm_model_path to benchmark your own retraining runs.

Add --feature_importance to additionally compute mean-absolute SHAP values per input feature and time step for the two learning-based controllers (MS-NN and LSTM). The resulting shap_summary.svg, shap_importance_bar.svg, and shap_importance.csv are written into each model's own folder (next to the checkpoint), not into --save_dir. Uses 1000 random samples by default; expect several minutes per model.

3. Fine-tune the learning-based controllers

Both LSTM_NN and NNodelyFF support iterative fine-tuning on additional data with a reduced learning rate:

# LSTM
python src/lstm_ff/retrain.py \
    --model <path/to/previous/run> \
    --data  <new_lap.csv>

# MS-NN
python src/nnodely_ff/retrain.py \
    --model <path/to/previous/run> \
    --data  <new_lap.csv>

The MS-NN script copies the original model folder into a fresh timestamped output before resuming training; the LSTM script reloads weights into a new folder. Both write their fine-tuned model under trained_models/<ModelClass>/YYYY_MM_DD/HH_MM_SS/.

Reproducing the paper

The checkpoints committed under trained_models/*/example/ are the ones used to produce the paper figures. Re-training from scratch is not guaranteed bit-for-bit reproducible because PyTorch is not seeded globally; use the shipped checkpoints if you need the exact numbers in the paper.

End-to-end smoke test (open-loop benchmark on the paper's test lap):

cd data_analysis
python evaluate_ff_algorithms.py

Outputs land in data_analysis/logs/. The headline figure you should get back is the per-FF prediction-error / FVU table from the paper:

Sign-corrected steering-angle prediction error vs. longitudinal acceleration for the four feedforwards, plus an RMSE / MAE / FVU table. The learning-based methods reach the lowest open-loop error; the proposed EHD sits between them and the baseline.
Paper Fig. 5 — open-loop prediction error per FF on the test lap. The evaluator reproduces this plot and the underlying numbers.

C++ smoke test

Once the workspace builds (colcon build --packages-up-to lat_acc_feedforward_cpp), the ff_emulator binary can replay the same test lap through any of the four C++ FFs. Example for the empirical handling diagram:

source install/setup.bash
ros2 run lat_acc_feedforward_cpp ff_emulator \
    EmpiricalHandlingDiagram \
    data/example/test/EAV24_A2RL_2026-02-12_15-20_lap_8.csv \
    /tmp/ehd_pred.csv \
    --param config/vehicle_config.yml \
    --param trained_models/EmpiricalHandlingDiagramFF/example/config.yaml

Required arguments differ per FF (the neural FFs need only vehicle_config.yml; the empirical ones need their parameter YAML too). See lat_acc_feedforward_cpp/README.md for the per-FF table and the invocations for the other three FFs (EmpiricalBaseline, NNodely, LSTM).

Hardware

The reported numbers were produced on:

  • CPU: Intel-class workstation (any modern x86-64)
  • GPU: NVIDIA, CUDA 12.4 (training only; evaluation runs CPU-only)
  • OS: Ubuntu 22.04, Python 3.11
  • Approximate training time: EHD <1 min, MS-NN ~30 min, LSTM ~45 min on a single mid-range NVIDIA GPU.

Evaluation runs on CPU in under a minute.

Citation

Pre-print citation. Until the ITSC 2026 proceedings publish on IEEEXplore, you can find the accompanying paper on arXiv (arXiv:2605.21111). The BibTeX below will be updated with the IEEEXplore DOI as soon as it is available. Nevertheless please re-check if an IEEExplore DOI is available before submitting a paper that cites this code.

% TODO: once ITSC 2026 proceedings publish, replace with the IEEEXplore DOI.
@inproceedings{Jank2026,
  author        = {Jank, Georg and Piccinini, Mattia and Wenk, Sebastian and
                   Pitschi, Phillip and Betz, Johannes and Lohmann, Boris},
  title         = {Benchmarking Empirical and Learning-Based Approaches for
                   Feedforward Steering Control in Autonomous Racing},
  booktitle     = {Accepted to the 29th IEEE International Conference on Intelligent Transportation Systems (ITSC 2026)},
  year          = {2026},
  eprint        = {2605.21111},
  archivePrefix = {arXiv},
  doi           = {10.48550/arXiv.2605.21111}
}

Authors

License

Apache-2.0. See LICENSE.

This project includes code from TAM_common, which is licensed under the Apache License 2.0.

AI usage disclaimer. All scripts in this repository were designed and implemented manually by the author. AI tools (Claude Code) were used as assistants for code review and for applying mechanical clean-up edits (import deduplication, indentation, docstring style, refactoring duplicated blocks, implementing smoke tests). Algorithmic logic, model architectures, parameter choices, and experimental decisions are the author's own.

About

Code for the paper "Benchmarking Empirical and Learning-Based Approaches for Feedforward Steering Control in Autonomous Racing" (IEEE ITSC 2026).

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors