开源AGV调度系统OpenTCS中的路由器(router)详解

news2024/12/24 0:30:34

OpenTCS中的任务分派器router详解

  • 1. 引言
  • 2. 路由器(router)
    • 2.1 代价计算函数(Cost functions)
    • 2.2 2.1 Routing groups
    • 2.1 默认的停车位置选择
    • 2.2 可选停车位置属性
    • 2.3 默认的充电位置选择
    • 2.4 即时运输订单分配
  • 3. 默认任务分派器的配置项
  • 4. 参考资料与源码

1. 引言

openTCS是一项著名的开源运输控制系统,我在之前的文章中对该系统也做了初步介绍:

  • 开源AGV调度系统 OpenTCS 5.4 开发环境配置与编译运行
  • 开源AGV调度系统OpenTCS中的任务分派器(dispatcher)详解
    在这里插入图片描述

2. 路由器(router)

openTCS中默认的任务路由器(Default router)是openTCS内置的重要策略模块,当然也是允许用户自定义和替换的。
默认路由器会在行驶路线上找到从一点到另一点消耗成本最低的路线。通过使用Dijkstra算法的实现来实现。它考虑已经被锁定的路径,但不考虑其他车辆的位置或被假定的未来行为。因此它不会绕过速度较慢或停在路上的车辆。

2.1 代价计算函数(Cost functions)

可用于评估驾驶过程中路径的成本函数可以通过配置进行选择。以下成本函数/配置选项可用:
DISTANCE (default):路由成本等同于路径长度;
TRAVELTIME:路由成本的计算是以在路径上行驶的预期时间,即路径长度/车辆允许的最大速度;
EXPLICIT_PROPERTIES:路径上行驶车辆的路由成本通过以下两个带键的路径属性中获取 tcs:routingCostForward and tcs:routingCostReverse。
HOPS:模型中每条路径的路由成本为1,得到的路由代价最小路径/点被选中。

2.2 2.1 Routing groups

计算车辆的路径时,对工厂中的不同车辆以不同的方式处理是可以的,如果车辆有不同的特点并且实际上路径行驶有不同的最佳路线,那么这是可取的。
为了实现这一点,模型中的路径或所用的成本函数需要反映出来这种差异。默认情况下不会这样做,因为默认路由器为所有的车辆计算路径同样的方式,除非另有指示。
要让路由器知道它应该单独计算车辆的路由,可以将键tcs:routingGroup的属性设置为任意字符串。(具有相同值集的车辆共享相同的路由表,空字符串为所有车辆的默认值。)

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");
  }

  @Override
  public 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;
  }

  @Override
  public void terminate() {
    if (!isInitialized()) {
      return;
    }

    LOG.debug("Terminating...");

    periodicDispatchTaskFuture.cancel(false);
    periodicDispatchTaskFuture = null;

    eventSource.unsubscribe(implicitDispatchTrigger);
    implicitDispatchTrigger = null;

    fullDispatchTask.terminate();

    initialized = false;
  }

  @Override
  public boolean isInitialized() {
    return initialized;
  }

  @Override
  public void dispatch() {
    LOG.debug("Scheduling dispatch task...");
    // Schedule this to be executed by the kernel executor.
    kernelExecutor.submit(fullDispatchTask);
  }

  @Override
  public 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);
    });
  }

  @Override
  public 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);
    });
  }

  @Override
  public 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);
      });
    }
  }

  @Override
  public 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);
    });
  }

  @Override
  public 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.coloradmin.cn/o/1821169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测

区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测 目录 区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测效果一览基本介绍程序设计参考资…

Java——IO流(一)-(4/8):前置知识-字符集、UTF-8、GBK、ASCII、乱码问题、编码和解码等

目录 常见字符集介绍 标准ASCII字符集 GBK&#xff08;汉字内码扩展规范&#xff0c;国标&#xff09; Unicode字符集&#xff08;统一码&#xff0c;万国码&#xff09; 小结 字符集的编码、解码操作 方法 实例演示 常见字符集介绍 标准ASCII字符集 ASCll(American St…

python数据分析--- ch8-9 python函数及类

python数据分析--- ch8-9 python函数及类 1. Ch8--函数1.1 函数的定义1.2 形参与实参1.2.1 使用位置参数调用函数1.2.2 使用关键字参数调用函数 1.3 参数的默认值1.4 可变参数(*)1.4.1 基于元组的可变参数(* 可变参数)1.4.2 基于字典的可变参数(** 可变参数) 1.5 函数中变量的作…

【PHP开发工程师系统性教学】——thinkPHP的分页操作,不管有几页,用这个你想分几页就分几页

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【单片机毕业设计选题24005】-基于STM32的智能家居环境监测系统

系统功能: 此设计采用STM32单片机将采集到的环境环境温湿度,光照强度,火焰传感器状态,烟雾值,空气质量值等数据显示在OLED上&#xff0c;并将这些信息通过上报至手机APP。系统可通过手机蓝牙APP修改各传感器阈值. 蓝牙连接后&#xff0c;如果系统处于自动状态则每隔5秒钟上报…

多表联查小情景例子

这里有个需求&#xff1a; 需要给定套餐表setmeal 的 id 查询这个套餐内的所有菜品 dish 实际上如果可能&#xff0c;只需要查询套餐菜品表(setmeal_dish)&#xff0c;查看一个套餐内包含包含的所有菜品&#xff0c;然后把这些菜品全部取出即可。 看一下setmeal_dish 表&…

