2.内核的JavaAPI
使用内核API所需的接口和类是opentcs-api-base
JAR文件,所以您应该将它添加到您的类路径/声明它上的一个依赖项。(见 可用工件和API兼容性 .工厂模型组件和运输订单的基本数据结构通常如下:
图1基本数据结构
为获取和操作这些数据结构而经常与之进行交互的服务接口如下:
图2与服务接口相关
如下图所示,还有一些接口可以与内核的各个部分进行交互:
图3额外服务接口
周边* 类/接口与外围设备的实验集成有关。这些特性目前还没有详细的记录,而使用其中任何一种特性的开发人员现在都是独立的。 |
2.1.获取服务对象
使用在内核JVM中运行的代码中的服务,例如。一个司机,简单地要求一个实例。PlantModelService
通过依赖性注入提供。你也可以处理一个例子InternalPlantModelService
这里,它提供了仅对内核应用程序组件可用的其他方法。
访问来自另一个JVM的服务,例如。在一个客户端中,您需要通过远程方法调用(RMI)来创建运输订单或接收运输订单或车辆的状态更新。最简单的方法是创建一个实例KernelServicePortalBuilder
把它建成KernelServicePortal
你的例子。(目前,对用户管理没有多少支持,因此建议忽略需要用户凭证的方法。)在创作后KernelServicePortal
实例,您可以使用它来获取服务实例并从中获取内核事件。请参阅KernelServicePortalBuilder
在基地API的javadOC文档中。
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>KernelServicePortal servicePortal = <span style="color:#000000"><strong>new</strong></span> KernelServicePortalBuilder().build();
<span style="color:#999988"><em>// Connect and log in with a kernel somewhere.</em></span>
servicePortal.login(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">someHost</span><span style="color:#dd1144">"</span></span>, <span style="color:#009999">1099</span>);
<span style="color:#999988"><em>// Get a reference to the plant model service...</em></span>
PlantModelService plantModelService = servicePortal.getPlantModelService();
<span style="color:#999988"><em>// ...and find out the name of the currently loaded model.</em></span>
<span style="color:inherit">String</span> modelName = plantModelService.getLoadedModelName();
<span style="color:#999988"><em>// Poll events, waiting up to a second if none are currently there.</em></span>
<span style="color:#999988"><em>// This should be done periodically, and probably in a separate thread.</em></span>
<span style="color:inherit">List</span><<span style="color:inherit">Object</span>> events = servicePortal.fetchEvents(<span style="color:#009999">1000</span>);</code></span></span></span></span>
2.2.与运输订单合作
由类的实例表示的传输命令TransportOrder
,描述由车辆执行的过程。通常,这一过程是货物从一个地点到另一个地点的实际运输。ATransportOrder
不过,也可以描述车辆向目的地的移动和要执行的可选车辆操作。
以下所有的例子都是OCTCS中"运输订单"的例子,即使实际上没有运输:
-
把货物从别处运到别处的经典订单:
-
移动到"A"位置,在那里执行"装载货物"操作。
-
移动到"B"位置,在那里执行"卸货"操作。
-
-
运输或固定货物的操纵:
-
移动到"A"位置,在那里进行操作"钻头"。
-
移动到"B"位置,在那里执行"锤子"操作。
-
-
命令将车辆移至停车位:
-
移至"01公园"(不进行任何特定操作)。
-
-
给车辆电池充电的命令:
-
移动到"充电站",在那里执行"充电电池"操作。
-
2.2.1.运输订单的生命周期
-
当一个运输订单被创建时,它的初始状态是
RAW
. -
用户/客户机为传输订单设置参数,这些参数被认为会影响传输过程。这些参数可以是例如。运输订单的最后期限,应该处理运输订单的车辆或一组通用的,通常是特定项目的属性。
-
传送令启动,即:参数设置完成。它的国家准备
ACTIVE
. -
内核的路由器检查传输命令的目的地之间的路由是否完全可能。如果是,它的状态将改变为
DISPATCHABLE
.如果无法进行路由,则将运输订单标记为UNROUTABLE
也不再进一步处理。 -
内核的调度程序检查执行传输命令的所有要求是否都得到了满足,是否有车辆可以处理它。只要有任何要求尚未得到满足,或没有车辆能够执行,运输订单就会等待。
-
内核的调度程序将传输订单分配给车辆进行处理。它的状态变成了
BEING_PROCESSED
.-
如果正在处理的传输订单被(客户/用户)撤回,其状态首先会更改到
WITHDRAWN
当车辆执行任何已经发送给它的命令时。然后运输令的状态改变到FAILED
.它不再进一步处理。 -
如运输订单的处理因任何原因而失败,则注明为:
FAILED
也不再进一步处理。 -
如果车辆成功地处理了整个运输订单,则其标记为:
FINISHED
.
-
-
最终--在一个较长的时间内,或者当最终状态中有太多的传输订单在内核的订单池中积累时--内核删除了传输订单。
下面的状态机形象化了这个生命周期:
图4运输订单国
2.2.2.运输订单的结构和处理
图5运输订单类别
传送命令是通过TransportOrderService.createTransportOrder()
.作为它的参数,它期望TransportOrderCreationTO
载有前往目的地的顺序和车辆应该在那里进行的操作。内核将每个Destination
新创造的DriveOrder
实例。这些DriveOrder
它们自己被一个新创造的核包裹着TransportOrder
依其指定的顺序。
从前TransportOrder
会被派往一辆车上Dispatcher
,aRoute
是为它的每一个DriveOrder
s. TheseRoute
然后储存在相应的DriveOrder
s.
一旦车辆(司机)能够处理DriveOrder
,单身Step
它的Route
会被映射到MovementCommand
s. TheseMovementCommand
它包含了所有车辆驾驶员到达最终目的地和在那里进行所需操作所需的信息。
图6与移动命令相关的类
…MovementCommand
对于将要行驶的部分路线,将逐点发送给车辆驾驶员。内核只发送尽可能多的MovementCommands
这是为了让司机正常工作所必需的。它这样做是为了维护对所有车辆使用的路径/资源的细粒度控制。车辆驾驶员可设定MovementCommand
它通过调整其命令队列容量提前到达。
一旦DriveOrder
已经结束了,Route
下一个DriveOrder
已经映射到MovementCommand
S.最后一次DriveOrder
一种TransportOrder
结束了,整个TransportOrder
也结束了。
2.2.3.如何创建传输订单
创建一个交通工具的目的地列表。在工厂模型中,每个目的地都由目的地的名称描述,车辆应该在那里执行的操作:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code><span style="color:inherit">List</span><DestinationCreationTO> destinations
= <span style="color:inherit">List</span>.of(
<span style="color:#000000"><strong>new</strong></span> DestinationCreationTO(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some location</span><span style="color:#dd1144">"</span></span>, <span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some operation</span><span style="color:#dd1144">"</span></span>)
);</code></span></span></span></span>
根据需要尽可能多地把目的地放在列表中。然后用新的运输订单名称和目的地列表创建一个运输订单描述。
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>TransportOrderCreationTO orderTO
= <span style="color:#000000"><strong>new</strong></span> TransportOrderCreationTO(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">MyTransportOrder</span><span style="color:#dd1144">"</span></span>, destinations);</code></span></span></span></span>
可选地,表示顺序的全名应该由内核生成。(如果您不这样做,则需要确保上述传输命令的名称是唯一的。)
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>orderTO = orderTO.withIncompleteName(<span style="color:#008080">true</span>);</code></span></span></span></span>
可选择地为运输订单设置更多的参数,例如。订明订购日期或指定特定车辆:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>orderTO = orderTO
.withIntendedVehicleName(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some vehicle</span><span style="color:#dd1144">"</span></span>)
.withDeadline(Instant.now().plus(<span style="color:#009999">1</span>, ChronoUnit.HOURS));</code></span></span></span></span>
得到TransportOrderService
,
-
并要求其使用所述的描述来创建运输订单:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>TransportOrderService transportOrderService = getATransportOrderService();
transportOrderService.createTransportOrder(orderTO);</code></span></span></span></span>
有选择地,得到DispatcherService
并触发内核的调度器显式地让它检查能够处理传输订单的车辆。(只在创建传输命令后需要立即触发调度器时才需要这样做。如果您不这样做,调度器仍会定期被触发。)
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>DispatcherService dispatcherService = getADispatcherService();
dispatcherService.dispatch();</code></span></span></span></span>
2.2.4。如何创建一个将车辆发送到某一地点而不是某一地点的运输订单
创建一个包含单个目的地的列表,使用Destination.OP_MOVE
待执行的行动:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code><span style="color:inherit">List</span><DestinationCreationTO> destinations
= <span style="color:inherit">List</span>.of(
<span style="color:#000000"><strong>new</strong></span> DestinationCreationTO(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some point</span><span style="color:#dd1144">"</span></span>, <span style="color:inherit">Destination</span>.OP_MOVE)
);</code></span></span></span></span>
为新的运输订单和目的地(单一要素)列表创建一个运输订单说明:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>TransportOrderCreationTO orderTO
= <span style="color:#000000"><strong>new</strong></span> TransportOrderCreationTO(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">MyTransportOrder</span><span style="color:#dd1144">"</span></span>, destinations)
.withIntendedVehicleName(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some vehicle</span><span style="color:#dd1144">"</span></span>)
.withIncompleteName(<span style="color:#008080">true</span>);</code></span></span></span></span>
得到TransportOrderService
(见 获取服务对象 )并要求其使用所述的描述来创建运输订单:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>TransportOrderService transportOrderService = getATransportOrderService();
transportOrderService.createTransportOrder(orderTO);</code></span></span></span></span>
有选择地,得到DispatcherService
并触发内核的调度器显式地让它检查能够处理传输订单的车辆。(只在创建传输命令后需要立即触发调度器时才需要这样做。如果您不这样做,调度器仍会定期被触发。)
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>DispatcherService dispatcherService = getADispatcherService();
dispatcherService.dispatch();</code></span></span></span></span>
2.2.5.如何处理顺序序列
订单顺序可以用来强迫单个车辆按给定的顺序处理多个运输订单。在API文档中描述了使用顺序序列的一些规则。OrderSequence
但这是你通常会做的。首先,创建一个订单序列描述,提供一个名称:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>OrderSequenceCreationTO sequenceTO
= <span style="color:#000000"><strong>new</strong></span> OrderSequenceCreationTO(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">MyOrderSequence</span><span style="color:#dd1144">"</span></span>);</code></span></span></span></span>
或者,表示序列的全名应该由内核生成。(如果您不这样做,则需要确保上面给出的订单序列的名称是唯一的。)
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>sequenceTO = sequenceTO.withIncompleteName(<span style="color:#008080">true</span>);</code></span></span></span></span>
可选择的,设置序列的失败致命标志:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>sequenceTO = sequenceTO.withFailureFatal(<span style="color:#008080">true</span>);</code></span></span></span></span>
得到TransportOrderService
(见 获取服务对象 ),并要求它使用所述的描述来创建一个订单序列:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>TransportOrderService transportOrderService = getATransportOrderService();
OrderSequence orderSequence
= transportOrderService.createOrderSequence(sequenceTO);</code></span></span></span></span>
像往常一样为传输顺序创建描述,但是通过withWrappingSequence()
将传输顺序与订单顺序关联起来.然后,使用TransportOrderService
.
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>TransportOrderCreationTO orderTO
= <span style="color:#000000"><strong>new</strong></span> TransportOrderCreationTO(
<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">MyOrder</span><span style="color:#dd1144">"</span></span>,
<span style="color:inherit">List</span>.of(
<span style="color:#000000"><strong>new</strong></span> DestinationCreationTO(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some location</span><span style="color:#dd1144">"</span></span>, <span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">Some operation</span><span style="color:#dd1144">"</span></span>)
)
)
.withIncompleteName(<span style="color:#008080">true</span>)
.withWrappingSequence(orderSequence.getName());
transportOrderService.createTransportOrder(orderTO);</code></span></span></span></span>
必要时创建并向订单序列添加更多订单.最后,设定顺序 完整的 标记表明不再增加运输订单:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>transportOrderService.markOrderSequenceComplete(
orderSequence.getReference()
);</code></span></span></span></span>
只要序列没有被标记为完整和完全完成,为其第一个顺序选择的车辆将被绑定到这个序列。在整个序列完成之前,它不会处理任何不属于同一序列的订单。
一旦 完整的 已设置顺序标志,所有属于该序列的运输订单均已处理完毕。 完成的 标记将由内核设置。
2.2.6。如何撤回运输订单
为了撤回运输订单DispatcherService
(见 获取服务对象 )并要求撤回命令,同时提供参考:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>DispatcherService dispatcherService = getADispatcherService();
dispatcherService.withdrawByTransportOrder(someOrder.getReference(), <span style="color:#008080">true</span>);</code></span></span></span></span>
第二种论点是指车辆是否应完成已分配给(false
)或立即终止(true
).
2.2.7.如何透过车辆参考资料撤回运输订单
若要撤回某车辆目前正在处理的运输订单,请按DispatcherService
(见 获取服务对象 ),并要求撤回订单,提供有关车辆的参考资料:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code>DispatcherService dispatcherService = getADispatcherService();
dispatcherService.withdrawByVehicle(curVehicle.getReference(), <span style="color:#008080">true</span>);</code></span></span></span></span>
第二种论点是指车辆是否应完成已分配给(false
)或立即终止(true
).
2.3.使用事件总线
每一个主要的OPECS应用程序--内核、内核控制中心、模型编辑器和操作台--都提供了一个事件总线,可以用来接收或发出整个应用范围内的事件对象。要获取相应应用程序的事件总线实例,请通过依赖项注入提供该实例。下列三种构造函数参数的任何一种都是等价的:
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code><strong>public</strong> MyClass(<span style="color:#000077">@ApplicationEventBus</span> <span style="color:inherit">EventHandler</span> eventHandler) {
...
}</code></span></span></span></span>
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code><strong>public</strong> MyClass(<span style="color:#000077">@ApplicationEventBus</span> EventSource eventSource) {
...
}</code></span></span></span></span>
<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f7f7f8"><span style="color:rgba(0, 0, 0, 0.9)"><code><strong>public</strong> MyClass(<span style="color:#000077">@ApplicationEventBus</span> EventBus eventBus) {
...
}</code></span></span></span></span>
获得了EventHandler
,EventSource
或EventBus
这样的实例,您可以使用它向它发送事件对象和/或订阅接收事件对象。
注意,在内核应用程序中,事件对象应该通过内核执行器发出,以避免并发性问题--参见 在内核上下文中执行代码 .