配置机器人外设
《机器人编程》的一章摘录。
![]() |
机器人编程
作者:Paul J. Perrone 通过简单地设置几个配置文件和少量自定义代码,就可以使用 MAX 和 Java 快速配置机器人组件、它们的互连和执行。在这篇基于 Programming Robots 第 3 章的文章中,作者 Paul Perrone 解释了您的机器人大部分的智能和特定行为将隐藏在行为、传感器和执行器组件本身之中。 |
传感器和执行器是连接到您的机器人并与物理世界交互的设备。对于传感器,我们通常是从物理世界感知信息。对于执行器,我们通常根据来自您机器人的信息命令来影响物理世界。传感器和执行器之间存在共性,以实现这种与世界的物理接口,我们利用图 1 中所示的外设抽象来利用这一事实。
这里我们看到,外设最终派生自组件和系统抽象。此外,外设被视为一种硬件组件,因此它有一个硬件抽象作为其直接父抽象。在 MAX 库中,有外设和硬件的接口,以及相关的通用类实现,称为 PeripheralGeneric 和 HardwareGeneric。
外设接口
由于外设是与您的机器人进行外部接口,因此必须有一些方法可以与该外部设备进行通信和交互。也就是说,如果您的外设是 GPS 传感器,您可以通过串行端口接口与该 GPS 设备进行交互。或者,您也可以有一个以太网接口连接到这样的设备。您的机器人与不同外设设备之间的物理接口范围可能非常广泛。无论是串行端口、以太网、数字 I/O、模拟 I/O,还是其他物理连接,您的外设都将与您的机器人拥有某种物理接口。因此,如图 1 所示,外设抽象与接口对象之间存在关系。外设可以作为您机器人外部设备的软件表示,但接口代表该外设与外部设备的物理接口。这种关系由您的外设通过 InterfaceManager 在后台管理。InterfaceManager 可以管理一个或多个物理接口。但是,它通常仅用于管理一个主要接口。它管理接口何时打开、关闭、如何将信息写入接口以及如何从接口传播信息。
这种程度的抽象有助于构建与接口无关的机器人应用程序。因此,例如,如果您构建一个通过串行端口与 GPS 传感器通信的应用程序,然后稍后更改为使用以太网接口或串行到以太网转换器的不同 GPS 设备,您可以更改接口类型而无需更改 GPS 类和代码。这只是 MAX 中内置的一种抽象形式,有助于隔离更改,并为编写可移植和可扩展的机器人应用程序提供了极大的灵活性。如图 2 所示,InterfaceGeneric 类被 MAX 中的各种具体接口类型扩展,并且还提供了一个钩子,可以更快地构建和集成您自己的物理接口(如果您愿意)。
配置执行器外设
有了关于外设的背景知识,让我们来看一下我们的“Hello World”示例。清单 1 显示了我们示例执行器的配置。我们将此配置及其接口配置直接从 [templates-config]/actuators/standardoutput 目录复制到我们的 [src-config]/HelloWorld/actuators 目录。在这里,我们配置了一个通用执行器,指定了 ActuatorGeneric 类。与所有 MAX 对象一样,我们可以通过 ReferencePolicy 配置规范来指示该对象将如何被其他对象引用。我们的 Actuator 实例由任何引用此对象的对象共享。这些是常见的引用策略类型:
- Dedicated(专用)—表示此对象在进程中被其他对象引用的每个实例都是唯一实例化的。也就是说,当被引用时,会返回该对象的新实例。这是默认配置。
- Shared(共享)—表示此对象配置实例被所有引用此对象的对象共享。因此,将创建一个对象副本,并将该副本返回给所有引用对象。
- Pooled(池化)—表示此对象配置创建了一个对象池。因此,引用对象获得由对象池管理的唯一句柄。返回到池中的对象将被释放,供其他对象引用。
清单 1 配置执行器外设
<?xml version="1.0"?>
<!-- The configuration for a robot actuator -->
<hashtable id="Actuator">
<!-- A sample template for MAX actuators -->
<string id="ClassName">
com.perronerobotics.actuator.ActuatorGeneric
</string>
<!-- Specifies the reference policy of the object
(i.e. Dedicated (default), Shared, Pooled) -->
<id id="ReferencePolicy">Shared</id>
<!-- Specify the base and object specific configuration -->
<hashtable id="Configuration">
<!-- If true, automatically start interfaces (open them) at
the tail end of configuration -->
<boolean id="AutoStart">true</boolean>
<!-- Specify the Object ID of a primary singular interface -->
<id id="Interface">./StandardOutputInterface</id>
</hashtable>
</hashtable>
我们还将我们的执行器配置为 AutoStart。这是此基础 HardwareGeneric 类的一部分配置参数,其行为在 PeripheralGeneric
类中进一步细化。将此值设置为 true 会导致外设在配置结束时调用其 InterfaceManager 上的 openInterfaces()
。这会促使 InterfaceManager 调用其配置的每个接口上的 open()
。因此,例如,如果接口是串行端口,则此时可能会自动打开该端口。否则,外设的客户端对象必须显式地触发其底层接口的打开。
在此示例中,如清单 1 所示,执行器外设指示其配置的接口的 ID 标记为 "./StandardOutputInterface"。我们之前看到,机器人的配置指定其组件之一的 ID 为 actuators.Actuator。在 [src-config]/HelloWorld/actuators 目录中,有一个 Actuator.xml 文件,如清单 1 所示。在这种情况下,执行器指示其接口与自身处于同一上下文中,使用 "./" 表示法。因此,接口的完全限定名称是 actuators.StandardOutputInterface,您会在 [src-config]/HelloWorld/actuators 中找到一个 StandardOutputInterface.xml 文件。
这个 StandardOutputInterface.xml 配置如图 2 所示。这里我们看到,该接口是 StandardIOInterface
类(在 MAX 库中)。此类扩展了 InterfaceGeneric
类,并提供了与标准输入和输出的简单接口。在这种情况下,类配置为默认配置。当外设触发向其输出写入信息时,它仅写入标准输出。这为我们提供了一种简单的方法来查看执行器如何插入应用程序。此类仅将信息转储到标准输出,但其他执行器可能具有写入计算机端口命令或通过离散数字、脉冲宽度调制或模拟输出接口直接控制输出的接口。
清单 2 配置执行器接口
<?xml version="1.0"?>
<!-- The configuration for a robot peripheral interface -->
<hashtable id="StandardOutputInterface">
<!-- A sample template for an interface to standard I/O (output) -->
<string id="ClassName">
com.perronetech.comm.stdio.StandardIOInterface
</string>
</hashtable>
正如您所见,配置外设(在本例中为执行器外设)相当简单。如果我们能够利用通用类(如 ActuatorGeneric
)或 MAX 库中的更具体的类(如 StandardIOInterface
),写入执行器可能就像将几个配置文件放入项目目录一样简单。当然,还有更复杂的场景需要考虑,例如将应用程序信息映射到/从特定外设设备和接口的低级协议信息。您也可能希望利用外设和接口的某些通用功能,并用您自己创建的具体类来扩展它们的服务。因此,您可以定义自己的 ActuatorGeneric
或 InterfaceGeneric
的具体扩展。
配置传感器外设
我们的示例机器人利用的另一个外设是传感器。清单 3 提供了位于 sensors.Sensor 上下文和 [src-config]/HelloWorld/sensors/Sensor.xml 文件中的 Sensor 对象的配置信息,我们将其从 [templates-config]/sensors/standardinput 目录中提取出来。您现在应该开始发现其中的模式了。您会看到我们定义了一个 SensorGeneric 类,具有共享引用策略,配置为 AutoStart 其接口,并定义了其接口。在这里,接口是存储在传感器同一上下文中的 StandardInputInterface 对象(在 sensors.StandardInputInterface 中)。
对于传感器,以及任何接收输入的 Peripherals,我们需要定义一种从传感器读取信息的方式。在这种情况下,我们配置了一个 AsynchronousPolicy,它指示外设自动侦听其接口上的事件。因此,当接口驱动程序级别有信息可用时,它将被接收并推送到 Peripherals 的 InterfaceManager
。这会在信息从接口接收时自动将信息从接口推送到 InterfaceManager
。为了将信息从 InterfaceManager
自动推送到 Peripherals 对象本身,我们配置了一个 ListenForInterfaceUpdates
变量。这会将信息自动从 InterfaceManager
路由到 Peripherals,无论接收到什么类型的信息。由于一个 Interface 对象可能实际上会馈送一个或多个 Peripherals 对象,因此这种过滤将非常有用。
<?xml version="1.0"?>
<!-- The configuration for a robot actuator -->
<hashtable id="Actuator">
<!-- A sample template for MAX actuators -->
<string id="ClassName">
com.perronerobotics.actuator.ActuatorGeneric
</string>
<!-- Specifies the reference policy of the object
(i.e. Dedicated (default), Shared, Pooled) -->
<id id="ReferencePolicy">Shared</id>
<!-- Specify the base and object specific configuration -->
<hashtable id="Configuration">
<!-- If true, automatically start interfaces (open them) at
the tail end of configuration -->
<boolean id="AutoStart">true</boolean>
<!-- Specify the Object ID of a primary singular interface -->
<id id="Interface">./StandardOutputInterface</id>
</hashtable>
</hashtable>
我们将信息从该传感器外设的接口传播到传感器外设对象本身。可以子类化并进一步配置 SensorGeneric
类,并对它从外部世界接收的信息进行一些预处理。但在我们的 HelloWorld 传感器配置中,我们只是将信息传递到 downstream 的 conduct.Plan
对象。我们通过向模板中的 TriggerAlwaysObjectID
s 配置部分添加一个条目来实现这一点。对于清单 3 中我们预构建的 HelloWorld 示例,此值已添加。TriggerAlwaysObjectIDs
配置内置于 SystemGeneric 类(SensorGeneric 的父类)中,并自动将接收到的事件传播到其配置中列出的对象。在这里,我们将应用程序配置为将事件推送到我们已配置为我们示例机器人子组件的自定义 Plan 对象。
我们的 Sensor 对象配置了清单 4 中列出的接口配置。这里我们看到,我们的 HelloWorld 传感器的接口只是与执行器相同的 StandardIOInterface
类的实例化。区别在于,我们将此接口对象定义为 ListenOnConsole
,这意味着它将在标准输入上侦听输入信息。这是我们说明传感器接口如何配置的简单方法。您扮演外部传感器的角色,并在运行此示例时在命令行上输入整数值。您输入的数字由 StandardIOInterface
读取,传播到 Sensor 的 InterfaceManager
,然后到 Sensor 本身,最后到 Plan 对象。
清单 4 配置传感器接口
<?xml version="1.0"?>
<!-- The configuration for a robot peripheral interface -->
<hashtable id="StandardInputInterface">
<!-- A sample template for an interface to standard I/O (input) -->
<string id="ClassName">
com.perronetech.comm.stdio.StandardIOInterface
</string>
<!-- Specify the base and object specific configuration -->
<hashtable id="Configuration">
<!-- Configure this standard I/O interface to listen on
its stdin console -->
<boolean id="ListenOnConsole">true</boolean>
</hashtable>
</hashtable>
摘要
外设,无论是传感器还是执行器,都是任何机器人系统的关键组件。正如我们在基本示例中所见,使用此处显示的技术可以非常容易地配置一个基本的传感器和执行器供我们的机器人使用。外设接口也易于配置,并且可以通过这种方式实现外设对象与其物理接口之间的解耦。
![]() |
Arduino 实战 |
![]() |
扎实的 Java 开发者 |
![]() |
机器学习实战 |