VDA5050协议介绍 和 详细翻译

VDA5050协议介绍

1 介绍

1.1 官网介绍

在这里插入图片描述
该接口是由德国汽车工业协会和德国机械与物流研究所(KIT IFL)在卡尔斯鲁厄理工学院(Karlsruhe Institute of Technology)的支持下合作建立的,作为主控制系统和自动引导车辆系统之间通信的通用接口。

你可以在这里免费下载当前版本。建议的更改可以发布到GitHub存储库http:/github.com/vda5050/vda5050。它们将由VDA和VDMA进行审查,如果做出积极的决定,将被纳入新版本。不再推荐旧版本的VDA 5050或进一步开发。你可以在这里下载。

在这里插入图片描述
第三次,AGV Mesh-Up于2023年3月29日和30日在多特蒙德进行了VDA 5050通信接口的现场测试,作为test CAMP INTRALOGISTICS的一部分。VDA 5050确保了自动引导车辆和移动机器人的互操作性。在这种情况下,车辆可以通过接口在一个主控制系统下一起操作,而不考虑其设计和制造商。

有了这种AGV网格,公司就能够在观众面前测试他们的车辆和控制系统的接口适用性。首次使用了KINEXON和SIEMENS提供的两种控制系统。在活动的两天里,现场的车辆都是用两种控制系统中的一种移动的。总共有9个设备在AGV Mesh-Up区域移动。

1.2 VDA 5050 的目标(混合调度、集群调度)

一旦客户需要采用两个或更多不同供应商的 AGV就会带来严峻挑战,其中包括:

  • 调试复杂 — 每个品牌的AGV都需要单独安装。
  • 相互操作性问题 — 如果 AGV 需要交叉路径或共享电梯,管理它们会变得更困难。
  • 丢失空间 — 独立的 AGV 品牌可能需要使用完全独立的路径。

VDA 5050 的目标是让每个合规的自动导航车 (AGV) 通过一个车队管理软件(左)协同工作。
在这里插入图片描述

1.3 依赖 MQTT 通信协议和 Json 数据交换协议

VDA5050以MQTT为标准协议,使用JSON数据结构,明确界定了操作员、调度系统和AGV/AMR各自的作用和功能。

1.4 边界在哪?

单体智能/群体智能 要有边界,目前 V2.0.0 版本的 VDA5050 协议关于 slam 车没看到清晰的定义。
传统kiva类型车完全受控,这个在行业内达成统一。slam车的分为两派,一派是kiva思路下开发的slam车厂商,一派是纯自由导航的slam厂商。前者车完全受控,RCS规划路径;后者车有更高自主权,RCS规划自由导航路线。后者更像是将在外君命有所不受。

1.5 VDA5050 兼容绕障?

vda5050 兼容 绕障功能 ?还没研究明白,貌似支持,具体看RCS设计。

1.6 二维码车与slam车对比

二维码车特色:

  • 地码,高精度代价低
  • 纯执行机构

slam车特色:

  • 能自主定位
  • 基于绕障做调度,车只是障碍物,不容易锁环。

2 协议介绍

术语

  • Verband der Automobilindustrie (VDA) 德国汽车工业协会
  • Driverless transport systems (DTS) 无人驾驶交通系统
  • master control 主站(RCS)
  • NURBS: Non-uniform rational basis spline 非均匀有理B样条

4 协议需求和定义

通信接口的设计满足以下要求:

  • 控制最少1000辆车
  • 实现不同自主程度车辆的集成
  • 启用决策,例如,关于路线的选择或十字路口的行为

车辆应定期或在状态发生变化时进行状态转换。

考虑到连接失败和信息丢失的影响,通信是通过无线网络完成的。

消息日志是消息队列遥测传输(MQTT),它将与JSON结构一起使用。MQTT 3.1.1在该协议的开发过程中进行了测试,是兼容性所需的最低版本。MQTT允许将消息分发到子通道,这些子通道称为“主题”。MQTT网络中的参与者订阅这些主题并接收与他们有关或感兴趣的信息。

JSON结构允许使用附加参数对协议进行未来扩展。参数用英语描述,以确保协议可读、可理解,并适用于德语地区以外的地区。

5 交互过程和内容

在这里插入图片描述

实施阶段:

  • 路线定义:可以使⽤CAD导⼊,路线可以是单向,可以设置速度约束,车型号等信息;
  • 路线网络配置:路线内定义装卸站、充电站、周边环境(闸⻔、电梯、道闸)、候车位、缓冲站等。
  • 车辆配置:AGV 的物理属性(尺⼨、可⽤的负载载体安装座等)由操作员存储。

AGV 的最终命令通过 MQTT 消息代理传输到车辆。然后,在执行作业的同时,不断向主控制器报告其状态。

主控的功能有:

  • 将命令分配给 AGV
  • AGV的路线计算和引导(考虑到每个AGV个体物理特性的限制,例如尺寸、可操纵性等)
  • 阻塞(“死锁”)的检测和解决
  • 能源管理:充电指令可以中断转移指令
  • 交通管制:缓冲路线和等候位置
  • (临时)环境变化,例如释放某些区域或更改最大速度
  • 门、大门、电梯等外围系统的通信。
  • 通信错误的检测和解决

AGV的功能有:

  • 本地化
  • 沿相关路线导航(引导或自主)
  • 车辆状态持续传输

此外,集成商在配置整个系统时必须考虑以下因素(不完整列表):

  • 地图配置:主控和AGV 的坐标系必须匹配。
  • 枢轴点:使用AGV 的不同点或充电点作为枢轴点会导致车辆的不同包络线。 参考点可以根据情况而变化,例如,对于承载负载的AGV和不承载负载的AGV来说,参考点可能不同。

集成商在配置整个系统时必须考虑以下因素:

  • 地图配置:主控和AGV的坐标系必须进⾏匹配。
  • 枢轴点:使⽤ AGV 的不同点或充电点作为枢轴点会导致⻋辆的不同包络线。参考点可以根据情况⽽变化,例如对于承载负载的AGV和不承载负载的AGV来说可以是不同的。

6 协议规范

6.1 表格符号及格式含义

识别描述
标准变量是一种基本数据类型
加粗变量是非基本数据类型(JSON对象或数组)并单独定义
斜体变量可选
[方括号]包含数据类型的数组
6.1.1 可选字段

如果一个变量被标记为可选,则意味着它对于发送者来说是可选的,因为该变量在某些情况下可能不适用(例如,当主控制器向AGV发送命令时,某些AGV自己规划其轨迹,并且可以省略该命令的边缘对象内的场轨迹)。

如果AGV接收到包含该协议中标记为可选字段的消息,则AGV将相应地采取行动,而不能忽略该字段。如果AGV不能相应地处理消息,那么预期的行为是在错误消息中进行通信并拒绝命令。

主控只发送AGV支持的可选信息。
示例:轨迹是可选的。如果AGV不能处理轨迹,主控不应向AGV发送轨迹。
AGV必须通过AGV信息表消息来传递它需要的可选参数。

6.1.2 允许的字符和字段长度

所有通信均以 UTF-8 编码,以实现描述的国际适应。建议 ID 应仅使⽤以下字符:

A-Z a-z 0-9 _ - . :

最⼤消息⻓度未定义。如果AGV内存不⾜以处理收到的命令,则会拒绝该命令。最⼤字段⻓度、字符串⻓度或值范围的匹配由
积分器决定。为了便于集成,AGV 供应商必须提供 AGV 资料表。

6.1.3 枚举的表示法

枚举必须以大写形式书写。这包括诸如操作状态(WAITING, FINISHED, etc…)或“方向”字段的值(LEFT, RIGHT, 443MHZ, etc…)之类的关键字。

6.1.4 JSON 数据类型

如果可能,必须使用JSON数据类型。因此,布尔值由“true / false”编码,而不是枚举 (TRUE, FALSE)或幻数。

6.2 MQTT 连接处理、安全性和 QoS

MQTT协议提供了为客户机设置最后将消息的选项。如果客户端因任何原因意外断开连接,则最后的遗嘱将由代理分发给其他订阅的客户端。此功能的使用在章节6.14主题“连接”中进行了描述。

如果AGV与代理断开连接,它将保留所有命令信息并履行命令,直到最后一个释放的节点。

代理配置需要考虑协议安全性。

为了减少通信开销,MQTT QoS级别0 (Best Effort)将用于主题顺序、状态、概况表和可视化。主题连接应使用QoS级别1(至少一次)。

6.3 MQTT 主题级别

由于云提供商的强制性主题结构,MQTT-Topic结构没有严格定义。对于基于云的MQTT-Broker,必须单独调整主题结构以匹配此协议中定义的主题。这意味着在以下部分中定义的主题名称是强制性的。
对于本地代理,MQTT主题级别建议如下:
interfaceName/majorVersion/manufacturer/serialNumber/topic
Example: uagv/v2/KIT/0001/order

MQTT Topic LevelData typeDescription
interfaceNamestringName of the used interface
majorVersionstringMajor version number, preceded by “v”
manufacturerstringManufacturer of the AGV (e.g., RobotCompany)
serialNumberstringUnique AGV Serial Number consisting of the following characters:
A-Z
a-z
0-9
_
.
:
-
topicstringTopic (e.g. Order or System State) see Cap. 6.5

注意:由于/字符用于定义主题层次结构,因此不能在上述任何字段中使用它。$字符也在一些MQTT代理中用于特殊的内部主题,因此也不应该使用它。

