Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

QTR-8A PID line follower


#1

Hi,

I am trying to make a linefollowing robot and I am using the Pololu QTR-8A, the pololu micro metal gear (30:1) motors, and the pololu DRV8835 arduino motor shield.
I am using six of the eight sensors from the QTR (sensor 2,3,4,5,6,7) and are connected to an arduino UNO to analog pins
0-5.

This is my code:

#include <DRV8835MotorShield.h>


#include <QTRSensors.h>


#define Kp 0.05 // experiment to determine this, start by something small that just makes your bot follow the line at a slow speed
#define Kd 2 // experiment to determine this, slowly increase the speeds and adjust this value. ( Note: Kp < Kd) 
#define rightMaxSpeed 200 // max speed of the robot
#define leftMaxSpeed 200 // max speed of the robot
#define rightBaseSpeed 150 // this is the speed at which the motors should spin when the robot is perfectly on the line
#define leftBaseSpeed 150  // this is the speed at which the motors should spin when the robot is perfectly on the line
#define NUM_SENSORS  6     // number of sensors used
#define TIMEOUT       2500  // waits for 2500 us for sensor outputs to go low
#define EMITTER_PIN   2     // emitter is controlled by digital pin 2


DRV8835MotorShield motors; //don't forget this line


QTRSensorsAnalog qtra((unsigned char[]) {  0, 1, 2, 3, 4, 5} ,NUM_SENSORS, TIMEOUT, EMITTER_PIN); // sensor connected through analog pins A0 - A5 i.e. digital pins 14-19

unsigned int sensorValues[NUM_SENSORS];

void setup()
{

motors.flipM1(true);
motors.flipM2(true);
  
  
  

  /* comment this part out for automatic calibration 
  if ( i  < 25 || i >= 75 ) // turn to the left and right to expose the sensors to the brightest and darkest readings that may be encountered
     turn_right();  
   else
     turn_left(); */ 
   qtra.calibrate(QTR_EMITTERS_ON);   
   delay(20);
  
delay(10000); // wait for 10s to position the bot before entering the main loop 
    
    /* comment out for serial printing
    
    Serial.begin(9600);
    for (int i = 0; i < NUM_SENSORS; i++)
    {
      Serial.print(qtrrc.calibratedMinimumOn[i]);
      Serial.print(' ');
    }
    Serial.println();

    for (int i = 0; i < NUM_SENSORS; i++)
    {
      Serial.print(qtrrc.calibratedMaximumOn[i]);
      Serial.print(' ');
    }
    Serial.println();
    Serial.println();
    */
  } 

int lastError = 0;

void loop()
{
  unsigned int sensors[6];
  int position = qtra.readLine(sensors); // get calibrated readings along with the line position, refer to the QTR Sensors Arduino Library for more details on line position.
  int error = position - 2500;

  int motorSpeed = Kp * error + Kd * (error - lastError);
  lastError = error;

  int rightMotorSpeed = rightBaseSpeed + motorSpeed;
  int leftMotorSpeed = leftBaseSpeed - motorSpeed;
  
    if (rightMotorSpeed > rightMaxSpeed ) rightMotorSpeed = rightMaxSpeed; // prevent the motor from going beyond max speed
  if (leftMotorSpeed > leftMaxSpeed ) leftMotorSpeed = leftMaxSpeed; // prevent the motor from going beyond max speed
  if (rightMotorSpeed < 0) rightMotorSpeed = 0; // keep the motor speed positive
  if (leftMotorSpeed < 0) leftMotorSpeed = 0; // keep the motor speed positive
  
   {
  // move forward with appropriate speeds

  motors.setM1Speed(rightMotorSpeed); //only works if "DRV8835MotorShield motors;" is defined in the beginning
  motors.setM2Speed(leftMotorSpeed);
 
}
}

All the robot does is driving fast in circles.
I do get readings from the QTR sensor when I read it from the serial monitors. It also gets 5V from the arduino, so as far as hardware is concerned, I don’t think that is the problem.

Could someone look at my code and tell me if it is any good?


#2

Hello.

I am sorry you are having trouble getting your line follower working. TIMEOUT is a parameter for the digital version of those sensors (QTR-8RC), not the QTR-8A analog version that you have. So, you are actually setting the number of samples per sensor to 2500. That parameter should be a much smaller value (e.g. 4 instead of 2500). Can you try lowering that value to see if it solves the problem? If not, do your sensor readings make sense? Can you try adding Serial.print() calls inside the loop function to test the value of error and position, and post the results here?

-Jon


#3

Hi tank you for anwsering.
I change the code like you suggested. So I change in the beginning:
to "#define TIMEOUT 4"
and I also changed “Int error = position - 4” (instead of - 2500)

All it does now is both wheels spinning in opposite direction.

So I have a feeling the sensors arent reading anything, not because they don’t work, but because of the code I think.

I also wanted to know if the sensor are always on by default or not?
So if say if I wanted to use the sensor without the library, I would have to declare the input analog pins and make sure the sensors are always on.

By the way isn’t there some sort of example code to use the sensors with a PID?

