QTR-8RC reads too big values after calibration

I am using Arduino Nano Every piggyback mounted on Pololu QTR-8RC sensor. In the Arduino I installed my code based on the Pololu example and modified it to communicate with my rpi and to store and retrieve calibration results in/from EEPOM.
On my test desk, the whole setup works just fine. When I mounted the sensor assembly on my robotic vehicle, I am experiencing weird behavior. Sometimes the read after the calibration reports “normal” results with reasonably low min values and max values up to 2500 or a bit lower. The positional readings are just fine then. However, just with the next calibration a mere minute latter, in the same environmental lighting and other conditions, the max values red after calibration are somewhere between 44000 and 65000. Off course, the positional readings are all wrong then. This drives me crazy. I use two sensor assemblies (left and right on the vehicle) and both display the same weird behavior.

Hello.

Are your readings being reported from the Arduino directly or through the Raspberry Pi (i.e. after the communication with the Arduino)?

The readings should be capped at the timeout value (which is 2500 by default in our library), so they shouldn’t be able to reach values as high as 44000. So, my initial thought is that there might be a problem with how you are communicating or storing/reading the values from EEPROM. If you are not directly reading the value reported from the Arduino (e.g. through the Serial Monitor), could you explain how you are handling the communication?

Brandon

Hi Brandon,

thank you for your explanation.
Here is the python program that communicates with arduino:

#this program communicates with arduino
# dataa - returns data row containing readings of each of the 8 sensors

import serial,time


if __name__ == '__main__':
	
    print('Running. Press CTRL-C to exit.')
    with serial.Serial("/dev/ttyACM0", 115200, timeout=1) as arduino: #orig 9600,uno:115200
        time.sleep(0.1) #wait for serial to open
        if arduino.isOpen():
            print("{} connected!".format(arduino.port))
            try:
                while True:
                    cmd=input("Enter command: data, dataa, cal, read, store, recall: ")
                    arduino.write(cmd.encode())
                    #time.sleep(0.1) #wait for arduino to answer
                    while arduino.inWaiting()==0: pass
                    if  arduino.inWaiting()>0: 
                        answer=arduino.readline()
                        answerX=answer
                        answer= answer.decode("utf-8")
                        answer=answer.strip("\r,\n")
                        if answer.isdigit():
                            print("int: ",answer)
                        else:
                            print("not int: ",answerX)
                        arduino.flushInput() #remove data after reading
            except KeyboardInterrupt:
                    print("KeyboardInterrupt has been caught.")

Here is the Arduino code:

#include <QTRSensors.h>
#include <EEPROM.h>

#define NUM_SENSORS   8     // number of sensors used
#define TIMEOUT       2500  // waits for 2500 microseconds for sensor outputs to go low
#define EMITTER_PIN   3     // emitter is controlled by digital pin 2

// this program communicates with rpi. It receives commands and returns results. 
// originaly using EEPROMex library, latter converted to work with Arduino EEPROM library.



// sensors 0 through 7 are connected to digital pins 3 through 10, respectively
QTRSensorsRC qtrrc((unsigned char[]) {4, 5, 6, 7, 8, 9, 10, 11}, NUM_SENSORS, TIMEOUT, EMITTER_PIN); 
unsigned int sensorValues[NUM_SENSORS];

//EEPROM Addressing for calibration storage
#define addrCalibratedMinimumOn 0
#define addrCalibratedMaximumOn 100


const int ledPin=13;
String nom = "Arduino";
String msg;
int termination = 0;

void setup() {
  Serial.begin(115200); //original 9600, na uno 115200
  pinMode(ledPin,OUTPUT);
}

void loop() {
  readSerialPort();
  unsigned int position = qtrrc.readLine(sensorValues);

  if (msg == "data") {
    sendData();
  }else if(msg == "dataa") {
    termination=0;
    sendDataa();    
  }else if(msg=="cal"){
    calibrateQTR();  
  }else if(msg=="read"){
    readQTR();
  }else if(msg=="store"){
    storeQTR();
  }else if(msg=="recall"){
    recallQTR();       
  }
  delay(250); // originalno 500, QTRExample ima 250
}

