<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E</id>
	<title>使用手册 - MDCS适配详细说明 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E"/>
	<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;action=history"/>
	<updated>2026-04-15T16:07:43Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;diff=561&amp;oldid=prev</id>
		<title>Artheru：​/* 三，Detour 建图方法 */</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;diff=561&amp;oldid=prev"/>
		<updated>2024-05-15T08:29:09Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;三，Detour 建图方法&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2024年5月15日 (三) 16:29的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l197&quot;&gt;第197行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第197行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;===== 三，Detour 建图方法 =====&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;===== 三，Detour 建图方法 =====&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;请参考示范协议以及说明\&lt;/del&gt;MDCS 建图和路线绘制.pdf&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;[[文件:MDCS建图和路线绘制.pdf|缩略图|0x0像素]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;===== &lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;请参考 [[:文件:MDCS建图和路线绘制.pdf|&lt;/ins&gt;MDCS 建图和路线绘制.pdf&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;nowiki&amp;gt;=====四，Detour 定位接口 =====&amp;lt;/nowiki&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;nowiki&amp;gt;=====四，Detour 定位接口 =====&amp;lt;/nowiki&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Artheru</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;diff=469&amp;oldid=prev</id>
		<title>Cola ding：​/* = */</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;diff=469&amp;oldid=prev"/>
		<updated>2023-12-15T06:05:10Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年12月15日 (五) 14:05的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l199&quot;&gt;第199行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第199行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;请参考示范协议以及说明\MDCS 建图和路线绘制.pdf&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;请参考示范协议以及说明\MDCS 建图和路线绘制.pdf&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=====  &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=====  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;四，Detour 定位接口 =====&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;nowiki&amp;gt;=====&lt;/ins&gt;四，Detour 定位接口 =====&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/nowiki&amp;gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;1，暂停 Detour 地图匹配功能&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;1，暂停 Detour 地图匹配功能&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;1.1 此功能主要用于，特殊位置由于变化比较大，防止带飞小车定位，我们在小车不运动的&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;1.1 此功能主要用于，特殊位置由于变化比较大，防止带飞小车定位，我们在小车不运动的&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;diff=468&amp;oldid=prev</id>
		<title>Cola ding：​创建页面，内容为“==== 一、介绍 ==== MDCS（Medulla,Detour,Clumsy ,Simple ）是一套完整的 AGV（Automated Guided Vehicle）小车自动驾驶模型与控制架构，它由以下 4 个软件组成：  Medulla：硬件适配软件，针对不同的硬件进行通讯以及驱动适配；  Detour：AGV 导航定位软件，可以进行 SLAM、二维码或 UWB 定位等；  Clumsy：自动驾驶软件，定义了 AGV 的基本动作单元，例如转向/差动驱…”</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_MDCS%E9%80%82%E9%85%8D%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E&amp;diff=468&amp;oldid=prev"/>
		<updated>2023-12-15T06:04:25Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“==== 一、介绍 ==== MDCS（Medulla,Detour,Clumsy ,Simple ）是一套完整的 AGV（Automated Guided Vehicle）小车自动驾驶模型与控制架构，它由以下 4 个软件组成：  Medulla：硬件适配软件，针对不同的硬件进行通讯以及驱动适配；  Detour：AGV 导航定位软件，可以进行 SLAM、二维码或 UWB 定位等；  Clumsy：自动驾驶软件，定义了 AGV 的基本动作单元，例如转向/差动驱…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==== 一、介绍 ====&lt;br /&gt;
MDCS（Medulla,Detour,Clumsy ,Simple ）是一套完整的 AGV（Automated Guided&lt;br /&gt;
Vehicle）小车自动驾驶模型与控制架构，它由以下 4 个软件组成：&lt;br /&gt;
 Medulla：硬件适配软件，针对不同的硬件进行通讯以及驱动适配；&lt;br /&gt;
 Detour：AGV 导航定位软件，可以进行 SLAM、二维码或 UWB 定位等；&lt;br /&gt;
 Clumsy：自动驾驶软件，定义了 AGV 的基本动作单元，例如转向/差动驱动控制，以&lt;br /&gt;
及取放料等动作；&lt;br /&gt;
 Simple：AGV 调度软件，进行多车的任务调度和路径规划。&lt;br /&gt;
请按照以下步骤进行适配：&lt;br /&gt;
 ==== 第一步，适配底盘--Medulla ====&lt;br /&gt;
一，根据通讯协议，我们先了解该车具备哪些硬件?&lt;br /&gt;
本适配工程硬件如下：IO 模块(modbus Tcp),电机驱动(can 总线),电池（串口 485）&lt;br /&gt;
&lt;br /&gt;
====二、工程的组成 ====&lt;br /&gt;
工程的组成主要有：设备定义类为{proName}Cart.cs 还有其他 3 种主要的外设类，采用轮询&lt;br /&gt;
方式，分别控制 IO、电机、音乐和电池。命名为 IORoutine,MotorRoutine 和 MusicRoutine 和&lt;br /&gt;
BatteryRoutine，周期可以根据设备要求进行配置。&lt;br /&gt;
//梯形图逻辑，scanInterval 为扫描周期&lt;br /&gt;
[UseLadderLogic(logic = typeof(MotorRoutine), scanInterval = 20)]&lt;br /&gt;
[UseLadderLogic(logic = typeof(IORoutine), scanInterval = 100)]&lt;br /&gt;
[UseLadderLogic(logic = typeof(BatteryRoutine), scanInterval = 1000)]&lt;br /&gt;
[UseLadderLogic(logic = typeof(MusicLightRoutine), scanInterval = 100)]&lt;br /&gt;
&lt;br /&gt;
===== 三、基本概念 =====&lt;br /&gt;
AsUpperIO:指 Clumsy 或遥控器等指定的属性，如下发速度，角度，避障区域等&lt;br /&gt;
AsLowerIO:指从硬件读取的信号属性，如按钮，灯光，音乐，编码器值等&lt;br /&gt;
IOObjectMonitor:用于界面显示供监控的变量&lt;br /&gt;
&lt;br /&gt;
===== 四 、进入适配 =====&lt;br /&gt;
了解以上概念，我们开始进入适配：&lt;br /&gt;
===== '''1,定义基础变量''' =====&lt;br /&gt;
分为与 Clumsy 交互的变量，IO 硬件控制的输入输出变量，编码器变量，通讯硬件变量，报&lt;br /&gt;
警变量，需要显示或中转使用的变量，具体可以根据项目协议表进行编写，如下：&lt;br /&gt;
[AsUpperIO(desc = &amp;quot;下发速度(0-1000)&amp;quot;, timeOutReset= true)] public float velocity;&lt;br /&gt;
[AsUpperIO(desc = &amp;quot;下发方向盘角度&amp;quot;, timeOutReset = true)] public float theta;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;实际方向盘角度&amp;quot;)] public float actualTh;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;实际速度&amp;quot;)] public float actualV;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;举升控制&amp;quot;)] public int lift=0;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;货叉高度控制&amp;quot;)] public int liftHeight;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;启动&amp;quot;)] public int start;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;停止&amp;quot;)] public int stop;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;复位&amp;quot;)] public int reset;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;急停&amp;quot;)] public int emergencyStop;&lt;br /&gt;
&lt;br /&gt;
 ===== '''2，适配 IO 类''' =====&lt;br /&gt;
