Blog.

IBM AI Racing League: Empowering Tech Skills Through IBM Granite

Cover Image for IBM AI Racing League: Empowering Tech Skills Through IBM Granite
Sam Moss
Sam Moss

As part of a pilot challenge between a four-person team, the team was tasked with optimising an AI race car in a TORCS reinforcement learning environment, using Python and IBM Granite, with the objective of achieving the fastest possible standing start lap on the corkscrew race circuit. Think Formula 1 qualifying — but instead of beating rival teams on a weekend, we were competing against other universities, optimising code and excelling the performance of the AI driver to make the most out of the car.

The real challenge wasn’t what we were trying to achieve. It was deciding where performance actually comes from when the driver is software, whilst balancing stability to keep the car on track.

Setting Up

Setting up powerful hardware to host the latest IBM Granite models (4.0) locally using Ollama and additional tools for integration in Visual Studio Code, which demand significant hardware resources. Luckily, for this project, we had access to top-end hardware (incl. RTX 3090s), which proved excellent for hosting the Granite LLM locally.

Framing the Problem

With the task defined, the most challenging part was deciding where to start. The first day was deliberately research-heavy, focused on understanding where lap time is actually won.

That research phase was structured around IBM SkillsBuild courses, including Innovation with Design Thinking and AI, and was further sharpened by additional courses offered by IBM, ensuring clarity and a solid approach. But this also led to researching what cars need to do to maximise performance, and avoid time-penalising errors such as locking up the brakes, going off track, or losing traction control.

But before focusing on improving the time, the first step was to keep the car on track.

IBM AI Racer setup

Stability Before Speed

Keeping the car on track significantly compromised speed, but it provided much higher reliability and consistently completed laps without crashes or off-track failures. Using IBM Granite to prompt and understand how to improve the code, a more stable strategy was created by adding corner awareness, essentially slowing the car and adjusting steering input before making a high-risk turn. Fundamentally, steering was about keeping the car balanced, correcting early, smoothing inputs, and avoiding aggressive movements that would unsettle the car at speed.

And by doing so, we slowly had a reliable car — but also a slow one. Our first fully recorded lap time was 03:14:90, almost 2 minutes off pace. The cause of this had been the top speed, limited at 75 km/h, but a start to eventually greater performance, as on the same day, we were able to reach a quicker but non-perfect lap time of 02:25. Almost an entire minute above what we had earlier in the day.

The rest of the week had been spent optimising this time, improving the stability of gear changes and steering to make the car feel a lot smoother on track. Each improvement was incremental, but together they transformed how the car behaved on track. By the end of the week, this approach delivered a standing start lap time of 1:50:88 and a best lap time of 1:47:16, with no damage and a significantly higher top speed. However, there was still clear room for improvement: the AI wasn’t fully utilising the gearbox, and performance off a standing start remained weak due to intentional limitations designed to prevent wheel spin in the lower gears.

A Week of Minor Improvements

By the second week, we already had a car capable of going around the track; this was what we hoped to achieve by the end of the project, but achieving it in our first week gave us time to improve lap times lap by lap. We ran through a number of laps, jotted down the issues, and began making minor improvements. The focus from this point on was more on improving the car's standing-start performance (first lap) than on the best overall lap.

1. Improving the standing start launch

Due to code implemented to prevent the car from spinning out in lower gears, starting from a standing start resulted in a 3+ second delay in completing the lap. However, simply configuring code to regulate gear control to allow greater acceleration became a simple solution to save some time.

 if gear == 1:
        accel = min(accel, 0.80 + 0.20 * smoothstep(speed_x, 4.0, 20.0))
     elif gear == 2:
        accel = min(accel, 0.85 + 0.15 * smoothstep(speed_x, 10.0, 40.0))

By modifying the values of the restrictive throttle caps as shown above, the car would now achieve slight performance improvements without complex changes to the underlying control logic. This simple change alone had cut the first lap time from 1:50:88 to 1:50:19. A small improvement, but in a challenge like this, every tenth of a second counts.

2. Improving speeds on the final straight

Improving the time whilst keeping the car on track had proven difficult, with many failed prompts and manual edits to Python code and configuration. However, we considered reducing the 'risk' configuration once 1 minute and 41 seconds had elapsed, i.e., the time taken to pass the final bend on the first lap. This essentially meant that shortly after the final bend, the car could accelerate quickly, whilst having less concern about upcoming shallow turns (highlighted in red). This saved around half a second, resulting in a new standing-start best lap time of 1:49:58 (lap 1) and a new personal best lap of 1:46:63 (lap 2).

Map

3. Adjust and Optimise Configurations (Steering, Speed, etc)

Based on visual feedback from the car, how likely it was to go off track, and whether max speed could be increased, opportunities for further configuration became clear. Specifically, with every change, adjustments to all variables were required to avoid oversteer or understeer in certain parts of the track, even those that did not directly involve steering!

gh

These configurations are not aimed at improving a specific part of the circuit; they have further improved lap times to 1:48:49 standing start, showcasing again extremely strong performance without major additions to code.

The rest of the time was spent reflecting on results, writing up blogs and videos, and packaging deliverables for final submission.

The Final Straight

By the end of the project, the final system delivered a stable, competitive AI driver capable of completing clean laps at speed. What began as a car barely able to stay on track evolved into a controlled, reliable racer with a best lap time of 01:45:47 and a standing start best lap time of 1:48:49, achieved without damage and with consistent behaviour across laps.

More broadly, the project demonstrated how large language models like IBM Granite can be used not just as development aids but as active collaborators in the engineering process. Beyond explanation and refactoring, Granite was able to suggest informed improvements, challenge assumptions, and occasionally steer design decisions toward more effective outcomes, accelerating progress without replacing human judgment.

Interestingly, exactly one year before the project's deadline, I had the opportunity to visit the McLaren Technology Centre. That experience stuck with me. Not because of what I was doing there at the time, but because it reinforced why I take on technically demanding projects like this. They align directly with a long-term ambition to work in Formula 1. In that sense, this project achieved what I wanted it to and felt less like an academic exercise and more like a step in a much longer journey.

mcl

With that being said, I'd like to thank John McNamara for the invitation, the opportunity, and the challenge, as well as the wider IBM team for the tooling, resources, and support throughout: the lap time was the output, but the process was the real value. And that’s exactly the kind of work I want to keep doing.

Congratulations to the rest of the team at Bath Spa University, including Daniel Bunning, Billy Robjohn and Ethan Davies, on achieving a decent and competitive lap time, and thank you to Emily Barrett, Jake Hobbs, Coral Manton and Samuel Sturtivant for background support.

Result: Runner Up! 🏆