构建基于命令的机器人项目
用户可以随意使用自己喜欢的基于命令的库(鼓励高级用户使用),但是新用户可能需要一些有关如何构建基本的基于命令的机器人项目的指南。
A standard template for a command-based robot project is included in the WPILib examples repository (Java, C++). This section will walk users through the structure of this template.
根包/目录通常将包含四个类:
“Main”,这是主要的机器人应用程序(仅Java)。新用户*不应*接触此类。“Robot”,负责机器人代码的主控制流程。 “RobotContainer”包含机器人子系统和命令,是执行大多数声明性机器人设置(例如按钮绑定)的地方。 “Constants”,其中包含可在整个机器人中使用的全局可访问常量。
根目录还将包含两个子包/子目录:“Subsystems”包含所有用户定义的子系统类。 “Commands”包含所有用户定义的命令类。
Robot
As Robot (Java, C++ (Header), C++ (Source)) is responsible for the program’s control flow, and command-based is an declarative paradigm designed to minimize the amount of attention the user has to pay to explicit program control flow, the Robot class of a command-based project should be mostly empty. However, there are a few important things that must be included
21 /**
22 * This function is run when the robot is first started up and should be used for any
23 * initialization code.
24 */
25 public Robot() {
26 // Instantiate our RobotContainer. This will perform all our button bindings, and put our
27 // autonomous chooser on the dashboard.
28 m_robotContainer = new RobotContainer();
29 }
In Java, an instance of RobotContainer should be constructed during the Robot constructor - this is important, as most of the declarative robot setup will be called from the RobotContainer constructor.
在C ++中,这是不需要的,因为RobotContainer是值成员,并且将在构建“Robot”时进行构造。
31 /**
32 * This function is called every 20 ms, no matter the mode. Use this for items like diagnostics
33 * that you want ran during disabled, autonomous, teleoperated and test.
34 *
35 * <p>This runs after the mode specific periodic functions, but before LiveWindow and
36 * SmartDashboard integrated updating.
37 */
38 @Override
39 public void robotPeriodic() {
40 // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled
41 // commands, running already-scheduled commands, removing finished or interrupted commands,
42 // and running subsystem periodic() methods. This must be called from the robot's periodic
43 // block in order for anything in the Command-based framework to work.
44 CommandScheduler.getInstance().run();
45 }
11/**
12 * This function is called every 20 ms, no matter the mode. Use
13 * this for items like diagnostics that you want to run during disabled,
14 * autonomous, teleoperated and test.
15 *
16 * <p> This runs after the mode specific periodic functions, but before
17 * LiveWindow and SmartDashboard integrated updating.
18 */
19void Robot::RobotPeriodic() {
20 frc2::CommandScheduler::GetInstance().Run();
21}
“robotPeriodic()”方法中必须包含“CommandScheduler.getInstance().run()”调用;没有此调用,调度程序将不会执行任何调度的命令。由于“TimedRobot”以默认的主循环频率50Hz运行,因此这是将调用定期命令和子系统方法的频率。不建议新用户从其代码中的其他任何地方调用此方法。
54 /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */
55 @Override
56 public void autonomousInit() {
57 m_autonomousCommand = m_robotContainer.getAutonomousCommand();
58
59 // schedule the autonomous command (example)
60 if (m_autonomousCommand != null) {
61 CommandScheduler.getInstance().schedule(m_autonomousCommand);
62 }
63 }
32/**
33 * This autonomous runs the autonomous command selected by your {@link
34 * RobotContainer} class.
35 */
36void Robot::AutonomousInit() {
37 m_autonomousCommand = m_container.GetAutonomousCommand();
38
39 if (m_autonomousCommand) {
40 frc2::CommandScheduler::GetInstance().Schedule(m_autonomousCommand.value());
41 }
42}
“autonomousInit()”方法调度由“RobotContainer”实例返回的自治命令。选择要运行的自治命令的逻辑可以在“RobotContainer”内部处理。
69 @Override
70 public void teleopInit() {
71 // This makes sure that the autonomous stops running when
72 // teleop starts running. If you want the autonomous to
73 // continue until interrupted by another command, remove
74 // this line or comment it out.
75 if (m_autonomousCommand != null) {
76 m_autonomousCommand.cancel();
77 }
78 }
46void Robot::TeleopInit() {
47 // This makes sure that the autonomous stops running when
48 // teleop starts running. If you want the autonomous to
49 // continue until interrupted by another command, remove
50 // this line or comment it out.
51 if (m_autonomousCommand) {
52 m_autonomousCommand->Cancel();
53 }
54}
“teleopInit()”方法取消所有仍在运行的自治命令。这通常是好的做法。
高级用户可以随意在自己认为合适的各种初始化和定期方法中添加其他代码;但是,应该注意的是,在“Robot.java”中包含大量命令式机器人代码与基于命令的范例的声明式设计哲学相反,并且可能导致结构混乱/结构混乱的代码。
RobotContainer
This class (Java, C++ (Header), C++ (Source)) is where most of the setup for your command-based robot will take place. In this class, you will define your robot’s subsystems and commands, bind those commands to triggering events (such as buttons), and specify which command you will run in your autonomous routine. There are a few aspects of this class new users may want explanations for:
23 private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem();
32 ExampleSubsystem m_subsystem;
请注意,子系统在“RobotContainer”中被声明为私有字段。这与基于命令的框架的前身形成了鲜明的对比,但与商定的面向对象的最佳实践更加一致。如果子系统被声明为全局变量,则它允许用户从代码中的任何位置访问它们。虽然这可以使某些事情变得容易(例如,无需将子系统传递给命令以使这些命令可以访问它们),但由于不立即执行,因此使得程序的控制流更难以跟踪很明显,代码的哪些部分可以更改或可以被代码的其他哪些部分更改。这也妨碍了资源管理系统执行其工作的能力,因为易于访问使用户更容易意外地在资源管理命令之外意外调用子系统方法。
61 return Autos.exampleAuto(m_exampleSubsystem);
34 return autos::ExampleAuto(&m_subsystem);
由于子系统被声明为私有成员,因此必须将它们显式传递给命令(一种称为“依赖注入”的模式),以便这些命令在其上调用方法。这是通过“ExampleCommand”完成的,该示例传递了指向“ExampleSubsystem”的指针。
35 /**
36 * Use this method to define your trigger->command mappings. Triggers can be created via the
37 * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary
38 * predicate, or via the named factories in {@link
39 * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link
40 * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller
41 * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight
42 * joysticks}.
43 */
44 private void configureBindings() {
45 // Schedule `ExampleCommand` when `exampleCondition` changes to `true`
46 new Trigger(m_exampleSubsystem::exampleCondition)
47 .onTrue(new ExampleCommand(m_exampleSubsystem));
48
49 // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed,
50 // cancelling on release.
51 m_driverController.b().whileTrue(m_exampleSubsystem.exampleMethodCommand());
52 }
19void RobotContainer::ConfigureBindings() {
20 // Configure your trigger bindings here
21
22 // Schedule `ExampleCommand` when `exampleCondition` changes to `true`
23 frc2::Trigger([this] {
24 return m_subsystem.ExampleCondition();
25 }).OnTrue(ExampleCommand(&m_subsystem).ToPtr());
26
27 // Schedule `ExampleMethodCommand` when the Xbox controller's B button is
28 // pressed, cancelling on release.
29 m_driverController.B().WhileTrue(m_subsystem.ExampleMethodCommand());
30}
As mentioned before, the RobotContainer() constructor is where most of the declarative setup for the robot should take place, including button bindings, configuring autonomous selectors, etc. If the constructor gets too “busy,” users are encouraged to migrate code into separate subroutines (such as the configureBindings() method included by default) which are called from the constructor.
54 /**
55 * Use this to pass the autonomous command to the main {@link Robot} class.
56 *
57 * @return the command to run in autonomous
58 */
59 public Command getAutonomousCommand() {
60 // An example command will be run in autonomous
61 return Autos.exampleAuto(m_exampleSubsystem);
62 }
63}
32frc2::CommandPtr RobotContainer::GetAutonomousCommand() {
33 // An example command will be run in autonomous
34 return autos::ExampleAuto(&m_subsystem);
35}
最后,“getAutonomousCommand()”方法为用户提供了一种方便的方法,可以将所选的自主命令发送到主要的Robot类(需要在启动自主类时对其进行调度)。
Constants
The Constants class (Java, C++ (Header)) (in C++ this is not a class, but simply a header file in which several namespaces are defined) is where globally-accessible robot constants (such as speeds, unit conversion factors, PID gains, and sensor/motor ports) can be stored. It is recommended that users separate these constants into individual inner classes corresponding to subsystems or robot modes, to keep variable names shorter.
在Java中,所有常量都应声明为“public static final”,以便它们可以全局访问且不能更改。在C ++中,所有常量都应为“constexpr”。
有关实践中“constants”类的外观的更多说明性示例,请参见各种基于命令的示例项目的示例:
在Java中,建议通过静态导入必要的内部类从其他类中使用常量。“import static”语句将类的静态名称空间导入到您正在工作的类中,以便可以直接引用任何“static”常量,就好像它们是在该类中定义的一样。在C ++中,使用``使用命名空间’’可以达到相同的效果:
import static edu.wpi.first.wpilibj.templates.commandbased.Constants.OIConstants.*;
using namespace OIConstants;
Subsystems
用户定义的子系统应放在此软件包/目录中。
Commands
用户定义的命令应放在此软件包/目录中。