The last skills you need before the capstone.
Sometimes you need two things to happen at the same time. The driver wants to raise the arm while the intake keeps spinning. Odometry needs to update while autonomous code runs. That's what tasks are for.
int intakeTask() {
while (true) {
if (Controller1.ButtonL1.pressing()) {
Intake.spin(forward);
} else {
Intake.stop();
}
wait(20, msec);
}
}
int main() {
task t1(intakeTask); // runs forever in the background
// ... main code runs without waiting for intakeTask
}
A class bundles related data and functions. For a drivetrain:
class Drive {
public:
motor &left;
motor &right;
Drive(motor &l, motor &r) : left(l), right(r) {}
void forward(int pct) {
left.spin(vex::forward, pct, percent);
right.spin(vex::forward, pct, percent);
}
void stop() {
left.stop();
right.stop();
}
void turnRight(int deg) {
left.spinFor(vex::forward, deg, vex::deg, false);
right.spinFor(vex::reverse, deg, vex::deg, true);
}
};
// Usage
motor L = motor(PORT1, false);
motor R = motor(PORT6, true);
Drive drive(L, R);
int main() {
drive.forward(50);
wait(1, seconds);
drive.turnRight(90);
drive.stop();
}
Now your main code reads like English. Behind the scenes, the Drive class hides the messy motor details. Add encoder-based driving and PID inside the class, and your top-level code never changes.
Most beginners debug by guessing. Pros debug by narrowing down. The five-step process:
// Print to the Brain screen
Brain.Screen.clearScreen();
Brain.Screen.setCursor(1, 1);
Brain.Screen.print("error: %.2f", error);
Brain.Screen.setCursor(2, 1);
Brain.Screen.print("power: %.2f", motorPower);
// Print to the terminal for longer logs
printf("encoder L=%.1f R=%.1f\n",
LeftMotor.position(degrees),
RightMotor.position(degrees));
Use Git. At minimum: commit when something works. That way, when your "small change" breaks everything, you can roll back. For a high schooler: GitHub Desktop is the easy way in, install it, click Commit when things work, click Discard when they don't.
Create a Drive class that wraps your left and right motors plus the gyro. Give it three public methods:
forwardInches(double inches): drives forward using encoders.turnByGyro(double degrees): turns to a relative angle using the gyro and a P-controller.stop().Then write a 4-line autonomous routine that uses only your class to drive in a 24-inch square. The point is that good classes hide complexity from the code that uses them.
Two programs that misuse tasks or classes. Spot the bug.
int intakeTask() {
if (Controller1.ButtonL1.pressing()) {
Intake.spin(forward);
} else {
Intake.stop();
}
return 0;
}
int main() {
task t1(intakeTask);
while (true) {
wait(20, msec);
}
}
drive.forward(50), the robot doesn't move at all. The motors are powered. What is the class doing wrong?class Drive {
public:
motor left = motor(PORT1, false);
motor right = motor(PORT6, true);
void forward(int pct) {
left.spin(vex::forward, pct, percent);
right.spin(vex::forward, pct, percent);
}
};
motor L = motor(PORT1, false);
motor R = motor(PORT6, true);
Drive drive;
int main() {
drive.forward(50);
wait(2, seconds);
drive.left.stop();
drive.right.stop();
}