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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot3 整合 Mybatis 完整版

本文记录一下完整的 SpringBoot3 整合 Mybatis 的步骤。 只要按照本步骤来操作&#xff0c;整合完成后就可以正常使用。1. 添加数据库驱动依赖 以 MySQL 为例。 当不指定 依赖版本的时候&#xff0c;会 由 springboot 自动管理。 <dependency><groupId>com.mysql&l…

C++ 33 之 const 修饰静态成员

#include <iostream> #include <string.h> using namespace std;// 定义静态const数据成员时&#xff0c;最好在类内部初始化,避免在类外重复初始化&#xff0c;也为了代码的可读性和可维护性class Students03{ public:// 两种写法都可以const static int s_a 10;…

期末测试2(1)---PTA

一开始写错了&#xff0c; 因为这个再定义一个和原函数一样类型的进行存储&#xff0c; 然后将第一个设置为最大的&#xff0c;依次用循环比较后面的&#xff0c; 最后输出 但是这个适用于找最大的、字符串这样最后只输出一个最大项比较好 对于结构体不好将比较的这个数所…

Java9 后String 为什么使用byte[]而不是char?

之前认知里面&#xff0c;java的String一直是使用char数组&#xff0c;但是今天点进去瞟了一眼&#xff0c;发现不对。 源码如下&#xff1a; /*** The value is used for character storage.** implNote This field is trusted by the VM, and is a subject to* constant fold…

boot项目配置邮箱发送

最近项目准备进入测试阶段&#xff0c;时间相对充沛些&#xff0c;便对邮箱的信息发送记录下&#xff01; 邮箱设置-开启smtp协议及获取授权码 以QQ邮箱为例&#xff0c;其他邮箱大同小异&#xff01; 开启协议 获取授权码 具体代码 基于javax.mail实现 原文可看 前辈帖子…

vscode 终端无法正常执行脚本命令如何解决

我们经常需要在vscode的中安装第三方依赖包&#xff0c;npm是前端目前最大的Node.js模块化管理系统&#xff0c;它能帮助开发者管理和发布Node.js模块。但很多时候我们在vscode的终端中执行npm install命令时经常会报以下错误&#xff1a; 但是在Windows的cmd命令提示符中执行n…

观测云产品更新 | BPF 网络日志、智能监控、告警策略等

观测云更新 网络 BPF 网络日志&#xff1a;优化 BPF 网络功能&#xff0c;增强 L4/L7 网络联动。 APM/RUM APM/RUM&#xff1a;新增 【Issue 自动发现】功能。启用该配置后&#xff0c;观测云会将符合配置项规则的错误数据记录自动创建 Issue。 监控 1、智能监控&#xff1…

【CT】LeetCode手撕—102. 二叉树的层序遍历

目录 题目1-思路2- 实现⭐102. 二叉树的层序遍历——题解思路 3- ACM实现3-1 二叉树构造3-2 整体实现 题目 原题连接&#xff1a;102. 二叉树的层序遍历 1-思路 1.借助队列 Queue &#xff0c;每次利用 ①while 循环遍历当前层结点&#xff0c;②将当前层结点的下层结点放入 …

GitCode热门开源项目推荐:Spider网络爬虫框架

在数字化高速发展时代&#xff0c;数据已成为企业决策和个人研究的重要资源。网络爬虫作为一种强大的数据采集工具受到了广泛的关注和应用。在GitCode这一优秀的开源平台上&#xff0c;Spider网络爬虫框架凭借其简洁、高效和易用性&#xff0c;成为了众多开发者的首选。 一、系…

反向海淘建站技术:开启跨境电商新篇章

反向海淘&#xff0c;作为跨境电商的一种创新模式&#xff0c;正逐渐改变着传统贸易的格局。在这个模式下&#xff0c;国内消费者能够直接购买到国外的商品&#xff0c;而国内的商家也能将产品销往海外市场。为了抓住这一机遇&#xff0c;建立一套高效、稳定的反向海淘网站至关…

