利用openTCS实现车辆调度系统(三)车辆适配器解读,封装自己的适配器

news2024/10/6 4:06:05

适配器的官方解释:openTCS 支持自定义车辆驱动程序的集成,这些驱动程序实现特定于车辆的通信协议,从而在内核和车辆之间进行调解。 由于其功能,车辆驾驶员也称为通信适配器。 openTCS适配器。欢迎随时沟通

1、源码下载

github下载:openTCS源码
在这里插入图片描述

2、源码运行

源码在Idea中打开,依次运行kernel,editor,desk,controller模块,依次双击运行。
在这里插入图片描述
运行后的页面和使用方法和上一篇说的完全一致,可以参考利用openTCS实现车辆调度系统(二)openTCS下载部署

3、车辆适配器

在这里插入图片描述
车辆适配器是我们通过tcs控制车辆的关键组成,适配器为我们提供了一组很有用的方法,我们只要实现这些方法,就可以实现自己的设备控制。具体可以参考官方API车辆适配器接口文档
在这里插入图片描述
我们说几个最主要的方法,实现了这几个方法就可以让我们的车动起来。
1、enable/disable:控制车辆开启和关闭,一般开启时,我们会通过网络协议建立适配器与车辆的连接,更新连接状态。关闭时断开连接。
2、execute:执行指令,这里的指令指的是单步的调试指令,比如车辆前进、后退、顶升、充电等指令。
3、sendCommand:发送指令,这里的指令指的是订单指令,这里的指令是连续的,有前后关联的。比如我们的订单是让车辆到达地图中的某个点送货,openTCS的内核会把一整条规划路径拆分成每一步,分别发给适配器。比如下图,小车在Point-0001时,openTCS会通过sendCommand把Point-0003、Point-0004…这些点依次发给适配器。适配器将这些指令发给车辆,高速车辆去往物理中的Point-0003点。
在这里插入图片描述
默认适配器中,这一步是模拟执行的,适配器并没有给任何真实物理设备发信号,只是在一段时间后默认执行事件完成了。将当前步骤完成,更新地图中车辆的位置和状态等。代码如下:

  @Override
  public synchronized void sendCommand(MovementCommand cmd) {
    requireNonNull(cmd, "cmd");
    LOG.info("==CommandQueue:{}", getCommandQueue());
    // Start the simulation task is the single step modus is not active.
    if (!getProcessModel().isSingleStepModeEnabled()) {
      isSimulationRunning = true;
      ((ExecutorService) getExecutor()).submit(() -> startVehicleSimulation(cmd));
    }
  }
  
    private void startVehicleSimulation(MovementCommand command) {
    LOG.debug("Starting vehicle simulation for command: {}", command);
    Step step = command.getStep();
    getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
    operationSimulationTimePassed = 0;

    if (step.getPath() == null) {
      LOG.debug("Starting operation simulation...");
      ((ScheduledExecutorService) getExecutor()).schedule(() -> operationSimulation(command),
                                                          SIMULATION_TASKS_DELAY,
                                                          TimeUnit.MILLISECONDS);
    }
    else {
      getProcessModel().getVelocityController().addWayEntry(
          new WayEntry(step.getPath().getLength(),
                       maxVelocity(step),
                       step.getDestinationPoint().getName(),
                       step.getVehicleOrientation())
      );

      LOG.debug("Starting movement simulation...");
      ((ScheduledExecutorService) getExecutor()).schedule(() -> movementSimulation(command),
                                                          SIMULATION_TASKS_DELAY,
                                                          TimeUnit.MILLISECONDS);
    }
  }
