Skip to content

Repository files navigation

VDSP

Simulation of a racecar in Angular/TS

Motivation

This project is for myself to learn a bit more physics and get more experience. The purpose of this web-app is to simulate a specified car around a user-created track.

These attributes are these at the moment:

  • Weight (Kg)
  • Engine Power output (Kw)
  • Drag Coefficient
  • Frontal area (width*height of the car in m2)
  • Tire grip (μ)
  • Downforce (N)
  • Final drive ratio (NOT YET WORKING)
  • Wheelbase (in meter NOT YET WORKING)
Képernyőkép 2026-07-29 130328

How to use (Inside powershell):

  1. Download the code using Git
git clone https://github.com/Aredarn/Vehicle-Dynamics-Simulation-Platform.git
  1. Install Node.JS
winget install nodejs
  1. Install Angular CLI:
npm install -g @angular/cli
  1. Navigate to code in terminal
cd C:\YOUR_FILE_LOCATION\Vehicle-Dynamics-Simulation-Platform
  1. start the server:
ng serve
  1. Open the webapp in a browser
http://localhost:4200

Formulas — How the Training Works

The AI isn't told how to drive. It's given a car, a track, and a score — then a genetic algorithm breeds better drivers over many generations.

Each generation runs the same loop:

population of neural networks
        ↓  each one drives the track in a physics simulation
trajectories + lap times
        ↓  each run is scored by the fitness function
ranked drivers
        ↓  best are kept, mutated and recombined
next generation

1. The Car — Physics

Every simulation step (1/30 s) resolves the forces on the car.

Longitudinal forces

N      = m·g + downforce                  (load pressing the tyres down)
F_drag = ½·ρ·Cd·A·v²                      (ρ = 1.225 kg/m³)
F_roll = 0.015·N
F_eng  = min(0.9·P/v · finalDrive/3.8, μ·Fz_rear) · throttle
a_x    = (F_eng − F_drag − F_roll − F_brake) / m

Weight transfer — braking pushes load onto the front axle, accelerating onto the rear (h = 0.5 m assumed CG height, L = wheelbase):

ΔFz      = m·a_x·h / L
Fz_front = N/2 − ΔFz
Fz_rear  = N/2 + ΔFz

This is what makes trail braking a real trade-off: braking into a corner loads the front tyre and buys grip for turn-in, but spends part of that tyre's budget on braking. Brake bias is 60% front.

The friction circle — each tyre has one grip budget shared between braking and cornering. Whatever a tyre spends going forwards, it can't spend turning:

F_lat_max = √(1 − (F_long / (μ·Fz))²) · μ·Fz          per axle
a_lat_max = (F_lat_front + F_lat_rear) / m

Rotation — the steering command asks for a yaw rate, and grip decides whether the car can deliver it:

ω = clamp(steer · 2.2 rad/s,  ±a_lat_max / v)
a_x' = a_x · √(1 − (a_lat_used / a_lat_max)²)

Ask for more rotation than grip allows and the car simply understeers instead.


2. The Reference Speed Profile

Before training, the optimizer computes a near-ideal speed for every point on the track. This becomes the speed limit the AI is judged against.

v_corner = √(a_lat_max / κ)               κ = curvature (1/radius)

Then two passes make it physically reachable — you can't accelerate or brake instantly:

forward  (from a standing start, v₀ = 0):
    vᵢ = min(vᵢ, √(vᵢ₋₁² + 2·a_accel·ds))

backward (so the car is already slowing for the next corner):
    vᵢ = min(vᵢ, √(vᵢ₊₁² + 2·a_brake·ds))

reference lap time = Σ ds / v_avg

3. The Driver — Neural Network

A small feed-forward network: 14 inputs → 12 hidden (tanh) → 3 outputs, giving (14+1)·12 + (12+1)·3 = 219 weights. That weight array is the genome.