6.4 协议头

每个JSON都以协议头开始。在接下来的章节中,为了可读性,以下字段将被引用为协议头。协议头由以下单独的元素组成。
头文件不是JSON对象。

Object structure/IdentifierData typeDescription
headerIduint32header ID of the message. The headerId is defined per topic and incremented by 1 with each sent (but not necessarily received) message.
timestampstringTimestamp (ISO 8601, UTC); YYYY-MMDDTHH:mm:ss.ssZ (e.g.“2017-04-15T11:40:03.12Z”)
versionstringVersion of the protocol [Major].[Minor].[Patch] (e.g. 1.3.2)
manufacturerstringManufacturer of the AGV
serialNumberstringSerial number of the AGV

协议版本
协议版本使用语义版本控制作为版本控制模式。

主要版本变更示例:

  • 破坏性更改,例如,新的非可选字段

小版本变化的例子:

  • 新功能,如额外的可视化主题

补丁版本示例:

  • 更高的电池充电精度

6.5 通信子主题

AGV协议使⽤以下主题进⾏主控与AGV之间的信息交换

Subtopic namePublished bySubscribed byUsed forImplementationSchema
ordermaster controlAGVCommunication of driving orders from master control to the AGVmandatoryorder.schema
instantActionsmaster controlAGVCommunication of the actions that are to be executed immediatelymandatoryinstantActions.schema
stateAGVmaster controlCommunication of the AGV statemandatorystate.schema
visualizationAGVvisualization systemsHigher frequency of position topic for visualization purposes onlyoptionalvisualization.schema
connectionBroker/AGVmaster controlIndicates when AGV connection is lost, not to be used by master control for checking the vehicle health, added for an MQTT protocol level check of connectionmandatory connection.schema
factsheetAGVmaster controlSetup of AGV in master controlmandatoryfactsheet.schema

6.6 主题:“命令”(从主控到AGV)order

主题“order”是MQTT主题,AGV通过该主题接收JSON封装的命令。

6.6.1 概念与逻辑

命令的基本结构是由节点和边组成的图。AGV需要遍历节点和边缘来完成命令。所有连接节点和边的完整图由主控控制。

主控件中的图形表示包含限制,例如,允许哪个AGV遍历哪个边。这些限制不会传达给AGV。主控制只包括AGV顺序中允许相关AGV遍历的边。

要避免主控制器对每种类型的AGV都有单独的图形表示。在可能的情况下,一个位置,例如在防火门前的等待位置,所有类型的AGV应该只有一个节点。然而,由于AGV的尺寸和规格不同,在某些情况下可能需要偏离此标准。

在这里插入图片描述

节点和边作为两个列表在命令消息中传递。列表的顺序还控制遍历节点和边的顺序。

对于有效的命令,必须至少存在一个节点。可接受边的数量是节点数减1,而不是多或少。

命令的第一个节点必须是AGV可以轻松到达的。这意味着AGV已经站在节点上,或者AGV在节点偏差范围内。

节点和边都有一个布尔属性“释放”。如果一个节点或边缘被释放,AGV预计会遍历它。如果一个节点或边缘没有被释放,AGV不能遍历它。

只有在边的起始节点和结束节点都被释放的情况下,一条边才能被释放。

在一条未释放的边之后,序列中不能有任何被释放的节点或边。

释放的节点和边的集合称为“base”基。未释放的节点和边的集合称为“horizon”地平线。

发送没有 horizon 的命令是有效的。

命令消息不一定描述完整的传输顺序。为了进行交通控制并容纳资源受限的车辆,可以将完整的传输顺序(可能由许多节点和边组成)拆分为许多子顺序,这些子顺序通过orderId和orderUpdateId进行连接。下一节将描述更新命令的过程。

6.6.2 命令和命令更新

对于流量控制,order-topic只包含到决策点的路径。在到达决策点之前,主控件将发送带有附加路径段的更新路径。为了向AGV传达到达决策点后最有可能要做的事情,命令由两个独立的部分组成:

  • 驱动到决策点“base”:“base”是AGV行驶的定义路线。“base”路线的所有节点和边缘已经由车辆的控制面板批准。
  • 从决策点“horizon”开始的估计行程:如果没有交通堵塞,“horizon”是AGV可能行驶的路线。“horizon”航线还没有得到控制面板的批准。AGV最初只会行驶到“base”路线的最后一个路口。

由于MQTT是一种异步协议,并且通过无线网络传输是不可靠的,因此必须注意,不能更改"base”。因此,主控制可以假设“base”由AGV执行。后面的部分描述了取消命令的过程,但由于上面提到的通信限制,这也被认为是不可靠的。

主控制器有可能改变"Horizon"路线的驾驶命令。在AGV通过“base”路由到达决策点之前,主控制将向AGV发送一条更新的路由,其中包括其他节点。更改Horizon路由的过程如图4所示。
在这里插入图片描述

在图4中,控制面板在时间t = 1时首先发送初始作业。图5显示了一个可能命令的伪代码。为了可读性,这里省略了一个完整的JSON示例。

图5
{
	orderId: "1234"
	orderUpdateId:0,
	nodes: [
		6 {released: True},
		4 {released: True},
		7 {released: True},
		2 {released: False},
		8 {released: False}
	],
	edges: [
		e1 {released: True},
		e3 {released: True},
		e8 {released: False},
		e9 {released: False}
	]
}

在时间 t = 3 时,通过发送命令的扩展来更新命令(参见图6中的示例)。注意,“orderUpdateId”是递增的,并且作业更新的第一个节点对应于前一个命令消息的最后一个共享基本节点。

这确保了AGV也可以执行作业更新,也就是说,通过执行AGV已知的边,可以到达作业更新的第一个节点。

图6
{
	orderId: 1234,
	orderUpdateId: 1,
	nodes: [
		7 {released: True},
		2 {released: True},
		8 {released: True},
		9 {released: False}
	],
		edges: [
		e8 {released: True},
		e9 {released: True},
		e10 {released: False}
	]
}

这也有助于在orderUpdate丢失的情况下(由于不可靠的无线网络)。AGV总是可以检查最后一个已知的基本节点是否与第一个新基本节点具有相同的nodeId(以及稍后详细介绍的nodeSequenceId)。

还要注意,节点7是再次发送的唯一 base 节点。由于不能更改base,因此节点6和4的重传是无效的。

重要的是,拼接节点(在示例中为节点7)的内容不被更改。对于动作、偏差范围等,AGV必须使用第一个命令中提供的指令(图5,orderUpdateId 0)。

在这里插入图片描述

图7描述了应该如何扩展命令。它显示了AGV上当前可用的信息。orderId保持不变,orderUpdateId增加。

前一个基本节点的最后一个节点是更新顺序中的第一个基本节点。有了这个节点,AGV可以将更新的命令添加到当前命令(拼接)上。来自前一个基的其他节点和边不会重新生成。

主控件可以选择通过发送完全不同的节点作为新的 base 来更改 Horizon。Horizon也可以被删除。

为了允许按顺序循环(比如从节点1到节点2,然后再返回到节点1),为节点和边缘对象分配了一个sequenceId。这个sequenceId在节点和边上运行(命令的第一个节点接收到0,然后第一个边得到1,第二个节点得到2,依此类推)。这样可以更容易地跟踪命令进度。

一旦分配了sequenceId,它就不会随着顺序更新而改变(参见图7)。这对于确定AGV一侧的主控制指向哪个节点是必要的。

图8描述了接受命令或orderUpdate的过程。
在这里插入图片描述

6.6.3 命令取消(主控)

在基本节点发生计划外更改的情况下,必须使用 instantAction cancelOrder 取消命令。

在接收到 instantAction cancelOrder 后,车辆会停止(基于其能力,例如,在当前位置或在下一个节点上)。

如果计划了操作,则必须取消这些操作,并在其操作状态中报告“failed”。如果有正在运行的操作,则应该取消这些操作,并将其报告为失败。

如果操作不能被中断,那么该操作的actionState应该通过在运行时报告“running”来反映这一点,然后报告各自的状态(如果成功,则报告“finished”,如果失败,则报告“failed”)。当操作正在运行时,cancelOrder操作必须报告“running”,直到所有操作都被取消/完成。在所有车辆移动和所有动作停止后,cancelOrder动作状态必须报告“finished”。

orderId和orderUpdateId被保留。

图9显示了不同AGV功能的预期行为。
在这里插入图片描述

6.6.3.1 取消命令后收到新命令

命令取消后,车辆必须处于接收新命令的状态。

如果AGV通过标记将自身定位在节点上,则新命令必须从AGV现在所在的节点开始(参见图8)。

如果AGV可以在节点之间停止,则选择由主控制如何启动下一个命令。AGV必须接受这两种方法。

有两种选择:

  • 发送命令,其中第一个节点是位于AGV当前位置的临时节点。然后,AGV必须意识到该节点可以轻松到达,并接受命令。
  • 发送一个命令,其中第一个节点是前一个命令的最后一个遍历节点,但设置偏差范围太大,以至于AGV在此范围内。因此,AGV必须意识到该节点必须被计算为遍历,并接受该顺序。
6.6.3.2 当AGV没有命令时接收一个cancelOrder动作

如果AGV接收到cancelOrder操作,但是AGV当前没有命令,或者之前的命令被取消,那么cancelOrder操作必须报告为失败。

AGV必须报告“noOrderToCancel”错误,并将errorLevel设置为警告。instantAction的actionId必须作为errorReference传递。