private void movementSimulation(MovementCommand command) {
    if (!getProcessModel().getVelocityController().hasWayEntries()) {
      return;
    }

    WayEntry prevWayEntry = getProcessModel().getVelocityController().getCurrentWayEntry();
    getProcessModel().getVelocityController().advanceTime(getSimulationTimeStep());
    WayEntry currentWayEntry = getProcessModel().getVelocityController().getCurrentWayEntry();
    //if we are still on the same way entry then reschedule to do it again
    if (prevWayEntry == currentWayEntry) {
      ((ScheduledExecutorService) getExecutor()).schedule(() -> movementSimulation(command),
                                                          SIMULATION_TASKS_DELAY,
                                                          TimeUnit.MILLISECONDS);
    }
    else {
      //if the way enties are different then we have finished this step
      //and we can move on.
      getProcessModel().setVehiclePosition(prevWayEntry.getDestPointName());
      LOG.debug("Movement simulation finished.");
      if (!command.isWithoutOperation()) {
        LOG.debug("Starting operation simulation...");
        ((ScheduledExecutorService) getExecutor()).schedule(() -> operationSimulation(command),
                                                            SIMULATION_TASKS_DELAY,
                                                            TimeUnit.MILLISECONDS);
      }
      else {
        finishVehicleSimulation(command);
      }
    }
  }

  private void operationSimulation(MovementCommand command) {
    operationSimulationTimePassed += getSimulationTimeStep();

    if (operationSimulationTimePassed < getProcessModel().getOperatingTime()) {
      getProcessModel().getVelocityController().advanceTime(getSimulationTimeStep());
      ((ScheduledExecutorService) getExecutor()).schedule(() -> operationSimulation(command),
                                                          SIMULATION_TASKS_DELAY,
                                                          TimeUnit.MILLISECONDS);
    }
    else {
      LOG.debug("Operation simulation finished.");
      String operation = command.getOperation();
      if (operation.equals(getProcessModel().getLoadOperation())) {
        // Update load handling devices as defined by this operation
        getProcessModel().setVehicleLoadHandlingDevices(
            Arrays.asList(new LoadHandlingDevice(LHD_NAME, true))
        );
      }
      else if (operation.equals(getProcessModel().getUnloadOperation())) {
        getProcessModel().setVehicleLoadHandlingDevices(
            Arrays.asList(new LoadHandlingDevice(LHD_NAME, false))
        );
      }
      finishVehicleSimulation(command);
    }
  }

  private void finishVehicleSimulation(MovementCommand command) {
    //Set the vehicle state to idle
    if (getSentQueue().size() <= 1 && getCommandQueue().isEmpty()) {
      getProcessModel().setVehicleState(Vehicle.State.IDLE);
    }
    if (Objects.equals(getSentQueue().peek(), command)) {
      // Let the comm adapter know we have finished this command.
      getProcessModel().commandExecuted(getSentQueue().poll());
    }
    else {
      LOG.warn("{}: Simulated command not oldest in sent queue: {} != {}",
               getName(),
               command,
               getSentQueue().peek());
    }
    isSimulationRunning = false;
  }

其中getProcessModel().commandExecuted(getSentQueue().poll());是告诉openTCS内核,该指令执行完成。与之对应的有getProcessModel().commandFailed()告诉内核,当前指令执行出错。在实际应用开发中只需要把自己的发送报文业务和接收报文加上即可。

上一篇:利用openTCS实现车辆调度系统(二)openTCS下载部署
下一篇:利用openTCS实现车辆调度系统(四)利用已有RMI接口做二次开发

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

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

相关文章

arcgis宗地或者地块四至权利人信息提取教程

ARCGIS怎样将图斑四邻的名称及方位加入其属性表 以前曾发表过一篇《 如何把相邻图斑的属性添加在某个字段中》的个人心得,有些会员提出了进一步的要求,不但要相邻图斑的名称,还要求有方位,下面讲一下自己的做法。 基本思路是:连接相邻图斑质心,根据连线的角度确定相邻图斑…

动态规划(二)

一、线性DP 1.1数字三角形 #include<iostream> #include<algorithm>using namespace std;const int N 510,INF 1e9;int n; int a[N][N]; int f[N][N];int main() {scanf("%d",&n);for(int i 1;i < n;i ){for(int j 1;j < i; j )scanf(&qu…

【2.3】Java微服务:sentinel服务哨兵

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; Java微服务 ✨特色专栏&#xff1a; 知识分享 &am…

Spring 事务失效的八种场景

