Taking a look at Team Engima's winning entry

Now all the racing is over it is time to have a bit of a look back at what happened during the last series. Today I am taking a look at the winning entry to see what the Team Enigma magic is and how everyone can learn from it.

A brief roam around their code shows that they have made small changes in a lot of places. This seems to be a strategy of tweaking the existing code so that it runs to its maximum potential.

So let us take a look at what changes have been made and how they affect the performance of the YetiBorg on the track.

Race strategy

I will start by looking at Race.py since almost every team modified this in some way.

### Settings for this race ###
laps = 99

### Start of the race ###
# Wait until we can see the track
while not TrackFound():
        WaitForSeconds(1.0)
# We can see the track now, start by following the lane we are on
trackLane = round(CurrentTrackPosition())
AimForLane(trackLane)
# Save a start-line image
photo = GetLatestImage()
SaveImage(photo, 'Start-line')
# Start logging what happens
StartUserLog()
StartDetailedLog()
# Wait for the go signal from the start/stop lights.
WaitForGo()
# Go at max speed
Speed(100)

### During the race ###
# Keep going until we have fished all of the laps
while True:
        WaitForWaypoint(3)
        AimForLane(0.0)
        WaitForWaypoint(4)
        AimForLane(0.0)
        WaitForWaypoint(5)
        AimForLane(0.0)
        WaitForWaypoint(6)
        AimForLane(-1.0)
        WaitForWaypoint(7)
        AimForLane(-1.0)
        WaitForWaypoint(8)
        AimForLane(-1.0)
        WaitForWaypoint(9)
        AimForLane(-1.0)
        WaitForWaypoint(1)
        AimForLane(-1.0)
        WaitForWaypoint(2)
        AimForLane(-1.0)

        
### End of the race ###
# Save a finish-line image
photo = GetLatestImage() # continue running just for a bit to ensure we've definately crossed the finish line!
SaveImage(photo, 'Finished')
WaitForWaypoint(3)
# Slow the YetiBorg down gradually from 100% to 0%
for slowing in range(99, -1, -1):
        Speed(slowing)
        WaitForSeconds(0.01)
# Stop the logging
EndUserLog()
EndDetailedLog()
# End the race (will stop the robot and end the program)
FinishRace()

For the most part there are not many real changes here, the top and bottom sections are very similar to our examples. The main change is the AimForLane values around the track:

  1. Between waypoint 3 (end of turn 1) and waypoint 6 (start of turn 4):
    Aim for the middle of the track.
  2. Between waypoint 6 (start of turn 4) and waypoint 3 (end of turn 1):
    Aim one lane closer to the inner wall.

This shows that Team Enigma were not heavily relying on the Race Code Functions to improve their performance. They are slightly further in than the standard code for most of the lap, then a bit wider through the tricky S-curve section. This means that their real improvements can be found elsewhere...

Logging

There are a few changes that suggest Team Enigma tried to improve the logging information recorded during the race.

First they have reduced the polling delay in Globals.py:

This has two main effects:

  1. The Race Code Functions which poll, such as WaitForWaypoint check if they are done more often
  2. When these functions call other ones, such as GetDistance it causes more log lines to be created

This will make the log times more accurate, as well as making the waypoints a little faster to respond to crossing them.

The big changes however are in RaceCodeFunctions.py:

What they have done here is added extra logging calls into the functions which get polled. This adds a lot of additional information to the logs, making them more detailed.

For example the CurrentAngle call logs what the returned angle was in degrees. This makes it easier to follow what the code has done when reading the logs after the race. Between these changes Team Enigma would have had more accurate and detailed logs, allowing them to better understand what happened in each race.

There is another little nugget of information in this lone line:

#Speed(100-(math.fabs(CurrentAngle()/8))) #

It looks like they were trying to reduce their speed based on how much the YetiBorg would be trying to steer. From the fact it is commented out we can presume this either did not work as intended or did not help. Still it is a good insight into the kind of tweaking they have been trying to do to the code through the series.

Override settings

This is where we start to see how they stayed ahead during a race. In Settings.py they have changed the settings used for the various override modes:

For the stuck override they have reduced the time taken both to reverse and to spin themselves straight. This increases the likelihood of having to reverse twice, but means that if the first attempt is successful it will be quicker. On balance this probably saved them some wasted time after colliding with another robot.

For the wrong way detection they have reduced how many wrong points need to be detected and how long the YetiBorg spends turning. This means it should be quicker to react to going the wrong way, but is more likely to end up facing the wall instead of turning around. I am not sure if this helped them or not, some experimenting may be in order :)

Next we have the overtaking settings, these have been tweaked a lot. The detection threshold has been lowered, this gives an earlier response to obstacles but does run the risk of false detections. The number of lanes to move over has also been reduced, which a quick test with the simulator shows to be a much more sensible value than our default. The final part is that the length of time spent overtaking has been reduced, this means they spend less time off-course at the expense of potentially moving back before clearing the other robot.