6.6.4 拒绝命令

有几种情况下,命令必须被拒绝。
图8对此进行了解释。

6.6.4.1 车辆得到一个畸形的新顺序

解决方法:

  1. 车辆不会接管其内部缓冲区中的新命令。
  2. 车辆报告警告“validationError”。
  3. 该警告必须在车辆接受新命令之前报告。
6.6.4.2 车辆收到一个命令,命令中包含了它不能执行的操作

(例如举升高度高于最大举升高度或举升动作,没有安装举升机构),或带有无法使用的区域(例如轨迹)。
解决方法:

  1. 车辆不会接管其内部缓冲区中的新命令。
  2. 车辆报告带有错误字段作为错误引用的警告“orderError”。
  3. 该警告必须在车辆接受新命令之前报告。
6.6.4.3 车辆获得一个具有相同orderId的新命令,但orderUpdateId比当前的orderUpdateId低

解决方法:

  1. 车辆不会接管其内部缓冲区中的新命令。
  2. Vehicle 将先前的顺序保存在它的缓冲区中。
  3. 车辆报告警告“orderUpdateError”。
  4. 车辆继续执行前一个命令。
    如果AGV两次接收到具有相同orderId和orderUpdateId的命令,则第二个命令将被忽略。如果主控件再次发送命令,则可能发生这种情况,因为状态消息来得太晚,并且主控件无法验证是否收到了第一个命令。
6.6.5 地图

为了确保不同类型的AGV之间的导航一致,位置总是参照当地地图坐标系指定的(见图10)。为了区分不同的级别,使用唯一的mapId。
地图坐标系统被指定为右手坐标系,z轴指向天空。因此,正旋转可以理解为逆时针旋转。
车辆坐标系也被指定为右手坐标系,其中x轴指向车辆的前方,z轴指向天空。这符合DIN ISO 8855第2.11章。
在这里插入图片描述

X、Y 和 Z 坐标必须以米为单位。 方向必须以弧度为单位并且必须在 +Pi 和 -Pi 之间。

在这里插入图片描述

6.7 命令消息的实现 order

Object structureUnitData typeDescription
headerIduint32Header ID of the message.The headerId is defined per topic and incremented by 1 with each sent (but not necessarily received) message.
消息头ID。headerId为每个主题定义,每发送(但不一定接收)一条消息,headerId就增加1
timestampstringTimestamp (ISO 8601, UTC); YYYY-MMDDTHH:mm:ss.ssZ (e.g.“2017-04-15T11:40:03.12Z”)
versionstringVersion of the protocol[Major].[Minor].[Patch] (e.g. 1.3.2)
manufacturerstringManufacturer of the AGV
serialNumberstringSerial number of the AGV
orderIdstringOrder identification. This is to be used to identify multiple order messages that belong to the same order
命令ID,这将用于标识属于同一命令的多个命令消息
orderUpdateIduint32Order update identification. Is unique per orderId. If an order update is rejected, this field is to be passed in the rejection message
命令更新标识。每个orderId都是唯一的。如果命令更新被拒绝,该字段将在拒绝消息中传递
zoneSetIdstringUnique identifier of the zone set, that the AGV has to use for navigation or that was used by master control for planning. Optional: Some master control systems do not use zones. Some AGV do not understand zones. Do not add to message, if no zones are used.
区域集的唯一标识符,AGV必须用于导航或主控制用于规划。可选:一些主控系统不使用分区。一些AGV不理解区域。如果没有使用任何区域,则不要添加到消息中。
nodes [node]arrayArray of nodes objects to be traversed for fulfilling the order. One node is enough for a valid order. Leave edge list empty for that case.
为完成命令而遍历节点对象数组,对于一个有效的命令,一个节点就足够了。在这种情况下,让边列表为空。
edges [edge]arrayArray of edge objects to be traversed for fulfilling the order. One node is enough for a valid order. Leave edge list empty for that case.
为完成命令而遍历边对象数组,对于一个有效的命令,一个节点就足够了。在这种情况下,让边列表为空。
node{JSON-object
nodeIdstringUnique node identification
sequenceIduint32Number to track the sequence of nodes and edges in an order and to simplify order updates. The purpose is to distinguish between a node, which is passed more than once within one orderId. The variable sequenceId runs across all nodes and edges of the same order and is reset when a new orderId is issued.
编号为了在一个命令中跟踪节点和边的序列,并简化命令更新。目的是区分在一个orderId中多次传递的节点。变量sequenceId在相同顺序的所有节点和边上运行,并在发出新orderId时重置。
nodeDescriptionstringAdditional information on the node
releasedboolean“true” indicates that the node is part of the base. “false” indicates that the node is part of the horizon.
"true"表示该节点是base节点的一部分。"false"表示该节点是horizon的一部分。
nodePositionJSON-objectNode position. Optional for vehicle-types that do not require the node position (e.g., line-guided vehicles).
节点的位置。对于不需要节点位置的车辆类型(例如,直线导向车辆)可选。
actions [action]}arrayArray of actions to be executed on a node. Empty array, if no actions required.
nodePosition {JSON-objectDefines the position on a map in a global project specific world coordinate system. Each floor has its own map. All maps must use the same project specific global origin.
在全局项目特定的世界坐标系统中定义地图上的位置。每层楼都有自己的地图。所有地图必须使用相同的项目特定的全局原点。
xmfloat64X-position on the map in reference to the map coordinate system. Precision is up to the specific implementation.
ymfloat64Y-position on the map in reference to the map coordinate system. Precision is up to the specific implementation.
thetaradfloat64Range: [-Pi … Pi] Absolute orientation of the AGV on the node. Optional: vehicle can plan the path by itself. If defined, the AGV has to assume the theta angle on this node. If previous edge disallows rotation, the AGV must rotate on the node. If following edge has a differing orientation defined but disallows rotation, the AGV is to rotate on the node to the edges desired rotation before entering the edge.
allowedDeviationXYfloat64Indicates how exact an AGV has to drive over a node in order for it to count as traversed.
If = 0: no deviation is allowed (no deviation means within the normal tolerance of the AGV manufacturer).
If > 0: allowed deviation-radius in meters. If the AGV passes a node within the deviation-radius, the node is considered to have been traversed.
指示AGV在节点上行驶的精确程度,以便将其算作已遍历。If = 0:不允许偏差(不偏差是指在AGV制造商的正常公差范围内)。> 0:允许偏差半径,单位为米。如果AGV通过偏离半径内的节点,则认为该节点已经遍历。
allowedDeviationThetafloat64Range: [0 … Pi] Indicates how big the deviation of theta angle can be. The lowest acceptable angle is theta - allowedDeviationTheta and the highest acceptable angle is theta + allowedDeviationTheta.
mapIdstringUnique identification of the map in which the position is referenced. Each map has the same project specific global origin of coordinates. When an AGV uses an elevator, e.g., leading from a departure floor to a target floor, it will disappear off the map of the departure floor and spawn in the related lift node on the map of the target floor.
mapDescription}stringAdditional information on the map.
action {JSON-objectDescribes an action that the AGV can perform.
actionTypestringName of action as described in the first column of “Actions and Parameters”. Identifies the function of the action.
actionIdstringUnique ID to identify the action and map them to the actionState in the state. Suggestion: Use UUIDs.
actionDescriptionstringAdditional information on the action
blockingTypestringEnum {NOTE, SOFT, HARD}: “NONE”- allows driving and other actions; “SOFT”- allows other actions, but not driving; “HARD”- is the only allowed action at that time.
Enum {NOTE, SOFT, HARD}: NONE -允许驱动和其他动作;“SOFT”-允许其他动作,但不允许驱动;“HARD”-是当时唯一允许的动作。
actionParameters [actionParameter] }arrayArray of actionParameter-objects for the indicated action, e.g., deviceId, loadId, external Triggers. See “Actions and Parameters”
edge {JSON-objectDirectional connection between two nodes.
edgeIdstringUnique edge identification.
sequenceIdIntegerNumber to track the sequence of nodes and edges in an order and to simplify order updates. The variable sequenceId runs across all nodes and edges of the same order and is reset when a new orderId is issued.
edgeDescriptionstringAdditional information on the edge.
releasedboolean“true” indicates that the edge is part of the base. “false” indicates that the edge is part of the horizon.
startNodeIdstringnodeId of startNode.
endNodeIdstringnodeId of endNode.
maxSpeedm/sfloat64Permitted maximum speed on the edge. Speed is defined by the fastest measurement of the vehicle.
maxHeightmfloat64Permitted maximum height of the vehicle, including the load, on edge.
minHeightmfloat64Permitted minimal height of the load handling device on the edge.
orientationradfloat64Orientation of the AGV on the edge. The value orientationType defines if it has to be interpreted relative to the global project specific map coordinate system or tangential to the edge. In case of interpreted tangential to the edge 0.0 = forwards and PI = backwards. Example: orientation Pi/2 rad will lead to a rotation of 90 degrees. If AGV starts in different orientation, rotate the vehicle on the edge to the desired orientation if rotationAllowed is set to “true”. If rotationAllowed is “false", rotate before entering the edge. If that is not possible, reject the order. If no trajectory is defined, apply the rotation to the direct path between the two connecting nodes of the edge. If a trajectory is defined for the edge, apply the orientation to the trajectory.
AGV在边的方向。值orientationType定义了它是必须相对于全局项目特定的地图坐标系统进行解释,还是与边相切。在解释与边相切的情况下,0.0 =向前,PI =向后。例如:方向Pi/2 rad将导致旋转90度。如果AGV以不同的方向启动,如果rotationAllowed设置为“true”,则在边将车辆旋转到所需的方向。如果rotationAllowed为“false”,则在进入边之前旋转。如果这是不可能的,拒绝命令。如果没有定义轨迹,则将旋转应用于边的两个连接节点之间的直接路径。如果为边定义了轨迹,则将方向应用于轨迹。
orientationTypestringEnum {GLOBAL, TANGENTIAL}: “GLOBAL”- relative to the global project specific map coordinate system; “TANGENTIAL”- tangential to the edge. If not defined, the default value is “TANGENTIAL”.
Enum {GLOBAL, TANGENTIAL}: “GLOBAL”-相对于全局项目特定的地图坐标系;“TANGENTIAL”——与边相切。如果未定义,则默认值为“TANGENTIAL”。
directionstringSets direction at junctions for line-guided or wire-guided vehicles, to be defined initially (vehicle-individual). Examples: left, right, straight, 433MHz.
rotationAllowedboolean“true”: rotation is allowed on the edge. “false”: rotation is not allowed on the edge. Optional: No limit, if not set.
maxRotationSpeedrad/sfloat64Maximum rotation speed Optional: No limit, if not set.
trajectoryJSON-objectTrajectory JSON-object for this edge as a NURBS. Defines the curve, on which the AGV should move between startNode and endNode. Optional: Can be omitted, if AGV cannot process trajectories or if AGV plans its own trajectory.
轨迹json对象作为 NURBS 的边,定义曲线,AGV应在此曲线上在startNode和endNode之间移动。可选:如果AGV不能处理轨迹或者AGV规划自己的轨迹,可以省略。
lengthmfloat64Length of the path from startNode to endNode Optional: This value is used by line-guided AGVs to decrease their speed before reaching a stop position.
从startNode到endNode的路径长度可选:该值用于直线引导agv在到达停止位置之前降低速度。
actions [action] }arrayArray of actionIds to be executed on the edge. Empty array, if no actions required. An action triggered by an edge will only be active for the time that the AGV is traversing the edge which triggered the action. When the AGV leaves the edge, the action will stop and the state before entering the edge will be restored.
要在线上执行的actionid数组。如果不需要操作,则为空数组。由线触发的动作仅在AGV穿越触发该动作的线时有效。当AGV离开线时,动作停止,恢复进入线前的状态。
trajectory {JSON-object
degreefloat64Range: [1 … infinity] Defines the number of control points that influence any given point on the curve. Increasing the degree increases continuity. If not defined, the default value is 1.
范围:[1…]定义影响曲线上任何给定点的控制点的数目。增加程度可以增加连续性。如果未定义,则默认值为1。
knotVector [float64]arrayRange: [ 0.0 … 1.0] Sequence of parameter values that determines where and how the control points affect the NURBS curve. knotVector has size of number of control points + degree + 1.
范围:[0.0…1.0]决定控制点在何处以及如何影响NURBS曲线的参数值序列。knotVector的大小为控制点数+ degree + 1。
controlPoints [controlPoint] }arrayList of JSON controlPoint objects defining the control points of the NURBS, which includes the beginning and end point.
定义NURBS控制点的JSON控制点对象列表,其中包括起点和终点。
controlPoint {JSON-object
xfloat64X coordinate described in the world coordinate system.
yfloat64Y coordinate described in the world coordinate system.
weightfloat64Range: (0 … infinity) The weight, with which this control point pulls on the curve. When not defined, the default will be 1.0.
}

