Can't get QTR-8RC to work

I have the Arduino Mega and just bought from Pololu the QTR-8RC array and like some others here I am getting all zeros all the time. I have never seen a solution to this problem. My code is simple and right from this site. Since the QTR-8RC is suppose to be digital, I am connecting 5 of the 8 outputs (just to test it out) to digital pins 44, 46, 48, 50 and 52 on the Mega. When I run the program I get 0 0 0 0 0 always. I connected a scope to one of the pins and I see no activity on the pin so I am wondering if the software library works with the Ardiuno Mega. I am using the digital pins for other functions and they work well. Any ideas? The code is attached.

#include <PololuQTRSensors.h>  

PololuQTRSensorsRC qtr((unsigned char[]) {44,46,48,50,52}, 5);  //digital pins
  
void setup()  
{
  Serial.begin(9600);  
  int i;  
  for (i = 0; i < 250; i++)  // make the calibration take about 5 seconds  
  {  
   qtr.calibrate();  
   delay(20);  
  }  
 }  

void loop()  
{  
  unsigned int sensors[5];  // change 6 to whatever number of sensors you are using
  int position = qtr.readLine(sensors);  
  // output to Serial monitor
Serial.print(sensors[0]); 
Serial.print(" ");
Serial.print(sensors[1]); 
Serial.print(" ");
Serial.print(sensors[2]); 
Serial.print(" ");
Serial.print(sensors[3]); 
Serial.print(" ");
Serial.print(sensors[4]); 
Serial.print(" ");
Serial.println();
}

Hello.

I wouldn’t expect the code to work with the Arduino Mega as it was written for a different microcontroller. However, interfacing with the QTR sensors is pretty easy. The procedure is documented on the product page and in the user’s guide:

  1. Make the pin an output and drive it high for 10 us.
  2. Make the pin an input and time how long it takes for the input value to read low.

The C code we provide for converting the readings into a single value represeting the position of the line should still work if you can write Arduino code to obtain values for each sensor as described above.

- Ben

Thank you for your quick reply. When I downloaded the library I did not see where it was not for Arduino Mega. The thing about writing and waiting 10us, etc, I have seen already. But being new to Arduino and C, I am not sure where to start to code that. The biggest challenge seems to be polling the pin and waiting for it to change state. That is why I was happy when I saw the library. Can you even measure stuff in microseconds in C, do you need machine code? I have never seen anyone post code for this for the Arduino, maybe it is too hard?

JC

The library was written before the Arduino Mega existed and it hasn’t been updated in quite a while. You would most likely want to do the timing using one of the AVR’s hardware timers, which can be controlled in C and can time on the order of microseconds. While there might not be Arduino libraries out there for interacting specifically with the QTR sensors, I’m sure there are tons of libraries for using the hardware timers to time things. If you’ve already seen how to do the digital I/O manipulation, then the only remaining task is timing how long a digital input takes to go from high to low, which is not hard at all. It might even be possible to use the Arduino’s built-in PulseIn() function.

For a crude but simple solution, you could always do something like:

pinMode(qtrPin, OUTPUT);  // make pin an output
digitalWrite(qtrPin, HIGH);  // drive pin high
delayMicroseconds(10);  // delay for 10 us
pinMode(qtrPin, INPUT);  // make pin an input (internal pull-up will be enabled)
digitalWrite(qtrPin, LOW);  // disable internal pull-up resistor

unsigned int sensorValue = 0;
while (digitalRead(qtrPin) == HIGH && sensorValue < 50000)
{
  // check the input value of the sensor pin every 10 us
  // (timeout after 50 ms)
  delayMicroseconds(10);
  sensorValue += 10;  // keep track of how much time has passed (in us)
}

If you put the above code into a sketch and print sensorValue, do you see results that make sense?

- Ben

I starting thinking about what you posted the first time and with my scope in hand I was able to get the sensor to work (with at least 2 pins at least, need to expand it to all pins). Using the scope I determined that if I wait 2 ms, I can get a good reading. The code, which I just got working a few seconds ago, is below. If I can expland to the 5 sensors I want to use, I should be all set. As I said before I am new to C and the Ardiuno but I am learning very fast. Thanks for your help.

int jj;
int kk;

void setup()   {                
  Serial.begin(9600); 
  pinMode(50, OUTPUT);    
  pinMode(52, OUTPUT);   
}

void loop()                     
{
  pinMode(50, OUTPUT);    
  pinMode(52, OUTPUT);   
  digitalWrite(50, HIGH);   // set the LED on
  digitalWrite(52, HIGH);
  pinMode(50, INPUT);    
  pinMode(52, INPUT);
  delay(2);
  jj = digitalRead(50);   // set the LED on
  kk = digitalRead(52);
  Serial.print(jj);
  Serial.print(kk);
  Serial.println();
 
}

