什么是 “Command-Based” 编程?

WPILib支持一种称为“基于命令”编程的机器人编程方法。通常,“基于命令的”既可以引用一般的编程范例,也可以引用为方便起见而包括的WPILib库资源集。

“基于命令”编程是所谓的“设计模式”的一个示例。 <https://en.wikipedia.org/wiki/Design_pattern>`__这是一种组织机器人代码的通用方法,该代码非常适合特定的问题空间。这不是编写机器人程序的唯一方法,但它是一种非常有效的方法。基于命令的机器人代码趋向于干净,可扩展,并且(具有一些技巧)易于年复一年地重复使用。

基于命令的范例也是所谓的“声明性<https://en.wikipedia.org/wiki/Declarative_programming>” __编程的示例。在声明式编程中,重点放在程序应该做什么,而不是程序应该如何做。因此,基于命令的库允许用户定义所需的机器人行为,同时将他们必须编写的逐次迭代的机器人逻辑的数量减至最少。例如,在基于命令的程序中,用户可以指定“按下按钮时机器人应执行操作”(请注意使用:ref:lambda <docs/software/commandbased/convenience-features:Lambda Expressions (Java)>):

aButton.whenPressed(intake::run);

相反,在普通的`imperative <https://en.wikipedia.org/wiki/Imperative_programming>`__程序中,用户将需要在每次迭代时检查按钮状态,并根据按钮的状态执行适当的操作。

if(aButton.get()) {
  if(!pressed) {
    intake.run();
    pressed = true;
  }
} else {
  pressed = false;
}

子系统和指令

image of subsystems and commands

基于命令的编程模式基于两个核心抽象类:指令**和**子系统。

**子系统**是基于设计的范式中机器人组织的基本单元。子系统“封装<https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)>” __下层机器人硬件(例如电机控制器,传感器和/或气动执行器),并定义接口,其余的机器人代码可通过该接口访问硬件。子系统允许用户从其余代码中“隐藏”其实际硬件的内部复杂性-这不仅简化了其余的机器人代码,而且允许更改子系统的内部细节,而无需同时更改其余的机器人代码。 。子系统实现``子系统’’接口。

**命令**定义利用子系统定义的方法的高级机器人动作或行为。命令是一个简单的“状态机<https://en.wikipedia.org/wiki/Finite-state_machine>” __,它正在初始化,执行,结束或空闲。用户编写代码,指定在每种状态下应采取的操作。简单的命令可以组成“命令组”以完成更复杂的任务。命令(包括命令组)实现“命令”界面。

指令如何运行

注解

有关更详细的说明,请参考:doc:command-scheduler.。

命令由CommandScheduler(Java <https://first.wpi.edu/wpilib/allwpilib/docs/release/java/edu/wpi/first/wpilibj2/command/CommandScheduler.html>`__,C ++)运行,这是基于命令的库的核心的单例类。 CommandScheduler负责轮询按钮以安排新命令,检查这些命令所需的资源以避免冲突,执行当前已调度的命令以及删除已完成或已中断的命令。可以在用户代码中的任意位置调用调度程序的run()方法;通常建议从“ Robot”类的“ robotPeriodic()”方法调用它,该方法以默认频率50Hz(每20ms一次)运行。

只要这些指令不需要“Robot”类中的相同资源,就可以同时运行多个指令。资源管理是在每个子系统的基础上进行的:指令可以指定与之交互的子系统,并且调度程序每一次运行都只会调度一个需要一个特定子类的指令。这样可以确保一种情况,例如,用户不会以试图将同一电动机控制器设置为不同输出值的两个不同的代码结尾。如果调度了一个需要已在使用的子系统的新指令,则它将中断需要该子系统的当前正在运行的指令(如果该指令已被安排为可中断),否则前者将不会被调度。

子系统还可以与“默认命令”相关联,当当前没有其他命令正在使用子系统时,将自动计划这些子系统。这对于连续的“后台”操作(例如控制机器人驱动器或将手臂保持在设定点)很有用。

调度一个指令后,其“initialize()”方法将被调用一次。然后,每次调用“CommandScheduler.getInstance.run()”时都会调用其“execute()”方法。当指令的“isFinished()”方法返回true或该指令被打断(被另一个使用相同子系统的指令打断或被取消)时,该指令将取消调度并调用其“end(boolean interrupted)”方法。

指令组

通常需要从简单的片段构建复杂的命令。这可以通过将__命令组成“命令组”来实现。命令组<command-groups>是一个命令,其中包含多个命令,这些命令可以并行或顺序运行。基于命令的库提供了几种类型的命令组供团队使用,如果需要,鼓励用户编写自己的命令组。当命令组本身实现``Command’’接口时,它们是可递归组合的<https://en.wikipedia.org/wiki/Object_composition#Recursive_composition>`__-一个命令组可以*在*其他命令组中。这为使用简单的库构建复杂的机器人动作提供了一种非常强大的方法。

创建一个机器人项目

在:ref:`docs/software/vscode-overview/creating-robot-program:Creating a Robot Program`中详细介绍了创建项目。选择“模板”,然后选择您的编程语言,然后选择“新指令机器人”,以创建一个基于命令的基本机器人程序。

当使用 “New Command Robot” 创建新项目时,基于命令的新供应商库将被自动导入。如果您导入了 2019 年的项目或创建了其他类型的项目,则将导入旧的命令库,并且有必要根据 3rd Party Libraries 导入基于命令的新供应商库并删除旧的指令库。