1. 抛出检查异常导致事务不能正确回滚 Service public class Service1 {Autowiredprivate AccountMapper accountMapper;Transactionalpublic void transfer(int from, int to, int amount) throws FileNotFoundException {int fromBalance accountMapper.findBalanceBy(from…

Butterfly 安装文档(一) 快速开始

安装 在你的Hexo根目录里面 git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly 应用主题 修改 Hexo 根目录下的 _config.yml&#xff0c;把主题改为 butterfly theme: butterfly 安装插件 如果你没有 pug 以及 stylus 的渲染…

字符串查找匹配算法

概述 字符串匹配&#xff08;查找&#xff09;是字符串的一种基本操作&#xff1a;给定带匹配查询的文本串S和目标子串T&#xff0c;T也叫做模式串。在文本S中找到一个和模式T相符的子字符串&#xff0c;并返回该子字符串在文本中的位置。 暴力匹配 Brute Force Algorithm&a…

20天突破英语四级高频词汇——第②天

2&#xfeff;0天突破英语四级高频词汇~第2天加油(ง •_•)ง&#x1f4aa; &#x1f433;博主&#xff1a;命运之光 &#x1f308;专栏&#xff1a;英语四级高频词汇速记 &#x1f30c;博主的其他文章&#xff1a;点击进入博主的主页 目录 2&#xfeff;0天突破英语四级高…

LouvainMethod分布式运行的升级之路

1、背景介绍 Louvain是大规模图谱的谱聚类算法&#xff0c;引入模块度的概念分二阶段进行聚类&#xff0c;直到收敛为止。分布式的代码可以在如下网址进行下载。 GitHub - Sotera/spark-distributed-louvain-modularity: Spark / graphX implementation of the distri…

SQL server 与 MySQL count函数、以及sum、avg 是否包含 为null的值

sql server 与 mysql count 作用一样。 count 计算指定字段出现的个数&#xff0c; 不是计算 null的值 获取表的条数 count(n) n:常数 count(1),count&#xff08;0&#xff09;等 count(*) count(字段) 其中字段为null 不会统计在内。 avg(字段)、sum(字段) 跟count(字段)…

数字孪生技术的实用价值体现在哪?

随着科技的不断进步&#xff0c;数字孪生技术已成为引领未来发展的重要驱动力。数字孪生是将现实世界与数字世界紧密结合的技术&#xff0c;通过创建虚拟的物理模型&#xff0c;实时模拟和分析真实世界中的物体和过程&#xff0c;让数字孪生在各个领域都展现出了巨大的潜力&…

通用Mapper的四个常见注解

四个常见注解 1、Table 作用&#xff1a;建立实体类和数据库表之间的对应关系。 默认规则&#xff1a;实体类类名首字母小写作为表名&#xff0c;如 Employee -> employee 表 用法&#xff1a;在 Table 注解的 name 属性中指定目标数据库的表名&#xff1b; 案例&#…

vscode extension 怎么区分dev prod

开发模式注入环境变量 使用vsode 提供的api

【返回时间字段问题--消息转换器】

文章目录 前言一、第一种方式一、第二种方式&#xff08;推荐 ) 前言 一、第一种方式 1). 方式一 在属性上加上注解&#xff0c;对日期进行格式化 但这种方式&#xff0c;需要在每个时间属性上都要加上该注解&#xff0c;使用较麻烦&#xff0c;不能全局处理。 一、第二种方…

【数理知识】旋转矩阵的推导过程,基于向量的旋转来实现,同时解决欧式变换的非线性局限

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】协…

WGS_1984_UTM、WGS_1984_Mercator坐标转化为经纬度坐标python

1、遥感影像的PROJECTION有哪些 遥感影像常见的投影类型有很多&#xff0c;具体选择哪种投影方式取决于数据的特性和使用需求。以下列举了一些常见的遥感影像投影类型&#xff1a; UTM (Universal Transverse Mercator) 投影&#xff1a;最常见的投影类型之一&#xff0c;将地…

[原创]从强化学习的本质推导到PPO

前言 这篇博客很久之前就想做了&#xff0c;一直在拖是因为觉得自己对知识点理解还没有足够的透彻。但是每当去复盘基本概念的时候又很难理清逻辑&#xff0c;所以觉得即便现在半吊子水平&#xff0c;但是也想通过博客记录一下自己肤浅的学习心得&#xff0c;权当是为自己巩固…

ParallelCollectionRDD [0] isEmpty at KyuubiSparkUtil.scala:48问题解决

ParallelCollectionRDD [0] isEmpty at KyuubiSparkUtil.scala:48问题解决 这个问题出现在使用Kyubi Spark Util处理ParallelCollectionRDD的过程中&#xff0c;具体是在KyubiSparkUtil.scala文件的第48行调用isEmpty方法时出现的。该问题可能是由以下几个原因引起的&#xff1…

C语言文件操作笔记

目录 1.文件 1.1 文件名 1.2 文件类型 1.3 文件缓冲区 1.4 文件指针 1.5 文件的打开和关闭 1.6 文件的顺序读写 1.6.1 fputc():向指定的文件中写入一个字符 1.6.2 fgetc():从指定的文件中读取一个字符 1.6.3 fgets():从指定的流 stream 读取一行 1.6.4 puts():向标准…

华为发布数字资产继承功能

在华为开发者大会2023&#xff08;HDC.Together&#xff09;上&#xff0c;华为常务董事、终端BG CEO、智能汽车解决方案BU CEO余承东正式发布了数字资产继承功能&#xff0c;HarmonyOS提供了安全便捷的数字资产继承路径。 在鸿蒙世界中&#xff0c;我们每个人在每台设备、应用…

开箱报告,Simulink Toolbox库模块使用指南(二)——MATLAB Fuction模块

文章目录 前言 MATLAB Fuction模块 采样点设置 FFT 求解 分析和应用 总结 前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;一&#xff09;——powergui模块》 MATLAB Fuction模块 MATLAB Fuction模块是在Simulink建模仿真或生成代码时&#x…