Library Basics - Optimization

The first Library Basics blog covered a basic conversion from a working sketch to a very simple library using the C++ class.  User mogul correctly pointed out some code optimizations that we can make.  His original message was:


You seem to waste a little resources here and there:

You store 4 private variables.

  • sensorPin could have been a 8bit type (uint8_t)
  • duration should have been unsigned long. (more "correct", but not an optimization)
  • cm and inches can be omitted

The current code calculates both inches and cm on all pings, but in real life applications often  only the one of them will be needed. I suggest to make the Ping::pulse ping and store in duration, and then let the two accessor functions do the conversions. This way you do not need the functions Ping::microsecondsToInches and Ping::microsecondsToCentimeters

And then it's a bit unconventional to have actual functionality placed in the .h file. Even if its only a single line of code the 3 return statements should not be there. You should have put them and their methods i the .cpp file and left the pure prototypes in the .h fiile.


Let's make these changes to see how they would look.  First let's look at the header file.


Ping.h

#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

#ifndef PING_H
#define PING_H

class Ping
{
  private:
    uint8_t sensorPin;              // pin to use for the sensor
    unsigned long duration;       // microseconds of the ultrasonic pulse

    Ping();          // don't allow default constructor

  public:
    Ping(uint8_t pin);      // constructor
    void pulse();             // send the command to send a ultrasonic pulse

    unsigned long getInches();              // get our reading in inches
    unsigned long getCentimeters();      // get our reading in cm
    unsigned long getMicroseconds();   // get our reading in microseconds
};

#endif


Some notes on the header file:

  1. If #if code involving the ARDUINO definition is used to ensure we put the proper Arduino header in for the 1.0 version of the IDE vs the older versions.
  2. I moved all code to the '.cpp' file.  There may be a bit of style or some programming standards that you may want to use, so just Google a few and see what seems to make the most sense to you. I don't really have a true preference but I've seen very simple methods in the header file and people make a good argument to put all code in the '.cpp' file.

Now our changes to the '.cpp' file.


Ping.cpp

#include "Ping.h"

Ping::Ping() {
  // Do nothing
}

Ping::Ping(uint8_t pin) {
  sensorPin = pin;
}

void Ping::pulse() {
  // Tell the sensor to send a signal

  pinMode(sensorPin, OUTPUT);
  digitalWrite(sensorPin, LOW);
  delayMicroseconds(2);
  digitalWrite(sensorPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(sensorPin, LOW);

  // Read the duration of the ping 

  pinMode(sensorPin, INPUT);
  duration = pulseIn(sensorPin, HIGH);
}

unsigned long Ping::getCentimeters() {
  return duration / 58;
}

unsigned long Ping::getInches() {
  return duration / 148;
}

unsigned long Ping::getMicroseconds() {
  return duration;
}


The code file:

  1. I simplified the getInches() method calculations since we could do some of the divisions ahead of time.
  2. Calculations are done when they are need, not every time we measure the ultrasonic pulse.

Conclusion

Original size: 3432 bytes
Library size: 3518 bytes
Optimized size: 3368 bytes

Converting our library from our working, non-class code had an increase of 86 bytes.  By going over our code and eliminating variables that are not needed, doing any precalculations and reducing our variable datatypes to the smallest types that accomodate our values, we saved 64 bytes from our original code.

Maus



Update 2012-2-09

After discussing the formulas with Mogul and others in the shout box, I've updated the code above to use the proper conversion formulas.  These numbers are working with my current robot code and seem to be doing fine.

Maus