指令与控制教程

../../../../_images/ni-logo.png

简介

命令与控制是为2016赛季添加的新LabVIEW模板,用于将机器代码植入命令和控制器以形成机器特定子系统的集合。每个子系统都有一个独立的控制循环或状态机制,以适当的速率运行,用于更新所需操作和设置节点的方法和高级命令。这使得自动代码非常容易构建命令的同步序列。同时,TeleOp的好处在于它可以重复执行相同的命令而无需等待完成,从而可以根据驱动团队的输入轻松取消或启动新命令。每个子系统都有一个面板,显示其随时间变化的传感器和控制值以及命令跟踪,以帮助调试。

什么是指令与控制?

指令与控制系统认识到FRC|reg|机器倾向于由相对独立的机制组成,例如Drive,Shooter,Arm等。每一个机制都称为子系统,并且需要代码来协调子系统的各种传感器和执行器以完成要求的命令或动作,例如“合拢抓手”或“放下手臂”。该框架的主要原理之一是,每个子系统将具有一个独立的控制回路,该回路仅负责更新电机和其他执行器。子系统控制器外部的代码可以发出命令,这些命令可能会更改机器的输出,但不应直接更改任何输出。两者差异非常细微,但这意味着只能从项目中的一个位置更新输出。这通过使您能够查看发送到子系统的命令列表加快了调试行为异常的机器的速度,而不是通过在项目中搜索可能已修改输出的地方。无需在控制器外部修改代码也将添加其他传感器、更改齿轮或禁用机制变得更加容易。

游戏代码(主要由自动程序和TeleOp组成)通常需要更新节点并对某些方法的状态做出反应。对于自动程序,常见的做法是将机器的操作定义为一系列操作-前进到这里、拾取、搬运、射出等。可以将命令与附加逻辑顺序连接,以快速构建复杂的例程。对于teleOp,相同的命令可以异步执行,从而使机器始终能够处理最新的驱动程序输入,如果实施得当,新命令将中断,从而使驱动团队可以快速响应现场条件,同时还利用自动化命令和命令序列。

z为什么要使用指令和控制?

指令与控制功能为现有的LabVIEW项目模板增加了功能,使代码可以通过更复杂的机器和机器代码更好地扩展。子系统用于抽象实现细节,游戏代码由高级指令VI组成的序列构建而成。这些指令本身是VI,可以更新节点,在工程单位和机械单位之间执行数值缩放/映射并提供同步选项。如果对机器进行了物理更改,例如更改传动比,则可以仅对几个指令Vi进行更改,以在整个代码库中反映此更改。

当发生资源冲突时,I / O封装可实现更可预测的操作和更快的调试。由于每个指令都是VI,因此您可以单步执行命令,也可以使用内置的Trace功能查看发送给每个子系统的所有命令的列表。该框架使用异步通知和一致的数据传播,可以轻松地对序列进行编程命令或添加简单的逻辑以确定要运行的正确指令。

第1部分:项目资源管理器

项目资源管理器将用于为机器系统的所有Vi和文件提供组织。以下是项目资源管理器中有助于扩展系统的主要组件的说明。最常用的项目以粗体标出。

../../../../_images/project-explorer-1.png
我的电脑

定义在项目被加载到的计算机上的操作的项目。对于机器项目,将其用作模拟目标并填充模拟文件。

Sim支持文件

该文件夹包含3D CAD模型和模拟机器的描述文件。

机器人仿真文档.html

记录您需要的PWM通道和机器信息,以便编写与模拟机器的接线匹配的机器代码。

依赖

显示模拟机器代码使用的文件。

构造规范

这将包含有关定义如何为模拟机器目标构建并部署代码的文件。

目标 (roboRIO-TEAM-FRC.local)

定义roboRIO上位于(地址)上的操作与项目。

Drive

机器驱动基础的子系统执行和命令。这可以自行替代WPILib RobotDrive VI。

框架

用于不属于子系统的机器代码的VI很少被使用。

开始

机器代码首次启动时调用一次。这对于不属于特定子系统的初始化代码很有用。

禁用

为每个禁用的数据包调用一次,当您不希望机器移动时,可用于调试传感器。

结束

