Hi Cyber Vipers,
What you’re looking for is a user triggered subroutine, which by itself is somewhat easy but it can get a little tricky, so let me just kind of go into this…
Let’s take a really simple task, like raising the arm. We could write something like this…
// WARNING - Pseudo code
void raiseArm() {
while(true) {
// Check to see if the arm is raised
if(armRaised) break;
// Set the motors
setMotor(5, 127);
setMotor(6, 127);
// Wait a little bit
delay(20);
}
// Stop the arm motors
setMotor(5, 0);
setMotor(6, 0);
}
while(teleop) {
// Driver controls
setMotor(1, joystick(1, LEFT));
setMotor(2, joystick(1, LEFT));
setMotor(3, joystick(1, RIGHT));
setMotor(4, joystick(1, RIGHT));
// Raise arm control
if(button(1)) raiseArm();
// Wait a little bit
delay(20);
}
It’ll work, the arm will raise when you press the mapped button, but during that time you won’t be able to control the robot because the code for your task will be trapped in the raiseArm() function.
This is where I could / world post a huge runt / lecture on parallel programming and parallelism, if I had more time. But I don’t so, oh well.
Multithreaded tasks are kind of like the difference between writing with one pen v/s writing with many. With one pen, you can only be writing ONE word at a time, with many pens we could write many words at once if we knew what words came next and in what order, etc.
You COULD use another “pen” (more formally called a “thread”) or more robotics oriented “task” to accomplish what you want.
For this you need to defer to whatever package you’re using. I know ROBOTC has a help page on tasks and how to use them, I also know that both PROS and ConVEX have tasks. I assume EasyC does too, but I don’t use that package.
What you’ll want to do is convert the raiseArm function into a task (see the help page for your package on how to do this), once it’s a task all you need to do is invoke it (run it) which will also be covered in the help page on tasks for your particular package.
ANOTHER WAY would be to program in a little clever way, for example this could work without another task…
// WARNING - Pseudo code
// Are we currently raising the arm?
char armRaising = false;
while(teleop) {
if(armRaising) {
// Check to see if the arm is raised
if(armRaised) {
setMotor(5, 0);
setMotor(6, 0);
}
// Set the motors
setMotor(5, 127);
setMotor(6, 127);
}
// Driver controls
setMotor(1, joystick(1, LEFT));
setMotor(2, joystick(1, LEFT));
setMotor(3, joystick(1, RIGHT));
setMotor(4, joystick(1, RIGHT));
// Raise arm control
if(button(1)) armRaising = true;
// Wait a little bit
delay(20);
}
Notice how we abuse the fact that our teleop code already has a loop that runs every 20ms? We simply run some arm code only if that armRaising flag is set. This way of doing this is nice because it’s very easy to stop the arm raising procedure mid-way, just unset the armRaising flag. (IE armRaising = false;).
However this approach has some disadvantages, some tasks are more complex or don’t lend themselves to running in this fashion.
Before I end this, let’s do one thing for the sake of readability, let’s move the arm raising code into it’s own function just so it isn’t in the middle of our tele-op section.
// WARNING - Pseudo code
void raiseArm() {
// Check to see if the arm is raised
if(armRaised) {
setMotor(5, 0);
setMotor(6, 0);
}
// Set the motors
setMotor(5, 127);
setMotor(6, 127);
}
// Are we currently raising the arm?
char armRaising = false;
while(teleop) {
// Check to see if we need to run the raise arm sub-task
if(armRaising) raiseArm();
// Driver controls
setMotor(1, joystick(1, LEFT));
setMotor(2, joystick(1, LEFT));
setMotor(3, joystick(1, RIGHT));
setMotor(4, joystick(1, RIGHT));
// Raise arm control
if(button(1)) armRaising = true;
// Wait a little bit
delay(20);
}
Now this is where you bust out the calculus and PID the crap out of that arm, but that’s another day…
Hope that helps, -Cody