# David's line following robot that learns the course

Posted by David on 1 May 2015

Several people here made robots to compete in the recent LVBots line following competition. The goal of the competition is to make an autonomous robot that follows a line on the ground as fast as possible. I made a robot called LearnBot for the competition. LearnBot is able to learn the line course on the first lap and then use that information to its advantage on the second and third laps.

This is actually the same robot that I used in the dead reckoning contest last year. See my previous post about the robot if you want to know about its hardware.

Most of the line following robots that I have seen at LVBots and on our forum run simple software: they read their line sensors to get an idea of how well they are aligned, and then they adjust their motors based on that using a PID algorithm. If you are not familiar with how a simple line follower works, I recommend reading the “Line Following” example project in the Pololu 3pi Robot User’s Guide. This robot does all the same things as a simple line follower, but it also learns the course at the same time.

This robot uses optical quadrature encoders to measure how far it has traveled. The optical encoders were the best option available in 2014 when the robot was originally built, but if I were building it again today, I would use the newer magnetic encoders, since they output cleaner signals and are not affected by light from the environment.

The robot also has a MinIMU-9 v3, which I added for this contest. The MinIMU-9 v3 has a 3-axis gyroscope, 3-axis accelerometer, and 3-axis magnetometer, but I only used the gyroscope. By adding up the readings from the Z axis of the gyroscope on the MinIMU-9 v3 over time, the robot gets a pretty good measurement of its current heading (the direction it is facing). Absolute heading does not matter; the robot just needs to know how far it has turned since starting the course.

By combining the information from the encoders and gyro, the robot can calculate its position relative to the point where it started as a pair of coordinates. In general, it is also possible to use encoders alone to calculate the heading and coordinates, but for this robot I think using the gyro improved the accuracy of the measurements.

With the position measurements, the robot is able to know approximately when it reaches the starting point of the line course. The X and Y axes of my measurements are defined so that the robot initially starts at the origin (0, 0) and is facing in the positive X direction when it starts. To detect its return to the starting point, the robot waits for the X coordinate to change from negative to non-negative at a time when the Y coordinate is close to 0. To avoid false positives, it also checks that the total number of encoder counts detected during this lap is not too small, and it checks that the heading points roughly in the positive X direction.

Every 100 encoder ticks, the robot saves its X and Y coordinates into its log, along with the current heading. The log was very useful for debugging and I also used it to detect straightaways. Here is a visualization of the robot’s log from one of the last test runs I did before the competition:

Each dot represents the coordinates from a reading in the robot’s log. The blue dots represent the first lap, while the green dots represent the second lap, and the red dots represent the third lap. When the robot starts the race or detects the start of a new lap, it resets its coordinates to (0, 0) and resets its heading to point in the positive X direction. That is why there is a big gap between the ending dot of one lap and the starting dot of the next lap. The position of the robot at the start of the lap defines the X and Y coordinate axes for that lap, so a little bit of error in the robot’s position at that time can make the whole lap appears shifted or rotated relative to the other laps. If I simply rotate the log data for the first lap by 1.7 degrees and translate the other laps horizontally, I can get the data to match up very nicely, as shown below:

So what can be done with all of this information? I can imagine doing some fun things with the data, but this robot only uses it to do two relatively simple things. First of all, on the second and third laps, it uses the data from the first lap to detect when it is on a long straightaway, and increases the motors to their maximum speed if so. This didn’t make much of a difference since the motors were already running at 83%. Secondly, it automatically stops after it has finished the three-lap race so that I can just pick it up instead of having to catch it as it is moving. I was worried that this would backfire on me and the robot would stop before completing the race, but that feature worked correctly 100% of the time during the 5 or 6 times that I ran my robot in the contest.

Just to be clear, a normal line following PID algorithm is in charge of the robot’s movements whenever it is moving; the learning system only serves to notify the PID algorithm of times when it can drive the motors faster. It might be fun to try to turn off the line sensors and navigate the course from memory, but that is not something I attempted.

I definitely recommend using an advanced microcontroller like the one on the mbed if you want to do this kind of learning. LearnBot uses 12 KB of RAM to hold its log, and it was computing sines and cosines very frequently. I don’t think it would be easy to make this work on an 8-bit AVR.

LearnBot is not super fast, and there was no real hope of winning the competition. However, it was fun to write some more advanced firmware to make my line follower a little smarter than the others. For more information, you can see my line following code for the mbed or ask questions in the comment section.

If you're willing to have the robot run the course from memory, it could steer wider on the curves and cut the corners to achieve a faster time. What do the rules say about how close to the course the robot has to be?
Hi, Dan.

Our rules are not developed enough to cover that case well. Informally, the robot needs to generally be following the path of the line. It would be nice if we could develop objective criteria for "following the line" that still allows the behavior you are describing.

Ryan
Where can I buy the complete kit of this robot?
Hi, Dattaraj.

The robot in this post is a custom robot. We do not sell a kit of the parts used in it, but there is a list of most of the components used in this earlier blog post about the robot.

-Claire
any sample code or tutorial to use the encoder with line follower ??
Hello, Srikrishna.

There is a link to the code David used in the last sentence of the post.

-Derrill
Sir, I wanted to know how to change the program if the lines are not straight. I mean the line between 2 points in the grid is curved at 3 degrees.how to alter the program
Hello, Pratz.

A 3 degree curve is almost a straight line, so I suspect the behavior of David's code would not be very different in that system. If you want to change how the robot drives for other curves or features on the third lap, you would have to come up with a way of telling when the robot got to that feature and add some your own code to handle it.

-Jon
So i downloaded and looked throug the code but i cant find the real code. the only thing i see are the librarys. i couldnt fint the void loop(){ or void setup(){ either. so what I am wondering is, where is the main code, and if there is none how does the code work, and where does it start?
Also, where does he get the map from, is there some kind of special program or somthing?

I am quite new to coding in general, so i would really apriciate some help.
The main function is defined in main.cpp at line 37.

I used the Logger::dump function defined in logger.cpp to format the log data as CSV and send it via USB to a computer. I could have used a spreadsheet program to plot the data, but I wrote a tiny Ruby program (which I have not published) to generate a simple SVG image from it.