## Thursday, September 30, 2010

### Lab Session 5 : Preparation for the Robot Race

Date: 30. September 2010
Duration of activity:
Group members participating : all group members, that is Michal Owsinski, Anders Dyhrberg, Guillaume Depoyant, MichaĆ«l Ludmann.

I. Objectives and summary

I. 1. Objectives

In this lab session we are suppose to make the LEGO 9797 car follow a black line and stop at the end of the line when the car drives into a goal zone - a green rectangular piece of paper at the end of the black line. The idea is that we will try to use the light sensor to detect three different colors.

I. 2. Summary

Line follower with calibration
Color sensor with calibration
Line follower that stops in a goal zone

II. Line follower with calibration

II. 1. Finding good input values for PID

To make the robot follow the line we used the proportional regulation described in the [1] document. This page is worth reading thoroughly, since it explains steps by steps how to methodically calibrate each PID value. On top of that, it provides a really good understanding of how and why those values can make the system actually behave better.

First we calibrated the Kp value simply by trying different values. Kp=Kc. Our final value was Kc=1000. Then we measured the oscillation period Pc ("The oscillation period (Pc) is how long it takes the robot to swing from one side of the line to the other then back to the side where it started. " [1]), which was Pc= 0,25 seconds. Then we measured the time of one control loop of our line follower program - dT=10 ms.

To get those results properly and with a good accuracy, we ran the robot for a chosen amount of oscillations or loops (preferably a big number : like 20 oscillations or 10000 loops) and we recorded the time taken by the robot to fulfill the goal.

We used the table below to calculate the Kp, Ki, and Kd values, depending on what kind of control we wanted to implement (that is : P, PI, or the full PID).

table source: [1] A PID controller for lego mindstorms Robots

 Ziegler–Nichols method giving K' values (loop times considered to be constant and equal to dT) Control Type Kp Ki' Kd' P 0.50Kc 0 0 PI 0.45Kc 1.2KpdT/ Pc 0 PID 0.60Kc 2KpdT / Pc KpPc / (8dT)

We therefore ended with those values :
• For a Proportional system only :
• Kp = 500
• Por a Proportional Derivative sytem :
• Kp = 450
• Ki = 21,6
• For a full PID system :
• Kp = 600
• Ki = 48
• Kd = 3

II. 2. Code and results

Obviously, such figures don't mean anything if we do not talk about the code implemeting them. Because the way it is done make it indeed necessary for us to multiply Kp, Ki and Kd by 100 (so the real values seen above should be 100 times smaller).

So, eventually, we have the code below, all embedded in a while loop :

 lightValue = sensor.light(); error = lightValue - offset; if ( lastError * error < 0 ) { integral = 0; } else { integral = (integral + error);   // calculate the integral } derivative = error - lastError;       // calculate the derivative Turn = Kp*error + Ki*integral + Kd*derivative;  // P, I and D terms Turn = Turn/100;                               // REMEMBER to undo the affect of the factor of 100 in Kp, Ki and Kd! powerA = Tp + Turn;      // the power level for the A motor powerC = Tp - Turn;      // the power level for the C motor if (powerA > 100) { powerA = 100; } else { if(powerA < 0){ powerA = 0; } } if (powerC > 100) { powerC = 100; } else { if(powerC < 0){ powerC = 0; } } MotorPort.A.controlMotor((int) powerA, 1); MotorPort.C.controlMotor((int) powerC, 1); lastError = error;
As for the results, it was not so obvious that the theory would apply exactly in the real world as we wanted it to do. And in fact, despite the previous measurements, we still needed to do some tuning in the PID values. The article we read in [1] made us espect that and was quite good at providing the answers in what and how we still had to change.

The proportinal only system (i.e. putting Ki and Kd equal to zero) was quite straightforward and immediatly worked. The challenge increased while using the integral term, but we still succeeded in having our robot doing its task without failing - as you can see in the video below.

However, for some reason, the integral term messed up the system, and we didn't have enough time to figure it out. But we will do that for sure, since it has proven to be a really efficient and accurate way of properly controlling our motors - we will certainly need that again in a future project.

III. Black White sensor with calibration

Basically, this technique takes two values in order to initiate itself and follow the line. Those two values are kept in memory (called "white value" and "black value") and then a average value is computed (obviously, the average between the black and the white)

This way, in order to detect if the sensor is sampling white or black, we just need to compare the value with the middle value: either we're above (white), either we're below (black). This technique is quite efficient but knowing that we had to use it later for three colors (black, white and the color of the arrival), we had to think about another tip.

IV. Line follower that stops in a goal zone

The problem with the robot stopping in a goal zone was not solved on todays lab session due to lack of time. However We had an idea which could solve the problem. Our proposition was to implement in to the sample loop a condition that would check last 3 or 4 samples (to avoid the problem with the black-white edge) which would compare those samples with the predefined color value on which the robot should stop.

So this way, we took the BlackWhiteSensor file and add another condition. The "average" value was still the main technique used in order to find the first two colors, but so as to figure out wether the sensor was sampling the color of the arrival, we made a loop: if the sampled value was close to the arrival color with an error epsilon and for N times straight, we assumed that the robot had to stop (epsilon and N can be edited)

 final int power = 80; int i = 0; ColorBWSensor sensor = new ColorBWSensor(SensorPort.S3); String black = "black"; String white = "white"; String color = "finish color"; sensor.calibrate(); LCD.clear(); LCD.drawString("Light: ", 0, 2); LCD.drawString("Color: ", 0, 3); while (! Button.ESCAPE.isPressed() || i < 5 ) { LCD.drawInt(sensor.light(),4,10,2); LCD.refresh(); if ( sensor.finishColor() ){ LCD.drawString(color,1,4); i++; } else{ i = 0; if ( sensor.black() ) { Car.forward(power, 0); LCD.drawString(black,1,4); } else { Car.forward(0, power); LCD.drawString(white,1,4); } } Thread.sleep(10); }

V. References