使用手册 - Simple:coder(路径编译器)机制详解:修订间差异
(创建页面,内容为“== 1.概念 == 路径编译是MDCS架构中一个重要概念,它是上位调度系统与下位车端系统之间的桥梁。路径编译发生在寻路完成之后,路径编译的操作对象是由“站点、路径、站点、路径......”构成的序列,路径编译的结果是一串AGV可以执行的命令脚本,该脚本对应车端SimpleAGVInterface里面定义的接口。 == 2.机制介绍 == 我们将编译器称为“coder”,实际业务…”) |
无编辑摘要 |
||
| 第13行: | 第13行: | ||
== 3.TemplateCoderSettings使用方法 == | == 3.TemplateCoderSettings使用方法 == | ||
=== 3.1 | === 3.1 CoderSettings中字段含义 === | ||
<code>TemplateTrackCoderSettings</code>和<code>TemplateSiteCoderSittings</code>是分别实现trackCoder和SiteCoder的[https://learn.microsoft.com/zh-cn/dotnet/csharp/advanced-topics/reflection-and-attributes/attribute-tutorial Attribute],通过在Simple工程中xxxCar.cs中小车类之前添加<code>TemplateTrackCoderSettings</code>和<code>TemplateSiteCoderSittings</code>定义站点编译器。下方DummyCar的示例,无条件地将所有路径编译为agv.Go()这一动作:<syntaxhighlight lang="c#" line="1"> | <code>TemplateTrackCoderSettings</code>和<code>TemplateSiteCoderSittings</code>是分别实现trackCoder和SiteCoder的[https://learn.microsoft.com/zh-cn/dotnet/csharp/advanced-topics/reflection-and-attributes/attribute-tutorial Attribute],通过在Simple工程中xxxCar.cs中小车类之前添加<code>TemplateTrackCoderSettings</code>和<code>TemplateSiteCoderSittings</code>定义站点编译器。下方DummyCar的示例,无条件地将所有路径编译为agv.Go()这一动作:<syntaxhighlight lang="c#" line="1"> | ||
class DummyCarTrackField | class DummyCarTrackField | ||
| 第66行: | 第66行: | ||
|触发后,若blockVerb为"true",则不再检查其他优先级更低的coder;若为"false",则继续检查剩余优先级更低的coder。默认为"false" | |触发后,若blockVerb为"true",则不再检查其他优先级更低的coder;若为"false",则继续检查剩余优先级更低的coder。默认为"false" | ||
|} | |} | ||
其中,<code>templateString</code>、<code>useVerb</code>、<code>blockVerb</code>都是字符串,通过[https://github.com/sebastienros/jint Jint]将字符串视为JavaScript代码,进行解析执行。 | |||
<code>templateString</code>、<code>useVerb</code>、<code>blockVerb</code>中可以使用如下定义好的对象。'''注意,<code>TemplateCoderSittings</code>中不可使用<code>src</code>这一字段,<code>dst</code>代表当前站点。''' | |||
{| class="wikitable" | |||
|+ | |||
!对象 | |||
!含义 | |||
! colspan="2" |包含字段 | |||
|- | |||
| rowspan="2" |car | |||
| rowspan="2" |当前plan所使用的小车 | |||
|car.id | |||
|小车id | |||
|- | |||
| colspan="2" |carFields中定义的其他字段 | |||
|- | |||
| rowspan="4" |src | |||
| rowspan="4" |路径起点 | |||
|src.id | |||
|起点的id | |||
|- | |||
|src.x | |||
|起点的x坐标 | |||
|- | |||
|src.y | |||
|起点的y坐标 | |||
|- | |||
| colspan="2" |siteFields中定义的其他字段 | |||
|- | |||
| rowspan="4" |dst | |||
| rowspan="4" |路径终点 | |||
|dst.id | |||
|终点的id | |||
|- | |||
|dst.x | |||
|终点的x坐标 | |||
|- | |||
|dst.y | |||
|终点的y坐标 | |||
|- | |||
| colspan="2" |siteFields中定义的其他字段 | |||
|- | |||
| rowspan="4" |plan | |||
| rowspan="4" |当前任务 | |||
|segN | |||
|任务总元素数 | |||
|- | |||
|curSeg | |||
|当前元素下标 | |||
|- | |||
|src | |||
|任务起点 | |||
|- | |||
|dst | |||
|任务终点 | |||
|- | |||
|prev | |||
|前一个segment,若无返回null | |||
| | |||
| | |||
|- | |||
|next | |||
|后一个segment,若无返回null | |||
| | |||
| | |||
|} | |||
<code>templateString</code>、<code>useVerb</code>、<code>blockVerb</code>中还预定义了如下方法: | |||
{| class="wikitable" | |||
|+ | |||
!'''方法''' | |||
!'''含义''' | |||
|- | |||
|getSite | |||
|返回指定id的站点 | |||
|- | |||
|getTrack | |||
|返回指定id的路径 | |||
|- | |||
|getCar | |||
|返回指定id的小车 | |||
|- | |||
|getSegment | |||
|返回指定下标的segment | |||
|} | |||
=== 3.2 编写自己的coderSitting === | |||
以最常见的取放货为例,首席需要将使用的字段定义在类中,站点字段定义在SiteFields类中,路径字段定义在TrackFields类中。 | |||
下述coder的执行条件为<code>plan.action=='put'&& dst.shelf</code>,即站点上标记了<code>shelf = true</code>字段,并且这是放货plan时,才会下发<code>templateString</code>中的脚本,并且站点及路径上标记的响应字段的值也会跟随脚本下发。<syntaxhighlight lang="c#" line="1"> | |||
class SiteFields | |||
{ | |||
public bool shelf = false; | |||
public int obArea = -1; | |||
public int ASNub = -1; | |||
public float angle = 0; | |||
public float shelfWidth = 1030; | |||
public float distance = 500; | |||
} | |||
[TemplateTrackCoderSettings( | |||
priority = 5, | |||
useVerb = "plan.action=='put' && dst.shelf ", | |||
templateString = "agv.Wait();agv.Put(${dst.ASNub},${dst.shelfWidth},${dst.obArea},${src.x},${src.y},${src.id},${dst.x},${dst.y},${dst.id},${track.id},${track.speed},${dst.reverse},${dst.xbias},${dst.ybias},${dst.angle},${dst.distance});agv.Wait();", | |||
blockVerb = "true", | |||
siteFields = typeof(SiteFields), | |||
trackFields = typeof(TrackFields), | |||
planFields = typeof(PlanField))] | |||
</syntaxhighlight> | |||
=== 3.3 simple内置的coder === | |||
所有的小车类均继承了车体抽象类<code>AbstractCar</code>,抽象类中定义了如下几个coder: | |||
队列动作。在站点的codeQueue字段上定义脚本,在该站点发生路径切换时执行。<syntaxhighlight lang="c#" line="1"> | |||
[TemplateSiteCoderSettings(priority = 100, | |||
useVerb = "dst.codeQueue!=null", | |||
templateString = "agv.Queue(()=>{},()=>{${dst.codeQueue}});", | |||
blockVerb = "true", | |||
siteFields = typeof(StandardSiteFields))] | |||
</syntaxhighlight>到达动作。在站点的codeArrive字段上定义AGV脚本,在AGV达到该站点发时(完全停车后)执行。<syntaxhighlight lang="c#" line="1"> | |||
[TemplateSiteCoderSettings(priority = 100, | |||
useVerb = "dst.codeArrive!=null && plan.curSeg!=0", | |||
templateString = "agv.Wait(); ${dst.codeArrive};", | |||
siteFields = typeof(StandardSiteFields))] | |||
</syntaxhighlight>离开动作。在站点的codeLeave字段上定义AGV脚本,在AGV从该站点离开之前执行。<syntaxhighlight lang="c#" line="1"> | |||
[TemplateSiteCoderSettings(priority = 100, | |||
useVerb = "dst.codeLeave!=null && plan.curSeg!=plan.segN-1", | |||
templateString = "agv.Wait(); ${dst.codeLeave};", | |||
siteFields = typeof(StandardSiteFields))] | |||
</syntaxhighlight>空路径。即指定某段路径不执行具体动作(相当于直接跳过)。<syntaxhighlight lang="c#" line="1"> | |||
[TemplateTrackCoderSettings( | |||
priority = 100, | |||
siteFields = typeof(StandardSiteFields), | |||
useVerb = "track.nop && (track.nopDst==-1 || track.nopDst==dst.id)", | |||
blockVerb = "true", | |||
templateString = "agv.Nop(${src.id},${dst.id},${track.id});", | |||
trackFields = typeof(StandardTrackFields))] | |||
</syntaxhighlight>切换动作。在站点的switchString字段上定义脚本,在该站点发生路径切换时执行。一般用于进行障碍物切换。<syntaxhighlight lang="c#" line="1"> | |||
[TemplateTrackCoderSettings( | |||
priority = 20, | |||
useVerb = "track.switcher", | |||
templateString = "agv.Queue(()=>{}, ()=>{${dst.switchString};});", | |||
siteFields = typeof(StandardSiteFields), | |||
trackFields = typeof(StandardTrackFields))] | |||
</syntaxhighlight> | |||
2023年10月26日 (四) 11:09的版本
1.概念
路径编译是MDCS架构中一个重要概念,它是上位调度系统与下位车端系统之间的桥梁。路径编译发生在寻路完成之后,路径编译的操作对象是由“站点、路径、站点、路径......”构成的序列,路径编译的结果是一串AGV可以执行的命令脚本,该脚本对应车端SimpleAGVInterface里面定义的接口。
2.机制介绍
我们将编译器称为“coder”,实际业务中,整个编译逻辑是由若干的coder构成的。也就是说,coder在同一个站点或者可以叠加使用。处理路径的,称为trackCoder;处理站点的,称为siteCoder。定义好某个车型的所有coder,就完成了该车型的业务层面的所有行为定义(即,在什么路径/站点上触发什么样的行为)。下面用一个具体的例子详细解释coder运行的机制。
我们将“小车从A到B”的过程称为一个“plan”。如上图所示,假设已经生成了`模拟车1`的一段plan。该plan包含6个site(站点)、5段track(路径),共11个segment。编译路径时,依据通行顺序检查所有segment。对于每一个segment,若它是站点,则检查所有的siteCoder;若它是路径,则检查所有的路径trackCoder。对于每一个被检查的coder,依次判断其是否能够触发,触发后生成AGV脚本,并判断是否继续检查剩余的coder。如下图所示,为车辆执行的脚本。
3.TemplateCoderSettings使用方法
3.1 CoderSettings中字段含义
TemplateTrackCoderSettings和TemplateSiteCoderSittings是分别实现trackCoder和SiteCoder的Attribute,通过在Simple工程中xxxCar.cs中小车类之前添加TemplateTrackCoderSettings和TemplateSiteCoderSittings定义站点编译器。下方DummyCar的示例,无条件地将所有路径编译为agv.Go()这一动作:
class DummyCarTrackField
{
public int speed = -1;
public bool reverse = false;
public int reverseDst = -1;
}
[TemplateTrackCoderSettings(
templateString = "agv.Go(${src.x},${src.y},${src.id},${dst.x},${dst.y},${dst.id},${track.id},${track.speed},${track.reverse || track.reverseDst == dst.id});",
priority = 0,
trackFields = typeof(DummyCarTrackField),
useVerb = "true",
blck)]
[CarType("模拟车")]
public class DummyCar : Car
CoderSitting中包含以下字段:
| 字段 | 类型 | 含义 |
|---|---|---|
| templateString | string | 编译后执行的命令 |
| priority | int | 优先级,数值越大越先被检查 |
| siteFields | Type | 定义站点字段的类的Type |
| trackFields | Type | 定义路径字段的类的Type |
| planFields | Type | 定义车辆字段的类的Type |
| useVerb | string | 触发条件。默认为"true" |
| blockVerb | string | 触发后,若blockVerb为"true",则不再检查其他优先级更低的coder;若为"false",则继续检查剩余优先级更低的coder。默认为"false" |
其中,templateString、useVerb、blockVerb都是字符串,通过Jint将字符串视为JavaScript代码,进行解析执行。
templateString、useVerb、blockVerb中可以使用如下定义好的对象。注意,TemplateCoderSittings中不可使用src这一字段,dst代表当前站点。
| 对象 | 含义 | 包含字段 | |
|---|---|---|---|
| car | 当前plan所使用的小车 | car.id | 小车id |
| carFields中定义的其他字段 | |||
| src | 路径起点 | src.id | 起点的id |
| src.x | 起点的x坐标 | ||
| src.y | 起点的y坐标 | ||
| siteFields中定义的其他字段 | |||
| dst | 路径终点 | dst.id | 终点的id |
| dst.x | 终点的x坐标 | ||
| dst.y | 终点的y坐标 | ||
| siteFields中定义的其他字段 | |||
| plan | 当前任务 | segN | 任务总元素数 |
| curSeg | 当前元素下标 | ||
| src | 任务起点 | ||
| dst | 任务终点 | ||
| prev | 前一个segment,若无返回null | ||
| next | 后一个segment,若无返回null | ||
templateString、useVerb、blockVerb中还预定义了如下方法:
| 方法 | 含义 |
|---|---|
| getSite | 返回指定id的站点 |
| getTrack | 返回指定id的路径 |
| getCar | 返回指定id的小车 |
| getSegment | 返回指定下标的segment |
3.2 编写自己的coderSitting
以最常见的取放货为例,首席需要将使用的字段定义在类中,站点字段定义在SiteFields类中,路径字段定义在TrackFields类中。
下述coder的执行条件为plan.action=='put'&& dst.shelf,即站点上标记了shelf = true字段,并且这是放货plan时,才会下发templateString中的脚本,并且站点及路径上标记的响应字段的值也会跟随脚本下发。
class SiteFields
{
public bool shelf = false;
public int obArea = -1;
public int ASNub = -1;
public float angle = 0;
public float shelfWidth = 1030;
public float distance = 500;
}
[TemplateTrackCoderSettings(
priority = 5,
useVerb = "plan.action=='put' && dst.shelf ",
templateString = "agv.Wait();agv.Put(${dst.ASNub},${dst.shelfWidth},${dst.obArea},${src.x},${src.y},${src.id},${dst.x},${dst.y},${dst.id},${track.id},${track.speed},${dst.reverse},${dst.xbias},${dst.ybias},${dst.angle},${dst.distance});agv.Wait();",
blockVerb = "true",
siteFields = typeof(SiteFields),
trackFields = typeof(TrackFields),
planFields = typeof(PlanField))]
3.3 simple内置的coder
所有的小车类均继承了车体抽象类AbstractCar,抽象类中定义了如下几个coder:
队列动作。在站点的codeQueue字段上定义脚本,在该站点发生路径切换时执行。
[TemplateSiteCoderSettings(priority = 100,
useVerb = "dst.codeQueue!=null",
templateString = "agv.Queue(()=>{},()=>{${dst.codeQueue}});",
blockVerb = "true",
siteFields = typeof(StandardSiteFields))]
到达动作。在站点的codeArrive字段上定义AGV脚本,在AGV达到该站点发时(完全停车后)执行。
[TemplateSiteCoderSettings(priority = 100,
useVerb = "dst.codeArrive!=null && plan.curSeg!=0",
templateString = "agv.Wait(); ${dst.codeArrive};",
siteFields = typeof(StandardSiteFields))]
离开动作。在站点的codeLeave字段上定义AGV脚本,在AGV从该站点离开之前执行。
[TemplateSiteCoderSettings(priority = 100,
useVerb = "dst.codeLeave!=null && plan.curSeg!=plan.segN-1",
templateString = "agv.Wait(); ${dst.codeLeave};",
siteFields = typeof(StandardSiteFields))]
空路径。即指定某段路径不执行具体动作(相当于直接跳过)。
[TemplateTrackCoderSettings(
priority = 100,
siteFields = typeof(StandardSiteFields),
useVerb = "track.nop && (track.nopDst==-1 || track.nopDst==dst.id)",
blockVerb = "true",
templateString = "agv.Nop(${src.id},${dst.id},${track.id});",
trackFields = typeof(StandardTrackFields))]
切换动作。在站点的switchString字段上定义脚本,在该站点发生路径切换时执行。一般用于进行障碍物切换。
[TemplateTrackCoderSettings(
priority = 20,
useVerb = "track.switcher",
templateString = "agv.Queue(()=>{}, ()=>{${dst.switchString};});",
siteFields = typeof(StandardSiteFields),
trackFields = typeof(StandardTrackFields))]