线代老师大PK,这四位胜出!

说实话&#xff0c;线代真的别乱跟老师 因为每个老师讲课适用的人群不一样&#xff0c;比如都说李永乐老师线代讲的好&#xff0c;但是我去听完发现&#xff0c;李永乐老师的线代讲的虽然好&#xff0c;但是对于零基础或者基础不好的考生来说&#xff0c;真的有点不友好&#…

AI绘画SD3已来,本地首发实测体验,含本地部署说明(内附网盘模型及ComfyUI工作流下载)

大家好&#xff0c;我是画画的小强 SD3已来&#xff0c;Stability AI 此前宣布SD3将于6月12开源20 亿参数的SD3 模型SD3 Medium&#xff0c;昨天它已如期而至了。 根据官方内容所了解&#xff0c;SD3 Medium 可以说是目前很先进的文本到图像开放模型&#xff0c;包含 20 亿个…

C++ 34 之 单例模式

#include <iostream> #include <string.h> using namespace std;class King{// 公共的函数&#xff0c;为了让外部可以获取唯一的实例 public:// getInstance 获取单例 约定俗成static King* getInstance(){return true_king;}private: // 私有化// 构造函数设置为…

线性代数|机器学习-P12Ax=b条件下x最小值问题

文章目录 1. Axb下的最值问题-图形转换2. Gram-Schmidt 标准形3. 迭代法-Krylov子空间法 1. Axb下的最值问题-图形转换 假设我们有一个直线方程如下&#xff1a; 3 x 1 4 x 2 1 \begin{equation} 3x_14x_21 \end{equation} 3x1​4x2​1​​ 在二维平面上&#xff0c;各个范…

微信小程序投票系统(包含微信小程序端)

&#x1f4f1;微信投票小程序&#xff1a;轻松发起&#xff0c;快速统计 一、引言 在数字化时代&#xff0c;微信作为我们日常生活中不可或缺的社交工具&#xff0c;不仅为我们提供了沟通交流的平台&#xff0c;还衍生出了许多实用的小程序。其中&#xff0c;微信投票小程序凭…

C# WPF入门学习主线篇(三十三)—— 使用ICommand实现命令绑定

C# WPF入门学习主线篇&#xff08;三十三&#xff09;—— 使用ICommand实现命令绑定 在MVVM模式中&#xff0c;命令绑定是将用户交互&#xff08;如按钮点击&#xff09;与ViewModel中的方法连接起来的一种机制。使用ICommand接口可以实现这一功能&#xff0c;从而将UI逻辑与业…

快速掌握 Python requests 库发送 JSON 数据的 POST 请求技巧

在现代 Web 开发中&#xff0c;客户端与服务器之间进行数据交换的需求越来越普遍。而在 Python 这个强大的编程语言中&#xff0c;requests 库是一个广泛使用且功能强大的 HTTP 请求库。特别是在进行 API 调用时&#xff0c;发送 POST 请求并附带 JSON 数据是一个非常常见的需求…

跟卖五种常用采集方式,关键词采集升级,更加让新手上手更快!

今天给大家分享一个跟卖选品软件&#xff0c;相信很多卖家都在为选品而苦恼&#xff0c;人工筛选一天也筛选不出几个能用的链接&#xff0c;不仅耗费时间精力&#xff0c;还提升不了选品效率&#xff0c;今天就分享一款实用的选品工具&#xff0c;它能够帮助我们节省选品时间&a…

C++ 35 之 对象模型基础

#include <iostream> #include <string.h> using namespace std;class Students05{ public:// 只有非静态成员变量才算存储空间&#xff0c;其他都不算int s_a; // 非静态成员变量&#xff0c;算对象的存储空间double s_c;// 成员函数 不算对象的存储空间void f…

uniapp 仿写弹窗

页面 <template><view click"close" class"mask"><view click.stop"onClick" class"content"><text class"text">点击蒙层关闭</text></view></view> </template><scr…