6.8 动作 actions

如果 AGV 支持行驶以外的操作,则这些操作通过附加到节点或边的操作字段执行,或通过单独的主题 instantActions 发送(参见 6.9)。

要在边缘执行的操作只能在 AGV 位于边缘时运行(参见 6.10.2)。

在节点上触发的操作只要需要运行就可以运行。 节点上的操作应该是自动终止的(例如,持续五秒的音频信号或拾取动作,在拾取负载后完成)或者应该成对地制定(例如,activateWarningLights 和 deactivateWarningLights),尽管可能存在 例外情况。

以下部分介绍了 AGV 必须使用的预定义操作(如果 AGV 功能映射到操作描述)。 如果有合理的方法来使用定义的参数,则必须使用它们。 如果需要成功执行操作,则可以定义其他参数。

如果无法将某些操作映射到以下部分的操作之一,AGV 制造商可以定义主控制必须使用的附加操作。

6.8.1 预定义动作定义、参数、效果和范围
generalgeneralgeneralgeneralgeneralscopescopescope
actioncounter actionDescriptionimportentParameterlinked stateinstantnodeedge
startPausestopPauseActivates the pause mode. A linked state is required, because many AGVs can be paused by using a hardware switch. No more AGV driving movements - reaching next node is not necessary. Actions can continue. Order is resumable.yes-pausedyesnono
stopPausestartPauseDeactivates the pause mode. Movement and all other actions will be resumed (if any). A linked state is required because many AGVs can be paused by using a hardware switch. stopPause can also restart vehicles that were stopped with a hardware button that triggered startPause (if configured).yes-pausedyesnono
startChargingstopChargingActivates the charging process. Charging can be done on a charging spot (vehicle standing) or on a charging lane (while driving). Protection against overcharging is responsibility of the vehicle.yes-.batteryState
.charging
yesyesno
stopChargingstartChargingDeactivates the charging process to send a new order. The charging process can also be interrupted by the vehicle / charging station, e.g., if the battery is full. Battery state is only allowed to be “false”, when AGV is ready to receive orders.yes-.batteryState
.charging
yesyesno
initPosition-Resets (overrides) the pose of the AGV with the given paramaters.yesx (float64)
y (float64)
theta (float64)
mapId (string)
lastNodeId (string)
.agvPosition.x .agvPosition.y .agvPosition.theta .agvPosition.mapId .lastNodeIdyesyes
(Elevator)
no
stateRequest-Requests the AGV to send a new state report.yes--yesnono
logReport-Requests the AGV to generate and store a log report.yesreason (string)-yesnono
pickdrop (if automated)Request the AGV to pick a load. AGVs with multiple load handling devices can process multiple pick operations in parallel. In this case, the paramater lhd needs to be present (e.g. LHD1). The paramater stationType informs how the pick operation is handled in detail (e.g., floor location, rack location, passive conveyor, active conveyor, etc.). The load type informs about the load unit and can be used to switch field for example (e.g., EPAL, INDU, etc). For preparing the load handling device (e.g., pre-lift operations based on the height parameter), the action could be announced in the horizon in advance. But, pre-Lift operations, etc., are not reported as running in the AGV state, because the associated node is not released yet. If on an edge, the vehicle can use its sensing device to detect the position for picking the node.nolhd (string, optional) stationType (string) stationName(string, optional) loadType (string) loadId(string, optional) height (float64) (optional) defines bottom of the load related to the floor depth (float64) (optional) for forklifts side(string) (optional) e.g. conveyor.loadnoyesyes
droppick (if automated)Request the AGV to drop a load. See action pick for more details.nolhd (string, optional) stationType (string, optional) stationName (string, optional) loadType (string, optional) loadId(string, optional) height (float64, optional) depth (float64, optional) ….loadnoyesyes
detectObject-AGV detects object (e.g. load, charging spot, free parking position).yesobjectType(string, optional)-noyesyes
finePositioning-On a node, AGV will position exactly on a target. The AGV is allowed to deviate from its node position. On an edge, AGV will e.g. align on stationary equipment while traversing an edge. InstantAction: AGV starts positioning exactly on a target.yesstationType(string, optional) stationName(string, optional)-noyesyes
waitForTrigger-AGV has to wait for a trigger on the AGV (e.g. button press, manual loading). Master control is responsible to handle the timeout and has to cancel the order if necessary.yestriggerType(string)-noyesno
cancelOrder-AGV stops as soon as possible. This could be immediately or on the next node. Then the order is deleted. All actions are canceled.yes--yesnono
factsheetRequest-Requests the AGV to send a factsheetyes--yesnono
6.8.2 预定义的动作定义,其状态的描述
actioninitializingrunningpausedfinishedfailed
startPause-Activation of the mode is in preperation. If the AGV supports an instant transition, this state can be omitted.-Vehicle stands still. All actions will be paused. The pause mode is activated. The AGV reports .paused: true.The pause mode can not be activated for some reason (e.g., overridden by hardware switch).
stopPause-Deactivation of the mode is in preparation. If the AGV supports an instant transition, this state can be omitted.-The pause mode is deactivated. All paused actions will be resumed. The AGV reports .paused: false.The pause mode can not be deactivated for some reason (e.g., overwritten by hardware switch).
startCharging-Activation of the charging process is in progress (communication with charger is running). If the AGV supports an instant transition, this state can be omitted.-The charging process is started. The AGV reports .batteryState.charging: true.The charging process could not be started for some reason (e.g., not aligned to charger). Charging problems should correspond with an error.
stopCharging-Deactivation of the charging process is in progress (communication with charger is running). If the AGV supports an instant transition, this state can be omitted.-The charging process is stopped. The AGV reports .batteryState.charging: falseThe charging process could not be stopped for some reason (e.g., not aligned to charger). Charging problems should correspond with an error.
initPosition-Initializing of the new pose in progress (confidence checks etc.). If the AGV supports an instant transition, this state can be omitted.-The pose is reset. The AGV reports
.agvPosition.x = x,
.agvPosition.y = y,
.agvPosition.theta = theta
.agvPosition.mapId = mapId
.agvPosition.lastNodeId = lastNodeId
The pose is not valid or can not be reset. General localization problems should correspond with an error.
stateRequest---The state has been communicated-
logReport-The report is in generating. If the AGV supports an instant generation, this state can be omitted.-The report is stored. The name of the log will be reported in status.The report can not be stored (e.g., no space).
pickInitializing of the pick process, e.g., outstanding lift operations.The pick process is running (AGV is moving into station, load handling device is busy, communication with station is running, etc.).The pick process is being paused, e.g., if a safety field is violated. After removing the violation, the pick process continues.Pick is done. Load has entered the AGV and AGV reports new load state.Pick failed, e.g., station is unexpected empty. Failed pick operations should correspond with an error.
dropInitializing of the drop process, e.g., outstanding lift operations.The drop process is running (AGV is moving into station, load handling device is busy, communication with station is running, etc.).The drop process is being paused, e.g., if a safety field is violated. After removing the violation the drop process continues.Drop is done. Load has left the AGV and AGV reports new load state.Drop failed, e.g., station is unexpected occupied. Failed drop operations should correspond with an error.
detectObject-Object detection is running.-Object has been detected.AGV could not detect the object.
finePositioning-AGV positions itself exactly on a target.The fine positioning process is being paused, e.g., if a safety field is violated. After removing the violation, the fine positioning continues.Goal position in reference to the station is reached.Goal position in reference to the station could not be reached.
waitForTrigger-AGV is waiting for the Trigger-Trigger has been triggered.waitForTrigger fails if order has been canceled.
cancelOrder-AGV is stopping or driving, until it reaches the next node.-AGV stands still and has canceled the order.-
factsheetRequest---The factsheet has been communicated-

