Timer Class

In the last exercise, we drove the robot forward for two seconds.  In order to do that, we needed to compute the elapsed time by storing the current time at the start of the program and then computing the elapsed time by taking the difference between the current time and the starting time. Since measuring elapsed time is a very useful function, we want to encapsulate it into a C++ class because managing multiple start times quickly becomes rather messy.

We will start this exercise by loading the example program SimpleRobotDrive.  This program is basically the one you just created in the last section and should look like:

#include <Servo.h>
#include  <MsTimer2.h>

#include <SimpleRobot.h>

class MyRobot : public Robot
{
public:
    RobotMotor  *  m_pRightMotor;
    RobotMotor  *  m_pLeftMotor;
    unsigned long  m_time;
    
    void Setup()
    {
      Serial.println("Setup");
      
      m_pLeftMotor  = new RobotYellowMotor(1);
      m_pRightMotor = new RobotYellowMotor(0);
      
      m_pLeftMotor->SetPower(0.75);
      m_pRightMotor->SetPower(0.75);
      
      m_time  = millis();
    }
    
    void Loop()
    {
      unsigned long elapsedTime = millis() - m_time;
      
      if (elapsedTime > 2000)
      {
        m_pLeftMotor->SetPower(0);
        m_pRightMotor->SetPower(0);
      }
    }
    
    void Terminate()
    {
    }
} MyRobot;

Robot    *    g_pRobot    = &MyRobot;

Now what we want to do is to create a C++ class to replace the elapsed timer calculation.

We will call our new class Timer.  First we will add the framework for the class and then fill in the details. Add the following code just before the declaration of you MyRobot  class:

class Timer
{
public:
};

This is how you declare a class in C++.  The public declaration separates those elements of the class that users of the class can access from those that they cannot.  Anything declared before the public statement are private to the class and can only be accessed by methods within the class itself.

Since we are going to want to measure elapsed time, we are going to need a variable to hold the starting time, just as we did in the previous example.  Once again we will use an unsigned long  as opposed to an int because we need to handle times longer than 32,000 milliseconds (about 32 seconds).  We will call this variable m_startTime and since we want this variable to be private to the class (i.e. not accessible to users of the class), we will declare it before the public statement as follows:

class Timer
{
    unsigned long    m_startTime;
    
public:
};

As we have discussed in the past, declaring the variable m_startTime does not initialize it.  The place to initialize member variable of a class in the constructor for the class.  The constructor  is a special function which is always named the same as the class itself but has no return value.  Add the following constructor right after the public statement.

    Timer()
    {
        m_startTime = millis();
    }

Note that we need to make the constructor public because it will need to be called by anyone using the class.  In the constructor we set the member variable m_startTime to the current time.

Now we need a function that will return the elapsed time.  Add the following code after the constructor we just entered:

    long GetTime()
    {
        return(millis() - m_startTime);
    }

Once again, we need to make this function public because we will be calling when we use the class.

We are almost done, but the class as it is will not be as useful as it might otherwise be. Currently the elapsed time will always be measured from the creation of the instance of the class. What we really want is to be able to ‘reset’ the start time at any point so that we can measure any arbitrary interval. Add the following function:

    void Reset()
    {
        m_startTime = millis();
    }

This function will reset the m_startTime to the current time. Then when we call the GetTime function we will get the elapsed time from the last time the timer was reset, rather than when it was created.

Now that we have created the Timer class, let’s put it to use.  We will no longer need the declaration of m_time  in our MyRobot  class, so replace it by declaring an instance of our new Timer class as follows:

class MyRobot : public Robot
{
public:
    RobotMotor  *  m_pRightMotor;
    RobotMotor  *  m_pLeftMotor;
    Timer          m_timer;

Then in the Setup function we will reset the timer by adding the following just after the lines where we set the motor power:

      m_timer.Reset();

Finally, in our Loop function, we will change the if statement to use the new timer as follows:

      if (m_timer.GetTime() > 3000)
      {
        m_pLeftMotor->SetPower(0);
        m_pRightMotor->SetPower(0);
      }

Our completed program should now look like:

#include <Servo.h>
#include  <MsTimer2.h>

#include <SimpleRobot.h>

class Timer
{
    long    m_startTime;
    
public:
    Timer()
    {
        m_startTime = millis();
    }
    
    long GetTime()
    {
        return(millis() - m_startTime);
    }
    
    void Reset()
    {
        m_startTime = millis();
    }
};

class MyRobot : public Robot
{
public:
    RobotMotor  *  m_pRightMotor;
    RobotMotor  *  m_pLeftMotor;
    Timer          m_timer;
    
    void Setup()
    {
      Serial.println("Setup");
      
      m_pLeftMotor  = new RobotYellowMotor(1);
      m_pRightMotor = new RobotYellowMotor(0);
      
      m_pLeftMotor->SetPower(0.75);
      m_pRightMotor->SetPower(.75);
      
      m_timer.Reset();
    }
    
    void Loop()
    {
      if (m_timer.GetTime() > 3000)
      {
        m_pLeftMotor->SetPower(0);
        m_pRightMotor->SetPower(0);
      }
    }
    
    void Terminate()
    {
    }
} MyRobot;

Robot    *    g_pRobot    = &MyRobot;

Now compile and upload the program. Then switch to the driver station and run our program, and we will see that the robot once again drives forward for 3 seconds.

Creating and using the class may seem to be a lot of unnecessary work, but it will be very useful in the long run.  If we later need to have a second time, we can create one by simply declaring another Timer instance:

    Timer          m_timer2;

In fact the class is so useful, that there is a built in timer class called RobotTimer so you don’t always have to create your own. If we consult the SimpleRobot documentation, we find:

RobotTimer Class

The RobotTimer class provides a useful method of measuring elapsed time.

Methods:

void Reset()
Resets the timer value to zero.

unsigned long GetTime()
Returns the elapsed time since the last call to Reset in microseconds.

So the previous program can be rewritten using the built in timer class as follows.

#include <Servo.h>
#include  <MsTimer2.h>

#include <SimpleRobot.h>

class MyRobot : public Robot
{
public:
    RobotMotor  *  m_pRightMotor;
    RobotMotor  *  m_pLeftMotor;
    RobotTimer     m_timer;
    
    void Setup()
    {
      Serial.println("Setup");
      
      m_pLeftMotor  = new RobotYellowMotor(1);
      m_pRightMotor = new RobotYellowMotor(0);
      
      m_pLeftMotor->SetPower(0.75);
      m_pRightMotor->SetPower(.75);
      
      m_timer.Reset();
    }
    
    void Loop()
    {
      if (m_timer.GetTime() > 3000)
      {
        m_pLeftMotor->SetPower(0);
        m_pRightMotor->SetPower(0);
      }
    }
    
    void Terminate()
    {
    }
} MyRobot;

Robot    *    g_pRobot    = &MyRobot;

In this version we don’t declare our own Timer class but, rather, use the built in timer class RobotTimer.

Now that we have learned how to do this, I have to tell you that driving by time is not the best approach.  We usually don’t care how long we drive, but rather how far we drive.

In the next section we will show you how to drive a specific distance rather than time.

Next: Drive Distance