Thanks for the great help! I am currently testing out the vehicle.ai_set_script, which looks amazing. However, I also observe that you can control the vehicle through vehicle.control().
So I am wondering what is the relationship between the two? For the AI controller, is it in essence a PID controller or MPC or anything else? What is the underlying mechanisms to control the vehicle?
I am trying to tune a basic PID controller and plug it into vehicle.control(), but it seems that even after extensive tuning, I still could not get a performance as good as the AI controller.
But because I want to see the exact commands used to control the vehicle, is there any interface that exposes the actual commands to control the vehicle? I know we can read throttle and brake through the electric sensors, but it seems that there is no such reading for the steering input (I mean the actual steering input that we can put into vehicle.control, not the steering angle).
Is there a way that I can somehow replicate the AI controller? and get the commands and input them to vehicle.control() to produce the same vehicle behaviour?
Thank you so much for your help! Looking forward to your reply.
To access the steering input (in radians), you can use the following line of Lua code:
local steer = (electrics.values.steering or 0) * math.pi / 180
Please note that this value is derived from the vehicle’s electric system and is generally considered more of an output rather than a direct input.
For more accurate/raw steering input values, we recommend using the input module instead. For example:
input.steering
input.throttle
These values typically reflect the actual user or AI inputs directly and are not modified elsewhere in the code.
Regarding the AI steering behavior, it’s based on a spring-spline system (to paraphrase in simple terms). This approach makes it quite complex to replicate precisely in external scripts.
Please let us know if you’d like that or have any other questions!
Yes I am actually looking at the input level. For example, if I use vehicle.control(1, 1, 1), I know these are the values that I input into the system to drive the car. But since ai.set_script() directly takes in the waypoints, I am not sure how to access the corresponding inputs that correspond to the AI control.
If I understand correctly, the AI actually also uses the same underlying input system (hidden, not exposed at the python level) as in the vehicle.control() method? And the unified level where we can read the input is through
input.steering
input.throttle
In this way, for example, I have a circle and I pass this circle into vehicle.ai.set_script(), the vehicle will drive along the circle. If I read the values and save them somewhere, and later import these control commands back through vehicle.control(), would I be able to reproduce the behaviours of the AI controller?
it’s based on a spring-spline system
I see, so I guess this is more complicated than a MPC?
Thank you so much for your help! Really appreciate your patience and kindness!
Yes, you’re correct—when you pass waypoints to the AI via vehicle.ai.set_script(), the vehicle follows a trajectory generated dynamically. Under the hood, lateral control (steering) is managed by a pure pursuit controller, as you suspected—not Model Predictive Control (MPC). This controller handles real-time path tracking using a spring-spline-based navigation graph embedded in the map—think of it like an internal version of Google Maps. Longitudinal control (throttle and braking) uses a PID controller to match a target velocity derived from a velocity profile, which itself accounts for road curvature, predicted friction limits, dynamic obstacles, and desired acceleration comfort.
Reference: A great in-depth paper that helped shape this system is “Minimum Curvature Trajectory Planning and Control for an Autonomous Racecar” (Heilmeier et al., 2020).
To monitor the AI’s actual control outputs, use the Electrics sensor (e.g., throttle, brake, steering values). You can log these and later replay them with vehicle.control() to approximate AI behavior.
Thank you so much for the detailed reply! I think I have a solid understanding of it, and I have inspected the electrics sensor readings.
Initially I only saw the “steering”, “braking” and “throttle” field, but now I see that there is actually also an “X_input” field for each one of them. I suspect that is the reading I can save to reproduce the AI behaviour later through vehicle.control().
I will first give it a try, and also take a look at the paper you mentioned, and let you know if I have further questions.
Really appreciate all your help! BeamNG has been a really fascinating product and your team is so supportive, thank you very much!