6.9 主题:“即时动作”(从主站到中控再到AGV) instantActions

在某些情况下,需要向 AGV 发送即时操作。这是通过向主题发布 instantAction 消息来实现的即时操作。 instantActions不得与AGV当前命令内容冲突(例如,instantAction 降低货叉,而命令说升高货叉)。
与即时操作相关的一些示例包括:
• 暂停AGV,不改变当前命令中的任何内容;
• 暂停后恢复命令;
• 激活信号(光学、音频等)。
有关更多信息,请参阅第 7 章最佳实践。

Object structureData typeDescription
headerIduint32header ID of the message. The headerId is defined per topic and incremented by 1 with each sent (but not necessarily received) message.
timestampstringTimestamp (ISO 8601, UTC); YYYY-MMDDTHH:mm:ss.ssZ (e.g., “2017-04-15T11:40:03.12Z”)
versionstringVersion of the protocol [Major].[Minor].[Patch] (e.g., 1.3.2).
manufacturerstringManufacturer of the AGV.
serialNumberstringSerial number of the AGV.
actions [action]arrayArray of actions that need to be performed immediately and are not part of the regular order (see chapter 6.7).

当AGV接收到一个instantAction时,一个适当的actionStatus被添加到AGV状态的actionStates数组中。actionStatus根据动作的进度进行更新。另请参见图12,了解actionStatus的不同转换。

6.10 主题:“状态”(从AGV到主控) state

agv状态将只在一个主题上传输。与单独的消息(例如,命令、电池状态和错误)相比,使用一个主题将减少代理和主控制处理消息的工作量,同时还保持AGV状态信息的同步。

AGV-State消息将在相关事件发生时发布,或最迟每隔 30秒 通过mqtt代理发布一次,以实现主控制。

触发状态消息传输的事件有:

  • 接收命令
  • 接收命令更新
  • 负载状态的变化
  • 错误或警告
  • 在节点上行驶
  • 切换工作模式
  • “driving”领域的变化
  • nodeStates、edgeStates或actionStates的变化

应该努力控制交流的数量。如果两个事件相互关联(例如,接收新命令通常会强制更新点与边状态;与节点上的驱动一样),触发一个状态更新而不是多个状态更新是明智的。

6.10.1 概念和逻辑

命令进度由nodeStates和edgeStates跟踪。此外,如果AGV能够导出其当前位置,它可以通过“position”字段发布其位置。

如果AVG自己规划路径,它必须通过状态消息中的轨迹对象以 NURBS 的形式传达其计算的轨迹(包括 base 和 horizon ),除非主控制不能使用该字段并且在集成过程中同意不发送该字段。主控制释放节点后,AGV不允许改变轨迹。

nodeStates和edgeStates包括AGV仍然必须遍历的所有节点/边。
在这里插入图片描述

6.10.2 遍历节点和进出边,触发动作

AGV自行决定何时将节点算作遍历。一般情况下,AGV控制点应在节点的deviationRangeXY范围内,其方向应在deviationRangeTheta范围内。

AGV通过从nodeStates数组中删除节点的nodeState并将lastNodeId、lastNodeSequenceNumber设置为所遍历节点的值来报告节点的遍历。

一旦AGV报告节点已遍历,AGV必须触发与该节点相关的操作(如果有的话)。

节点的遍历也标记了通向该节点的边的离开。然后必须将边缘从edgeStates中移除,并且必须完成在边缘上活动的操作。

节点的遍历也标记了AGV进入下一条边(如果有)的时刻。现在必须触发边缘动作。这条规则的一个例外是,如果AGV必须在边缘暂停(因为软或硬阻塞边缘,或其他)-然后AGV进入边缘后,它再次开始移动。

在这里插入图片描述

6.10.3 Base request

如果AGV检测到它的 base 少,它可以将newBaseRequest标志设置为true,以防止不必要的制动。

6.10.4 信息

AGV可以通过信息阵列向主控提交任意附加信息。通过信息消息报告信息的时间长短取决于AGV。
主控不能将信息消息用于逻辑,它只能用于可视化和调试目的。

6.10.5 错误

AGV通过错误数组报告错误。错误有两个级别:警告和致命。【WARNING and FATAL】
WARNING 是一个自动解决的错误,例如,区域冲突。致命的错误需要人为干预。错误可以通过 errorReferences 数组传递有助于查找错误原因的参考。

