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

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?

MyWindSim_V2_01.zip (1.03 MB)

Serial.parseInt() is a blocking function. It sits and waits for the all of the Integer to arrive. Serial input basics will show how to receive data without blocking. Why are you running serial at only 9600 baud? You might want to try it faster. You will need to have the baud rate the same on both ends.

Sending start and end markers as described in the above link will improve reliability.

I did read the Serial Input Basics and tried some more experiments with the examples they provide. I think I figured out what was going on.

The routine running on the PC is getting data at 60Hz and thats setting the frequency for how often data is being sent to/from the Arduino. At 60Hz 9600 baud is only 16 bytes per cycle.

When I was just sending the numbers, it was within that range. When I started adding the debug/description strings it was easy to go over that 16 character limit.

Even when using start/end characters and no longer using the blocking methods to read the data on the Arduino it was easy to see the data get corrupted when trying to send too much.

I knew that 9600 baud was not fast, but I thought it would be sufficient for this kind of data transfer without realizing how little data there is to work with when running at 60Hz.

The obvious solution is to increase the baud rate, but its also important to do simple optimizations (send int values for numbers instead of strings strings, etc). I think the biggest lesson for me is to know the limitations of the serial communication at the speed things are running and make sure there is enough headroom.