I hope this helps someone with a similar issue. Feedback/Comments appreciated!
M’Aiken Magic Vex Team 1102X
On our robot we have a motor that drives a threaded rod to set the distance between the intake flappers. This allows us to grab and hold cubes and place them in the towers, as well as release and drop them into the towers. Sometimes the spreader gets hung up trying to close to the SQUEEZE position if a cube got cockeyed in the ramp holding the cubes. When this happens, the operator’s controller becomes inoperative as it was waiting for the spreader motor to get to the desired position that it would never reach.
We could have just ignored the completion of the Spreader motor by using the function call SpreaderMotor.spinToPosition(SQUEEZE,degrees,false). We would not know when to stop the motor and it could overheat and stop working.
We created a separate task “DoSpreader” that starts the motor and waits for it to complete while watching the elapsed time. If it is exceeded, the motor is stopped and it signals to the caller that the task has completed and the motor is protected.
Here are the defines for the Spreader on our robot
#define SPREADERMAX 0000 // Starting point as Autonomous starts.
#define SPREADEROPEN 0200 // Open enough to drop the cube into tower.
#define SPREADERLOOSE 1450 // This is used to determine when we can back up
#define SPREADERSNUG 3750 // As Ramp is raising, this allows cubes to slide down
#define SPREADERINTAKE 5500 // Normal Intake position
#define SPREADERTIGHT 6250 //Used doing autonomous after 5 cubes.
#define SPREADERSQUEEZE 7500 // Hold on tight for the towers
#define SPREADERTIMEOUT 4000 // Time allowed to do any spreader movement
#define SPREADERSPEED 90
double SpreaderPosition = 0; // Used to tell task where to position the spreader
Below is the new task that gets the desired position from the double variable “SpreaderPosition” and starts the motor going to that position. It does not wait for that command to complete but watches for the motor to signal that it “isDone”. All the while it is watching the elapsed time to make sure it does not exceed the limit. If so, it stops the motor and sets the completion flag.
//*//
// Task to prevent Operator Lockup if Spreader Jams //
// Caller set SpreaderPosition to where spreader should go //
// Then starts this task and waits for flag to be true //
////
int DoSpreader(void){
double SpTime = Timer.time(msec); // Starting Time for Timeout
SpreaderMotor.setVelocity(SPREADERSPEED,percent); // Set Speed
SpreaderMotor.spinToPosition(SpreaderPosition,degrees,NOWAIT); // Start Motor
while (SpreaderMotor.isDone() == false){ // Wait for it to be done
if (Timer.time(msec) - SpTime > SPREADERTIMEOUT) break; //Watch time
}
SpreaderMotor.stop(brake); // Stop the motor in any case
SpreaderDone = true; // Set flag to tell caller we are done.
return 1; // Terminate the task properly
}
Here is the calling code in the operator’s task that causes the variable to be set, resets the completion flag and starts the task. It waits for the task to complete or timeout. Notice that we check the completion flag before we get started to make sure any previous operations were completed in case the previous caller opted not to wait for completion.
Since the operation is very short (< 3 Seconds), I would suggest waiting for it to complete but that is between the driver/operator and programmer. Perhaps the Operator can use the overlapping of the spreader movement with the moving of arms or driving of the robot. If it is decided not to wait for completion or timing out, just remove the last line that waits for SpreaderDone to be true. As an aside, since VEX Text is a “cooperative” scheduler, the task::yield or some system/API call like time, inside the while loop is a requirement to give the scheduler a chance to do its job. [Thanks JPearman]
// check the ButtonL1/ButtonL2,Left, Right status to control Spreader Motor
if (Operator.ButtonL1.pressing()) {
while(!SpreaderDone){task::yield();} // Previous Operation Not complete
SpreaderDone = false;
SpreaderPosition = SPREADERSQUEEZE;
task Squeeze1(DoSpreader);
while(!SpreaderDone){task::yield();} // Current Operation Not complete
}
if (Operator.ButtonL2.pressing()) {
while(!SpreaderDone){task::yield();} // Previous Operation Not complete
SpreaderDone = false;
SpreaderPosition = SPREADEROPEN;
task Open1(DoSpreader);
while(!SpreaderDone){task::yield();} // Current Operation Not complete
}
if (Operator.ButtonLeft.pressing()) {
while(!SpreaderDone){task::yield();} // Previous Operation Not complete
SpreaderDone = false;
SpreaderPosition = SPREADERINTAKE;
task Intake1(DoSpreader);
while(!SpreaderDone){task::yield();} // Current Operation Not complete
}
if (Operator.ButtonRight.pressing()) {
while(!SpreaderDone){task::yield();} // Previous Operation Not complete
SpreaderDone = false;
SpreaderPosition = SPREADERSNUG;
task Snug1(DoSpreader);
while(!SpreaderDone){task::yield();} // Current Operation Not complete
}