How to use 9 QTR-RC sensors properly?

I am building a line-follower using an array of QTR-RC sensors. Ideally I want to use 9 sensors. Please help me with the proper edits in the library files:

  1. I found that in Pololu3pi.cpp one needs to change in Pololu3pi::init the pins numbers and quantity and then re-compile the library. Is this the ritght way? What other changes may be needed to switch from 5 sensors to 9?

  2. There is a numSensors variable in PololuQTRSensors. The comments says:
    // ‘numSensors’ specifies the length of the ‘pins’ array (i.e. the
    // number of QTR-RC sensors you are using). numSensors must be
    // no greater than 8.

    Can I still set it to 9? I understand that 8 is a limit for analog sensors, but with RC you can have all 20. Right?


The library assumes that the number of sensors will not exceed 8, so several of the arrays and other data structures have sizes based on this limit. You can increase the number of allowed sensors to 9, but you will have to modify the library code in a number of places before it will work. For example, the private data members _bitmask[8] and _register[8] in PololuQTRSensors.h have to be made bigger.

My recommendation is that you scan through the PololuQTRSensor source code line by line looking for anything that is hardcoded for a limit of 8 and change it as necessary (I don’t remember the code well enough to give you specifics, so this is what I would have to do, too). Note that, as a power of two, 8 is a special number that lets you do things like:

i = (i+1) & 0x07;

to increment a variable from 0 to 7 and then reset it back to 0. To increment i from 0 to 8 and reset it back to 0 again, you would need to change this line to:

if (++i > 8) i = 0; // i = (i+1) & 0x08 will not work!!!

A limit of 8 also means that you can use a single byte to store eight bits associated with your eight sensors, while going to nine sensors would require changing this data type to a two-byte integer. I don’t think the Pololu QTR library does this, but it’s something else to look out for when changing a limit from 8 to 9.

Another option would be to partition your sensors into two independent banks and create a PololuQTRSensor object for each bank. You would not need to modify the QTR library code at all in this case.

What is the motivation behind using nine sensors? How do you plan to arrange them? It definitely sounds like you have an interesting project in the works!

- Ben

Ben, Thanks for the tips, I will try them in the next few days. On new class - I am not good with C++ so I will stick to plain C methods for now. It would double the time though. So I may be better-off to edit the original library code.

The reason for 9 sensors is to have sure coverage for a rather narrow (half-inch) line. I placed them in line, slightly densier in the middle. Maybe I will move the ones at the ends forward, to have advance warning of a sharp turn. There may be smarter solutions out there with fewer sensors, but I found this straightforward design easier.
The 9-sensor bar will be used to upgrade my robot from this thread: I’ll let you know how it goes.

Question: How to read and set calibratedMaximumOn value from main program body (it is in plain C).

The QTR sensor library provides C functions for accessing the calibration value arrays:

extern "C" unsigned int *qtr_calibrated_minimum_on()
	return qtr->calibratedMinimumOn;

extern "C" unsigned int *qtr_calibrated_maximum_on()
	return qtr->calibratedMaximumOn;

extern "C" unsigned int *qtr_calibrated_minimum_off()
	return qtr->calibratedMinimumOff;

extern "C" unsigned int *qtr_calibrated_maximum_off()
	return qtr->calibratedMaximumOff;

Your program can call these functions. For example:

unsigned int *calibratedMaximumOn = qtr_calibrated_maximum_on();

Please let me know if you have any more questions, and good luck with your project. I’d love to hear about your results!

- Ben

I tried to edit the library code to read 9 sensors but it was not stable after it. I was only able to read some of the sensors. Maybe I missed some of the places that still needed edits. BTW, did you actually use the i = (i+1) & 0x07 trick? I did not find it in the code.
So as a workaround I copied code from read_private function (+ added some calibration) and used it to read the 9th sensor separately.
Now my robot is all built and I move on to the fun stage of PID tuning.

I’m glad to hear you found an adequate workaround. I don’t think we used anything like

i = (i+1) & 0x07

anywhere, but I’m not absolutely certain of that. Mainly I was giving that as an example of something to be cautious of when changing a limit that’s a power.

- Ben

