ROBOTC.net forums
http://www.robotc.net/forums/

Multitasking Issue
http://www.robotc.net/forums/viewtopic.php?f=11&t=12784
Page 1 of 1

Author:  Fritz [ Wed Dec 09, 2015 4:18 pm ]
Post subject:  Multitasking Issue

Hello,
I have attempted to apply multitasking to my program, but some unexpected behavior occurred and I am unable to discover why or where the error occurs. The program should flow as follows:

When a button is pressed, it is determined whether or not the button has been pressed before. If so, the speedMotor task is activated and regulates the speed of the motors, spinning them up to motor power 127 when the getVelocity() function returns a value less than the value of max_vel, the value returned at motor power 67. When getVelocity() returns a value greater than or equal to max_vel, the motors are set to 67. This system is supposed to reduce the spin-up time for the motors so that vex balls can be fired faster. The problems comes when the button that activates this process is pressed again. When it is pressed again, the motors cut off momentarily before turning back on again, as if speedMotor was never stopped! I don't know if it's a simple fix and I've been staring at a screen for far too long, or that the logic is flawed, but any help would be appreciated. The relevant code is posted below:

[edit] When the button is held down, the motors slow to a stop without jolting back on again
Code:
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1,  ,               sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Sensor, I2C_2,  ,               sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Motor,  port7,           leftFireMech,  tmotorVex393_MC29, openLoop, reversed, encoderPort, I2C_1)
#pragma config(Motor,  port8,           rightFireMech, tmotorVex393_MC29, openLoop, reversed, encoderPort, I2C_2)

#include "JoystickDriver.c"

bool button_toggle = false;//toggle button boolean
float max_vel = 0.616; //velocity of motors at power level 67

float getVelocity(){
   nMotorEncoder[leftFireMech] = 0; //reset encoder

        //check to see if the encoders have moved
   clearTimer(T1);
   while(time1[T1] < 50) {}
   if(nMotorEncoder[leftFireMech] == 0) return 0;
       
        //get the time it takes for the encoder to count a revolution (vex 393 motor)
   clearTimer(T1);
   while(abs(nMotorEncoder[leftFireMech]) < 627.2){}

   return 627.2 / time1[T1];
}

task speedMotors(){
   while(true){
      if(getVelocity() < max_vel){
         motor[leftFireMech] = 127;
         motor[rightFireMech] = 127;
      }else{
         motor[leftFireMech] = 67;
         motor[rightFireMech] = 67;
      }
      EndTimeslice();
   }
}

task main(){
   while(true){
      getJoystickSettings(joystick);

      if(vexRT[Btn8U] == 1){
         if(button_toggle == false){
            startTask(speedMotors);
            button_toggle = true;
         }else if(button_toggle == true){
            stopTask(speedMotors);
            motor[leftFireMech] = 0;
            motor[rightFireMech] = 0;
            button_toggle = false;
         }
      }
        }
}

Author:  Tabor473 [ Fri Dec 11, 2015 10:24 pm ]
Post subject:  Re: Multitasking Issue

So the problem you are running into is actually not multitasking related. It is the classic problem of making a toggle with a single button. Remember the while loop in your main runs through extremely quickly so what happens is in the time your finger is on the button the loop executes multiple times so your task is started and stopped over and over again. The final outcome in this circumstance depends entirely on when your finger released the button.

So there is a couple simple to conceptualize ways to solve this problem. The first is to not allow the loop in main to continue until the button is release. This guarantees that loop is only run once while the button was down. This could be added on to your current main function like this.
Code:
task main(){
   while(true){
      getJoystickSettings(joystick);

      if(vexRT[Btn8U] == 1){
         if(button_toggle == false){
            startTask(speedMotors);
            button_toggle = true;
            }else if(button_toggle == true){
            stopTask(speedMotors);
            motor[leftFireMech] = 0;
            motor[rightFireMech] = 0;
            button_toggle = false;
         }
         while(vexRT[Btn8U]==1){sleep(50);}//not hog CPU
      }
   }
}


The other common solution is to not look for when the button is equal to 1 but look for when the button changes from 0 to 1. That change only occurs once per button press but the rest of your code is able to still run in that task because you are not waiting. This would be equivalent to using the rising edge of the signal. (Don't ask "is button pushed" instead ask "was button just pushed")

This solution usually just requires tracking the last button value and looking for when new button is press AND last button wasn't. Example below.

Code:
task main(){
bool lastButtonValue=false;
   while(true){
      getJoystickSettings(joystick);

      if(vexRT[Btn8U] == 1&&lastButtonValue==0){
         if(button_toggle == false){
            startTask(speedMotors);
            button_toggle = true;
            }else if(button_toggle == true){
            stopTask(speedMotors);
            motor[leftFireMech] = 0;
            motor[rightFireMech] = 0;
            button_toggle = false;
         }
      }
      lastButtonValue=vexRT[Btn8U];
   }
}

Author:  Tabor473 [ Fri Dec 11, 2015 10:31 pm ]
Post subject:  Re: Multitasking Issue

A little aside that wasn't related to the question. In an if statement when you say if(button==1) the if statement is looking for a 0(false) or a 1(true) and the condition you put inside the if is evaluated to be either 0(false) or 1(true). Things like buttons are already 1 and 0 and the same is true for Boolean variables. This means if(button) and if(button==1) are equivalent. If you want to do the opposite of button then you can use the !(not) operator to flip boolean values.

if(button==0) is the same as if(!button) (read as if not button)

Here is same code that I used for solution two to your problem but using this technique to make it a little easier to read.

Code:
task main(){
bool lastButtonValue=false;
   while(true){
      getJoystickSettings(joystick);

      if(vexRT[Btn8U]1&&!lastButtonValue){
         if(!button_toggle){
            startTask(speedMotors);
            button_toggle = true;
            }else if(button_toggle){
            stopTask(speedMotors);
            motor[leftFireMech] = 0;
            motor[rightFireMech] = 0;
            button_toggle = false;
         }
      }
      lastButtonValue=vexRT[Btn8U];
   }
}

Page 1 of 1 All times are UTC - 5 hours [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/