水泥行业超低排放简介

在当今社会&#xff0c;随着环保意识的不断提高&#xff0c;水泥行业作为重要的工业领域&#xff0c;其超低排放的实施范围及成效日益受到人们的关注。朗观视觉小编将从多个角度探讨水泥行业超低排放的实施范围&#xff0c;分析其背后的意义与影响&#xff0c;展望未来的发展趋…

LogicFlow 学习笔记—7. LogicFlow 基础 背景 Background

背景 Background 提供可以修改画布背景的方法&#xff0c;包括背景颜色或背景图片&#xff0c;背景层位于画布的最底层。 info 创建画布时&#xff0c;通过 background 选项来设置画布的背景层样式&#xff0c;支持透传任何样式属性到背景层。默认值为 false 表示没有背景。 …

Adaboost集成学习 | Matlab实现基于CNN-LSTM-Adaboost集成学习时间序列预测(股票价格预测)

目录 效果一览基本介绍模型设计程序设计参考资料 效果一览 基本介绍 Adaboost集成学习 | Matlab实现基于CNN-LSTM-Adaboost集成学习时间序列预测&#xff08;股票价格预测&#xff09; 模型设计 融合Adaboost的CNN-LSTM模型的时间序列预测&#xff0c;下面是一个基本的框架。 …

软件性能测试基本概述

大家好&#xff0c;在性能测试的世界里&#xff0c;确保软件系统的高效运行至关重要。性能测试不仅仅是为了评估软件系统的性能&#xff0c;更是为了保障用户体验、提高系统稳定性和可靠性。本文将带您一览性能测试的基本概述&#xff0c;从性能测试的定义、重要性&#xff0c;…

【踩坑】修复Ubuntu远程桌面忽然无法Ctrl C/V复制粘贴及黑屏

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 说在前面&#xff1a; 需要注意的是&#xff0c;我发现他应该是新开了一个窗口给我。我之前打开的东西&#xff0c;在这个新窗口里都没有了&#xff0c…

【2024最新精简版】Redis面试篇

文章目录 什么是红锁Redis有哪些框架&#xff1f;你们项目中哪里用到了Redis ?Redis的常用数据类型有哪些 ?Redis的数据持久化策略有哪些 ?Redis的数据过期策略有哪些 ?Redis的数据淘汰策略有哪些 ?你们使用Redis是单点还是集群 ? 哪种集群 ?Redis集群有哪些方案, 知道嘛…

DockerCompose+Jenkins+Pipeline流水线打包Vue项目(解压安装配置Node)入门

场景 DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门&#xff1a; DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门-CSDN博客 以上使用流水线配置和打包springboot后台项目&#xff0c;如果要使…

二手物品交易系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;商家管理&#xff0c;用户管理&#xff0c;商品管理&#xff0c;用户咨询管理 商家账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;商品管理&#xff0c;用…

MySQL 用户权限管理:授权、撤销、密码更新和用户删除(图文解析)

目录 前言1. 授予权限2. 撤销权限3. 查询权限4. Demo 前言 公司内部的数据库权限一般针对不同人员有不同的权限分配&#xff0c;而不都统一给一个root权限 1. 授予权限 授予用户权限的基本命令是GRANT 可以授予的权限种类很多&#xff0c;涵盖从数据库和表级别到列和存储过…

【抽代复习笔记】19-群(十三):奇偶置换、循环置换的几个定理及例题

定义&#xff1a; ①在Sn中&#xff0c;能够表示为奇数多个对换乘积的置换称为“奇置换”&#xff0c;能够表示为偶数多个对换乘积的置换称为“偶置换”&#xff1b; ②所有偶置换的集合记为An。 例1&#xff1a;&#xff08;1&#xff09;计算S1和S2中奇、偶置换的数目&…

HTML初体验

可参考jd.com官网&#xff0c;ctrlu查看当前页面源代码 找到你的项目&#xff0c;在项目中创建html类型的网页文件 标准的HTML正确书写格式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title&…

UNIAPP-ADB无线调试

ADB下载 SDK 平台工具版本说明 | Android Studio | Android Developers (google.cn) 环境变量配置 ADB版本查看 adb version 手机使用数据线连接到电脑 手机需要授权adb调试(开发人员选项里面) CMD输入命令 adb tcpip 5555 到了这一步你手机已经启动了adb服务了&…

Linux DNS域名解析

DNS系统的作用及类型 整个 Internet 大家庭中连接了数以亿计的服务器、个人主机&#xff0c;其中大部分的网站、邮件等服务器都使用了域名形式的地址&#xff0c;如www.google.com、mail.163.com 等。很显然这种地址形式要比使用 64.233.189.147、202.108.33.74的IP地址形式更…

蚂蚁分类信息系统二开仿么么街货源客模板微商货源网源码(带手机版)

源码介绍 网站采用蚂蚁分类信息系统二次开发&#xff0c;模板仿么么街货源客模板&#xff0c;微商货源网定制版。 模板设计风格简洁&#xff0c;分类信息采用列表形式发布&#xff0c;这种设计方式非常符合度娘 SEO 规则。收录效果是杠杠的。 这个网站风格目前是用来做货源推…