开源AGV调度系统OpenTCS中的任务分派器(dispatcher)详解

OpenTCS中的任务分派器dispatcher详解

  • 1. 引言
  • 2. 任务分派器(dispatcher)
    • 2.1 默认的停车位置选择
    • 2.2 可选停车位置属性
    • 2.3 默认的充电位置选择
    • 2.4 即时运输订单分配
  • 3. 默认任务分派器的配置项
  • 4. 参考资料与源码

1. 引言

openTCS是一项著名的开源运输控制系统,我在之前的一篇文章
开源AGV调度系统 OpenTCS 5.4 开发环境配置与编译运行中对该系统也做了初步介绍,该项研究工作丢了快三年了,由于发现还有不少感兴趣的读者,因此,我想继续撰写系列文章对该系统进行详解。
在这里插入图片描述

2. 任务分派器(dispatcher)

openTCS中默认的任务分派器(Default dispatcher)是openTCS内置的重要策略模块,当然也是允许用户自定义和替换的。
任务分派器(dispatcher)的职能为:当订单或者车辆处于可用状态,默认分派器决定该订单或者车辆下一步的工作如何进行。并且,默认分派器在执行此操作时需遵循以下步骤:

在这里插入图片描述

  1. 将新的运输订单准备就绪。需要包括检查一般可达性和未完成的依赖项。
  2. 对当前正在进行的进程进行更新。一般包括:
  • 撤销运输订单
  • 成功完成的运输订单
  • 给正在执行序列订单的车辆分配后续的运输订单;
  1. 将当前闲置的车辆分配给可执行的订单。此时需要考虑到一些准则:
  • 车辆:
    • 该车辆在行驶路线上的位置必须已知;
    • 该车辆没有被分配给运输订单或分配的任务不是必要的(比如电量充足的情况下执行充电任务或或前往停车点);
    • 该车电量尚不影响使用;
  • 订单:
    • 该订单是一般可调度的;
    • 该订单不是已被某车辆执行的序列订单的一部分;
  • 分配机制:
    • 如果可处理的运输订单大于未占用的车辆,则车辆按照可配置的标准进行排序,然后,默认分派器迭代排序后的列表,对于每辆车,查找其可执行的所有订单,计算所需的路线,根据可配置的标准对候选车辆进行排序,并分配第一个任务;
    • 如果可处理的运输订单少于未占用的车辆,则运输订单按照可配置的标准进行排序,然后默认分派器对列表进行迭代,为每个运输订单找到所有可执行它的车辆,然后计算所需路径,并安排好第一个任务;
  1. 将仍闲置的车辆送往充电站。需要考虑的标准为:
  • 该车辆在行驶路线上的位置必须处于已知状态;
  • 该车辆的电量水平降低了。
  1. 将仍闲置的车辆送往充电站。需要考虑的标准为:
  • 该车辆在行驶路线上的位置必须处于已知状态;
  • 该车辆不能已经在停车点位置了。

2.1 默认的停车位置选择

当一辆小车被派往停车点时,默认选择最接近(依据路由)且未被占用的停车点。可以通过设置以下关键属性来给车辆分配固定的位置。

  • tcs:preferredParkingPosition:模型中的点名。如果此停车点已被占用,则车辆选择附近距离最近的停车点代替。
  • tcs:assignedParkingPosition:模型中的点名。如果此停车点已被占用,则车辆不会前往到其他停车点,而是保持原地不动。
    assignedParkingPosition优先级高于preferredParkingPosition

2.2 可选停车位置属性

停车位置的优先级是可以明确的,车辆也可以按照一种新的停车序列进行重新停车操作。例如将车辆停放在运输订单频繁的第一目的地附近的位置。
要给停车点设置一个优先级,可以用tcs:parkingPositionPriority键设置一个属性在点上。该属性的值应为十进制整数,值越小,则会导致停车位的优先级更高。
1.3. Default recharging location selection

