View unanswered posts | View active topics It is currently Tue Dec 11, 2018 7:51 am






Reply to topic  [ 3 posts ] 
Multitasking Issue 
Author Message
Rookie

Joined: Wed Dec 09, 2015 3:33 pm
Posts: 1
Post 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;
         }
      }
        }
}


Wed Dec 09, 2015 4:18 pm
Profile
Moderator
Moderator

Joined: Tue May 19, 2015 3:07 pm
Posts: 91
Post 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];
   }
}


Fri Dec 11, 2015 10:24 pm
Profile
Moderator
Moderator

Joined: Tue May 19, 2015 3:07 pm
Posts: 91
Post 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];
   }
}


Fri Dec 11, 2015 10:31 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 3 posts ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  



Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.