Multitasking Issues

I have been experimenting with the multitasking functions in RobotC but ran into some trouble. I know that it is probably very common this year to be using this method, so I was hoping I could get some help.

I ran into an issue where the task (I think) is not being executed enough or not using as much of the CPU as I think it should be. It runs with a sort of sputtering motion, pausing for very short intervals, just enough to slow down the process. I have tried to use the


hogCPU()

command, but to be honest, I think I’m really just guessing around at this point. I also cannot find a definite answer for the difference between the


endTimeSlice()

and


abortTimeSlice()

commands.

For my specific usage, I am attempting to load balls into both of my separate launchers. At the same time, I want to have full capability of everything else on the robot (which is located in my main task along with drive code as well). This means that I wouldn’t need to take the extra few seconds on the alliance tile to load, but instead, will be loading on the go. Sort of like a run and gun sort of deal. This is far to difficult to do manually (Unless I had an extra hand, literally or figuratively) so I was thinking that multiple tasks would be an excellent place to start.

Here is the code for the one with sputtering issues

task ludicrousFire(){
	while(true){
		if(vexRT[Btn6U]){
			motor[port2] = 127;
			motor[port3] = -127;
			motor[port4] = 127;
			if(SensorValue(touchLeft) && ballInQueue){
				motor[scoopEnd] = 127;
				wait1Msec(600);
			}
		}
		EndTimeSlice();
	}
}

And another bit of code I have been messing around with.

task ludicrousLoad()
{
	leftIsReady = true;
	rightIsReady = false;
	while(true){
		if(vexRT[Btn6D]){
			const int trackerThreshold=800;
			if(SensorValue(lineTracker1)>trackerThreshold){
				while(SensorValue(lineTracker1)>trackerThreshold){
					motor[scoop]=-127;
				}
				if(leftIsReady){
					motor[scoopEnd]=127;
				}
			}
			else if(SensorValue(lineTracker1)<trackerThreshold){
				if(leftIsReady){
					motor[scoopEnd]=127;
				}
				else if(rightIsReady){
					motor[scoopEnd]=-127;
				}
			}
		}
		EndTimeSlice();
	}
}

For this last task, I was trying to use a line sensor to sense whether or not a ball was ready to be loaded, and then load the ball into the corresponding launcher. Unfortunately, only the first part of the if statement seemed to be getting executed. The intake would turn until the ball was in the right spot, shut off, and then nothing would happen. As you can see, I even defined the booleans for each subsequent statement, so that seemed not to be the problem.

Here is my full main task

task usercontrol()
{
	int threshold = 10;

	while(true){
		if(abs(vexRT[Ch2]) > threshold || abs(vexRT[Ch4]) > threshold){
    	               motor[frontleft]  = (vexRT[Ch2] + vexRT[Ch4]);  // (y + x)/2
    	               motor[backleft]  = (vexRT[Ch2] + vexRT[Ch4]);  // (y + x)/2
    	               motor[frontright] = (vexRT[Ch2] - vexRT[Ch4]);  // (y - x)/2
    	               motor[backright] = (vexRT[Ch2] - vexRT[Ch4]);  // (y - x)/2
		}
		else{
			motor[frontright] = 0;
			motor[frontleft] = 0;
			motor[backright] = 0;
			motor[backleft] = 0;
		}
		//////////////////////////////////////////////////////////////////////
		if(SensorValue(lineTracker1)<600){
			ballInQueue = true;
		}
		else{
			ballInQueue = false;
		}
		startTask(ludicrousLoad);
		startTask(ludicrousFire);
		if(vexRT[Btn8L]==1){
			motor[scoopEnd]=127;
		}
		if(vexRT[Btn8R]==1){
			motor[scoopEnd]=-127;
		}
		else if(vexRT[Btn8L]==0 && vexRT[Btn8R]==0){
			motor[scoopEnd] = 0;
		}
		if(vexRT[Btn5U]==1){
			motor[scoop]=127;
		}
		if(vexRT[Btn5D]==1){
			motor[scoop]=-127;
		}
		else if(vexRT[Btn5U]==0 && vexRT[Btn5D]==0){
			motor[scoop] = 0;
		}
		if (vexRT[Btn7R] == 1){
			motor[port2] = -127;
			motor[port3] = 127;
			motor[port4] = -127;
		}
		else if (vexRT[Btn7L] == 1){
			motor[port2] = 127;
			motor[port3] = -127;
			motor[port4] = 127;
		}
		else if (vexRT[Btn7L] == 0 && vexRT[Btn7L] == 0){
			motor[port2] = 0;
			motor[port3] = 0;
			motor[port4] = 0;
		}
		if(vexRT[Btn7U] == 1){
			motor[scoop] = -127;
			motor[scoopEnd] = -127;
			wait1Msec(500);
			motor[scoopEnd] = 0;
			wait1Msec(300);
			motor[scoopEnd] = 127;
			motor[scoop] = 0;
			motor[port2] = 127;
			motor[port3] = -127;
			motor[port4] = 127;
			wait1Msec(700);
			wait1Msec(550);
		}
		if(vexRT[Btn7D] == 1){
			motor[port2] = 127;
			motor[port3] = -127;
			motor[port4] = 127;
			wait1Msec(700);
			//motor[scoopEnd] = -127;
			wait1Msec(550);
		}
		EndTimeSlice();
	}
}

