Nonlinear Model Predictive Self-Driving Car

Over the last few days, I have been working on a self-driving car on ROBLOX. Part of this experiment was to see how well ROBLOX physics could be characterized by traditional real-life physics: turns out it’s not that bad.

Information for the technically inclined, this system works through a “Model Predictive” control strategy. Essentially, a mathematical “model” which simulates how the car behaves given initial states (x, y, velocity, angle) and input states (throttle, steering). A program then picks the best steering and throttle values in order to keep the car moving at a high-velocity while still remaining on the track and not crashing. I decided to use this method over more naive control strategies for a few reasons:

1: prevents the need to laboriously “tune” your system.
2: works really well when it works.
3: is much more interesting than throwing PID and playing with numbers until it moves (lots of internet folk love PID for some reason)
4: this is what is used in industry to handle challenging control problems. companies like Tesla and Waymo usually use embedded MPC with some sort of adaptive system-identification in order to control their cars.
5: because I can. (and it’s a good way to learn python)

The optimization system is computationally intensive, as you are solving a large nonlinear non-convex optimization problem. In order to solve the problem real-time, data about the car state is sent to a local server on my computer. The server (written in Python) then sends the data off to the IPOPT solver. This data is then returned to the server. This entire pipeline is faster than attempting to perform the mathematical optimization in Lua. If enough people are interested in advanced controls or just self-driving cars in general, I am willing to properly document the Lua and Python code, then post it on Github or somewhere.

It would also be cool to hear how @badcc or @Widgeon implemented their self-driving car controllers. From what I have seen, most cars and planes on ROBLOX that are automated either are just directly positioned via CFrame (to negate physics) or utilize some PD control with a spline.

35 Likes

Here is a small clip of me abusing the robot car (ie; abruptly picking it up and placing it somewhere else). Even with major disturbances, the car is still able to converge and adjust back onto the path in a time-optimal manner.

If you have any questions, you can ask here and I will try my best to answer them in a somewhat timely manner.

13 Likes

Are you using PyPy or an API into some C code? This makes me wonder, because traditionally Lua implementations are faster than Python ones, and we just got the new Lua VM.

Python is used in order to host the webserver and solver-interface. The webserver library is called Tornado and supports signalling, which is needed for the solver-interface. The solver interface is called Pyomo. Pyomo, according to their own web page, is a “Python-based, open-source optimization modeling language with a diverse set of optimization capabilities”.

Essentially, you can describe a high-level optimization problem with Pyomo. The optimization problem is then translated to instructions for an underlying solver which Pyomo interfaces with. You can use a variety of solvers based on your problem type. For my problem, I use the IPOPT solver. The IPOPT solver is a “software library for large scale nonlinear optimization of continuous systems”. IPOPT is written as a native executable and uses an underlying linear system solver called MUMPS.

Writing these system in Lua would take lots and lots of time, as they are conceptually and mathematically complex. Writing the modelling language, interior-point optimizer, and linear solver would be a major project in of itself. I leave the actual researchers and scientists to write them for me.

Pyomo documentation includes example code for a simple optimization problem

3 Likes

Definitely interested in seeing how this works!

7 Likes

Yeah, I would love to see the code for this!

For reference mine is linear and is basically a programmed robot which follows a BSpline, all the physics is done by roblox, so basically it just has inputs such as TargetSpeed,LateralDisFromRaceLine, and outputs as you would expect, Throttle, Steer. You dont need to use PID, but using PID can be beneficial to make very smooth controlling cars, while remaining accurate on the track. https://www.youtube.com/watch?v=Msy7AZPgRnk

1 Like

Oh how interested, I’d be fascinated to see under the hood. If you do get around to writing an in depth article on it, I’d love to see it!

It looks like the self-driving car can’t brake for obstacles that it can’t avoid by steering at full speed (as shown in your “abuse” video). I think your next task should be to get that working :)

The car only has knowledge of the center line of the track, it does not know there is a wall that it has to absolutely not hit. One method of fixing this is creating circular-approximated constraints of where the car may not be for the optimization problem. This would indicate to the program that it needs to decelerate or steer out of the way over anything else. Doing this, however, increases the optimization algorithms runtime.

1 Like

Adding in centripetal-force constraints and having the car maximize speed allows the car to dynamically speed up and slow down in order to prevent skid out. The car will slow down, enter the turn, then automatically speed up while maintaining tire grip. https://jody.jp/vl578.mp4

2 Likes

That’s pretty cool! Basically if you wanted to, you can make it a Tesla.

The main control algorithm & grapher can be found at: https://github.com/Jody7/mpc_stuff/blob/master/car_mpc/car_mpc_pyomo.py

IPOPT solver is used in conjunction with Pyomo as the modelling framework. Tornado is used to serve up the HTTP-requests that the Roblox script sends.

If people are interested, I can probably do a write up later.

3 Likes