Well, I made it run with PID code reasonably well, a little short of 1 m/s. So I decided to take it to Vienna, Austria for Robotchallenge ( is perhaps the largest Robotics event in whole Europe. My robot took 3d place in parallel slalom (line-tracing) and 2d place in enhanced slalom (line tracing with obstacles) there. (I also had 2 mini-sumos but they did not make it to the finals).

I found that with 1:30 HP motors (, the robot will occasionally start jerking and H-Bridge would get very hot. So shortly before the competition I had to change the motors for Maxon 13017, which are no less powerful. They operated very reliably without any glitches. Would anyone know why Orangutan B-168 and Pololu HP 1:30 did not work together well?

Thank you for the update, and congratulations on your success at the competition! Do you have any videos or pictures from the competition? Did you win any interesting prizes?

I’m sorry to hear that the 30:1 HP micro metal gearmotors didn’t work out well for you. What voltage were you running the motors at? In general, the HP versions of our micro metal gearmotors are a little beyond what we recommend for the TB6612 motor drivers on the Baby Orangutan since their stall currents at 6V exceed what the Baby Orangutan can deliver continuously. In an application like a line follower, the many minor corrections you make to motor speed as you drive can cause the motor to rapidly alternate between high and low speeds, which can put the average current draw well above the free-run current and closer to the stall current. It sounds like this was overheating the Baby Orangutan’s motor drivers and causing the thermal protection to kick in. Out of curiosity, what is the stall current of your Maxon motors at 6V?

- Ben

The official video is not out yet. There are some good videos on youtube:
Minisumo matches:
Funny line tracer performance:
The official photos are available here:
There were no prizes besides medals and European-scale glory. :slight_smile:

Ben, I started a separate topic on the TB6612 issue. Please take a look here

Dear Ben,
I noticed that the latest library (April 20) still only allows for 8 sensors MAX:
"numSensors specifies the length of the ‘pins’ array (the number of QTR-RC sensors you are using). numSensors must be no greater than 8."
Would you please consider removing this limit in the next release.

I made a few fixes in the last library version but now it would be nice not to re-do it every time you have a new version.
PS: thanks for the encoders functions - I appreciate your responsiveness!

Hello Rio,

We have removed the 8-sensor restriction in the latest version of the library, so should now be able to use up to 16 QTR sensors at once. Please let us know if you get a chance to try it out and find out whether it works or not!


Hi, Paul,

I just reviewed the code in the latest Pololu AVR Library (released 2009-12-01). I noticed the new 16-sensor limit.
However I am not sure about this piece:
void PololuQTRSensors::read(unsigned int *sensor_values, unsigned char readMode)
unsigned int off_values[8]; < - can this still limit the library to 8 sensors support? Should it be [16] instead?

Also in the library manual you still limit # of QTR sensors to 8.

To make the practical test I wanted to use my newly purchased Orangutan SVP-324. Unfortunately I found that the code does not support PA0-PA7 input pins. Shall I just fix:

  1. PololuQTRSensorsRC::init - to allow for pins 21-28, tied to PORTA, + add corresponding variables
  2. PololuQTRSensorsRC::readPrivate - to read from PORTA.

Did I miss any other places that need fixing? Could you consider adding QTR support to PORTA in SVP-324 to the next version of the library?

Hi RiO,
It definitely looks like that is a bug in our library, and we will address it in the next release. I suggest that you fix it yourself as you said for now, and go ahead and add the PORTA support to the init() function - I recommend using the values from OrangutalDigital.h. Unfortunately, it looks like _bitmask and _register are also defined to have size 8 instead of 16 - you will need to fix that as well to make it truly work with 16 sensors.

Thanks for pointing out these inconsistencies and please let me know if you run into any problems trying to fix them up!



I was able to fix the code to allow for PORTA use in SVP-324. It required the edits from my previous post and couple of fixes in the .h file.
As a side effect, the library failed to compile for the other processors. :slight_smile: Presumably it gets fixed with preprocessor instructions. (10.8 KB)
I have yet to test the code with 9+ sensors. Hopefully it will work.

Thanks for posting the zip - I will use that as a reference when updating the library. Looks like you have fixed everything EXCEPT the bitmask array needs to be enlarged to size 16 as well. Also, I recommend getting the port numbering used by init() consistent with the IO* macros in OrangutanDigital.h so that you can use these macros when defining your pins. Unfortunately, it looks like it is not set up to work with the SVP numbering at all yet, since that is different from the Arduino numbering used on the other boards.


Hi, Paul,

I noticed that you made some of the discussed changes in the January 29 library version.
Unfortunately for some reason only 8 sensors are read in a 9-sensor array. I tested it with O-168 controller and the 9th sensor always gives zero. The code seems to be OK though, but I did not recompile it. Could you test it on your side?

I also noticed that you did not include support for Pins A of SVP. Could you add it in the next version please?

Hello, RiO.

I suspect that you are not using array indices properly when processing the readings: your first sensor should be at index 0 and your ninth sensor should be index 8. If you try to access index 9, you won’t get good values.

If that’s not the problem, please post the simplest possible code that reproduces the problem.