Author: Mohamed Elgouhary Affiliation: iCPS Lab, West Virginia University Project Type: ROS 2 Autonomous Racing Controller
This repository contains a ROS 2 Python implementation of a Linear Quadratic Regulator (LQR) controller for path tracking in F1TENTH-style autonomous racing.
The controller follows a precomputed raceline using a lateral kinematic vehicle model. It computes steering and speed commands based on lateral error, heading error, velocity error, and local track curvature.
Linear Quadratic Regulator control is a classical optimal-control method that is widely used for stabilizing dynamic systems. In autonomous racing, LQR can be used as a model-based path-tracking controller that balances tracking accuracy and control effort.
This repository provides an LQR-based controller that:
- Loads raceline waypoints from CSV files
- Computes lateral and heading errors relative to the reference path
- Uses a discrete-time LQR formulation for steering and speed control
- Publishes Ackermann drive commands
- Supports simulation and real-car topic configurations
- Publishes visualization markers for RViz
- Includes multiple raceline CSV files for different racing tracks
- ROS 2 Python implementation
- F1TENTH-compatible Ackermann drive output
- Lateral kinematic vehicle model
- Riccati-equation-based LQR gain computation
- Raceline tracking using nearest-waypoint projection
- Speed tracking based on reference raceline velocity
- RViz visualization of waypoints and vehicle front-axle point
- Support for multiple track CSV files
LQR/
├── README.md
└── src/
├── csv_data/
│ ├── Austin.csv
│ ├── Austin_fast.csv
│ ├── Catalunya_fast.csv
│ ├── Montreal_fast.csv
│ ├── Monza_fast.csv
│ ├── Spa_fast.csv
│ ├── YasMarina_fast.csv
│ └── ...
└── lqr_pkg/
├── package.xml
├── setup.py
├── setup.cfg
├── resource/
├── test/
└── lqr_pkg/
├── __init__.py
├── lqr.py
└── utils.py
| File | Description |
|---|---|
src/lqr_pkg/lqr_pkg/lqr.py |
Main ROS 2 LQR controller node |
src/lqr_pkg/lqr_pkg/utils.py |
Utility functions for waypoint processing and angle normalization |
src/lqr_pkg/setup.py |
ROS 2 Python package setup file |
src/lqr_pkg/package.xml |
ROS 2 package metadata and dependencies |
src/csv_data/ |
Raceline CSV files for different tracks |
The controller uses a lateral kinematic vehicle model with the following state-error representation:
x = [e_l, e_l_dot, e_theta, e_theta_dot, e_v]
where:
e_lis the lateral errore_l_dotis the lateral-error ratee_thetais the heading errore_theta_dotis the heading-error ratee_vis the velocity error
The LQR controller computes feedback commands using a discrete-time state-space model:
u = Kx
where the control output includes:
- Steering correction
- Speed correction
The final steering command combines:
- LQR feedback steering
- Curvature-based feedforward steering
This allows the vehicle to track the raceline while accounting for the local path curvature.
The controller uses the following topics by default:
| Type | Topic | Description |
|---|---|---|
| Input | /ego_racecar/odom |
Vehicle odometry in simulation |
| Input | /pf/viz/inferred_pose |
Estimated pose for real-car mode |
| Input | /pf/pose/odom |
Particle-filter odometry for real-car velocity |
| Output | /drive |
Ackermann steering and speed command |
| Output | /visualization_marker_array |
RViz visualization markers |
This package expects a ROS 2 environment with the following dependencies:
rclpystd_msgssensor_msgsgeometry_msgsnav_msgsackermann_msgsvisualization_msgstf2_ros
Python dependencies include:
numpyscipy
Depending on your setup, the package may also use:
cvxpynumba
Clone the repository into the src folder of your ROS 2 workspace:
cd ~/ros2_ws/src
git clone https://github.com/ICPS-LAB-WVU/LQR.gitBuild the workspace:
cd ~/ros2_ws
colcon build
source install/setup.bashAfter building and sourcing the workspace, run:
ros2 run lqr_pkg lqrYou should see output similar to:
Lateral Kinematic LQR Initialized
The node will subscribe to odometry, compute LQR-based steering and speed commands, and publish them to:
/drive
The controller loads raceline CSV files from:
src/csv_data/
The default map name in the code is:
Montreal_fast
This means the controller expects:
src/csv_data/Montreal_fast.csv
To use another track, modify the map_name variable in lqr.py, for example:
self.map_name = 'Catalunya_fast'Available track files include examples such as:
Austin_fast.csv
Catalunya_fast.csv
Hockenheim_fast.csv
Melbourne_fast.csv
MexicoCity_fast.csv
Montreal_fast.csv
Monza_fast.csv
Spa_fast.csv
YasMarina_fast.csv
The controller includes a flag for simulation or real-car operation:
self.is_real = FalseFor simulation, the controller uses:
/ego_racecar/odom
For real-car operation, the controller can use:
/pf/viz/inferred_pose
/pf/pose/odom
Before running on a real vehicle, carefully verify:
- Topic names
- Vehicle coordinate frames
- Wheelbase
- Speed limits
- Steering limits
- Raceline scaling
- Odometry direction
- Emergency stop behavior
- Start the F1TENTH simulator or real-car localization stack.
- Confirm that odometry or pose messages are being published.
- Select the desired raceline CSV file.
- Build and source the ROS 2 workspace.
- Run the LQR controller.
- Visualize waypoints and vehicle tracking behavior in RViz.
- Tune the LQR cost matrices if needed.
- Test at low speed before increasing the velocity profile.
Important parameters inside the controller include:
| Parameter | Description |
|---|---|
dt |
Controller time step |
wheelbase |
Vehicle wheelbase |
Q |
State-error cost matrix |
R |
Control-effort cost matrix |
map_name |
Selected raceline CSV file |
is_real |
Simulation or real-car mode |
The LQR cost matrices are defined in the LQRSolver class:
self.Q = np.diag([1.5, 0.5, 1.0, 0.5, 0.5])
self.R = np.diag([1, 1])Increasing values in Q generally makes the controller more aggressive in reducing tracking error. Increasing values in R generally penalizes control effort and can make the controller smoother.
The raceline CSV files are expected to contain waypoint information used by the controller, including:
- x-position
- y-position
- heading
- curvature
- reference velocity
The current implementation reads waypoint columns directly from the CSV file. If you use a custom raceline, make sure the column order matches the format expected in lqr.py.
This controller is intended for research and development. Before using it on physical hardware:
- Test first in simulation
- Start with low speeds
- Use an emergency stop
- Confirm steering direction
- Confirm odometry direction
- Verify the raceline is aligned with the map
- Check all ROS topic names
- Avoid running near people or obstacles during initial testing
This repository is developed and maintained by:
Mohamed Elgouhary PhD Student and Graduate Research Assistant Lane Department of Computer Science and Electrical Engineering West Virginia University
This repository is associated with autonomous vehicle and F1TENTH research at the iCPS Lab, West Virginia University.
For questions or collaboration, please contact:
Mohamed Elgouhary West Virginia University Email: mae00018@mix.wvu.edu