2020基于命令的重写:什么改变了?

本文提供了从基于命令的原始框架<docs/software/old-commandbased/basics/what-is-command-based:What is Command-Based Programming?>到2020年重写的变化的摘要。该摘要不一定是全面的-与往常一样,对于严格的文件,请参阅API文档(JavaC ++)。

包装位置

新的基于命令的框架位于WPILBJ2 Java中的包,以及FRC2 C++的命名空间。旧的基于命令的框架在原来的位置仍然可用。新框架必须使用指令安装:ref:docs/software/vscode-overview/3rd-party-libraries:WPILib Command Libraries.

主要构筑变化

基于命令的框架的总体结构基本保持不变。然而,仍有一些用户需要注意的主要体系结构变化:

命令和子系统作为接口

Command (Java, C++) and Subsystem (Java, C++) are both now interfaces as opposed to abstract classes, allowing advanced users more potential flexibility. CommandBase and SubsystemBase abstract base classes are still provided for convenience, but are not required. For more information, see 指令 and 子系统.

多命令组类

这个CommandGroup类不再存在,并且已经被许多递归类所组成的较窄类所取代,以创建更复杂的组结构。有关更多信息,请参见:doc:command-groups.

内联命令定义

以前,用户需要编写一个Command的子类。命令在几乎所有需要命令的情况下。许多新命令被设计为允许命令功能的内联定义,因此可以在不需要显式子类的情况下使用。有关更多信息,请参见 便捷功能.

注入命令依赖项

虽然不是对库的编码的实际改变,但是新的基于命令的框架的推荐使用模式利用子系统依赖性注入命令,因此子系统不被声明为全局。这是一种更清洁、更可维护、更可重用的模式,而不是以前所提倡的全局子系统模式。有关更多信息,请参见 构建基于命令的机器人项目.

命令所有权(C++)

以前的命令框架要求用户对所有命令使用原始指针,从而导致在所有基于C ++命令的项目中几乎不可避免的内存泄漏,并且为常见错误留出了空间,例如在命令组内双重分配命令。

新的命令框架为所有命令提供所有权管理。绑定到按钮的默认命令和命令通常由调度器拥有,组件命令由它们的封装命令组拥有。因此,用户通常不应该堆分配new命令。除非有一个很好的理由这样做。

所有权的转移是通过完美的转发完成的,<https://cpppatterns.com/patterns/perfect-forwarding.html>`__,这意味着右值将被移动,左值将被复制(右值/左值说明<http://thbecker.net/articles/rvalue_references/section_01.html>`__).

对调度程序的更改

  • Scheduler has been renamed to CommandScheduler (Java, C++).

  • 现在命令的可中断性是调度程序的责任,而不是命令的责任,可以在调用``schedule’’时指定。

  • 用户现在可以将操作传递给调度程序,只要命令被调度,中断或正常结束,便会采取这些操作。这对于事件记录之类的情况非常有用。

子系统变化

注解

有关子系统的更多信息,请参见子系统。

  • 如前所述,``子系统’’现在是一个接口(JavaC ++);与旧的Subsystem最接近的等效项是新的SubsystemBase类。许多与Sendable相关的构造函数重载已被删除,以减少混乱。如果需要,用户可以直接从自己的构造函数中调用设置方法。

  • initDefaultCommand已被删除;子系统不再需要“知道”它们的默认命令,而是直接注册到CommandScheduler. 新的setDefaultCommand方法简单地包装CommandScheduler程序打电话。

  • 子系统不再“知道”当前需要它们的命令;这只由CommandScheduler. 然而,一个方便包装命CommandScheduler.提供了方法。

命令更改

注解

有关命令的更多信息,请参见:doc:commands.

  • 如前所述,``Command’’现在是一个接口(JavaC ++);与旧版Command的最接近等效项是新版CommandBase。许多与Sendable相关的构造函数重载已被删除,以减少混乱。如果需要,用户可以直接从自己的构造函数中调用设置方法。

  • 命令不再处理自己的调度状态;现在这是调度程序的责任。

  • ``interrupted()’’方法已经被卷入到``end()``方法中,该方法现在使用一个参数来指定命令是否被中断(如果正常结束则为``false’’)。

  • requires()``方法已重命名为``addRequirement()

  • void setRunsWhenDisabled(boolean disabled)已由可重写的runsWhenDisabled()方法替换。禁用时应运行的命令应覆盖此方法以返回true。

  • ``void setInterruptible(boolean interruptible)``已被删除;可中断性不再是命令的固有属性,可以在计划命令时设置。

  • 添加了几种“ decorator”方法<docs / software / commandbased / convenience-features:Command Decorator Methods>`以允许轻松地内联修改命令(例如,添加超时)。

  • (仅C ++)为了允许装饰器使用命令所有权模型,请通过CommandHelper类<https://github.com/wpilibsuite/allwpilib/blob/main/wpilibNewCommands/src/main/native/include/frc2/command/CommandHelper.h>`__使用CRTP <https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`__。任何用户定义的Command子类“ Foo” *必须*扩展“ CommandHelper <Foo, Base>”,其中“ Base”是所需的基类。

PIDS子系统/ PIDCommand的变化

注解

更多的信息,请参见:doc:pid-subsystems-commands, and WPILib中的PID控制

  • 在对PIDController进行更改之后,这些类现在可以从机器人主循环中同步运行。

  • l  这个PIDController现在通过构造函数注入,删除许多转发方法,构筑后后可以改建为getController().

  • 如GyroDriveCommands示例(Java <https://github.com/wpilibsuite/allwpilib/tree/main/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/gyrodrivecommands>`__,C ++)所示,PIDCommand主要用于内联使用。

  • 如果用户希望更“传统地”使用PIDCommand,则已覆盖的受保护的“ returnPIDInput()”和“ usePIDOutput(double output)”方法已被修改为受保护的“ m_measurement”和“ m_useOutput”领域。同样,用户可以调用受保护的m_setpoint字段,而不用调用setSetpoint。