Using multitasking to monitor the encoders

From ROBOTC API Guide
< Tutorials‎ | Arduino Projects/Mobile Robotics/BoeBot
Revision as of 17:55, 17 October 2012 by Jwatson (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
ArduinoArduino Tutorials and Guided ProjectsParallax BoeBot + Arduino Shield, Mobile Robotics Platform → Tutorials/Arduino Projects/Mobile Robotics/BoeBot/Using multitasking to monitor the encoders

The problem

Due to their limitations, ROBOTC does not contain configuration options for non-quadrature encoders. This means that the raw SensorValue[ ] will only give a 1 or 0 depending on whether the light sensor reads a slot or not. For our encoders to be useful, we need a value that increases every time the light reading changes. We can then use that value to determine how many revolutions the robot has traveled.

The solution

To fix this problem, we are going to use one of ROBOTC's most powerful features, multitasking. This essentially lets a program run multiple Tasks or 'mini programs' concurrently. We are going to make a task (which will run in the background) that keeps track of the encoder ticks and writes the calculated values into a pair of global variables (one for each encoder). These variables can then be read by any other function or task in the program.

Theory

We will need to monitor when the encoder value changes. To do this, we create two variables: 'state', which is the current value of the sensor, and 'lastState', which is the value of the sensor from the previous run of the loop. If 'state' does not equal 'lastState', then we know the wheels have proceeded 1/16th of a revolution and we will add 1 to the global variable for that particular encoder.

The code

Here is the code without multitasking; its only job is to find the total ticks of each encoder. Be sure to read the comments so that you understand what it is doing. If the program is run with the 'global variables' debug window open, you can observe as the variables increment when the wheels rotate.

//used to store the count of the motor clicks
int leftEncoderCount = 0;
int rightEncoderCount = 0;
 
task main()
{
  // Get the state of the encoders so that we know when they have changed;
  // for example if the last state was high and the current state is low
  // or vice-versa, then we know that the encoder incremented another click.
  int lastStateLeft = SensorValue[leftEncoder];
  int lastStateRight = SensorValue[rightEncoder];
 
  while(true)
  {
 
    //get the current state of the left encoder
    int state = SensorValue[leftEncoder];
 
    //has the left encoder changed states?
    if (lastStateLeft != state) 
     {
      //if so, then increment the leftEncoderCount by 1
      leftEncoderCount++;
 
      //Then store the current state as the last state so that we can keep monitoring every change
      lastStateLeft = state;
     }
 
    //do the same for the right encoder.
 
    state = SensorValue[rightEncoder];
 
    if (lastStateRight != state) 
    {
      rightEncoderCount++;
      lastStateRight = state;
    }
 
    //we add a pause between updates to keep from hogging the CPU and
    // so that we debounce the encoders.
    wait1Msec(10);
  }
}

Monitoring the Encoders and Running a Program Simultaneously

So we know how to read the encoders, but modifying the code to have the robot perform other tasks would be tricky. To solve this problem we will use multitasking to have the program monitor the encoders in the background.

Breaking out of task main()

Until now, all of the program logic has executed step-by-step within task main(). Now, we are going to turn the encoder monitoring code into a background task so that we can use task main() for other code. Since only task main() is started by default, we will need to use the StartTask() function to start the encoder monitoring task (in this case, called 'encoderTask()').

//used to store the count of the motor clicks
int leftEncoderCount = 0;
int rightEncoderCount = 0;
 
//a background task used to monitor the encoders and count the clicks
task encoderTask()
{
  // Get the state of the encoders so that we know when they have changed
  // for example if the last state was high and the current state is low
  // or vice-versa, then we know that the encoder incremented another click.
 
  int lastStateLeft = SensorValue[leftEncoder];
  int lastStateRight = SensorValue[rightEncoder];
 
  while(true)
  {
 
    //get the current state of the left encoder
    int state = SensorValue[leftEncoder];
 
    //has the left encoder changed states
    if (lastStateLeft != state) 
    {
      //if so, then increment the leftEncoderCount by 1
      leftEncoderCount++;
 
      // then store the current state as the last state so that we can keep monitoring every change
      lastStateLeft = state;
    }
 
    //repeat for the right encoder.
 
    state = SensorValue[rightEncoder];
 
    if (lastStateRight != state) 
    {
      rightEncoderCount++;
      lastStateRight = state;
    }
 
    //we add a pause between updates to keep from hogging the CPU and
    // so that we debounce the encoders.
    wait1Msec(10);
  }
}
 
task main()
{
  StartTask(encoderTask); //Starts encoderTask. It will keep running in the background for the duration of the program.
 
  //Perform the rest of the program. You can access leftEncoderCount and rightEncoderCount from here (and anywhere else in the program).
}

Notepad.gif NOTE: By using multitasking you are able to use the BotBot encoders like a quadrature-encoder. Just replace "SensorValue[]" with the name of the encoder count variable.