Thanks in advance.


#4

The LEDs are all on by default. You can read more about that under the “Module Connections” section of the QTR-8A and QTR-8RC Reflectance Sensor Array User’s Guide, which you can find under the “Resources” tab of the QTR’s product page.

Changing the value of TIMEOUT should work okay for you, but you should undo your other change. If you are using N QTR sensors, and basing your line following code off of our example, the value to subtract from position to get error should be (1000 * (N-1) ) / 2. So, for N = 6, error should be:

int error = position - 2500;

We have example code for PID control using the QTR sensors in a line following robot under the “PID Control” section of the QTR array’s user’s guide. (It should work for the both the QTR-A and QTR-RC arrays.)

-Jon


#5

Thank you for answering Jon,

I changed the code like you said, but it didn’t change anything.

So now I tried to get the readings from the sensors via the serial monitor with this code:

#include <QTRSensors.h>

// This example is designed for use with six QTR-1A sensors or the first six sensors of a
// QTR-8A module.  These reflectance sensors should be connected to analog inputs 0 to 5.
// The QTR-8A's emitter control pin (LEDON) can optionally be connected to digital pin 2, 
// or you can leave it disconnected and change the EMITTER_PIN #define below from 2 to 
// QTR_NO_EMITTER_PIN.

// The setup phase of this example calibrates the sensor for ten seconds and turns on
// the LED built in to the Arduino on pin 13 while calibration is going on.
// During this phase, you should expose each reflectance sensor to the lightest and 
// darkest readings they will encounter.
// For example, if you are making a line follower, you should slide the sensors across the
// line during the calibration phase so that each sensor can get a reading of how dark the
// line is and how light the ground is.  Improper calibration will result in poor readings.
// If you want to skip the calibration phase, you can get the raw sensor readings
// (analog voltage readings from 0 to 1023) by calling qtra.read(sensorValues) instead of
// qtra.readLine(sensorValues).

// The main loop of the example reads the calibrated sensor values and uses them to
// estimate the position of a line.  You can test this by taping a piece of 3/4" black
// electrical tape to a piece of white paper and sliding the sensor across it.  It
// prints the sensor values to the serial monitor as numbers from 0 (maximum reflectance) 
// to 1000 (minimum reflectance) followed by the estimated location of the line as a number
// from 0 to 5000.  1000 means the line is directly under sensor 1, 2000 means directly
// under sensor 2, etc.  0 means the line is directly under sensor 0 or was last seen by
// sensor 0 before being lost.  5000 means the line is directly under sensor 5 or was
// last seen by sensor 5 before being lost.


#define NUM_SENSORS             6  // number of sensors used
#define NUM_SAMPLES_PER_SENSOR  4  // average 4 analog samples per sensor reading
#define EMITTER_PIN             QTR_NO_EMITTER_PIN  // emitter is controlled by digital pin 2

// sensors 0 through 5 are connected to analog inputs 0 through 5, respectively
QTRSensorsAnalog qtra((unsigned char[]) {0, 1, 2, 3, 4, 5}, 
  NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];


void setup()
{
  delay(500);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);    // turn on Arduino's LED to indicate we are in calibration mode
  for (int i = 0; i < 400; i++)  // make the calibration take about 10 seconds
  {
    qtra.calibrate();       // reads all sensors 10 times at 2.5 ms per six sensors (i.e. ~25 ms per call)
  }
  digitalWrite(13, LOW);     // turn off Arduino's LED to indicate we are through with calibration

  // print the calibration minimum values measured when emitters were on
  Serial.begin(9600);
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtra.calibratedMinimumOn[i]);
    Serial.print(' ');
  }
  Serial.println();
  
  // print the calibration maximum values measured when emitters were on
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtra.calibratedMaximumOn[i]);
    Serial.print(' ');
  }
  Serial.println();
  Serial.println();
  delay(1000);
}


void loop()
{
  // read calibrated sensor values and obtain a measure of the line position from 0 to 5000
  // To get raw sensor values, call:
   // qtra.read(sensorValues); //instead of unsigned int position = qtra.readLine(sensorValues);
  unsigned int position = qtra.readLine(sensorValues);
  
  // print the sensor values as numbers from 0 to 1000, where 0 means maximum reflectance and
  // 1000 means minimum reflectance, followed by the line position
  for (unsigned char i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(sensorValues[i]);
    Serial.print('\t');
  }
  //Serial.println(); // uncomment this line if you are using raw values
  Serial.println(position); // comment this line out if you are using raw values
  
  delay(250);
}

But I get very strange readings. Sometimes the values are always the same, like 0.

Other times I get sort readings, but then there is a sensor that always reads 0, even under a black line. (third picture)
I even get readings when the sensors are not connected. (last picture)

Here are the pictures:

http://imgur.com/lpO5Mj2

http://imgur.com/wQhUipi

http://imgur.com/w5zXMvQ

http://imgur.com/C3KrjkP


#6

