多自动选择Multiple Autonomous Routines
6.1 为什么需要多套自动?6.1 Why Do You Need Multiple Autonomous Routines?
比赛中,你的队伍可能站在场地的不同位置:During a competition, your team might be placed at different positions on the field:
- 红色联盟左侧Red Alliance Left Side:离某些得分物近: Close to certain scoring objects
- 红色联盟右侧Red Alliance Right Side:离另一些得分物近: Close to different scoring objects
- 蓝色联盟Blue Alliance:场地是对称的,路线正好相反: The field is symmetrical, so routes are mirrored
如果只有一套自动程序,站在不同位置就会跑错路线。所以我们需要多套自动,比赛前选一个。With only one autonomous routine, you'd run the wrong path from different positions. That's why we need multiple routines and select one before each match.
大多数队伍准备 2-3 套自动:Most teams prepare 2-3 autonomous routines:
- 近侧自动Near Side Autonomous:拿最近的得分物,稳定得分: Grab the closest scoring objects for reliable points
- 远侧自动Far Side Autonomous:走远一点,争取更多分: Travel farther for more points
- 技能赛自动Skills Autonomous:60 秒的技能赛用,不同于 15 秒的对抗赛: For the 60-second skills challenge, different from the 15-second match
6.2 用变量存选择6.2 Storing the Selection in a Variable
最简单的方法:用一个全局变量记录选了哪套自动,在 autonomous() 里用 if/switch 判断。The simplest approach: use a global variable to store which routine was selected, then use if/switch in autonomous() to decide which one to run.
// 全局变量:存储选择的自动编号
int autonChoice = 0;
// 自动策略 1:近侧
void autonNearSide() {
driveStraight(500);
turnToHeading(90);
driveStraight(300);
// ... 拿近处的得分物
}
// 自动策略 2:远侧
void autonFarSide() {
driveStraight(800);
turnToHeading(270);
driveStraight(600);
// ... 走远一点争取更多分
}
// 自动策略 3:技能赛
void autonSkills() {
// 技能赛有 60 秒,可以做更多事
driveStraight(500);
turnToHeading(90);
driveStraight(500);
turnToHeading(180);
driveStraight(500);
// ...
}
void autonomous() {
if (autonChoice == 0) {
autonNearSide();
} else if (autonChoice == 1) {
autonFarSide();
} else if (autonChoice == 2) {
autonSkills();
}
}
// 全局变量:存储选择的自动编号
int autonChoice = 0;
void autonNearSide() {
driveStraight(500);
turnToHeading(90);
driveStraight(300);
}
void autonFarSide() {
driveStraight(800);
turnToHeading(270);
driveStraight(600);
}
void autonSkills() {
driveStraight(500);
turnToHeading(90);
driveStraight(500);
turnToHeading(180);
driveStraight(500);
}
void autonomous() {
if (autonChoice == 0) {
autonNearSide();
} else if (autonChoice == 1) {
autonFarSide();
} else if (autonChoice == 2) {
autonSkills();
}
}
// 全局变量:存储选择的自动编号
int autonChoice = 0;
void autonNearSide() {
driveStraight(500);
turnToHeading(90);
driveStraight(300);
}
void autonFarSide() {
driveStraight(800);
turnToHeading(270);
driveStraight(600);
}
void autonSkills() {
driveStraight(500);
turnToHeading(90);
driveStraight(500);
turnToHeading(180);
driveStraight(500);
}
void autonomous() {
if (autonChoice == 0) {
autonNearSide();
} else if (autonChoice == 1) {
autonFarSide();
} else if (autonChoice == 2) {
autonSkills();
}
}
6.3 用 Brain 屏幕选择6.3 Selecting via the Brain Screen
问题来了:怎么在比赛前改变 autonChoice 的值?总不能每次改代码重新下载吧。Here's the question: how do you change autonChoice before a match? You can't re-download the code every time.
答案:用 Brain 屏幕做一个选择界面。在 main 函数的 while 循环里,触摸屏幕就切换选择。Answer: Build a selection screen on the Brain display. In the main function's while loop, touching the screen switches the selection.
int autonChoice = 0;
// 屏幕上显示当前选择
void displayAutonChoice() {
Brain.Screen.clearScreen();
Brain.Screen.setCursor(1, 1);
if (autonChoice == 0) {
Brain.Screen.print("Auton: Near Side");
} else if (autonChoice == 1) {
Brain.Screen.print("Auton: Far Side");
} else if (autonChoice == 2) {
Brain.Screen.print("Auton: Skills");
}
Brain.Screen.setCursor(3, 1);
Brain.Screen.print("Touch screen to switch");
}
// 屏幕被点击时切换选择
void onScreenPressed() {
autonChoice = (autonChoice + 1) % 3; // 0→1→2→0 循环
displayAutonChoice();
}
int main() {
Competition.autonomous(autonomous);
Competition.drivercontrol(userControl);
// 注册屏幕点击事件
Brain.Screen.pressed(onScreenPressed);
displayAutonChoice(); // 显示初始选择
while (true) {
wait(100, msec);
}
}
比赛前:点屏幕切换自动策略,看到想要的策略后就等比赛开始。autonomous() 会根据 autonChoice 的值运行对应策略。Before the match: tap the screen to cycle through strategies. When you see the one you want, just wait for the match to start. autonomous() will run the corresponding strategy based on the autonChoice value.
int autonChoice = 0;
void displayAutonChoice() {
Brain.Screen.clearScreen();
Brain.Screen.setCursor(1, 1);
if (autonChoice == 0) {
Brain.Screen.print("Auton: Near Side");
} else if (autonChoice == 1) {
Brain.Screen.print("Auton: Far Side");
} else if (autonChoice == 2) {
Brain.Screen.print("Auton: Skills");
}
Brain.Screen.setCursor(3, 1);
Brain.Screen.print("Touch screen to switch");
}
void onScreenPressed() {
autonChoice = (autonChoice + 1) % 3;
displayAutonChoice();
}
int main() {
Competition.autonomous(autonomous);
Competition.drivercontrol(userControl);
Brain.Screen.pressed(onScreenPressed);
displayAutonChoice();
while (true) {
wait(100, msec);
}
}
int autonChoice = 0;
// 用 PROS LCD 的三个按钮来选择
// 左按钮:上一个 中按钮:确认 右按钮:下一个
void displayAutonChoice() {
pros::lcd::clear();
if (autonChoice == 0) {
pros::lcd::set_text(1, "Auton: Near Side");
} else if (autonChoice == 1) {
pros::lcd::set_text(1, "Auton: Far Side");
} else if (autonChoice == 2) {
pros::lcd::set_text(1, "Auton: Skills");
}
pros::lcd::set_text(3, "L/R btn to switch");
}
// 左按钮回调:上一个
void onLeftButton() {
autonChoice--;
if (autonChoice < 0) autonChoice = 2;
displayAutonChoice();
}
// 右按钮回调:下一个
void onRightButton() {
autonChoice = (autonChoice + 1) % 3;
displayAutonChoice();
}
void initialize() {
pros::lcd::initialize();
pros::lcd::register_btn0_cb(onLeftButton); // 左按钮
pros::lcd::register_btn2_cb(onRightButton); // 右按钮
displayAutonChoice();
}
PROS 的 LCD 有三个按钮(左、中、右),用左右按钮切换自动策略。The PROS LCD has three buttons (left, center, right). Use the left and right buttons to cycle through autonomous strategies.
6.4 % 运算符的妙用6.4 The Magic of the % Operator
上面代码里有一行:autonChoice = (autonChoice + 1) % 3;In the code above there's this line: autonChoice = (autonChoice + 1) % 3;
% 是取余运算。3 % 3 = 0,所以数到 3 自动回到 0。这样就实现了 0→1→2→0→1→2 的循环切换。% is the modulo (remainder) operator. 3 % 3 = 0, so when it reaches 3, it wraps back to 0. This creates the cycling pattern 0->1->2->0->1->2.
如果你有 4 套自动策略,% 后面的数字应该改成多少?If you have 4 autonomous strategies, what number should come after %?
6.5 完整比赛模板6.5 Complete Competition Template
把所有东西放在一起,这就是一个完整的比赛程序框架:Putting it all together, here's a complete competition program framework:
// ===== 全局变量 =====
int autonChoice = 0;
// ===== 工具函数 =====
void driveStraight(double deg) { /* ... */ }
void turnToHeading(double targetDeg) { /* ... */ }
// ===== 自动策略 =====
void autonNearSide() { /* 近侧策略 */ }
void autonFarSide() { /* 远侧策略 */ }
void autonSkills() { /* 技能赛策略 */ }
// ===== 比赛回调 =====
void autonomous() {
if (autonChoice == 0) autonNearSide();
else if (autonChoice == 1) autonFarSide();
else if (autonChoice == 2) autonSkills();
}
void userControl() {
while (true) {
// 遥控器控制代码
wait(20, msec);
}
}
// ===== 屏幕选择 =====
void displayAutonChoice() { /* ... */ }
void onScreenPressed() {
autonChoice = (autonChoice + 1) % 3;
displayAutonChoice();
}
// ===== 主函数 =====
int main() {
IMU.calibrate();
wait(2, seconds);
Competition.autonomous(autonomous);
Competition.drivercontrol(userControl);
Brain.Screen.pressed(onScreenPressed);
displayAutonChoice();
while (true) {
wait(100, msec);
}
}
// ===== 全局变量 =====
int autonChoice = 0;
// ===== 工具函数 =====
void driveStraight(double deg) { /* ... */ }
void turnToHeading(double targetDeg) { /* ... */ }
// ===== 自动策略 =====
void autonNearSide() { /* 近侧策略 */ }
void autonFarSide() { /* 远侧策略 */ }
void autonSkills() { /* 技能赛策略 */ }
// ===== 比赛回调 =====
void autonomous() {
if (autonChoice == 0) autonNearSide();
else if (autonChoice == 1) autonFarSide();
else if (autonChoice == 2) autonSkills();
}
void userControl() {
while (true) {
wait(20, msec);
}
}
// ===== 屏幕选择 =====
void displayAutonChoice() { /* ... */ }
void onScreenPressed() {
autonChoice = (autonChoice + 1) % 3;
displayAutonChoice();
}
// ===== 主函数 =====
int main() {
IMU.calibrate();
wait(2, seconds);
Competition.autonomous(autonomous);
Competition.drivercontrol(userControl);
Brain.Screen.pressed(onScreenPressed);
displayAutonChoice();
while (true) {
wait(100, msec);
}
}
// ===== 全局变量 =====
int autonChoice = 0;
pros::Imu imu(10);
// ===== 工具函数 =====
void driveStraight(double deg) { /* ... */ }
void turnToHeading(double targetDeg) { /* ... */ }
// ===== 自动策略 =====
void autonNearSide() { /* 近侧策略 */ }
void autonFarSide() { /* 远侧策略 */ }
void autonSkills() { /* 技能赛策略 */ }
// ===== 比赛回调 =====
void autonomous() {
if (autonChoice == 0) autonNearSide();
else if (autonChoice == 1) autonFarSide();
else if (autonChoice == 2) autonSkills();
}
void opcontrol() {
while (true) {
// 遥控器控制代码
pros::delay(20);
}
}
// ===== 初始化 =====
void initialize() {
imu.reset();
pros::delay(2000);
pros::lcd::initialize();
// 按钮回调注册...
}
autonChoice 的值是 1,执行 autonChoice = (autonChoice + 1) % 3; 后,autonChoice 变成多少?autonChoice is currently 1. After running autonChoice = (autonChoice + 1) % 3;, what does autonChoice become?