I believe very well that my problem lies in the


EndTimeSlice()

and


abortTimeSlice()

commands and where I put them for each case. In the main task, I have the


EndTimeSlice()

command in the last line before the while loop is closed off. So, for clarification, it is inside the while loop.

Thanks for reading this and/or helping if you decided to do so.

1390 Omicron Theta, Galactic ltd.

You need a wait statement in your first task, the one that sputters. A wait1Msec(25); should do the trick.

I myself am not very familiar with the


timeSlice()

commands. Whenever I write tasks, I usually use a


wait1Msec()

statement with a value of 25 or 50. As far as I know, this method is what makes sure that certain tasks don’t hog the CPU.

I believe @jpearman has offered to explain the


timeSlice()

commands in another thread but hasn’t gotten around to doing so quite yet. Until that point, go ahead and use


wait1Msec()

in order to set the delay on your tasks.

Thanks you guys. I inserted a wait 25 ms delay at the end of both the main task and the task being executed. Sputtering is gone completely.

Hi @Omicron Theta, your EndTimeSlice() is in the wrong part of the task. Currently it is located after your while loop terminates, which never occurs as the condition for the loop is “true”. If you move your EndTimeSlice() to the last line before the end of your loop, it will work properly. My understanding of EndTimeSlice is to “give” time that a task is not using to other tasks that may need it. For a more thorough explanation of the command, @jpearman is probably to person to consult.

Look again. The


endTimeSlice()

command is contained fully within the braces of the while loop in all three tasks. The formatting is a bit wonky, but it’s definitely there.

@Nehalem whoops you are right! those braces were really odd.

I did start creating a new thread about tasks, just have not finished it yet and it was starting to get very technical. You are doing a couple of fundamental things wrong in this code.

  • Do not start tasks from within the while loop (there are some special cases where you would do this but generally this is the rule. When you call startTask guess what happens THE TASK STARTS AGAIN ! No matter what the task is doing it will be stopped and started over.
  • Do not access the same motor in more than one task. You have the following in the while loop of the main task.
if(vexRT[Btn8L]==1){
  motor[scoopEnd]=127;
}
if(vexRT[Btn8R]==1){
  motor[scoopEnd]=-127;
}
else if(vexRT[Btn8L]==0 && vexRT[Btn8R]==0){
  motor[scoopEnd] = 0;
}

But in your “ludicrousLoad” task you are also trying to control the same motor, scoopEnd. The tasks will fight with each other. ludicrousLoad will send a value to the motor, the other will be sending 0 if buttons are not pressed.

  • Avoid usiing EndTimeSlice (or abortTimeslice, they are exactly the same thing). Again, there are some specific situations to use it but the general rule of thumb is that it is the wrong function to call.
  • Always have a wait1Msec call at the end of a while loop no matter what the loop is doing. Suggested wait time is 10-25mS.
  • Use one task per sub-system or specific, non-motor related, area of functionality. Use a task for the robot drive system. Use a task for the shooter/flywheel. Perhaps use a task to calculate velocity (no motors involved). By using one task for each sub-system you can keep driving while, for example, waiting for the flywheel to reach speed.

I now have this I just wrote

task ludicrousFire(){
	while(true){
		if(vexRT[Btn6U]){
			motor[port2] = 127;
			motor[port3] = -127;
			motor[port4] = 127;
			wait1Msec(700);
		}
		wait1Msec(25);
	}
}

This basically only makes the motors move if I am physically pressing down the button.
Is there a way to have it run as a background process to the main function, so to speak? Right now it just acts as if it were any other button.

See previous post. Only control motors (meaning the same motor) from one task. You have two tasks sending values to motors on port2, port3 and port4.

Sweet man, thanks a bunch. I’m still working some bugs out, but I think I have come to a consensus about generally what is wrong. I am going to institute the other button commands into the separate tasks in which they are called with corresponding conditionals to make sure they are not cancelling each other out. I am also going to look into the


setTaskPriority()

function. I assume that if I call this in the sub-task, then it will overwrite the call from the main function. If this is true, then I don’t think I need to move the initial statements at all.

Either way, thanks so much for your help everyone.

Don’t over use tasks. Tasks are not functions! Think hard about whether you really need to use a task, does the code need to be run in parallel with other code. Most NBN code (for a typical robot with flywheel) should probably not be using more than three tasks, one for drive and joystick monitoring, one for velocity calculation, one for the flywheel PID. Also see this.
https://vexforum.com/index.php/conversation/post/122642