The code you posted won’t really tell you anything other than if the line is still high after 2 ms. Have you tried the code I posted, which should actually tell you how long the line has been high for? Also, you need to include a digitalWright(pin, LOW) call after you make the pin an input to disable the internal pull-up resistor (see the code I posted for an example).

- Ben

Thanks for the input. I tried your code and it does work. With white paper 0.125" away, I get low numbers like 20 and with nothing I get 17000 or more. So I should be all set! :sunglasses:

JC

I’m very glad to hear it works, but it can definitely be improved. For example, you probably want to make the timeout much shorter (maybe around 2000 us) so that you aren’t potentially stuck in a loop for 50 ms waiting to figure out if your surface is really black or really really black. The update rate of your sensors will be limited by your timeout, so your best bet is to make it as short as you can while still being able to differentiate between scenarios you care about.

Also, the QTR-RC sensors can be read in parallel, which can significantly increase the rate at which you can read the sensors, so you might want to try modifying your code to work for multiple sensors at once. For example:

unsigned int sensorValue[8] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned char sensorPins[8] = {50, 51, 52, 53, 54, 55, 56, 57};  // initialize to the pins you want to use
unsigned char i;

// drive all sensor pins high
for (i = 0; i < 8; i++)
{
  pinMode(sensorPins[i], OUTPUT);  // make pin an output
  digitalWrite(sensorPins[i], HIGH);  // drive pin high
}

delayMicroseconds(10);  // delay for 10 us

// make all sensor pins high-impedance inputs
for (i = 0; i < 8; i++)
{
  pinMode(sensorPins[i], INPUT);  // make pin an input (pull-up enabled mode)
  digitalWrite(sensorPins[i], LOW);  // disable internal pull-up resistor (make it a high-impedance input)
}

unsigned int time = 0;
while (time < 2000)
{
  // check the input value of all sensor pins every 10 us
  // (timeout after 2 ms)
  for (i = 0; i < 8; i++)
  {
    if (digitalRead(sensorPins[i]) == HIGH)
      sensorValues[i] = time;
  }
  delayMicroseconds(10);
  time += 10;  // keep track of how much time has passed (in us)
}

Even this code can be improved quite a bit, and the results would be much more accurate in an absolute time sense if you were to use a hardware timer instead of delayMicroseconds(10) since the rest of the stuff in the sensor reading loop probably now takes at least a few microseconds execute (and you’re not accounting for this extra time at all). Still, it provides a nice range of analog values that gives you a very good relative indication of how reflective something is.

I haven’t tried the code so it might be buggy. Please let me know if it works, and feel free to ask for clarification if there’s anything you don’t understand.

- Ben

Ben, right now I am mounting the sensor at the bottom of the robot and then I have to go to work but I will try that code when I get a chance. I have to make it so the sensor is removable as it has to be witihn .25" of the floor on hard floors but removable when the robot runs automonusly on carpeted floors.

JC

Hello.

I have updated the Arduino library for the QTR sensors. It should now work for both analog (A) and digital (RC) versions on all Arduinos, and it relies on standard Arduino functions, so it shouldn’t conflict with any other libraries. The library also now includes two sample sketches (one for each sensor version). Please let me know if you have any problems with it.

- Ben

Wow, sounds great. I will have to try that new library. During the past few days I have been playing with my code to read the sensors. As posted before, I write a 1, wait and read, finding either a ‘0’ or ‘1’. I leave the internal pullups active so when a sensor detects a black line, it is read as a ‘1’. So going over a black line straight I read 001100. An intersection as 111111, etc. Leaving the pullups active and looking just to see if I am over the line seems to work fine for my line/maze follower.

So I don’t understand

  1. why I need to play with the pullups to disable them? The pins stay active (1 or 0) for a long time, no problem missing a reading
  2. why I would want to look at the timings? I want a 1 or 0 so I know where the line is.

Could you please eplain?

JC

Using pull-ups will charge the sensors very slowly and will limit how quickly the sensors discharge, so they will limit your sensor update rate. The more often your sensor updates, the better performance you will be able to get at higher speeds because you’ll be operating on fresher data.

The reflectance sensors are capable of providing a lot more information than you are currently using. You are limiting your results to a simple “sensor sees line” or “sensor doesn’t see line”, but using the discharge time lets you include gray areas (literally) such as “sensor sees some of the line”. You can get a higher-resolution estimate of the line position if you use discharge times as analog measurements of reflectance than if you just use binary values.

If your plan is to make a slow, conservative robot, then what you’re doing will probably work fine. If you want to make your robot faster and smoother, the changes I made to the library should help you.

- Ben