void readSerialPort() {
  msg = "";
  if (Serial.available()) {
    delay(10);
    while (Serial.available() > 0) {
      msg += (char)Serial.read();
    }
    Serial.flush();
  }
}

void sendData() {
  //write data 
  unsigned int position = qtrrc.readLine(sensorValues);
  //for (unsigned char i = 0; i < NUM_SENSORS; i++)
  //{
   // Serial.print(sensorValues[i]);
    //Serial.print("__");
  //}
  Serial.println(position); // comment this line out if you are using raw values
  //Serial.println();
  delay(250);
}

void sendDataa() 
{
  //write data 
  unsigned int position = qtrrc.readLine(sensorValues);
  //test if senzor over black termination (cross) line
  for (unsigned char i = 0; i < NUM_SENSORS; i++)
  {
    if (sensorValues[i] > 800) {
      termination += 1;
      } 
   }     
  //print values
  for (unsigned char i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(sensorValues[i]);
    Serial.print("__");
  }
  if (termination == 8) {
    position = 8000;
  }
  Serial.print(termination); 
  Serial.print("_:");
  Serial.println(position);
  delay(250);
}

void calibrateQTR()
{
  
  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
  {
    qtrrc.calibrate();       // reads all sensors 10 times at 2500 us per read (i.e. ~25 ms per call)
  }
  digitalWrite(13, LOW);     // turn off Arduino's LED to indicate we are through with calibration
  Serial.println();
}

void readQTR() //Reading Calibration Data...
{

   for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtrrc.calibratedMinimumOn[i]);
    Serial.print("_");
  }
  
  // print the calibration maximum values measured when emitters were on
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtrrc.calibratedMaximumOn[i]);
    Serial.print("_");
  }
  Serial.println();
}

void storeQTR() //Storing Calibration Data into EEPROM...
{

  EEPROM.put(addrCalibratedMinimumOn, qtrrc.calibratedMinimumOn);
  //EEPROM.writeBlock<unsigned int>(addrCalibratedMaximumOn, qtrrc.calibratedMaximumOn, 8);
  EEPROM.put(addrCalibratedMaximumOn, qtrrc.calibratedMaximumOn);
  Serial.println();

}

void recallQTR() //Recalling Calibration Data from EEPROM...
{

  //qtrrc.calibrate(); 
  //EEPROM.readBlock<unsigned int>(addrCalibratedMinimumOn, qtrrc.calibratedMinimumOn, 8);
  //EEPROM.readBlock<unsigned int>(addrCalibratedMaximumOn, qtrrc.calibratedMaximumOn, 8);
  EEPROM.get(addrCalibratedMinimumOn, qtrrc.calibratedMinimumOn);
  EEPROM.get(addrCalibratedMaximumOn, qtrrc.calibratedMaximumOn);
  
  Serial.println();

}

It sounds like your readings are after the communication through the Raspberry Pi. I recommend simplifying your setup by taking the Raspberry Pi out for now and just printing the readings to the Serial Monitor to help determine if the problem is on the Arduino side or with the communication to the Raspberry Pi.

Brandon

Hi Brandon,

thank you for your answer. I’ll follow your advice. Obviously, I have no other choice. The challenge I am facing with my setup is that my rpi’s raspbian is a bit outdated and it will take some time to say at least. Nevertheless, I’ll come back to you (to this forum) with my findings once I succeed.

Hi Brandon,
working directly with arduino over serial monitor provided me with clues about what went wrong. It wasn’t the communication rpi-arduino though. The old qtr library I am using doesn’t reset old maxvalues and minvalues before writing to them. So, only the bigger values get recorded, but not the smaller ones. I had to include a function that writes zeros to all minvalues and maxvalues and call it before the calibration or the recall.