Search code examples
c++arduinoserial-communication

Arduino Serial.parseInt() data read corrupted by too much Serial.print()?


I am doing an Arduino project to have a fan spin based on the vehicle speed in iRacing. This is my very first arduino project, so please bear with me. I'm really confused by some strange behavior with the PC/Arduino serial communication and I'm hoping someone can help explain whats going on...

Basically, there is a C++ program on the PC that gets data from the iRacing SDK for the vehicle's velocity and sends that over the serial line to the Arduino. The Arduino does some simple processing and drives a motor controller to run the fan.

The phenomenon I'm trying to understand is that if I have the Arduino write too much to the serial with Serial.print() statements it starts corrupting the values that its reading in with Serial.parseInt().


I have gotten it to work by simply not writing "too much" to the serial line, but for a while it was behaving erratically - fan speed going up and down even when the iRacing value was steady. I added extra Serial.print stuff in my arduino sketch and serial.readSerial to try and see on the PC side what was going on with the values and it turns out that was making it worse.

After pulling my hair out for a bit, I started from scratch on the arduino sketch and it worked with all he same logic but with the Serial.print commands commented out! So I systematically added them back in and found that there is some threshold where if I print too much to the serial line it starts to malfunction.

Here is the output as seen on the PC when its working. The PC is sending 59 as an int to the Arduiono. The Arduino is receiving that with Serial.parseInt() doing a constrain() to 55, and then mapping it to a 40-255 range. The minimal Serial.print() statements send that data back to the PC where it is read and printf'd. All is well.

59     55      255
59     55      255
59     55      255
59     55      255
59     55      255
59     55      255
59     55      255
59     55      255

If I add more Serial.print() statements to describe the data, the value that I'm reading from the PC with Serial.parseInt() starts to get perturbed. This output shows what I'm seeing when that happens. The data looks messed up, and indeed the fan speed goes haywire. This is the same case as above and it should be steady at 59:

Car Vel: 59     55      255
Car Vel: 59     55      255
Car Vel: 9      9       71
Car Vel: 47     47      223
Car Vel: 59     55      255
Car Vel: 59     55      255
Car Vel: 9      9       71
Car Vel: 47     47      223
Car Vel: 59     55      255
Car Vel: 71     55      255
Car Vel: 47     47      223
Car Vel: 59     55      255
Car Vel: 59     55      255

Here is the Arduino sketch simplified all the way down so all it does is read in the int from the PC, constrain it, map it to a range and print the values. As it is presented below, it will malfunction and produce output (like the second listing above). If I comment out the "Car Vel:" print, then it works and the data is steady (like the first listing above).

#define MIN 40
#define MAX 255
#define TOPSPEED 55

void setup() {
  Serial.begin(9600);
}

void loop() {
  uint8_t v;
  uint8_t s;
  if (Serial.available() > 0) {
    v = Serial.parseInt();
    Serial.print("Car Vel: ");       //UNCOMMENT ANY OF THESE TO SEE THE FAIL
    Serial.print(v);
    Serial.print("\t");
    v = constrain(v,0,TOPSPEED);
//    Serial.print("Clamped Vel: ");   //UNCOMMENT ANY OF THESE TO SEE THE FAIL
    Serial.print(v);
    Serial.print("\t");
    s = map(v,1,TOPSPEED,MIN,MAX);   
//    Serial.print("Fan Speed: ");      //UNCOMMENT ANY OF THESE TO SEE THE FAIL
    Serial.println(s);
  }    
}

On the PC side, I'm using the irsdk_ir2ad C++ code from the iRacing SDK with only the run() routine modified like so:

void run()
{
    // wait up to 16 ms for start of session or new data
    if(irsdkClient::instance().waitForData(16))
    {
        // and grab the data
        int v = g_carVelX.getInt();
        serial.writeSerialPrintf("%d\n", v);
    }

    // check for data coming back from Arduino
    if (serial.serialHasData())
    {
        static char buffer[256];
        serial.readSerial(buffer, 256);
        printf("%s", buffer);
    }

    monitorConnectionStatus();
}

I'm confident that uncommenting the Serial.print lines does make the issue present, but I have no real good explanation as to why. Can anyone help? Is it some sort of send length thats being exceeded (seems like a really small amount of text)? Or too much data being written from the PC while the Arduino is writing its own data out? Or some sort of timing hickup where its just the extra time and not really anything to do with the amount of the data being written?


Solution

  • The answer turns out to be the character limitation of 9600 baud.

    In this particular case, the PC is getting data at 60Hz. At 9600 baud the serial line can only handle 16 characters per cycle.

    Trying to output the entire string exceeds that 16 byte limit: "Car Vel: 59 55 255"

    Experiments have shown that if I lower the combined send/receive data to <= 16 bytes it is consistently error free.