Inputs (14)
5 distance sensors rays at −43°, −20°, 0°, +20°, +43°
current speed normalised to top speed
lateral offset distance from centreline
3 lookahead limits corner speed limits ahead, scaled by braking distance
lap progress how far around the lap
yaw rate how fast the car is rotating
grip usage how close the tyres are to the limit
bias constant 1
Outputs (3) Range
steering −1 … 1 (tanh)
throttle 0 … 1 (sigmoid)
brake 0 … 1 (sigmoid)

A single linear layer can't represent "brake hard while turning in, then release as you unwind the steering" — the hidden layer is what makes trail braking learnable.


4. The Score — Fitness

fitness = 10000 · progress                  how far around the lap
        +   400 · Δprogress                 momentum this step
        +   800 · gripUse · progress        reward for using the tyres when trail braking
        −    12 · lapTime                   go faster
        −  qualityPenalty                   driving errors (capped at 3000)
        −   200 · offTrackTime
        −  2000 · (1 − progress)            if it crashed
        + 12000 · min(3, refLap / lapTime)  if it finished

qualityPenalty collects the driving mistakes:

qualityPenalty = 3000 · avg(overspeed²)     carrying more speed than the corner allows
               +  150 · avg(edgeProximity)  light wall-scrape deterrent
               + 1200 · avg(backwards)      facing the wrong way
               +  400 · avg(yawExcess)      sliding / spinning

Two deliberate choices worth knowing:

  • The speed profile is a limit, not a target. Only exceeding it is punished. Being slower is already punished by lap time — penalising both would double-count it and punish accelerating away from the start line.
  • There is no "stay near the centreline" term. A racing line is defined by leaving the centreline: wide entry, clip the apex, open the exit, straighten a chicane into one line. Penalising lateral offset would reward tracing the track's curvature instead. Staying on the road is enforced by hard track limits; the line is shaped purely by lap time.

5. Evolution

Each generation of population P is rebuilt as:

Share Source
8% Elites — top performers copied unchanged
40% Refinement — small mutations of the top 20%, at four step sizes (σ × 0.25, 0.5, 1, 1.5)
5–15% Fresh random genomes for diversity
rest Crossover — uniform, each weight taken whole from one parent or the other

Mutation is Gaussian with σ = 0.12 (typical weight magnitude is ~0.25), with a 10% chance of a 5× jump to escape a local optimum:

w' = w + N(0, σ)          90% of the time
w' = w + N(0, 5σ)         10% of the time

The refinement band is what produces steady, incremental gains — without it the only route to a better driver is one lucky large mutation, which makes progress arrive in sudden jumps.

Stagnation — if the best fitness doesn't improve, exploration widens:

level = min(3, ⌊flatGenerations / 5⌋)

This raises mutation size and random injection, but only for the exploration band — refinement always stays fine-grained, and the level is capped. Local search has to stay local to work.

The best genome ever seen is always carried forward, so the champion can never be lost.


6. Track Limits

The track is 5 m from centreline to edge. Leaving it isn't an instant fail — it's a grip penalty, like running onto grass:

grip multiplier: 1.0 → 0.35 over the first 0.5 m beyond the edge

A car is retired when it's clearly gone:

  • more than 8 m beyond the edge (in the barriers), or
  • more than 1.5–2.5 s cumulative off-track (depends on the car)

Two guards keep scores honest:

  • Progress is capped at 1.4× the distance actually travelled, so cutting across a corner's apex can't claim track it never drove.
  • Crossing the finish counts as a lap if the car is within 6 m of the end and pointing forward — otherwise driving through the finish line would score as leaving the track.

Each generation gets 3× the reference lap time to finish (minimum 75 s), since a learning driver laps far off the ideal pace.


Tuning Cheat Sheet

Setting Effect
Population More drivers per generation = better coverage, slower generations
Generations More time to refine. Lap times keep improving long after the first completed lap
Mutation Higher = more exploration, noisier population. 0.2–0.45 is a sensible range

Larger and tighter tracks need noticeably more generations — the AI must survive every corner before it can start optimising the line through them.

About

Angular webapp to train a ML vehicle on a user specified track. Rudimentary side project of mine to learn Reinforced learning.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages