It is quite hard to write a good assisted-teleop program in graphical. Mainly because the lack of parallelism and compound conditions. At least the graphical has variables, which makes it doable, if clumsy. I’ll use schematic pseudocode below.
Let’s call the complex autonomous part “a macro”
As the OP correctly observes, the problem is with anything blocking inside the macro. But since the macro needs to perform a sequence of operations, it is bound to block when structured this way. Besides explicit waitUntil blocks, you also have 2x 0.6s moveMotor. This is to say, while the block of code under “if (LUp)” is running, the main control loop is suspended, noone evaluates the joysticks, noone checks the LDown button before the macro finishes. If the drivebase was running at the time LUp was pressed, it would just keep running.
With compound conditions, you could at least fix the waitUntil blocks, such as waitUntil ( originalCondition || LDown ) {…}.
The best (IMHO) solution in current graphical would be to use a state variable (step counter) with purely non-blocking functions. I have never really used variables in graphical much, so I hope your students would be able to replicate the outline below:
[Variable counter = 0]
if (counter == 0) {
if (getJoystickValue(BtnLUp) == 1) {
counter = 1;
setTouchLedColor(violet)
setMotor(middleDrive, -45);
} else {
if (getJoystickValue(BtnLDOwn) == 1) {
stopAllMotors();
counter = 0;
}
}
} else if (counter == 1) {
if (Bump) {
counter = 2;
// instead of moveMotor, advance state and use timer
resetTimer(T3);
setMotor(middleDrive, 75)
}
} else if (counter == 2) {
if (getTimer(T3) > 300) { // milliseconds?
stopMotor(middleMotor);
setMultipleMotors(75, right, left);
counter = 3;
}
} else if (counter == 3) {
if (bumpFront) {
stopMultipleMotors(right, left);
setMultipleMotors(75, arm...)
counter = 4;
} ...
If they can understand it, they can actually implement it properly.
One thing that is missing above is skipping all armControl and the likes while the macro is running (counter != 0) as that would reset any ongoing parallel motor operation.
In text-based, everything is so much easier, since you have tasks - LUp would start a parallel task that would just perform the sequence, while RUp would just kill that task and stop motors.