The last change in this bit is a little more odd, they increased the light detection height. I am not sure why they did this, we did a lot of testing on the values used under different light conditions. Maybe they just wanted to play things safe :)

PID control values

This is where the changes get a little more technical. So still in Settings.py they have changed the PID values used for generating the steering output:

The values are used to take these inputs:

  1. The current offset from the center of the track
  2. The angle of the YetiBorg compared to the track
  3. How much the track appears to be curved ahead

and generates a single value to control the steering position.

PID control is a fairly complex topic, but the difference here is fairly drastic. Team Enigma has worked out their own values which are more precise than the default ones :) It is nearly impossible to look at the individual values and understand them, but the result is a definite improvement.

Given how much experimentation it typically takes to adjust these values I suspect a lot of time was spent using the simulator. The commented out older values show they have changed these values at least twice, suggesting they have been making improvements through the series. Having a quick test in the simulator myself it is clear this produces a better line for the YetiBorg from just these changes on their own.

PID control is used in a lot of computer systems which control real world devices like motor speeds, cooling systems, and servo positions. It is a reasonably complex topic which would deserve a whole article in its own right. I would highly recommend looking up about PID control and PID tuning if you are interested, but be prepared for some maths!

Frame rate

The last change is a little easier to explain, but may be the most important of all. So still in Settings.py they have increased the camera frame rate:

The change from 5 fps to 7 fps is a massive 40% boost in the frame rate.

I think most people will probably overlook this change, but I think it will be more important than anything above. This is because increasing the frame rate is much like improving the reaction times of your racing driver. Everything they react to should happen sooner and any mistakes made should be corrected earlier.

These are the main advantages to a higher frame rate:

  1. The PID loop gets updated more often, improving the steering
    This may be one reason they decided to improve the PID values :)
  2. React slightly earlier to obstacles in front
    This should make overtaking more reliable
  3. React to the light changes faster
    You might notice they started slightly earlier than the competition in the final :D
  4. Reduces problems due to camera noise
    Put simply most noise / errors in the camera image last for a single frame, they therefore corrected faster than normal
  5. React to track changes quicker
    This will have improved the line around the track, especially in the tricky S-curve section

Our testing showed that the Raspberry Pi Zero cannot handle our code running at 10 fps, but is rock-steady at 5 fps. My guess is that some experimenting showed 7 fps is the highest you can push before the Pi Zero cannot keep up.

It is important that the Pi Zero keeps up with the frame rate used. If it cannot then the frames will get increasingly late to be processed. When this happens the YetiBorg gets more sluggish to respond, resulting in very slow reaction times which get worse as the race goes on. Think of this as your racing driver starting to fall asleep at the wheel!

Final thoughts

Having been through all of the changes Team Enigma has made it is clear that small and careful changes work very well. It also seems like extra logging to gather data is a good plan for anyone seeking to improve things.

From what Team Enigma has done we can learn the following:

  1. Faster frame rates are good all round :)
  2. Improving the steering control helps significantly
  3. Shorter override durations get the YetiBorg going again sooner
  4. Improved logging helps learning from past races
  5. The position around the track does not have to be complicated

We can also see there is still plenty of room for improvement, here are some possible ideas for further gains:

  1. A tighter or more detailed line around the track to reduce how far the YetiBorg has to go
  2. Changing the not very reliable overtaking detection for a better algorithm
  3. Improve the speed of the image processing code so the frame rate can be further boosted
  4. Some kind of speed control to improve cornering
  5. A better way to tackle that tricky S-curve
  6. Trying to get the YetiBorg the right way up when we have been flipped over

We are all looking forward to seeing what the teams do in the next series. Congratulations to Team Enigma for some ingenious improvements and a well deserved first place.

Comments

Thought it might be useful to comment on the automatic speed adjustment, this had the effect of slowing the bot when it was at sharp track angles. This allowed for more aggressive PID tuning during testing and the early races without going out of control. As our PID terms improved we found we could take it out as we were losing time round the corners.

I had a look through Enigmas changes and was most impressed with their knowledge of the "back end" code and being able to win without really changing the race code itself. The one area I did not fully understand, even with some research, was PID control. You wrote:
"It is a reasonably complex topic which would deserve a whole article in its own right"
I'd be very interested if you could write an article and how PID control works in relation to the code?

Arron Churchill's picture

I think an article on PID control would be a great idea.

At the moment we are fairly busy with the preparations for the Summer series, in particular getting all of the robots in peak condition and calibrated :) This means we will probably have a couple of weeks before there are any longer blog posts.

Add new comment

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre>
  • Syntax highlight code surrounded by the <pre class="brush: lang">...</pre> tags, where lang is one of the following language brushes: bash, cpp, perl, python.
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.