2.3 默认的充电位置选择

当车辆被派往充电位置时,默认选择最接近(依据路由)且未被占用的充电位置。也可通过为以下键设置属性来给车辆分配固定位置:

  • preferredRechargeLocation:如果此充电位置已被占用,则选择附近距离最近的充电位置。
  • assignedRechargeLocation:如果此充电位置已被选择,则车辆不会被派往到其他充电位置。
    assignedRechargeLocation优先级高于preferredRechargeLocation

2.4 即时运输订单分配

系统除了根据默认的流程和规则分配运输订单外,还可以显式分配运输订单(即时)。运输订单的即时分配支持具有预期车辆的运输订单。在这样的情况下,运输订单及其预期车辆通常处于可能进行分配的状态,但在常规调度程序流中被某些过滤条件阻止,因此采取这种方法将会很有用。

Although the immediate assignment of transport orders bypasses some of the filter criteria in the regular dispatcher flow, it works only in specific situations. Regarding the transport order’s state:

尽管传输订单的即时分配绕过了常规调度流程中的一些过滤条件,但它只在特定情况下起作用。考虑运输订单的状态:

  • 运输订单的状态必须是可指派的(DISPATCHABLE)。
  • 运输订单不能是订单序列的一部分。
  • 必须设置运输订单的预定车辆。

至于(预定)车辆的状态:

  • 车辆的处理状态必须为IDLE
  • 车辆状态必须为IDLECHARGING
  • 车辆的集成级别必须是TO_BE_UTILIZED
  • 车辆必须被报告在已知位置。
  • 车辆不得处理订单序列。

除了运输订单和预定车辆的各自状态之外,分派器可能还有其他特定的原因来拒绝即时分配。

3. 默认任务分派器的配置项

默认任务分派器提供以下配置项实现可配置.
defaultdispatcher.orderCandidatePriorities

  • Type: Comma-separated list of strings
  • Trigger for changes to be applied: on application start
  • Description: Keys by which to prioritize transport order candidates for assignment.
    Possible values:
  • BY_AGE: Sort by transport order age, oldest first.
  • BY_DEADLINE: Sort by transport order deadline, most urgent first.
  • DEADLINE_AT_RISK_FIRST: Sort orders with deadlines at risk first.
  • BY_COMPLETE_ROUTING_COSTS: Sort by complete routing costs, lowest first.
  • BY_INITIAL_ROUTING_COSTS: Sort by routing costs for the first destination.
  • BY_ORDER_NAME: Sort by transport order name, lexicographically.

defaultdispatcher.orderPriorities

  • Type: Comma-separated list of strings
  • Trigger for changes to be applied: on application start
  • Description: Keys by which to prioritize transport orders for assignment.
    Possible values:
    BY_AGE: Sort by age, oldest first.
    BY_DEADLINE: Sort by deadline, most urgent first.
    DEADLINE_AT_RISK_FIRST: Sort orders with deadlines at risk first.
    BY_NAME: Sort by name, lexicographically.

defaultdispatcher.vehicleCandidatePriorities

  • Type: Comma-separated list of strings
  • Trigger for changes to be applied: on application start
  • Description: Keys by which to prioritize vehicle candidates for assignment.
    Possible values:
    BY_ENERGY_LEVEL: Sort by energy level of the vehicle, highest first.
    IDLE_FIRST: Sort vehicles with state IDLE first.
    BY_COMPLETE_ROUTING_COSTS: Sort by complete routing costs, lowest first.
    BY_INITIAL_ROUTING_COSTS: Sort by routing costs for the first destination.
    BY_VEHICLE_NAME: Sort by vehicle name, lexicographically.

defaultdispatcher.vehiclePriorities

  • Type: Comma-separated list of strings
  • Trigger for changes to be applied: on application start
  • Description: Keys by which to prioritize vehicles for assignment.
    Possible values:
    BY_ENERGY_LEVEL: Sort by energy level, highest first.
    IDLE_FIRST: Sort vehicles with state IDLE first.
    BY_NAME: Sort by name, lexicographically.