2.1 根据协议，此处我们使用 Modbus TCP 协议，驱动已经写好 ，直接&lt;br /&gt;
使用即可，首先初始化 ModbusTCP 服务，在 IORoutine 中进行编写,如下图&lt;br /&gt;
ModbusTCP mtcp = new ModbusTCP();&lt;br /&gt;
mtcp.start(&amp;quot;192.168.127.1&amp;quot;,502);//初始化 ModbusTCP 服务&lt;br /&gt;
2.2 初始化服务后，我们开始具体 IO 变量的读取和赋值。&lt;br /&gt;
var read = mtcp.registerBuffer(1, 0x0000, 1);//站号 起始地址 读取长度&lt;br /&gt;
var readData = read[0];&lt;br /&gt;
cart.start= readData &amp;gt;&amp;gt; 0 == 1 ? 1 : 0;&lt;br /&gt;
cart.stop= readData &amp;gt;&amp;gt; 1 == 1 ? 1 : 0;&lt;br /&gt;
........ 2.3 将所有 IO 适配后进行测试看读取和写入是否正确，然后我们进入下一步&lt;br /&gt;
&lt;br /&gt;
===== '''3，适配电机驱动--重要''' =====&lt;br /&gt;
3.1 根据 CAN 协议，确认电机控制方法，此项目协议如下示范协议\CAN 协议.xlsxx，在&lt;br /&gt;
MotorRoutine 中进行编写。&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw1.png]]&lt;br /&gt;
&lt;br /&gt;
3.2 根据协议，将速度以及角度通过报文下发给驱动器&lt;br /&gt;
public ZLGCAN can = new ZLGCAN();&lt;br /&gt;
public override void Operation()&lt;br /&gt;
{&lt;br /&gt;
var sendV = cart.velocity;&lt;br /&gt;
var sendTh = cart.theta;&lt;br /&gt;
can.sendMessage1(0x1a6, new byte[8]&lt;br /&gt;
{&lt;br /&gt;
(byte) (sendV &amp;gt; 0 ? 0x3 : 0x5), 0,&lt;br /&gt;
(byte) sendV,&lt;br /&gt;
(byte) (((int) sendTh * 10) &amp;amp; 0xff), (byte) (((int) -sendTh * 10) &amp;gt;&amp;gt; 8),&lt;br /&gt;
10, 10, 255&lt;br /&gt;
});&lt;br /&gt;
if (can.canRecv.TryGetValue(0x226, out var tup1))&lt;br /&gt;
{&lt;br /&gt;
cart.actualV = BitConverter.ToInt16(tup1.Item1, 2);&lt;br /&gt;
cart.actualTh = -BitConverter.ToInt16(tup1.Item1, 4) * 0.01f;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
3.3 这一步完成了，我们就可以初步进行小车行走测试，通过 medulla 遥控器，在&lt;br /&gt;
SteerWheelCart 里面配置&lt;br /&gt;
//设置 MedullaAPI，使得 clumsy 等系统可以直接设置 IO 变量&lt;br /&gt;
[UseMedullaAPI(name = &amp;quot;move&amp;quot;, UpperIOs = new[] {nameof(velocity), nameof(theta) })]&lt;br /&gt;
这时候我们要进行关键的一步，见文档示范协议\MDCS 部署程序配置.pdf 看 medulla 配置即&lt;br /&gt;
可&lt;br /&gt;
我们需要保证，下发-90° 驱动器实际反馈也是-90,并且实际舵轮转向也是左转 90°,下发线&lt;br /&gt;
速度，反馈的速度也应该和下发一致。&lt;br /&gt;
到这里 Medulla 的主要工作已经完成了，我们继续下面的其他硬件适配！&lt;br /&gt;
&lt;br /&gt;
===== '''4，适配电池''' =====&lt;br /&gt;
4.1 此处我们使用了 485 通讯，因此我们要实例化 SerialPort，并且调用我们写的初始化串口&lt;br /&gt;
方法，传入需要开启的端口以及端口波特率&lt;br /&gt;
public static SerialPort serialPort;&lt;br /&gt;
initSerialPort(&amp;quot;COM1&amp;quot;, 9600);//初始化 COM1 端口，波特率 9600&lt;br /&gt;
4.2，端口打开后，我们就根据具体的电池协议进行报文的发送和读取了-协议&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw2.png]]&lt;br /&gt;
&lt;br /&gt;
4.3 如下图 根据协议，我们获取电池电压和电量&lt;br /&gt;
byte[] ToReadBytes = new byte[8] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x23, 0x04, 0x13 };&lt;br /&gt;
if (serialPort.IsOpen)&lt;br /&gt;
{&lt;br /&gt;
serialPort.BaseStream.Write(ToReadBytes, 0, ToReadBytes.Length);//写数据&lt;br /&gt;
byte[] respLine = stringToHex(serialPort.ReadLine());&lt;br /&gt;
if (respLine.Length &amp;lt; 20)&lt;br /&gt;
throw new Exception($&amp;quot;wrong ER response: {respLine}&amp;quot;);&lt;br /&gt;
cart.voltage = (respLine[1] &amp;amp; 0xFF) &amp;lt;&amp;lt; 8 | respLine[0];//电压&lt;br /&gt;
cart.soc = respLine[13];//电量&lt;br /&gt;
}&lt;br /&gt;
至此，电池就适配好了，我们继续下一步，声光以及按钮的逻辑编写&lt;br /&gt;
&lt;br /&gt;
===== 5，声光按钮 =====&lt;br /&gt;
5.1 我们将声光报警分成这几个，然后我们针对这些模式，赋予不同的灯光以及音乐即可&lt;br /&gt;
var mode = 0;&lt;br /&gt;
if (cart.velocity != 0)&lt;br /&gt;
mode = 1;//运动状态模式 1&lt;br /&gt;
if (cart.soc &amp;lt; 25)&lt;br /&gt;
mode = 2;//低电压模式 2&lt;br /&gt;
if (cart.obstacleStop1==1 )&lt;br /&gt;
mode = 3;//近避障模式 3&lt;br /&gt;
if (cart.IsFault() || cart.com_can1 != 0 || cart.com_can2 != 0)&lt;br /&gt;
mode = 4;//报警模式 4&lt;br /&gt;
if (cart.lightFlash)&lt;br /&gt;
mode = 5;//声光报警模式 5&lt;br /&gt;
5.2 我们根据小车运动状态，将按钮逻辑写进程序里，保证按下启动按钮后，小车可以进行&lt;br /&gt;
移动，复位按钮可以复位报警或状态，停止或急停按钮可以停止小车，并且将报警状态显示&lt;br /&gt;
在监控画面，具体可参考代码。&lt;br /&gt;
&lt;br /&gt;
===== 6，雷达数据的测试 =====&lt;br /&gt;
可参考示范协议以及说明\MDCS 部署程序配置.pdf，其他品牌雷达的驱动程序可以找我们&lt;br /&gt;
要，目前市面大部分雷达都已有适配驱动。&lt;br /&gt;
至此，我们 Medulla 部分完成，进入下一部分，Detour 的使用&lt;br /&gt;
&lt;br /&gt;
=== 第二步，使用 Detour 定位软件-单线雷达 ===&lt;br /&gt;
&lt;br /&gt;
==== 一、Detour 基础知识 ====&lt;br /&gt;
===== 1、Detour-车体编辑器 =====&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念 3-1-1 车体编辑器，是一个用于编辑车体模型，激光参数的配置工具。&lt;br /&gt;
概念 3-1-1 车体编辑器-单线雷达位置(x,y,th)，表示雷达相对驱动中心位置，mm 单位。&lt;br /&gt;
概念 3-1-2 车体编辑器-单线雷达角度方向(angleSgn：±1)，表示雷达角度方向，如雷达倒&lt;br /&gt;
装情况。&lt;br /&gt;
概念 3-1-1 车体编辑器-单线雷达起始角度(rangeStartAngle)，表示雷达开始扫描的角度值。&lt;br /&gt;
概念 3-1-2 车体编辑器-单线雷达结束角度(rangeEndAngle)，表示雷达结束扫描的角度值。&lt;br /&gt;
概念 3-1-3 车体编辑器-单线雷达扫描开始距离(ignoreDist)，用于屏蔽激光周围杂点或车体&lt;br /&gt;
部分垃圾数据，mm 单位。&lt;br /&gt;
概念 3-1-4 车体编辑器-单线雷达最大扫描距离(maxDist)，表示雷达扫描最大半径，mm 单&lt;br /&gt;
位。&lt;br /&gt;
1.1 如果我们有其他外设，均可在添加中添加并且配置&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw4.png]]&lt;br /&gt;
&lt;br /&gt;
===== 2，Detour-detour.json 常用参数配置 =====&lt;br /&gt;
2.1 我们先打开 Detour 软件，然后界面左上角，导航配置，选择保存到 Detour 文件夹下，&lt;br /&gt;
命名 detour 即可，会保存一个 json 配置文件，里面存储了 Detour 初始的参数，有些我们需&lt;br /&gt;
要设置下会方便调试如下&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw5.png]]&lt;br /&gt;
&lt;br /&gt;
2.2 具体常用的 配置参数如下，我们先打开 detour.json 文件（右击记事本打开）&lt;br /&gt;
&amp;quot;recordLastPos&amp;quot;: true, //代表自动记录上一个位置信息，可以用于断电后或 detour 关闭后，&lt;br /&gt;
再次打开 detour 会自动定位小车断电前的或关闭前记录的位置信息，可以省去重复的手动&lt;br /&gt;
定位操作&lt;br /&gt;
&amp;quot;autoStart&amp;quot;: true,//表示打开软件是否自动启动激光，代替如下图按钮&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw6.png]]&lt;br /&gt;
&lt;br /&gt;
==== 二，Detour 基础设置 ====&lt;br /&gt;
===== 1、车体绘制 =====&lt;br /&gt;
为什么要进行车体绘制？&lt;br /&gt;
过滤车体部分的激光数据，以免影响后期建图&lt;br /&gt;
1.1 我们打开 Detour-概览-车体布局-选择默认车体边框，如果为红色说明选中，如下&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw7.png]]&lt;br /&gt;
&lt;br /&gt;
2，我们选择重绘值轮廓，在车体编辑器右上角，双击，然后我们我们根据车体大小 绘制出&lt;br /&gt;
车体轮廓即可，下图由于离线，所以无法看到激光数据，正常是可以看到激光数据的，我们&lt;br /&gt;
尽量让激光车体周围没有杂点即可。&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw8.png]]&lt;br /&gt;
&lt;br /&gt;
===== 3，激光参数 =====&lt;br /&gt;
3.1 完成车体绘制后，我们选中激光，右侧会刷新出属性，我们需要修改的主要是 xyth 参数，&lt;br /&gt;
以及 angleSgn 用于指示激光雷达扫描方向，1 为逆时针扫描，-1 为顺时针扫描。endAngle，&lt;br /&gt;
为激光雷达扫描的最后一个点的角度。这两个参数必须配置，常见的雷达配置如&lt;br /&gt;
下：&lt;br /&gt;
1. 倍加福、万集、科力、西克 Nano 系列雷达， angleSgn=1, endAngle=180&lt;br /&gt;
2. 星秒雷达：angleSgn=1，endAngle=0&lt;br /&gt;
3. 西克 LMS 系列雷达，angleSgn=1, endAngle=270&lt;br /&gt;
3.2 激光物体参数填写完成后，我们需要对激光再次进行二次标定，这个标定是用来修正机&lt;br /&gt;
械安装误差&lt;br /&gt;
&lt;br /&gt;
===== 三，Detour 建图方法 =====&lt;br /&gt;
请参考示范协议以及说明\MDCS 建图和路线绘制.pdf&lt;br /&gt;
===== &lt;br /&gt;
四，Detour 定位接口 =====&lt;br /&gt;
1，暂停 Detour 地图匹配功能&lt;br /&gt;
1.1 此功能主要用于，特殊位置由于变化比较大，防止带飞小车定位，我们在小车不运动的&lt;br /&gt;
时候关闭实时匹配功能。&lt;br /&gt;
http://{ip}:4321/switchPosMatch?disabled=true //true 是关闭匹配，false 是打开&lt;br /&gt;
2，重定位&lt;br /&gt;
2.1 此工主要用于现场加入丢失定位，现场人员不会操作 AGV，可以把小车开到复位点，通&lt;br /&gt;
过按钮或者触摸屏进行该点重定位。&lt;br /&gt;
http://{ip}:4321/setLocation?x=11&amp;amp;y=22&amp;amp;th=33&lt;br /&gt;
&lt;br /&gt;
=== 第三步，适配自动驾驶系统--Clumsy ===&lt;br /&gt;
&lt;br /&gt;
Clumsy 是小车的运动控制组件。开发者需要做的是：底盘性能测试，定义运动控制的输入&lt;br /&gt;
输出变量、定义参数表、定义动作、定义动作测试例程，并提供调度接口。 &lt;br /&gt;
===== 一，部署 Clumsy 以及测试优化底盘性能 =====&lt;br /&gt;
1,部署 Clumsy 请参考示范协议以及说明\MDCS 部署程序配置.pdf-Clumsy 配置&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 二，车型定义 =====&lt;br /&gt;
===== 1 定义车型 =====&lt;br /&gt;
1.1 首先我们在{proName}Def.cs 文件中，因为底盘是单舵轮，所以定义 SwSteering 类，并且&lt;br /&gt;
继承 SteeringWriterClass，然后重写 WriteSteering 方法获取算法速度&lt;br /&gt;
public override void WriteSteering(float angle, float velocity)//重写 WriteSteering 获取&lt;br /&gt;
算法速度&lt;br /&gt;
{&lt;br /&gt;
SWDef.self.velocity = velocity;&lt;br /&gt;
SWDef.self.th = angle;&lt;br /&gt;
}&lt;br /&gt;
1.2 车型定义文件还需要重写 Init 方法，这个方法会在 Clumsy 启动时调用。&lt;br /&gt;
public override void Init()&lt;br /&gt;
{&lt;br /&gt;
self = this;设置 self=this，//使得其它类可以访问 SWDef 的实例&lt;br /&gt;
ClumsyLib.Capture();//调用 ClumsyLib.Capture();从而启动 Clumsy 的传感器采集功能&lt;br /&gt;
}&lt;br /&gt;
1.3 此外还需要重写 DriveStop 方法。&lt;br /&gt;
public override void DriveStop()&lt;br /&gt;
{&lt;br /&gt;
velocity = 0;&lt;br /&gt;
th = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
===== 2  定义与 Medulla 交互的变量 =====&lt;br /&gt;
&lt;br /&gt;
2.1 MedullaAdapter 工程中设备定义类 SWDefCart.cs 中摘抄标记了 AsUpperIO 和 AsLowerIO&lt;br /&gt;
的字段。这些字段中，AsLowerIO 字段会自动更新，AsUpperIO 字段会自动下发,因此我们将&lt;br /&gt;
需要交互的变量复制过来即可。&lt;br /&gt;
public static SWDef self;&lt;br /&gt;
public static MedullaInterface mInterface = new MedullaInterface();&lt;br /&gt;
[AsUpperIO(desc = &amp;quot;下发速度(0-1000)&amp;quot;, timeOutReset = true)] public float velocity;&lt;br /&gt;
[AsUpperIO(desc = &amp;quot;下发方向盘角度&amp;quot;, timeOutReset = true)] public float th;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;实际方向盘角度&amp;quot;)] public float actualTh;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;实际速度&amp;quot;)] public float actualV;&lt;br /&gt;
[AsUpperIO(desc = &amp;quot;货叉移动方向&amp;quot;)] public int lift;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;电池充电接触器&amp;quot;)] public int chargeContactor;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;货叉位置&amp;quot;)] public int liftPos;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;货叉位置&amp;quot;)] public bool getItem;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;举升目标位置&amp;quot;)] public int liftTarget;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;障碍物减速区，为 0 时减速&amp;quot;)] public int obstacleRetard;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;障碍物停止区 1，为 0 时停止&amp;quot;)] public int obstacleStop1;&lt;br /&gt;
[AsLowerIO(desc = &amp;quot;障碍物停止区 2，为 0 时停止&amp;quot;)] public int obstacleStop2;&lt;br /&gt;
这部分完成后，我们就开始进行自动功能的测试&lt;br /&gt;
&lt;br /&gt;
===== 三 定义动作 =====&lt;br /&gt;
1，定义一个货叉举升下降的动作&lt;br /&gt;
动作我们定义在 Movement.cs 文件里面，里面已有一些常用的动作，我们先从简单的开始：&lt;br /&gt;
1.1，货叉举升的动作使用 MovementDefinition 来定义。该类的 Get 方法应是一个 Generator&lt;br /&gt;
函数，通过 yield return true 来表示动 作计算完毕待下发，释放 CPU 资源并等到下一个周期&lt;br /&gt;
再继续计算动作。这种方法可以使得动作编排足够紧凑，不需要复杂的状态机设计即可完成&lt;br /&gt;
复杂的动作序列。通过 Get()方法返回一个 IEnumerable &amp;lt;bool&amp;gt; 对象后，可产生一个 DriveTask&lt;br /&gt;
类进行动作执行。例子如下：&lt;br /&gt;
class LiftFork : MovementDefinition&lt;br /&gt;
{&lt;br /&gt;
public int liftTarget = 0;&lt;br /&gt;
public int liftStatu = 0;&lt;br /&gt;
public override IEnumerable&amp;lt;bool&amp;gt; Get()&lt;br /&gt;
{&lt;br /&gt;
Console.WriteLine($&amp;quot;Start lifting to {liftTarget}&amp;quot;);&lt;br /&gt;
SWDef.self.liftTarget = liftTarget;&lt;br /&gt;
//根据货叉目标位置判断提升还是下降，并且记忆其状态&lt;br /&gt;
if (SWDef.self.liftPos &amp;lt; SWDef.self.liftTarget) { SWDef.self.lift = 1;&lt;br /&gt;
liftStatu = 1; }&lt;br /&gt;
else if (SWDef.self.liftPos &amp;gt;= SWDef.self.liftTarget) { SWDef.self.lift = -1;&lt;br /&gt;
liftStatu = -1; }&lt;br /&gt;
//如果目标位置和当前位置在 10mm 以内，循环跳出&lt;br /&gt;
while (Math.Abs(SWDef.self.liftPos - liftTarget) &amp;gt; 10)&lt;br /&gt;
yield return true;&lt;br /&gt;
SWDef.self.lift = 0;//货叉动作使能关闭&lt;br /&gt;
SWDef.self.liftPos = liftStatu;//给定到位状态&lt;br /&gt;
Thread.Sleep(500);&lt;br /&gt;
Console.WriteLine($&amp;quot;Done lifting to {liftTarget}&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
1.2 以上我们一个货叉的动作就写好了，下面我们进行这个动作的测试&lt;br /&gt;
&lt;br /&gt;
===== 四 定义动作测试例程 =====&lt;br /&gt;
1，定义一个动作测试的流程&lt;br /&gt;
1.1 我们定义一个 ForkTest 类，继承 MovementTest，动作分为开始测试和停止，我们重写&lt;br /&gt;
TestStop 以及 Test 方法，Test 中我们先调出 UI 供输入货叉提升高度值，然后新建一个 DriveTask&lt;br /&gt;
任务，排列到任务中，进行执行，等到 LiftFork 中的 Get 方法完成返回 true ，任务结束。&lt;br /&gt;
class ForkTest : MovementTest&lt;br /&gt;
{&lt;br /&gt;
private DriveTask dt;&lt;br /&gt;
public override void TestStop()&lt;br /&gt;
{&lt;br /&gt;
dt?.Stop();&lt;br /&gt;
}&lt;br /&gt;
public override void Test()&lt;br /&gt;
{&lt;br /&gt;
//调出 UI 输入货叉提升高度值&lt;br /&gt;
if (InputBox.ShowDialog(&amp;quot;input fork height&amp;quot;) != DialogResult.OK) return;&lt;br /&gt;
dt = new DriveTask(new LiftFork()&lt;br /&gt;
{ liftTarget=Convert.ToInt32(InputBox.ResultValue) }.Get());&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
1.2，进行测试，我们重新编译 clumsy，在目录 build\clumsy 找到其生成的 dll，放到 clumsy.exe 目录下，我们打开 clsumy.exe，可以看到界面上有个“测试货叉起升”的按钮&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw9.png]]&lt;br /&gt;
&lt;br /&gt;
我们点击即可进行动作测试，如果需要停止点击 即可。&lt;br /&gt;
1.3 一个简单的动作测试我们就做好了，如果小车有其他功能也可以按照这个方法进行编&lt;br /&gt;
写。&lt;br /&gt;
注意：如果 clumsy 打开出现界面空白，后台没有加载插件或者加载其他插件失败请，点击&lt;br /&gt;
车辆配置，选择驱动，保存配置，再重启 clumsy 即可。&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw10.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw11.png]]&lt;br /&gt;
&lt;br /&gt;
=== 五 调度（Simple）接口编写 ===&lt;br /&gt;
===== 1 编写一个充电的接口 =====&lt;br /&gt;
&lt;br /&gt;
1.1 这一部分我们在 AGV.c 文件中编写，这一块我们只用编写具体需要执行的方法，用来承&lt;br /&gt;
接 Clumsy 和 Medulla 之间逻辑，供调度使用&lt;br /&gt;
1.2 我们也从简单的开始，有个需求我们需要在特定位置进行小车的充电工作，我们定义一&lt;br /&gt;
个方法 Charge,其中参数 isCharge 由调度控制，如下&lt;br /&gt;
public void Charge(bool isCharge)&lt;br /&gt;
{&lt;br /&gt;
SWDef.self.chargeContactor = isCharge ? 1 : 0;&lt;br /&gt;
Console.WriteLine($&amp;quot;chargeContactor update to-{SWDef.self.chargeContactor}&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
1.3 是不是很简单，将参数值赋给和 Medulla 交互的变量 chargeContactor 即可完成对充电口打开的&lt;br /&gt;
功能，如果有其他方法，比如切换障碍物区域控制音乐曲目，设置货叉高度等都可以这么实现。 第四步，Simpe 的适配&lt;br /&gt;
关于 Simpe 软件如何使用，可以参考示范协议以及说明\MDCS 建图和路线绘制.pdf 中路线绘&lt;br /&gt;
制内容，本适配主要是在已经熟悉 Simpe 基础操作的基础上进行具体场景的适配以及业务开&lt;br /&gt;
发&lt;br /&gt;
&lt;br /&gt;
==== 一，{proName}Car.cs 类中小车的动作编写 ====&lt;br /&gt;
===== 1  实现小车类 =====&lt;br /&gt;
1.1 我们在 DemoCar.cs 中创建一个 DemoCar 并且继承 ClumsyCar，并且在 DemoCar()方法中放置&lt;br /&gt;
我们需要执行的方法，用 Create()生成一个小车，给小车初始属性&lt;br /&gt;
public class DemoCar : ClumsyCar&lt;br /&gt;
{&lt;br /&gt;
static DemoCar()&lt;br /&gt;
{&lt;br /&gt;
//初始化小车需要实现的方法&lt;br /&gt;
}&lt;br /&gt;
public static async Task&amp;lt;DemoCar&amp;gt; Create() // boilerplate&lt;br /&gt;
{&lt;br /&gt;
var fl = new DemoCar()&lt;br /&gt;
{&lt;br /&gt;
lstatus = &amp;quot;连接中&amp;quot;,&lt;br /&gt;
address = &amp;quot;127.0.0.1&amp;quot;,&lt;br /&gt;
name = $&amp;quot;叉车底盘&amp;quot;,&lt;br /&gt;
speed = 50,&lt;br /&gt;
haveCoordination = true&lt;br /&gt;
};&lt;br /&gt;
return fl;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
===== 2 编写小车动作 =====&lt;br /&gt;
2.1 如果我想把所有线段都增加一个默认的 speed 标记，对于小场景可以手动添加，对于大&lt;br /&gt;
场景，我们可以动态的进行添加。&lt;br /&gt;
2.2 对于小车动作，我们带上 MethodMember 的标记，会显示在界面-车辆-选择小车-动作里面&lt;br /&gt;
[MethodMember(name = &amp;quot;增加 speed 标记&amp;quot;, desc = &amp;quot;双击增加 speed 标记&amp;quot;)]&lt;br /&gt;
public void AddSpeed()&lt;br /&gt;
{&lt;br /&gt;
//获取场景中所有的路线进行遍历&lt;br /&gt;
foreach (var tracks in SimpleLib.GetAllTracks())&lt;br /&gt;
{&lt;br /&gt;
//判断路线是否有 speed 字段，如果有不添加&lt;br /&gt;
if (!tracks.fields.ContainsKey(&amp;quot;speed&amp;quot;))&lt;br /&gt;
{&lt;br /&gt;
//给所有的线段加上 100 的速度，当前也可以根据业务逻辑等灵活使用&lt;br /&gt;
tracks.fields.Add(&amp;quot;speed&amp;quot;,&amp;quot;100&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
2.3 如下图，我们写好后生成 dll，到\build\Simple 目录下，打开 simpeComposer，添加托盘&lt;br /&gt;
车，选中小车就可以看到增加 speed 标记的方法，双击就可以把所有线段增加速度&lt;br /&gt;
拓展 1：这个方法的好处是我们可以根据现场业务逻辑灵活使用，如果现场都是重复性工位，&lt;br /&gt;
每个工位都需要增加一个 shelf 字段，那么我们就可以动态的给全场景增加和删除字段了。&lt;br /&gt;
拓展 2：我们也可以给小车增加其他功能比如关闭障碍物，远程关机，屏蔽报警等功能&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw12.png]]&lt;br /&gt;
&lt;br /&gt;
===== 3 编写 Coder-解释性编程 =====&lt;br /&gt;
&lt;br /&gt;
3.1 编写 coder 可以根据业务场景灵活的调用 AGV.cs 方法，我们示范一个可以让叉车 A-B 倒&lt;br /&gt;
走，B-A 正走的案例&lt;br /&gt;
3.2 首先我们线段标记 reverseDst:10 代表需要倒走的目标点&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw13.png]]&lt;br /&gt;
&lt;br /&gt;
3.3 然后程序中，我们需要在 TrackFields 类里面增加 reverseDst 属性&lt;br /&gt;
class TrackFields&lt;br /&gt;
{&lt;br /&gt;
public int speed = -1;&lt;br /&gt;
public int reverseDst = -1;&lt;br /&gt;
}&lt;br /&gt;
3.4 我 们 在 useVerb 里 面 判 断 &amp;quot;track.reverseDst == dst.id&amp;quot; 如 果 条 件 满 足 ， 就 执 行&lt;br /&gt;
templateString 内容，调用 AGV.cs 方法里面的 ReverseGo 方法。&lt;br /&gt;
[TemplateTrackCoderSettings(&lt;br /&gt;
priority = 5,&lt;br /&gt;
useVerb = &amp;quot;track.reverseDst == dst.id&amp;quot;,&lt;br /&gt;
blockVerb = &amp;quot;true&amp;quot;,&lt;br /&gt;
templateString =&lt;br /&gt;
&amp;quot;agv.ReverseGo(${src.x},${src.y},${src.id},${dst.x},${dst.y},${dst.id},${track.id},&amp;quot; +&lt;br /&gt;
&amp;quot;${track.speed});&amp;quot;,&lt;br /&gt;
siteFields = typeof(SiteFields),&lt;br /&gt;
trackFields = typeof(TrackFields))]&lt;br /&gt;
这样当我们需要小车从 A-B 走的时候就会自动将 ReverseGo 方法打包到 code 里面了&lt;br /&gt;
&lt;br /&gt;
==== 二 生成一个路径任务 ====&lt;br /&gt;
===== 1 创建一个移动任务 =====&lt;br /&gt;
1.1 我们首先要了解 Simple 的机制，Simple 中的路线编译器实现小车移动以及功能的脚本下&lt;br /&gt;
发，先创建一个计划 SegmentPlan，然后对这个计划进行寻路 FindRoute,会返回一个路线脚&lt;br /&gt;
本 code（包含 A-B 路线所有站点以及路线功能）,然后 SendScript(code)即可下发给 Clumsy，&lt;br /&gt;
Clumsy 解析然后进行移动或功能的实现。&lt;br /&gt;
1.2 了解以上我们开始编写一个简单的 move 动作，这一块我们在 Common.cs 里面编写，这&lt;br /&gt;
个方法和选中小车右击去某个点类似，具体流程如下方法：&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw14.png]]&lt;br /&gt;
&lt;br /&gt;
1.3 我们可以写一个动作或者通过其他接口来调用这个 move 方法 ，这边我们就先用选中右&lt;br /&gt;
击站点来看下，可以看到，右击站点的时候，小车 Clumsy 命令窗口收到了这一串脚本，这&lt;br /&gt;
个脚本就是 SendScript(code) 里面 code 的内容，调用了 AGV.cs 的 Go()方法，Go 里面的参&lt;br /&gt;
数见绿色注释。&lt;br /&gt;
var host=&amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;
var agv=new AGV(){id=12, baseSpeed=1};&lt;br /&gt;
//srcx:起始点 X 坐标(mm)，srcy:起始点 Y 坐标(mm)，srcid:起始站点 ID，&lt;br /&gt;
//dstx:终点 X 坐标，dsty:终点 Y 坐标，dstid：终点 ID，trackid:路径 ID,speed：路线速度&lt;br /&gt;
agv.Go(0,0,5,11507.2998046875,-5134.02587890625,8,9,100);&lt;br /&gt;
; agv.Wait();&lt;br /&gt;
;agv.Wait();&lt;br /&gt;
1.4 Clumsy 收到后解析器会进行脚本的解析执行&lt;br /&gt;
&lt;br /&gt;
==== 三 创建链式进程任务 ====&lt;br /&gt;
===== 1 创建链式进程任务 =====&lt;br /&gt;
1.1 一般链式任务用于取放料的业务场景中，小车会先去取料再去放料，因此，我们这边写&lt;br /&gt;
了一个通用的链式任务方法。&lt;br /&gt;
1.2 进程任务继承 Mission 类，我们可以在进程，新建自定义进程，选择链式进程即可，然&lt;br /&gt;
后我们双击下面动作的启动进程，就可以通过界面点击进行取放料连贯动作，具体可以参考&lt;br /&gt;
ChainedDeliveryMission.cs 文件&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw15.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw16.png]]&lt;br /&gt;
&lt;br /&gt;
1.2 这个是通过界面去调小车，我们也可以通过接口去调用，因此我们需要再写一个可以供&lt;br /&gt;
调用的接口出来 AutoEnqueue(),也很简单只用把 ManualEnqueue()复制，把起点和终点的赋值方法&lt;br /&gt;
改变即可，如下&lt;br /&gt;
public void AutoEnqueue(int getId,int putId)&lt;br /&gt;
{&lt;br /&gt;
try&lt;br /&gt;
{&lt;br /&gt;
Delivery former = null;&lt;br /&gt;
var missionField = StringDictConvert&amp;lt;ChainedDeliveryParams&amp;gt;.Convert(fields);&lt;br /&gt;
Delivery[] ls;&lt;br /&gt;
while (true)&lt;br /&gt;
{&lt;br /&gt;
var d = new Delivery();&lt;br /&gt;
if (former != null)&lt;br /&gt;
d.former = former;&lt;br /&gt;
Site srcSite, dstSite;&lt;br /&gt;
//获取起点 ID&lt;br /&gt;
srcSite =SimpleLib.GetSite(getId);&lt;br /&gt;
d.src = DemoCar.getId;&lt;br /&gt;
DemoCar.getId = 0;&lt;br /&gt;
if (former == null)&lt;br /&gt;
{&lt;br /&gt;
//获取终点 ID&lt;br /&gt;
dstSite = SimpleLib.GetSite(putId);&lt;br /&gt;
d.dst = DemoCar.putId;&lt;br /&gt;
DemoCar.putId = 0;&lt;br /&gt;
}&lt;br /&gt;
else&lt;br /&gt;
{&lt;br /&gt;
d.dst = d.former.src;&lt;br /&gt;
}&lt;br /&gt;
G.pushStatus($&amp;quot;排序了一个叉车搬运任务{d.id}: {srcSite.id} -&amp;gt; {d.dst}, 上序任&lt;br /&gt;
务:{former?.id}&amp;quot;);&lt;br /&gt;
lock (sync)&lt;br /&gt;
{&lt;br /&gt;
queue.Enqueue(d);&lt;br /&gt;
}&lt;br /&gt;
former = d;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
catch (Exception ex)&lt;br /&gt;
{&lt;br /&gt;
G.pushStatus($&amp;quot;结束任务链&amp;quot;);&lt;br /&gt;
Console.WriteLine(&amp;quot;ex&amp;quot;, ex.Message);&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
==== 三，webApi 编写 ====&lt;br /&gt;
假设某个现场第三方调度我们小车，我们需要提供任务接口，状态接口，而且对方需要我们&lt;br /&gt;
的路线地图来进行他们的地图显示我们从以下作为案例供大家参考（WebApi.cs 文件）&lt;br /&gt;
===== 1，接收任务 =====&lt;br /&gt;
1.1 任务分为 2 种，一种是单点任务，一种是链式任务，具体请看代码&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw17.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:Qw18.png]]&lt;br /&gt;
&lt;br /&gt;
===== 2 上传状态 =====&lt;br /&gt;
1,我们需要提供小车状态给第三方系统，根据对方查询小车的编号返回对于小车的状态即可&lt;br /&gt;
&lt;br /&gt;
[[文件:QW19.png]]&lt;br /&gt;
&lt;br /&gt;
===== 3 上传地图 =====&lt;br /&gt;
1，由于第三方需要我们的地图，我们地图是 json 格式因此直接发送给对方即可&lt;br /&gt;
&lt;br /&gt;
[[文件:QW20.png]]&lt;br /&gt;
&lt;br /&gt;
拓展 1：如果想打开 Simpe 自动加载路线项目，请打开项目后，点击保存配置到 Simpe.exe&lt;br /&gt;
目录下 simpe.json 文件即可&lt;br /&gt;
&lt;br /&gt;
[[文件:QW21.png]]&lt;br /&gt;
&lt;br /&gt;
拓展 2：如果 Simpe 和 Clumsy 通讯不上，检查防火墙关闭还有端口是否开放，Simple 端口&lt;br /&gt;
也可以在 simpe.json 文件中配置&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
</feed>