在开发过程中,机器代码完成时可以调用此方法。在中止或电源关闭时不调用。

周期任务

临时循环进行调试或监视的好方法

机器全局数据

用于共享不属于子系统的机器信息。

支持代码

调试和代码开发辅助工具。

视图

相机和图像处理的子系统和命令。

Robot Main.vi

开发代码时将运行的最高级VI。

Autonomous.vi

在自动阶段内运行的VI。

Teleop.vi

被每个TeleOp数据包调用的VI。

Test.vi

在driver station处于测试模式时运行的VI。

SubSystems.vi

包含并启动所有子系统的VI。

依赖

显示机器代码使用的文件。

构造规范

一旦代码正常运行,它将被用于将代码作为启动应用程序构建和运行。

../../../../_images/project-explorer-2.jpg

驱动器子系统项目资源管理器

../../../../_images/drive-subsystem-project-explorer.jpg
命令:

该文件夹包含要求控制器执行操作的指令VI。它还包含用于创建其他驱动器命令的模板。

注解

创建新指令后,您可能需要对 Drive Setpoints.ctl 进行编辑以添加或更新控制器以定义新操作的字段。您还需要进入Drive Controller.vi并修改案例结构以为每个值添加案例。

执行

这些是用于构建子系统的VI和控件。

基础架构VI
  • 驱动器检查新指令:称为控制器循环的每次迭代。它检查新指令,定时更新数据,并在完成后通知等待的指令。

  • 驱动器指令帮助.vi:命令调用该VI以通知控制器已发出新指令。

  • 驱动器控制器初始化.vi:它分配通知程序,并将定时、默认指令和其他信息组合到一条数据线上。

  • 驱动器控制器.vi:该VI包含控制/状态机制循环。该面板还可能包含对调试有用的显示。

  • 驱动器操作.ctl:此typedef定义控制器的操作模式。许多命令可以共享一个操作。

  • 驱动器设定.ctl:它包含Drive子系统的所有操作模式所使用的数据字段。

  • 驱动器发布的全局变量.vi:发布有关驱动器子系统的全局信息的有用位置。

第2部分:初始化驱动器子系统

控制器程序框图上有绿色注释,在关键区域指出了如何编辑的方法。

子系统启动时,控制循环左侧的区域将执行一次。通常在这里分配和初始化所有I / O和状态数据。您可以发布I / O引用句柄,也可以将它们注册为“测试模式”仅是为了使其私有,以便其他代码在不使用指令的情况下无法更新电动机。

../../../../_images/step-1.jpg

注解

在各自的Controller.vi中而不是Begin.vi中初始化每个子系统的资源可以改善I / O封装,减少潜在的资源冲突并简化调试。

../../../../_images/step-2.jpg

初始化的一部分是在不处理其他任何操作时选择默认操作和节点值。

../../../../_images/step-3.jpg

控制循环内部实际执行了操作的是一个case语句。设定节点值,迭代延迟,迭代计数和传感器都可能影响子系统的运行方式。此案例结构具有子系统的每个操作状态的值。

../../../../_images/step-4.jpg

控制器循环的每次迭代将可选地更新跟踪VI。该框架已经包含子系统名称,操作和描述,您可能会发现将其他设置点值格式化为跟踪信息很有用。在机器代码运行到当前设置点和发送到每个子系统的命令时,打开Trace VI,然后单击“启动”。

控制器的主要目标是更新子系统的执行器。这可以在case结构内进行,但是很多时候,在结构的下游进行操作以确保始终在代码中的一个位置始终以正确的值更新值是有益的。

../../../../_images/step-5.jpg

第3部分:驱动器子系统附带的命令

每个新子系统都有3个附带的示例命令:

Drive For Time.vi

../../../../_images/drive-for-time.jpg

该VI将电动机设置为运行给定的秒数。它可以选择与指令的完成同步。

“时间驱动”情况将在设定点操作电动机,直到计时器过去或发出新指令为止。如果电动机启用了安全超时功能,则必须每100毫秒至少更新一次电动机。这就是代码等待剩余时间和50ms中较小者的原因。

../../../../_images/drive-for-time-diogram.jpg

Drive Immediate.vi

../../../../_images/drive-immediate.jpg