defaultdispatcher.deadlineAtRiskPeriod
Type: Integer
Trigger for changes to be applied: on application start
Description: The time window (in ms) before its deadline in which an order becomes urgent.

defaultdispatcher.assignRedundantOrders

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether orders to the current position with no operation should be assigned.

defaultdispatcher.dismissUnroutableTransportOrders

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether unroutable incoming transport orders should be marked as UNROUTABLE.

defaultdispatcher.reroutingImpossibleStrategy

  • Type: String
  • Trigger for changes to be applied: instantly
  • Description: The strategy to use when rerouting of a vehicle results in no route at all.
    The vehicle then continues to use the previous route in the configured way.
    Possible values:
    IGNORE_PATH_LOCKS: Stick to the previous route, ignoring path locks.
    PAUSE_IMMEDIATELY: Do not send further orders to the vehicle; wait for another rerouting opportunity.
    PAUSE_AT_PATH_LOCK: Send further orders to the vehicle only until it reaches a locked path; then wait for another rerouting opportunity.

defaultdispatcher.parkIdleVehicles

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether to automatically create parking orders for idle vehicles.

defaultdispatcher.considerParkingPositionPriorities

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether to consider parking position priorities when creating parking orders.

defaultdispatcher.reparkVehiclesToHigherPriorityPositions

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether to repark vehicles to parking positions with higher priorities.

defaultdispatcher.rechargeIdleVehicles

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether to automatically create recharge orders for idle vehicles.

defaultdispatcher.keepRechargingUntilFullyCharged

  • Type: Boolean
  • Trigger for changes to be applied: instantly
  • Description: Whether vehicles must be recharged until they are fully charged.
    If false, vehicle must only be recharged until sufficiently charged.

defaultdispatcher.idleVehicleRedispatchingInterval

  • Type: Integer
  • Trigger for changes to be applied: when/after plant model is loaded
  • Description: The interval between redispatching of vehicles.

4. 参考资料与源码

本文内容参考:官方文档