6.10.6 实现
Object structureUnitData typeDescription
headerIduint32Header ID of the message.The headerId is defined per topic and incremented by 1 with each sent (but not necessarily received) message.
消息头ID。headerId为每个主题定义,每发送(但不一定接收)一条消息,headerId就增加1
timestampstringTimestamp (ISO 8601, UTC); YYYY-MMDDTHH:mm:ss.ssZ (e.g.“2017-04-15T11:40:03.12Z”)
versionstringVersion of the protocol[Major].[Minor].[Patch] (e.g. 1.3.2)
manufacturerstringManufacturer of the AGV
serialNumberstringSerial number of the AGV
orderIdstringUnique order identification of the current order or the previous finished order. The orderId is kept until a new order is received. Empty string (“”), if no previous orderId is available.
orderUpdateIduint32Order Update Identification to identify, that an order update has been accepted by the AGV. “0” if no previous orderUpdateId is available.
zoneSetIdstringUnique ID of the zone set, that the AGV currently uses for path planning. Must be the same as the one used in the order, otherwise the AGV has to reject the order. Optional: If the AGV does not use zones, this field can be omitted.
lastNodeIdstringNode ID of last reached node or, if AGV is currently on a node, current node (e.g., „node7”). Empty string (“”), if no lastNodeId is available.
lastNodeSequenceIduint32Sequence ID of the last reached node or, if AGV is currently on a node, Sequence ID of current node. “0” if no lastNodeSequenceId is available.
nodeStates [nodeState]arrayArray of nodeState-Objects, that need to be traversed for fulfilling the order(empty list if idle)
edgeStates [edgeState]arrayArray of edgeState-Objects, that need to be traversed for fulfilling the order(empty list if idle)
agvPositionJSON-objectCurrent position of the AGV on the map. Optional: Can only be omitted for AGV without the capability to localize themselves, e.g., line guided AGVs.
velocityJSON-objectThe AGV velocity in vehicle coordinates.
loads [load]arrayLoads, that are currently handled by the AGV. Optional: If AGV cannot determine load state, leave the array out of the state. If the AGV can determine the load state, but the array is empty, the AGV is considered unloaded.
drivingboolean“true”: indicates, that the AGV is driving and/or rotating. Other movements of the AGV (e.g., lift movements) are not included here. “false”: indicates that the AGV is neither driving nor rotating.
pausedboolean“true”: AGV is currently in a paused state, either because of the push of a physical button on the AGV or because of an instantAction. The AGV can resume the order. “false”: The AGV is currently not in a paused state.
newBaseRequestboolean“true”: AGV is almost at the end of the base and will reduce speed, if no new base is transmitted. Trigger for master control to send a new base. “false”: no base update required.
distanceSinceLastNodemeterfloat64Used by line guided vehicles to indicate the distance it has been driving past the „lastNodeId“. Distance is in meters.
actionStates [actionState]arrayContains a list of the current actions and the actions, which are yet to be finished. This may include actions from previous nodes, that are still in progress. When an action is completed, an updated state message is published with actionStatus set to finished and if applicable with the corresponding resultDescription. The action state is kept until a new order is received.
batteryStateJSON-objectContains all battery-related information.
operatingModestringEnum {AUTOMATIC, SEMIAUTOMATIC, MANUAL, SERVICE, TEACHIN} For additional information, see the table OperatingModes in the chapter 6.10.6.
errors [error]arrayArray of error-objects. All active errors of the AGV should be in the list. An empty array indicates that the AGV has no active errors
information [info]arrayArray of info-objects. An empty array indicates, that the AGV has no information. This should only be used for visualization or debugging – it must not be used for logic in master control.
safetyStateJSON-objectContains all safety-related information
nodeState {JSON-object
nodeIdstringUnique node identification.
sequenceIduint32sequenceId to discern multiple nodes with same nodeId.
nodeDescriptionstringAdditional information on the node.
nodePositionJSON-objectNode position. The object is defined in chapter 6.6 Optional: Master control has this information. Can be sent additionally, e. g. for debugging purposes.
released }boolean“true” indicates that the node is part of the base.“false” indicates that the node is part of the horizon.
edgeState {JSON-object
edgeIdstringUnique edge identification. sequenceId uint32 sequenceId to differentiate between multiple edges with the same edgeId.
edgeDescriptionstringAdditional information on the edge.
releasedboolean“true” indicates that the edge is part of the base. “false” indicates that the edge is part of the horizon.
trajectory }JSON-objectThe trajectory is to be communicated as a NURBS and is defined in chapter 6.4 Trajectory segments are defined from the point, where the AGV starts to enter the edge, to the point, where it reports, that the next node was traversed.
agvPosition {JSON-objectDefines the position on a map in world coordinates. Each floor has its own map.
positionInitializedboolean“true”: position is initialized. “false”: position is not initialized.
localizationScorefloat64Range: [0.0 … 1.0] Describes the quality of the localization and therefore, can be used, e.g. by SLAM-AGV to describe, how accurate the current position information is. 0.0: position unknown 1.0: position known Optional for vehicles, that cannot estimate their localization score. Only for logging and visualization purposes.
deviationRangemfloat64Value for the deviation range of the position in meters. Optional for vehicles that cannot estimate their deviation e.g. gridbased localization. Only for logging and visualization purposes.
xmfloat64X-position on the map in reference to the map coordinate system. Precision is up to the specific implementation.
ymfloat64Y-position on the map in reference to the map coordinate system. Precision is up to the specific implementation.
thetafloat64Range: [-Pi … Pi] Orientation of the AGV
mapIdstringUnique identification of the map in which the position is referenced. Each map has the same origin of coordinates. When an AGV uses an elevator, e.g., leading from a departure floor to a target floor, it will disappear off the map of the departure floor and spawn in the related lift node on the map of the target floor.
mapDescription }stringAdditional information on the map.
velocity {JSON-object
vxm/sfloat64The AVGs velocity in its x direction.
vym/sfloat64The AVGs velocity in its y direction.
omega}Rad/sfloat64The AVGs turning speed around its z axis.
load {JSON-object
loadIdstringUnique identification number of the load (e.g., barcode or RFID). Empty field, if the AGV can identify the load, but didn’t identify the load yet. Optional, if the AGV cannot identify the load.
loadTypestringType of load.
loadPositionstringIndicates, which load handling/carrying unit of the AGV is used, e.g., in case the AGV has multiple spots/positions to carry loads. For example: “front”, “back”, “positionC1”, etc. Optional for vehicles with only one loadPosition
boundingBoxReferenceJSON-objectPoint of reference for the location of the bounding box. The point of reference is always the center of the bounding box’s bottom surface (at height = 0) and is described in coordinates of the AGV’s coordinate system.
loadDimensionsJSON-objectDimensions of the load´s bounding box in meters.
weight}kgfloat64Range: [0.0 … infinity) Absolute weight of the load measured in kg.
boundingBoxReference {JSON-objectPoint of reference for the location of the bounding box. The point of reference is always the center of the bounding box’s bottom surface (at height = 0) and is described in coordinates of the AGV’s coordinate system.
xfloat64x-coordinate of the point of reference.
yfloat64y-coordinate of the point of reference.
zfloat64z-coordinate of the point of reference.
theta }float64Orientation of the loads bounding box. Important for tugger, trains, etc.
loadDimensions {JSON-objectDimensions of the load´s bounding box in meters.
lengthmfloat64Absolute length of the load´s bounding box.
widthmfloat64Absolute width of the load´s bounding box.
height }mfloat64Absolute height of the load´s bounding box. Optional: Set value only if known.
actionState {JSON-object
actionIdstringaction_ID
actionTypestringactionType of the action. Optional: Only for informational or visualization purposes. Order knows the type.
actionDescriptionstringAdditional information on the current action.
actionStatusstringEnum {WAITING; INITIALIZING; RUNNING; PAUSED; FINISHED; FAILED} WAITING: waiting for the trigger (passing the mode, entering the edge) PAUSED: paused by instantAction or external trigger FAILED: action could not be performed.
resultDescription }stringDescription of the result, e.g., the result of a RFID-read. Errors will be transmitted in errors. Examples for results are given in 6.5
batteryState {JSON-object
batteryCharge%float64State of Charge: if AGV only provides values for good or bad battery levels, these will be indicated as 20% (bad) and 80% (good).
batteryVoltageVfloat64Battery Voltage.
batteryHealth%int8Range: [0 … 100] State of Health.
chargingboolean“true”: charging in progress. “false”: AGV is currently not charging.
reach }muint32Range: [0 … infinity) Estimated reach with current State of Charge.
error {JSON-object
errorTypestringType/name of error
errorReferences[errorReference]arrayArray of references to identify the source of the error (e.g., headerId, orderId, actionId, etc.). For additional information see „Best practices“ chapter 7.
errorDescriptionstringError description.
errorLevel }stringEnum {WARNING, FATAL} WARNING: AGV is ready to start (e.g. maintenance cycle expiration warning). FATAL: AGV is not in running condition, user intervention required (e.g. laser scanner is contaminated).
errorReference {JSON-object
referenceKeystringReferences the type of reference (e.g., headerId, orderId, actionId, etc.).
referenceValue }stringReferences the value, which belongs to the reference key.
info {JSON-object
infoTypestringType/name of information.
infoReferences [infoReference]arrayArray of references.
infoDescriptionstringInfo of description.
infoLevel }stringEnum {DEBUG,INFO} DEBUG: used for debugging. INFO: used for visualization.
infoReference {JSON-objectreferenceKey string References the type of reference (e.g., headerId, orderId, actionId, etc.).
referenceValue }stringReferences the value, which belongs to the reference key.
safetyState {JSON-object
eStopstringEnum {AUTOACK,MANUAL,REMOTE,NONE} Acknowledge-Type of eStop: AUTOACK: auto-acknowledgeable estop is activated, e.g., by bumper or protective field. MANUAL: e-stop has to be acknowledged manually at the vehicle. REMOTE: facility e-stop has to be acknowledged remotely. NONE: no e-stop activated.
fieldViolation }booleanProtective field violation. “true”: field is violated “false”: field is not violated.
运行模式描述 operatingMode

下面描述例举 “state” 的操作模式,operatingMode

IdentifierDescription
AUTOMATICAGV is under full control of the master control. AGV drives and executes actions based on orders from the master control.
SEMIAUTOMATICAGV is under control of the master control. AGV drives and executes actions based on orders from the master control. The driving speed is controlled by the HMI (speed can’t exceed the speed of automatic mode). The steering is under automatic control (non-safe HMI possible).
MANUALMaster control is not in control of the AGV. Supervisor doesn’t send driving order or actions to the AGV. HMI can be used to control the steering and velocity and handling device of the AGV. Location of the AGV is send to the master control. When AGV enters or leaves this mode, it immediately clears all the orders (safe HMI required).
SERVICEMaster control is not in control of the AGV. Master control doesn’t send driving order or actions to the AGV. Authorized personal can reconfigure the AGV.
TEACHINMaster control is not in control of the AGV. Supervisor doesn’t send driving order or actions to the AGV. The AGV is being taught, e.g., mapping is done by a master control.

6.11 动作状态 actionStates

当AGV接收到一个动作(无论是附加到节点或边,还是通过一个instantAction)时,它必须用actionStates数组中的actionState来表示这个动作。
actionStates在actionStatus字段中描述该操作处于操作生命周期的哪个阶段。
下表描述了enum actionStatus可以保存的值。

actionStatusDescription
WAITINGAction was received by AGV but the node where it triggers was not yet reached or the edge where it is active was not yet entered.
INITIALIZINGAction was triggered, preparatory measures are initiated.
RUNNINGThe action is running.
PAUSEDThe action is paused because of a pause instantAction or external trigger (pause button on AGV)
FINISHEDThe action is finished. A result is reported via the resultDescription
FAILEDAction could not be finished for whatever reason

图14提供了一个状态转换图。
在这里插入图片描述

6.12 动作阻止类型和顺序 block & sequence

列表中多个操作的顺序定义了执行这些操作的顺序。操作的并行执行由它们各自的blockingType控制。
操作可以有三种不同的阻塞类型,如下表所示。

actionStatusDescription
NONEAction can be executed in parallel with other actions and while the vehicle is driving.
SOFTAction can be executed in parallel with other actions. Vehicle must not drive.
HARDAction must not be executed in parallel with other actions. Vehicle must not drive.

如果在同一节点上有多个具有不同阻塞类型的操作,图15描述了AGV应该如何处理这些操作。
在这里插入图片描述

6.13 主题“可视化” visualization