获得所需的电动机左右速度,并将电动机立即设置为这些设定点。

立即将电动机情况更新到指令定义的设定点。该指令未完成,因为您希望电动机在输入新指令或超时值之前保持该值。每当指令包含死区时,超时都是有用的。如果该值小于死区,则不会请求较小的值,且将导致咆哮或爬行除非指令超时。

../../../../_images/drive-immediate-diogram.jpg

Stop Driving.vi

../../../../_images/stop-driving.jpg

将驱动马达调零,使机器静止。

预定命令关闭电动机,并等待新指令。当与命名指令序列一起使用时,即使当前未移动机械臂,预定指令也标识驱动子系统是序列的一部分。这有助于在同时运行的指令之间仲裁子系统资源。

../../../../_images/stop-driving-diogram.jpg

第4部分:创建新命令

指令和控制框架使用户可以轻松地为子系统创建新指令。要创建新指令,请打开子系统文件夹/命令,在项目浏览器窗口中,选择一个VI模板作为新指令的起点,右键单击并选择“从模板新建”。

  • 瞬时: 该VI将新的设定值通知子系统。

  • 带有死区的瞬时: 该VI将输入值与死区进行比较,并有选择地将新的设定值通知子系统。当使用操纵杆连续值时,这非常有用。

  • 持续时间:该VI通知子系统在给定的持续时间内执行该命令,然后返回默认状态。同步决定该VI是启动该操作并立即返回,还是等待该操作完成。第一个选项通常用于TeleOp,第二个选项用于自动排序。

在此示例中,我们将添加新指令“ Drive for Distance”。

../../../../_images/new-vi.jpg

首先,使用诸如“ Drive for Distance”之类的描述性名称保存新的VI。接下来,确定新指令是否需要添加驱动器操作枚举typedef的新值。初始项目代码已经具有枚举Drive for Distance,但是下图显示了如何在需要时添加一个。

../../../../_images/edit-items.jpg

如果指令需要其他信息才能执行,请将其添加到设定控件中。驱动器子系统具有“左设定点”,“右设定点”和“持续时间”字样以及要执行的操作。默认情况下, “行驶距离”指令可以将“持续时间”重新用作距离,但让我们继续向“行驶距离”设置一个数字控件,称为“距离(英尺)”。

../../../../_images/add-distance.jpg

一旦有了指定指令所需的所有字段,便可以修改新创建的Drive for Distance.vi。如下所示,从枚举的下拉菜单中选择“Drive for Distance”,并添加VI参数以指定距离,速度等。如果单位不匹配,则指令VI是在单位之间进行映射的好方法。

../../../../_images/add-vi-parameters.jpg

接下来,将代码添加到“驱动器控制器”中,以定义执行“Drive for Distance”指令时发生的情况。右键单击案例结构,然后为每个值复制或添加案例。这将创建一个新的“ Drive for Distance”案例。

../../../../_images/add-case.jpg

为了访问新的设置点字段,请为“Access Cmd设置点”取消捆绑。在循环左侧的外部打开编码器。在新的案例结构图中,我们添加了一个调用以在第一次循环迭代时重置编码器,否则将其读取。还有一些简单的代码可以比较编码器值并更新电动机功率。如果将新控件添加到设定点集合中,则还应考虑将它们添加到跟踪中。下图显示了必要的更改。

../../../../_images/add-encoder-logic.jpg

第5部分:创建子系统

为了创建一个新的子系统,右键单击roboRIO目标并选择New»Subsystem。在弹出的对话框中,输入子系统的名称,列出操作模式,并指定图标的颜色。

../../../../_images/new-subsystem.jpg

单击确定时,将生成子系统文件夹并将其添加到项目磁盘文件夹和项目树中。它将包含构成子系统的VI和控件的基本执行操作。对新控制器的调用将插入子系统VI。控制器VI将打开,准备添加I / O并实现状态机或控制代码。生成的VI图标将使用对话框中提供的颜色和名称。生成的代码将typedef用于设置点字样和操作。

../../../../_images/new-subsystem-front-panel.jpg

下面是新创建的子系统的程序框图。创建子系统时,将自动生成此代码。

../../../../_images/new-subsystem-diogram.jpg