Search This Blog

Thursday, 13 February 2014

Minimizing timing impact of Diagnostic use of Serial.print function in Arduino

While developing routines for my rover, especially diagnostic routines to identify sensor errors or conflicts, I have been using the Serial.print() function.   

I've found it very useful over the past several months. 
However, like all high level functions, it comes at a cost... timing...  

I decided to see how much of a cost, and if there was anything I could do to reduce this cost.  

Here are my results....


This is a typical diagnostic report for my distance ranging module.  There are four Sharp Infrared Distance Sensors (one on each of front/rear/left/right)  and there are two MaxBotix Ultrasound modules on a servo 180 degrees from one another.  In this example, these give me Frontleft, Front, FrontRight, RearRight, Rear, RearLeft.

      Serial.print("StartTime with separate Serial.print statements = "); 
      Serial.println(test=millis()); 

         Serial.print("Front: ");  Serial.print(rangefront[midpoint]); 
         Serial.print("  Rear: ");  Serial.print(rangerear[midpoint]);  
         Serial.print("  Left: ");  Serial.print(rangeleft[midpoint]); 
         Serial.print("  Right: ");  Serial.print(rangeright[midpoint]);

         Serial.print("    Front Sonar: ");  Serial.print(FrontSonar[midpoint]/58); 
         Serial.print("  Rear Sonar: ");  Serial.print(RearSonar[midpoint]/58);  

         Serial.print("FrontLeft: ");  Serial.print(FrontLeft); 
         Serial.print("  FrontRight: ");  Serial.print(FrontRight);  
         Serial.print("  Front: ");  Serial.print(Front); 
         Serial.print("  RearLeft: ");  Serial.print(RearLeft); 
         Serial.print("  RearRight: ");  Serial.print(RearRight);  
         Serial.print("  Rear: ");  Serial.println(Rear); 

      Serial.print("EndTime with separate Serial.print statements = "); 
      Serial.println(millis()-test); 
On an 8Mhz Arduino Pro Mini, this snippit takes 17ms to generate and send this report.

But what if I used string concatenation, and only sent ONE string our Serial like this?
      Serial.print("StartTime with one Serial.print statement and concat strings = "); 
      Serial.println(test=millis()); 
        
         // Assemble the string first, then print it once.
         
         response = "";     // Flush previous message.
         response += "  Front: ";      response += rangefront[midpoint];  
         response += "  Rear: ";     response += rangerear[midpoint]; 
         response += "  Left: ";     response += rangeleft[midpoint];   
         response += "  Right: ";    response += rangeright[midpoint]; 

         response += "  Front Sonar: ";  response += FrontSonar[midpoint]/58; 
         response += "  Rear Sonar: ";  response += RearSonar[midpoint]/58;  

         response += "  FrontLeft: ";  response += FrontLeft; 
         response += "  FrontRight: ";  response += FrontRight;  
         response += "  Front: ";    response += Front; 
         response += "  RearLeft: "; response += RearLeft; 
         response += "  RearRight: ";  response += RearRight;  
         response += "  Rear: ";     response += Rear; 

         Serial.println(response);

      Serial.print("EndTime with one Serial.print statement and concat strings = "); 
      Serial.println(millis()-test); 
 On an 8Mhz Arduino Pro Mini, this snippit only takes 6ms to generate and send this report.
And before you ask why I don't just serially concatenate in one statement... the Arduino IDE doesn't seem to support that, at least not for mixed data types.

Can I do any better?  What if I reduces the TEXT portion to just comma separators, and only sent ONE string our Serial like this?

      Serial.print("StartTime with no filler and concat strings = "); 
      Serial.println(test=millis()); 
        
         // Assemble the string first, then print it once.
         
         response = "";     // Flush previous message.
         response += rangefront[midpoint];  response += ", ";    
         response += rangerear[midpoint];  response += ", "; 
         response += rangeleft[midpoint];   response += ", ";    
         response += rangeright[midpoint]; response += ", "; 

         response += FrontSonar[midpoint]/58; response += ", ";  
         response += RearSonar[midpoint]/58;   response += ", "; 

         response += FrontLeft; response += ", ";  
         response += FrontRight; response += ", ";    
         response += Front;  response += ", ";  
         response += RearLeft; response += ", ";  
         response += RearRight;  response += ", ";   
         response += Rear; 

         Serial.println(response);

      Serial.print("EndTime with no filler and concat strings = "); 
      Serial.println(millis()-test); 
 On an 8Mhz Arduino Pro Mini, this snippit now only takes between 3-4ms to generate and send this report.

This is a significant improvement, and reduces the overall impact diagnostics has on my loop timing....

Hope you find this helpful...