I think we should separately test the Arduino UNO and QTR sensor. Can you try measuring the output of the QTR sensors with a multimeter to see if you can observe predictable behavior? Can you also run that example sketch (without the QTR sensors attached) and try connecting each input to GND and 5V to see if you can reliably get 0 and 1000 for the individual sensor values? (You can ignore the last column, which shows the position parameter, for that test.)

-Jon


#7

Hi Jon,

I just did that and I got for all my sensors about 4.8 volts when measuring with a multimeter, except the 7th sensor,
wich always was at 0 volts. So I think that sensor is faulty like I was thinking before and conclude from the results from the serial monitor.
And i can get 0-1000 values except for that one.

It is really frustrating, because I have to make a line follower for a final years projects and this is taking sooo much time.

I also wanted to ask about the DRV8835 motor shield. Until now I have always been disconnecting the shield when powering the arduino from usb from my pc when serial monitoring. I read at the pololu webpage for the DRV8835 shield that you should never connect a seperate powersupply to the ardunio’s power jack when powering the arduino from the shield. So am I correct that I also shouldn’t connect the arduino to my pc and the shield at the same time?


#8

Are you saying that your array’s outputs are always 4.8V, except for sensor 7, which measures 0V? Can you confirm that you are moving a line in front of them while you perform this test, and that the distance to the face of the sensor is about 3mm (i.e. the optimal sensing distance)? Can you upload pictures that clearly show your sensor array’s connections and soldering joints?

If you have a camera phone or video recording device that can see IR light, can you verify that all of the LEDs are lit? You can see how in this picture, which uses a point-and-shoot camera.

Also, to be clear, by “i can get 0-1000 values except for that one”, are you confirming that you can connect each Arduino input to ground and logic high to appropriately read 0 and 1000 from the serial monitor, respectively?

As for your DRV8835 question, no, that is incorrect. It is okay to connect your Arduino to USB with the DRV8835 shield mounted to it, even if the shield is receiving power through VIN. What you should not do is connect power to the shield’s VIN and the Arduino’s barrel jack at the same time.

-Jon


#9

Hi Jon,

I have gone out of my way and ordered this time another sensor, the pololu QTR-8RC. Because this schoolproject is driving me crazy. I have been working non stop on this project and have tried all codes there are to find on the internet.

As you can see I have three microcontrollers, two uno’s and one mega. I checked these microcontrollers and they work fine, a few days ago I used these for another project (controlling servo’s and bluetooth communication). So I don’t think my microcontrollers are an issue.

I am using sensor 2,3,4,5,6 and 7. Sensor 2 is connected to A0, sensor 3 to A1, sensor 4 to A2, sensor 5 to A3, sensor 6 to A4, sensor 7 to A5.
Could you check this in the code if this alright or the order should be switched or something?
I also don’t uderstand where you can declare exactly wich sensor is atatched to wich pin. I can see that you have to specify the number of sensor and wich inputs are used, but I don’t see it specified exactly.

The motors also work correctly, if use the DRV8835 library and use the test code, both motors are turning in the right direction as specified. BTW I am using two lithium-ion 18650 batteries (wich should provide more than enough current). They are brand new, so no issue there.

Edit: I have now used the serial monitor to check the QTR-8RC and as far as I can see it works fine, it show a value around 200-300 if a black line is detected and a value around 10 if white background is detected.
But again no succes with line following.

And I am not sure If I should define the analog pins A0 to A5 as inputs, as they are receiving values from the QTR sensor.

Also if declaring the pins in the beginning, should I refer to the analog pins like I did now i.e. 14, 15,… or just A0,A1,A2…?


#10

Hi Jon,

Your sketch looks mostly fine, except it looks like your PID coefficients are both zero. Can you try playing with those values and see if you can get your robot to follow a line? If it is not going well, I am going to need a more accurate description than “no succes with line following”. For example, can you describe the actual behavior of your robot (e.g. runs straight for a little and immediately turns right and veers off the course) and what behavior you are expecting to see? It would also help if you post a link to a video.

It should be okay to use either 14, 15, 16,… or A0, A1, A2… to instantiate that QTR object.

-Jon


#11

I got it working now, the issue was that a wire from the right motor was broken off.


#12

I am glad things are working now; thanks for following up and letting us know what the issue was.

-Jon


#13

Hi everybody,

We’re working on the same project, with qtr-8a sensor. We have two linefollowers and we uploaded this code with some adjustments for our cars, but our problem is that the right motor doesn’t work, and we don’t know why but the problem seems to be in the code. @JonathanKosh can you help us with this please?


#14

I am sorry your line followers are not working. Are both line followers showing the same issue? Can you describe in more detail what exactly is happening when “the right motor doesn’t work” (e.g. is the motor rotating in the wrong direction, is it not moving at all, etc.)? It would help to post a video that shows the behavior you are referring to. What makes you suspect that the code is the issue?

Also, you mentioned that you are “working on the same project, with qtr-8a sensor”, but it is not obvious that you are using the same components (motors, motor drivers, Arduino, etc.) as the original poster. Can you tell me more about your system? What motors are you using? What are you using to control the motors? How are you supplying power?

-Jon