该模块源码位于:
openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/dispatching/DefaultDispatcher.java,代码如下:

 public DefaultDispatcher(OrderReservationPool orderReservationPool,TransportOrderUtil transportOrderUtil,InternalVehicleService vehicleService,@ApplicationEventBus EventSource eventSource,@KernelExecutor ScheduledExecutorService kernelExecutor,FullDispatchTask fullDispatchTask,Provider<PeriodicVehicleRedispatchingTask> periodicDispatchTaskProvider,DefaultDispatcherConfiguration configuration,RerouteUtil rerouteUtil,OrderAssigner orderAssigner,TransportOrderAssignmentChecker transportOrderAssignmentChecker) {this.orderReservationPool = requireNonNull(orderReservationPool, "orderReservationPool");this.transportOrderUtil = requireNonNull(transportOrderUtil, "transportOrderUtil");this.vehicleService = requireNonNull(vehicleService, "vehicleService");this.eventSource = requireNonNull(eventSource, "eventSource");this.kernelExecutor = requireNonNull(kernelExecutor, "kernelExecutor");this.fullDispatchTask = requireNonNull(fullDispatchTask, "fullDispatchTask");this.periodicDispatchTaskProvider = requireNonNull(periodicDispatchTaskProvider,"periodicDispatchTaskProvider");this.configuration = requireNonNull(configuration, "configuration");this.rerouteUtil = requireNonNull(rerouteUtil, "rerouteUtil");this.orderAssigner = requireNonNull(orderAssigner, "orderAssigner");this.transportOrderAssignmentChecker = requireNonNull(transportOrderAssignmentChecker,"transportOrderAssignmentChecker");}@Overridepublic void initialize() {if (isInitialized()) {return;}LOG.debug("Initializing...");transportOrderUtil.initialize();orderReservationPool.clear();fullDispatchTask.initialize();implicitDispatchTrigger = new ImplicitDispatchTrigger(this);eventSource.subscribe(implicitDispatchTrigger);LOG.debug("Scheduling periodic dispatch task with interval of {} ms...",configuration.idleVehicleRedispatchingInterval());periodicDispatchTaskFuture = kernelExecutor.scheduleAtFixedRate(periodicDispatchTaskProvider.get(),configuration.idleVehicleRedispatchingInterval(),configuration.idleVehicleRedispatchingInterval(),TimeUnit.MILLISECONDS);initialized = true;}@Overridepublic void terminate() {if (!isInitialized()) {return;}LOG.debug("Terminating...");periodicDispatchTaskFuture.cancel(false);periodicDispatchTaskFuture = null;eventSource.unsubscribe(implicitDispatchTrigger);implicitDispatchTrigger = null;fullDispatchTask.terminate();initialized = false;}@Overridepublic boolean isInitialized() {return initialized;}@Overridepublic void dispatch() {LOG.debug("Scheduling dispatch task...");// Schedule this to be executed by the kernel executor.kernelExecutor.submit(fullDispatchTask);}@Overridepublic void withdrawOrder(TransportOrder order, boolean immediateAbort) {requireNonNull(order, "order");checkState(isInitialized(), "Not initialized");// Schedule this to be executed by the kernel executor.kernelExecutor.submit(() -> {LOG.debug("Scheduling withdrawal for transport order '{}' (immediate={})...",order.getName(),immediateAbort);transportOrderUtil.abortOrder(order, immediateAbort);});}@Overridepublic void withdrawOrder(Vehicle vehicle, boolean immediateAbort) {requireNonNull(vehicle, "vehicle");checkState(isInitialized(), "Not initialized");// Schedule this to be executed by the kernel executor.kernelExecutor.submit(() -> {LOG.debug("Scheduling withdrawal for vehicle '{}' (immediate={})...",vehicle.getName(),immediateAbort);transportOrderUtil.abortOrder(vehicle, immediateAbort);});}@Overridepublic void topologyChanged() {if (configuration.rerouteOnTopologyChanges()) {LOG.debug("Scheduling reroute task...");kernelExecutor.submit(() -> {LOG.info("Rerouting all vehicles due to topology change...");rerouteUtil.reroute(vehicleService.fetchObjects(Vehicle.class), ReroutingType.REGULAR);});}}@Overridepublic void reroute(Vehicle vehicle, ReroutingType reroutingType) {LOG.debug("Scheduling reroute task...");kernelExecutor.submit(() -> {LOG.info("Rerouting vehicle due to explicit request: {} ({}, current position {})...",vehicle.getName(),reroutingType,vehicle.getCurrentPosition() == null ? null : vehicle.getCurrentPosition().getName());rerouteUtil.reroute(vehicle, reroutingType);});}@Overridepublic void assignNow(TransportOrder transportOrder)throws TransportOrderAssignmentException {requireNonNull(transportOrder, "transportOrder");TransportOrderAssignmentVeto assignmentVeto= transportOrderAssignmentChecker.checkTransportOrderAssignment(transportOrder);if (assignmentVeto != TransportOrderAssignmentVeto.NO_VETO) {throw new TransportOrderAssignmentException(transportOrder.getReference(),transportOrder.getIntendedVehicle(),assignmentVeto);}orderAssigner.tryAssignments(List.of(vehicleService.fetchObject(Vehicle.class, transportOrder.getIntendedVehicle())),List.of(transportOrder));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/295311.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第五篇:3.4 用户归因和受众(User attribution and audience) - IAB/MRC及《增强现实广告效果测量指南1.0》

翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效果测量定义和其他矩阵之- 3.1 广告印象&#xff08;AD Impression&#xff09;第三篇广告效果测量定义和其他矩阵之- 3.2 可见性 &#xff08;Viewability&#xff09;第四篇广…

SpringBoot+ECharts+Html 字符云/词云案例详解

1. 技术点 SpringBoot、MyBatis、thymeleaf、MySQL、ECharts 等 2. 准备条件 在mysql中创建数据库echartsdb&#xff0c;数据库中创建表t_comment表&#xff0c;表中设置两个字段word与count&#xff0c;添加表中的数据。如&#xff1a;附件中的 echartsdb.sql 3. SpringBoot…

el-table实现表格内部横向拖拽效果

2024.4.2今天我学习了如何对el-table表格组件实现内部横向拖拽的效果&#xff0c;效果&#xff1a; 代码如下&#xff1a; 一、创建utils/底下文件 const crosswise_drag_table function (Vue){// 全局添加table左右拖动效果的指令Vue.directive(tableMove, {bind: function…

智慧开发平台免!费!申请试用

原创 F学社 F学社 2024-04-01 17:13 江苏 扫描二维码即可申请试用 01 智慧开发平台简介 F1 WIFI智慧教育平台是可支持线上线下联动的基于FPGA的口袋式数字系统学习平台。其采用了AMD、Altera、安路、高云等国外国内主流公司的FPGA进行数字系统方向的教学实验设计&#xff0c…

Pyecharts绘制条形图

前言 条形图是一种把连续数据画成数据条的表现形式&#xff0c;通过比较不同组的条形长度&#xff0c;从而对比不同组的数据量大小。描绘条形图的要素有3个&#xff1a;组数、组宽度、祖限。绘制条形图时&#xff0c;不同组之间是由空隙的。条形用来比较两个或两个以上的价值&a…

Golang并发模型-Pipeline模型、Fan-in Fan-out模型

这段时间由于项目的需要&#xff0c;本人正在研究关于如何优雅的进行go的并发&#xff0c;以下是结合资料和视频的结果&#xff0c;文末会给出参考资料 Go语言的并发模型主要通过goroutine和channel实现&#xff0c;通过这个我们可以更有效地使用IO和CPU 这里我们围绕生成一个…

增强Java技能:使用OkHttp下载www.dianping.com信息

在这篇技术文章中&#xff0c;我们将探讨如何使用Java和OkHttp库来下载并解析www.dianping.com上的商家信息。我们的目标是获取商家名称、价格、评分和评论&#xff0c;并将这些数据存储到CSV文件中。此外&#xff0c;我们将使用爬虫代理来绕过任何潜在的IP限制&#xff0c;并实…

Set a Light 3D Studio:探索光影艺术的全新维度mac/win中文版

Set a Light 3D Studio 是一款领先的三维建模和渲染软件&#xff0c;它将设计师、艺术家和摄影师的创意想法转化为生动逼真的三维场景。这款软件以其强大的功能和直观的界面&#xff0c;成为行业内众多专业人士的首 选工具。 set.a.light 3D STUDIO中文版软件获取 在Set a Lig…

备战蓝桥杯---贪心刷题1

话不多说&#xff0c;直接看题&#xff1a; 本质是一个数学题&#xff1a; 我们令xi<0表示反方向传递&#xff0c;易得我们就是求每一个xi的绝对值之和min,我们令平均值为a爸。 易得约束条件&#xff1a; x1-x2a1-a,x2-x3a2-a..... 解得x1x1-0,x2x1-((n-1)*a-a2-...an)。…

火鸟门户系统—旅游度假模块

旅游度假 简介 旅游度假功能为用户提供一站式旅游度假服务&#xff0c;车站、酒店民宿、门票、跟团游、货运、签证等多个方面&#xff0c;满足用户多样化的旅游需求。 功能 订单&#xff1a;提供订单预订服务&#xff0c;用户可以根据自身需求选择合适的旅行产品。酒店民宿…

人工智能+的广泛应用,已渗透到生活的方方面面

引言 随着科技的不断进步和人工智能技术的快速发展&#xff0c;我们正处于一个人工智能时代。人工智能不仅仅是一种技术&#xff0c;更是一种革命性的变革力量&#xff0c;它正在以前所未有的方式改变着我们的生活和工作方式。 人工智能&#xff08;AI&#xff09;指的是人工…

C++算法补充---STL

这里写目录标题 CSTL容器字符串函数(string容器函数)字符串转字符 算法交换函数拿到容器或者数组的第一个最大&#xff08;小&#xff09;值元素的下标或者值排序函数求字符数组的有效长度atoi函数&#xff08;将字符串类型的数字转为真正的int型数字&#xff09;string转字符 …

mt7601 kernel 4.19内核版本使用iw,以及交叉编译后使用iwpriv

目录 内核自带 内核配置 移植 iw工具 移植mt7601源码 内核自带 内核配置 在linux内核4.19版本中已经把mt7601的驱动加入到内核源码中。 内核需要需要开启mac802.11 使用iwpriv 提示如下&#xff0c;iwpriv工具无法使用了&#xff0c;而iwconfig可以使用 /opt/ko # iwp…

数论与线性代数——整除分块【数论分块】的【运用】【思考】【讲解】【证明(作者自己证的QWQ)】

文章目录 整除分块的思考与运用整除分块的时间复杂度证明 & 分块数量整除分块的公式 & 公式证明公式证明 代码code↓ 整除分块的思考与运用 整除分块是为了解决一个整数求和问题 题目的问题为&#xff1a; ∑ i 1 n ⌊ n i ⌋ \sum_{i1}^{n} \left \lfloor \frac{n}{…

手写三维点云配准的迭代最近点(ICP)算法

在本篇博客中,主要深入研究迭代最近点(ICP)算法,特别是针对三维点云配准的实现。分析一个C++代码片段并解释其关键组成部分。(主要参考高博的ICP算法) 简介 ICP是计算机视觉和机器人领域广泛使用的技术,用于将两组三维点进行配准。其主要应用是将一组观测点与参考模型进…

在idea中使用sql语言提醒

1.Settings中设置 2. 配置好数据库名字 3. altenter 注入方言 注入后是下面这样

Linux:冯·诺依曼结构 OS管理机制

Linux&#xff1a;冯诺依曼结构 & OS管理机制 冯诺依曼结构OS管理机制OS对下层硬件的管理OS对上层用户的服务 冯诺依曼结构 我们常见的计算机&#xff0c;比如笔记本&#xff0c;台式电脑。以及一下不常见的计算机&#xff0c;比如服务器&#xff0c;几乎都遵循冯诺依曼体…

如何理解Java注解反射

Java 8 中文版 - 在线API手册 - 码工具 什么是注解 ◆Annotation是从JDK5.0开始引入的新技术 ◆Annotation的作用: 不是程序本身&#xff0c;可以对程序作出解释.(这一点和注释(comment)没什么区别) 可以被其他程序(比如:编译器等)读取 Annotation的格式: > 注解是以&quo…

redis 的StringRedisTemplate

6.3 StringRedisTemplate 尽管JSON的序列化方式可以满足我们的需求&#xff0c;但依然存在一些问题&#xff0c;如图&#xff1a; 为了在反序列化时知道对象的类型&#xff0c;JSON序列化器会将类的class类型写入json结果中&#xff0c;存入Redis&#xff0c;会带来额外的内存…

ES8 学习 -- async 和 await / 对象方法扩展 / 字符串填充

文章目录 1. async 和 await1.1 基本语法1.2 使用示例1.3 案例练习 2. 对象方法扩展2.1 Object.values(obj)2.2 Object.entries(obj)2.3 Object.getOwnPropertyDescriptors(obj)使用示例 3. 字符串填充4. 函数参数的末尾加逗号 1. async 和 await async 函数&#xff0c;使得异…