对于接近实时的位置更新,AGV可以在子主题可视化上广播其位置和速度。
位置信息的结构与状态中的位置和速度信息相同。更多信息请参见 6.7 实现。该主题的更新速率由积分器定义。

6.14 主题“连接” connection

在AGV客户端与代理连接期间,可以设置最后遗嘱主题和消息,并在AGV客户端与代理断开连接时由代理发布。因此,主控可以通过订阅所有AGV的连接主题来检测断开事件。断开连接是通过在代理和客户端之间交换的心跳检测的。该间隔在大多数代理中是可配置的,应该设置为15秒左右。连接主题的服务质量等级应为1 - 至少一次。

建议最后遗嘱主题结构是:【will topic】
uagv/v2/manufacturer/SN/connection
最后一个遗嘱消息被定义为JSON封装的消息,包含以下字段:

IdentifierData typeDescription
headerIduint32Header ID of the message. The headerId is defined per topic and incremented by 1 with each sent (but not necessarily received) message.
timestampstringTimestamp (ISO8601, UTC); YYYY-MMDDTHH:mm:ss.ssZ(e.g.“2017-04-15T11:40:03.12Z”).
versionstringVersion of the protocol [Major].[Minor].[Patch] (e.g. 1.3.2).
manufacturerstringManufacturer of the AGV.
serialNumberstringSerial number of the AGV.
connectionStatestringEnum {ONLINE, OFFLINE, CONNECTIONBROKEN} ONLINE: connection between AGV and broker is active. OFFLINE: connection between AGV and broker has gone offline in a coordinated way. CONNECTIONBROKEN: The connection between AGV and broker has unexpectedly ended.

当使用MQTT断开连接命令以一种优雅的方式结束连接时,将不会发送最后一个will消息。只有在连接意外中断的情况下,代理才会发送最后一条will消息。
注意:由于MQTT中最后一个will特性的性质,最后一个will消息是在AGV和MQTT Broker之间的连接阶段定义的。因此,时间戳和headerId字段总是过时的。

AGV想要优雅地断开连接:

  1. AGV发送“uagv/v2/manufacturer/SN/connection”,connectionState设置为OFFLINE。
  2. 使用Disconnect命令断开mqtt连接。

AGV上线:

  1. 当创建mqtt连接时,将最后一个will设置为“uagv/v2/manufacturer/SN/connection”,字段connectionState设置为CONNECTIONBROKEN。
  2. 发送主题“uagv/v2/manufacturer/SN/connection”,connectionState设置为ONLINE。
    关于此主题的所有消息都应带有保留标志发送。
    当AGV和代理之间的连接意外中断时,代理将发送最后一个will主题:“uagv/v2/manufacturer/SN/connection”,字段connectionState设置为CONNECTIONBROKEN。

6.15 主题“情况说明书” factsheet

该简报提供了关于特定AGV类型系列的基本信息。这些信息可以对不同类型的AGV进行比较,并可以应用于AGV系统的规划、尺寸和仿真。情况说明书还包括AGV通信接口的信息,这些接口是将AGV类型系列集成到符合vda-5050标准的主控中所必需的。

AGV概况表中某些字段的值只能在系统集成期间指定,例如项目特定负载和站点类型的分配,以及该AGV支持的站点和负载类型列表。

事实概况表既可以作为人类可读的文档,也可以用于机器处理,例如,由主控制应用程序导入,因此被指定为JSON文档。

MC 可以通过发送即时动作向AGV请求实况介绍:
factsheetRequest

关于此主题的所有消息都应带有保留标志发送。

6.15.1 概况表JSON结构

该概况表由下表中列出的json对象组成。

Fielddata typedescription
headerIduint32Header ID of the message. The headerId is defined per topic and incremented by 1 with each sent (but not necessarily received) message.
timestampstringTimestamp (ISO8601, UTC); YYYY-MMDDTHH:mm:ss.ssZ(e.g.“2017-04-15T11:40:03.12Z”).
versionstringVersion of the protocol [Major].[Minor].[Patch](e.g. 1.3.2).
manufacturerstringManufacturer of the AGV.
serialNumberstringSerial number of the AGV.
typeSpecificationJSON-objectThese parameters generally specify the class and the capabilities of the AGV.
physicalParametersJSON-objectThese parameters specify the basic physical properties of the AGV.
protocolLimitsJSON-objectLimits for length of identifiers, arrays, strings and similar in MQTT communication.
protocolFeaturesJSON-objectSupported features of VDA5050 protocol.
agvGeometryJSON-objectDetailed definition of AGV geometry.
loadSpecificationJSON-objectAbstract specification of load capabilities.
localizationParametersJSON-objectDetailed specification of localization.
typeSpecification

这个JSON对象描述了AGV类型的一般属性。

Fielddata typedescription
seriesNamestringFree text generalized series name as specified by manufacturer.
seriesDescriptionstringFree text human readable description of the AGV type series.
agvKinematicstringSimplified description of AGV kinematics-type. [DIFF, OMNI, THREEWHEEL]
DIFF: differential drive
OMNI: omni-directional vehicle
THREEWHEEL: three-wheel-driven vehicle or vehicle with similar kinematics
agvClassstringSimplified description of AGV class. [FORKLIFT, CONVEYOR, TUGGER, CARRIER]
FORKLIFT: forklift.
CONVEYOR: AGV with conveyors on it.
TUGGER: tugger.
CARRIER: load carrier with or without lifting unit.
maxLoadMassfloat64[kg], Maximum loadable mass.
localizationTypesArray of StringSimplified description of localization type. Example values:
NATURAL: natural landmarks;
REFLECTOR: laser reflectors;
RFID: RFID-tags;
DMC: data matrix code; SPOT: magnetic spots;
GRID: magnetic grid.
navigationTypesArray of StringList of path planning types supported by the AGV, sorted by priority. Example values:
PHYSICAL_LINE_GUIDED: No path planning, AGV follows physical installed paths.
VIRTUAL_LINE_GUIDED: AGV goes fixed (virtual) paths.
AUTONOMOUS: AGV plans its path autonomously.
physicalParameters

这个json对象描述了AGV的物理属性。

Fielddata typedescription
speedMinfloat64[m/s] Minimal controlled continuous speed of the AGV.
speedMaxfloat64[m/s] Maximum speed of the AGV.
accelerationMaxfloat64[m/s²] Maximum acceleration with maximum load.
decelerationMaxfloat64[m/s²] Maximum deceleration with maximum load.
heightMinfloat64[m] Minimum height of AGV.
heightMaxfloat64[m] Maximum height of AGV.
widthfloat64[m] Width of AGV.
lengthfloat64[m] Length of AGV.
protocolLimits

这个json对象描述了AGV的协议限制。如果参数没有定义或设置为零,则没有对该参数的显式限制。

Fielddata typedescription
maxStringLens {JSON-objectMaximum lengths of strings.
msgLenuint32Maximum MQTT message length
topicSerialLenuint32Maximum length of serial-number part in MQTT-topics. Affected parameters:
order.serialNumber
instantActions.serialNumber
state.SerialNumber
visualization.serialNumber
connection.serialNumber
topicElemLenuint32Maximum length of all other parts in MQTTtopics. Affected parameters:
order.timestamp
order.version
order.manufacturer
instantActions.timestamp
instantActions.version
instantActions.manufacturer
state.timestamp
state.version
state.manufacturer
visualization.timestamp
visualization.version
visualization.manufacturer
connection.timestamp
connection.version connection.manufacturer
idLenuint32Maximum length of ID-Strings. Affected parameters:
order.orderId
order.zoneSetId
node.nodeId
nodePosition.mapId
action.actionId
edge.edgeId
edge.startNodeId
edge.endNodeId
idNumericalOnlybooleanIf “true” ID-strings need to contain numerical values only.
enumLenuint32Maximum length of ENUM- and Key-Strings. Affected parameters:
action.actionType action.blockingType
edge.direction
actionParameter.key
state.operatingMode
load.loadPosition
load.loadType
actionState.actionStatus
error.errorType
error.errorLevel
errorReference.referenceKey
info.infoType
info.infoLevel
safetyState.eStop
connection.connectionState
loadIdLenuint32Maximum length of loadId Strings
}
maxArrayLens {JSON-objectMaximum lengths of arrays.
order.nodesuint32Maximum number of nodes per order processable by the AGV.
order.edgesuint32Maximum number of edges per order processable by the AGV.
node.actionsuint32Maximum number of actions per node processable by the AGV.
edge.actionsuint32Maximum number of actions per edge processable by the AGV.
actions.actionsParametersuint32Maximum number of parameters per action processable by the AGV.
instantActionsuint32Maximum number of instant actions per message processable by the AGV.
trajectory.knotVectoruint32Maximum number of knots per trajectory processable by the AGV.
trajectory.controlPointsuint32Maximum number of control points per trajectory processable by the AGV.
state.nodeStatesuint32Maximum number of nodeStates sent by the AGV, maximum number of nodes in base of AGV.
state.edgeStatesuint32Maximum number of edgeStates sent by the AGV, maximum number of edges in base of AGV.
state.loadsuint32Maximum number of load-objects sent by the AGV.
state.actionStatesuint32Maximum number of actionStates sent by the AGV.
state.errorsuint32Maximum number of errors sent by the AGV in one state-message.
state.informationuint32Maximum number of informations sent by the AGV in one state-message.
error.errorReferencesuint32Maximum number of error references sent by the AGV for each error.
information.infoReferencesuint32Maximum number of info references sent by the AGV for each information.
}
timing {JSON-objectTiming information.
minOrderIntervalfloat32[s], Minimum interval sending order messages to the AGV.
minStateIntervalfloat32[s], Minimum interval for sending statemessages.
defaultStateIntervalfloat32[s], Default interval for sending statemessages, if not defined, the default value from the main document is used.
visualizationIntervalfloat32[s], Default interval for sending messages on visualization topic.
}
agvProtocolFeatures

