SnakeOil Virtual Motor Sports Lubricants.™
2015 Competition Results
After sending in my submission for 2013 I continued to work on my bot. I had started planning how I could use my cluster to optimize the parameters. I made some decent progress and was ready for 2014. I awaited the announcement of the competition and it never came. There was no event in 2014. This was very frustrating and I pretty much closed the project. But then in 2015 only months before the deadline, I learned that there was to be an event for 2015. I scrambled to disinter my work.
There were some problems however. I could not get a definitive description of the kinds of tracks I could expect. There are some pretty wild dirt tracks that come with TORCS that had never been used which I did not train for. Also the track server that had been a repository of the computer generated tracks like the ones the competition usually featured was not quite working. Fortunately, I was able to pick through the broken web code and download all of the tracks. With thousands of tracks to train from I felt pretty good. Unfortunately the competition used tracks that I’ve never heard of and couldn’t obtain so it’s difficult for me to really get a good impression of exactly what went wrong. And what went right.
I did win the "2nd runner up" prize (i.e. 3rd place) of 100 Australian dollars which was duly delivered. Thanks to the organizers for that.
Here is the official results page but it’s not much to look at. I don’t think there was a nice summary video made as there was for previous competitions.
After this competition I was pretty tired from the effort. It’s likely they won’t have another one of these SCR competitions and I’m probably too burned out on it anyway. But it was definitely a very valuable learning experience.
2013 Competition Results
The SnakeOil interface was created for my entry in the 2013 Simulated Car Racing Championships. It performed fine and my driver did ok coming in 4th, the middle. Here are some highlights from the organizers showing the finals racing. I have added my own annotations.
The AI I entered, i.e. shown in the video, was not the best car that I developed in 2013, but I was behind schedule at the deadline and was going to save my substantial improvements for 2014. Unfortunately, the organizers decided not to hold the event in 2014. :-/ I may try to get the final bot running again and give it a proper demonstration. The AI in this video is pretty much all hand tuned while subsequent work went into extensive genetic optimization. That made a huge difference and I was planning on using this final car optimized on the Linux cluster I manage for 2014. I am convinced that optimization is critical to success and I believe that Autopia, the undefeated champion for many years, derives its success from this approach.
For 2014, I’m working on my C.A.R. Project.
SnakeOil is a Python library for interfacing with a TORCS race car simulator which has been patched with the server extensions used in the Simulated Car Racing competitions. To get a very nice introduction to the Simulated Car Racing scene you can watch the talk by Python SCR enthusiast Tennesse that inspired me to participate.
With SnakeOil you can very easily write an entry for an autonomous race car without dealing with any messy administrative details or regrettable programming languages. It allows you to focus exclusively on the mechanics of driving the car and not of messing around with implementation details.
snakeoil.py Size: 12.5kB Version: 20130506
To use it, you must import it and create a "drive()" function. This will take care of option handling and server connecting, etc. To see how to write your own client do something like this which is a complete working client:
#!/usr/bin/python import snakeoil if __name__ == "__main__": C= snakeoil.Client() for step in xrange(C.maxSteps,0,-1): C.get_servers_input() snakeoil.drive_example(C) C.respond_to_server() C.shutdown()
This should then be a full featured client. The next step is to
snakeoil.drive_example() with your own.
But Wait, There’s More
The Client object,
C in the above example, holds various values
and functionality needed to establish a complete client. There are
many useful things you could do with this. This class can be used to
make several clients that could all race at the same time from one
Here’s a complete example of a program that will spawn 4 clients to control 4 different cars.
#!/usr/bin/python import snakeoil if __name__ == "__main__": Cs= [ snakeoil.Client(p=P) for P in [3001,3002,3003,3004] ] for step in xrange(Cs.maxSteps,0,-1): for C in Cs: C.get_servers_input() snakeoil.drive_example(C) C.respond_to_server() else: for C in Cs: C.shutdown()
This program will make 4 identical cars on ports 3001-3004. This makes 4 cars with identical behavior.
Of course, you don’t have to structure all 4 to use the same
function. You can easily have competitions between different drive
functions available to the program.
Another thing to note about multiple Client objects is that the
settings for each client are controllable. There are default settings
if you do not do anything. Then there are global overrides that can be
specified as command line options. Finally each client object can have
overrides at object creation. This is how the
sets a different port for each client. Note that for things like
host and port that need to be known at connection time, these need to
be established early on. When instantiating a class, you can used
named parameters to specify settings specific to that client. The
parameters are named the same way as the short options (see
For properties that could change mid-race, you can simply set them any
time through the object members. For example:
Would turn on debugging for the client on 3004. It might be handy to turn on debugging only for a client that is stuck or passing, etc.
There are many member variables that contain important things to the
client. Many of these can be specified as options (try the
Many of these things won’t be of any concern to a bot creator.
stage are important when developing a
strategic bot though you can safely ignore those too at first.
This object also contains a ServerState object
S) and a DriverAction object (
R for response). This allows
you to get at all the information sent by the server and to easily
formulate your reply. These objects contain a member dictionary
(for data dictionary) which contain key value pairs based on the
server’s syntax. These aren’t even hard coded but are formed from the
server’s strings and can therefore, in theory, accommodate future
changes. With the current (2013) SCR server, you can read the
angle, curLapTime, damage, distFromStart, distRaced, focus, fuel, gear, lastLapTime, opponents, racePos, rpm, speedX, speedY, speedZ, track, trackPos, wheelSpinVel, z
The syntax specifically would be something like:
And you can set the following:
accel, brake, clutch, gear, steer, focus, meta
The syntax is:
|It is steer and not steering as described in the SCR manual!|
All values should be sensible for their type, including lists being lists. See the SCR manual for details or my TORCS/SCR notes.
Writing A drive() Function
The main work to be done when using SnakeOil is to write a drive function. This is pretty much exclusively focused on the business of controlling the car. All of the car’s inputs are available and all of the driver’s outputs can be specified. Basically for the conditions that present themselves to the function, you need to formulate a set of outputs that will result in the car doing The Right Thing.
The nice thing about this way of developing is that you can try many
drive() functions easily while keeping the base the same
Here is the sample drive function from the library. This has many bugs and is quite simplistic, but it will give you some idea of how to get going.
def drive_example(c): '''This is only an example. It will get around the track but the correct thing to do is write your own `drive()` function.''' S= c.S.d R= c.R.d target_speed=100 # Damage Control target_speed-= S['damage'] * .05 if target_speed < 25: target_speed= 25 # Steer To Corner R['steer']= S['angle'] * 10 / snakeoil.PI # Steer To Center R['steer']-= S['trackPos'] * .10 if R['steer'] < -1: R['steer']= -1 if R['steer'] > 1: R['steer']= 1 # Throttle Control if S['speedX'] < target_speed - (R['steer']*50): R['accel']+= .01 else: R['accel']-= .01 if S['speedX']<10: R['accel']+= 1/(S['speedX']+.1) # Traction Control System if ((S['wheelSpinVel']+S['wheelSpinVel']) - (S['wheelSpinVel']+S['wheelSpinVel']) > 5): R['accel']-= .2 if R['accel'] < 0: R['accel']= 0 if R['accel'] > 1: R['accel']= 1 # Automatic Transmission R['gear']=1 if S['speedX']>50: R['gear']=2 if S['speedX']>80: R['gear']=3 return
Notice how the only things you need to provide code for are related directly to your car’s performance.
Here is the driving behavior of this simple routine. Definitely a good starting point.
If you just run the
snakeoil.py base library itself it will implement a
serviceable client with a demonstration drive function that is
sufficient for getting around most tracks. Try
snakeoil.py --help to
Tragically Duplicated Effort
When I became interested in the SCR, I assumed I’d write a C client but when I saw how much text parsing there was I thought it would just be easier to write it from scratch in Python. I naturally assumed that there was no Python client (no one had submitted one from the previous years' competitions that I was made aware of). I was wrong.
The first Python client that the SCR organizers seem to have been aware of is Mr.Fish’s which seems to have been developed at exactly the same time I developed SnakeOil. I believe this client is a more faithful port of the C++ version written by the organizers of the SCR competitions. Unfortunately that’s not necessarily ideal for someone just starting out.
There is no option parsing and I found it to be quite a challenge to get running. The test bot will comfortably make it around the track.
Tennessee tells us about yet another Python client called pyScrcClient. I was not able to download an archive of this client but there are only 5 files and there were direct links on github so it wasn’t so bad.
I was pleased that this client had option parsing (using
make sure you don’t have an ancient Python version). Like SnakeOil it
also only imports
socket, and the parsing module keeping it
The default options worked right away and I was able to immediately race with this client. It’s more aggressive than SimplePythonClient. It is definitely a great example of using Python for SCR. I wish I had known about it before I started SnakeOil.
By the way if you have a Python client that you think would be helpful to share, I am interested in hosting it for you so that it can be downloaded easily from here.
And if you’re the author of SimplePythonClient or pyScrcClient I’ll host those too if you like. Let me know.