这个JSON对象定义了AGV支持的动作和参数。

Fielddata typedescription
optionalParameters[optionalParameter]Array of JSON-objectList of supported and/or required optional parameters. Optional parameters, that are not listed here, are assumed to be not supported by the AGV.
{
parameterstringFull name of optional parameter, e.g. “order.nodes.nodePosition.allowedDeviationTheta”.
supportenumType of support for the optional parameter, the following values are possible:
SUPPORTED: optional parameter is supported like specified.
REQUIRED: optional parameter is required for proper AGV-operation.
descriptionstringFree-form text: description of optional parameter, e.g.: Reason, why the optional parameter ‘direction’ is necessary for this AGV-type and which values it can contain. The parameter ‘nodeMarker’ must contain unsigned interger-numbers only. NURBS-Support is limited to straight lines and circle segments.
}
agvActions [agvAction]Array of JSON-objectList of all actions with parameters supported by this AGV. This includes standard actions specified in VDA5050 and manufacturerspecific actions.
{
actionTypestringUnique actionType corresponding to action.actionType.
actionDescriptionstringFree-form text: description of the action.
actionScopesarray of enumList of allowed scopes for using this actiontype.
INSTANT: usable as instantAction.
NODE: usable on nodes.
EDGE: usable on edges.
For example: [“INSTANT”, “NODE”]
actionParameters [actionParameter]Array of JSON-objectList of parameters If not defined, the action has no parameters
{
keystringKey-String for Parameter.
valueDataTypeenumData type of Value, possible data types are: BOOL, NUMBER, INTEGER, FLOAT, STRING, OBJECT, ARRAY.
descriptionstringFree-form text: description of the parameter.
isOptionalboolean“true”: optional parameter.
}
resultDescriptionstringFree-form text: description of the resultDescription.
}
agvGeometry

这个JSON对象定义了AGV的几何属性,例如轮廓和车轮位置。

Fielddata typedescription
wheelDefinitions [wheelDefinition]Array of JSON-objectList of wheels, containing wheelarrangement and geometry.
{
typeenumWheel type DRIVE, CASTER, FIXED, MECANUM.
isActiveDrivenboolean“true”: wheel is actively driven (de:angetrieben).
isActiveSteeredboolean“true”: wheel is actively steered (de:aktivgelenkt).
position {JSON-object
xfloat64[m], x-position in AGV-coordinate. system
yfloat64[m], y-position in AGV-coordinate. system
thetafloat64[rad], orientation of wheel in AGV-coordinate system Necessary for fixed wheels.
}
diameterfloat64[m], nominal diameter of wheel.
widthfloat64[m], nominal width of wheel.
centerDisplacementfloat64[m], nominal displacement of the wheel’s center to the rotation point (necessary for caster wheels). If the parameter is not defined, it is assumed to be 0.
constraintsstringFree-form text: can be used by the manufacturer to define constraints.
}
envelopes2d [envelope2d]Array of JSON-objectList of AGV-envelope curves in 2D (german: „Hüllkurven“), e.g., the mechanical envelopes for unloaded and loaded state, the safety fields for different speed cases.
{
setstringName of the envelope curve set.
polygonPoints [polygonPoint]Array of JSON-objectEnvelope curve as a x/y-polygon polygon is assumed as closed and must be non-selfintersecting.
{
xfloat64[m], x-position of polygon-point.
yfloat64[m], y-position of polygon-point.
}
descriptionstringFree-form text: description of envelope curve set.
}
envelopes3d [envelope3d]Array of JSON-objectList of AGV-envelope curves in 3D (german: „Hüllkurven“).
{
setstringName of the envelope curve set.
formatstringFormat of data, e.g., DXF.
dataJSON-object3D-envelope curve data, format specified in ‘format’.
urlstringProtocol and url-definition for downloading the 3D-envelope curve data, e.g. ftp://xxx.yyy.com/ac4dgvhoif5tghji.
descriptionstringFree-form text: description of envelope curve set
}
loadSpecification

这个JSON对象指定AGV的负载处理和支持的负载类型。

Fielddata typedescription
loadPositionsArray of StringList of load positions / load handling devices. This lists contains the valid values for the parameter “state.loads[].loadPosition” and for the action parameter “lhd” of the actions pick and drop. If this list doesn’t exist or is empty, the AGV has no load handling device.
loadSets [loadSet]Array of JSON-objectlist of load-sets that can be handled by the AGV
{
setNamestringUnique name of the load set, e.g., DEFAULT, SET1, etc.
loadTypestringType of load, e.g., EPAL, XLT1200, etc.
loadPositionsArray of StringList of load positions btw. load handling devices, this load-set is valid for. If this parameter does not exist or is empty, this load-set is valid for all load handling devices on this AGV.
boundingBoxReferenceJSON-objectBounding box reference as defined in parameter loads[] in state-message.
loadDimensionsJSON-objectLoad dimensions as defined in parameter loads[] in state-message.
maxWeightfloat64[kg], maximum weight of loadtype.
minLoadhandlingHeightfloat64[m], minimum allowed height for handling of this load-type and –weight references to boundingBoxReference.
maxLoadhandlingHeightfloat64[m], maximum allowed height for handling of this load-type and –weight references to boundingBoxReference.
minLoadhandlingDepthfloat64[m], minimum allowed depth for this loadtype and –weight references to boundingBoxReference.
maxLoadhandlingDepthfloat64[m], maximum allowed depth for this loadtype and –weight references to boundingBoxReference.
minLoadhandlingTiltfloat64[rad], minimum allowed tilt for this load-type and –weight.
maxLoadhandlingTiltfloat64[rad], maximum allowed tilt for this load-type and –weight.
agvSpeedLimitfloat64[m/s], maximum allowed speed for this loadtype and –weight.
agvAccelerationLimitfloat64[m/s²], maximum allowed acceleration for this load-type and –weight.
agvDecelerationLimitfloat64[m/s²], maximum allowed deceleration for this load-type and –weight.
pickTimefloat64[s], approx. time for picking up the load
dropTimefloat64[s], approx. time for dropping the load.
descriptionstringFree-form text: description of the load handling set.
}

7 最佳实践

7.1 错误参考 Error reference

如果由于命令错误而发生错误,AGV 应在 errorReference 字段中返回有意义的错误参考(参见 6.10.6)。 这可以包括以下信息:
• headerId
• 主题(顺序或即时操作)
• orderId 和 orderUpdateId(如果错误是由命令更新引起的)。
• 如果错误是由某个操作引起的,则为 actionId。
• 如果错误是由错误的操作参数引起的,则参数列表

如果由于外部因素(例如预期位置无负载)而导致某个动作无法完成,则应引用actionId。

7.2 参数格式 Format of parameters

错误、信息、操作的参数被设计为具有键值对的 JSON 对象数组。 操作“someAction”的 actionParameter 示例,其中包含 stationType 和 loadType 的键值对:

"actionParameters":[
    {"key":"stationType", "value": "floor"},
    {"key": "loadType", "value": "pallet_eu"}
]

使用建议方案“key”:“actualKey”、“value”:“actualValue”的原因是为了保持实现的通用性。 这个问题在多次会议上进行了深入且有争议的讨论。

8 术语表

ConceptDescription
Free navigation AGVVehicles that use a map to plan their own path. The master control sends only start and destination coordinates. The vehicle sends its path to the master control. When the communication to the master control is broken off, the vehicle is able to continue its journey. Free-navigation vehicles may be allowed to bypass local obstacles. It may also be possible that a fine adjustment of the receiving/dispensing position by the vehicle itself is carried out.
使用地图来规划自己路线的车辆。主控只发送起始和目标坐标。车辆将其路径发送给主控。当与主控的通信中断时,车辆能够继续其行程。 自由导航车辆可能被允许绕过当地的障碍物。也可能由车辆本身对接收/分配位置进行精细调整。
Guided vehicles (physical or virtual)Vehicles that get their path sent by the master control. The calculation of the path takes place in the master control. When communication to the master control is broken off, the vehicle terminates its released nodes and edges (the “base”) and then stops. Guided vehicles may be allowed to bypass local obstacles. It may also be possible that a fine adjustment of the receiving/dispensing position by the vehicle itself is carried out.
由主控发送路径的车辆。路径的计算在主控中进行。当与主控的通信中断时,车辆将终止其释放的节点和边缘(“基础”),然后停止。 引导车辆可以绕过当地的障碍物。也可能由车辆本身对接收/分配位置进行精细调整。
Central mapThe maps that will be held centrally in the master control. This is initially created and then used. A future version of the interface will make it possible to transfer this map to the vehicles (e.g., for free navigation).
这些地图将被集中保存在主控中。这是最初创建的,然后使用。未来版本的界面将允许将这张地图传输给车辆(例如,为了自由导航)。

参考

1、VDA官网
2、协议–VDA5050
3、github–VDA5050
4、libVDA5050库
5、壹悟科技–通讯的视角看 VDA5050 协议
6、简述AGV通信接口标准-VDA5050

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

worthsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值