<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.lessokaji.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cola+ding</id>
	<title>MDCS wiki - 用户贡献 [zh-cn]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.lessokaji.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cola+ding"/>
	<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E7%89%B9%E6%AE%8A:%E7%94%A8%E6%88%B7%E8%B4%A1%E7%8C%AE/Cola_ding"/>
	<updated>2026-04-15T17:21:50Z</updated>
	<subtitle>用户贡献</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%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E&amp;diff=476</id>
		<title>使用手册 - MDCS适配流程说明</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%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E&amp;diff=476"/>
		<updated>2023-12-15T06:18:39Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​/* 配置流程 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 配置流程 ==&lt;br /&gt;
&lt;br /&gt;
[[文件:Qwe1.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:MDCS部署方法介绍-PPT 03.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:车体配置流程 00.png]]&lt;br /&gt;
&lt;br /&gt;
==== MedullaAdapter车体适配-目录 ====&lt;br /&gt;
• {ModelName}Cart.cs&lt;br /&gt;
• 定义车体信号（AsUpperIO、AsLowerIO、IOObjectMonitor），重载Init&lt;br /&gt;
• 若干Routine.cs&lt;br /&gt;
• 通常包括MotorRoutine、IORoutine、BatteryRoutine等&lt;br /&gt;
• 通信协议文件（PLC、ModBus、CAN等）&lt;br /&gt;
• {ModelName}Remote.cs&lt;br /&gt;
• 遥控器，用于测试运动控制是否正确（控制权限相当于Clumsy）&lt;br /&gt;
&lt;br /&gt;
==== MedullaAdapter车体适配 ====&lt;br /&gt;
'''• {ModelName}Cart.cs'''&lt;br /&gt;
• 重载Init()函数：初始化时调用，通常对通信接口进行初始化&lt;br /&gt;
• 定义以下public member：&lt;br /&gt;
• AsUpperIO：上位向硬件发送的信号&lt;br /&gt;
• AsLowerIO：硬件向上位发送的信号&lt;br /&gt;
• IOObjectMonitor：其他通信协议中包含的信号，无需与上位交互&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''• 若干Routine.cs'''&lt;br /&gt;
• 重载Operation()函数：指定scanInterval，以该周期重复执行&lt;br /&gt;
Operation中读写信号的代码&lt;br /&gt;
 &lt;br /&gt;
• {ModelName}Remote.cs&lt;br /&gt;
• 重载Operation()函数：使用Throttle、DPad、Button等预定义好&lt;br /&gt;
的遥控器元件，实现对车体信号的遥控逻辑。可使用Medulla内&lt;br /&gt;
置的remote简单遥控器界面，也可以使用NetRemote界面&lt;br /&gt;
&lt;br /&gt;
==== Detour建图 ====&lt;br /&gt;
&lt;br /&gt;
• 里程计-&amp;gt;添加里程计-&amp;gt;2D激光 Odometry_0-&amp;gt;启动&lt;br /&gt;
• 单线激光SLAM-&amp;gt;添加图层-&amp;gt;mainmap-&amp;gt;闭环检测开启-&amp;gt;建图模式&lt;br /&gt;
• 概览-&amp;gt;车体布局-&amp;gt;编辑-&amp;gt;选中单线雷达frontlidar-&amp;gt;根据实际雷达更&lt;br /&gt;
改以下参数：&lt;br /&gt;
• angleSgn：1为逆时针，-1为顺时针&lt;br /&gt;
• endAngle：扫描结束角度&lt;br /&gt;
• rangeStartAngle：有效扫描角度起始位置&lt;br /&gt;
• rangeEndAngle：有效扫描角度结束位置&lt;br /&gt;
• x，y，th：相对于轮轴中心的偏移量&lt;br /&gt;
• 在场地中移动车辆&lt;br /&gt;
• 完成建图后：&lt;br /&gt;
• 单线激光SLAM-&amp;gt;mainmap-&amp;gt;另存图层&lt;br /&gt;
• 主菜单-&amp;gt;导航配置-&amp;gt;保存&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ClumsyAdapter运动适配-目录 ====&lt;br /&gt;
'''• {ModelName}cDef.cs'''&lt;br /&gt;
• 定义车体信号（AsUpperIO、AsLowerIO），重载Init、DriveStop&lt;br /&gt;
• Movements.cs&lt;br /&gt;
• 定义“单元动作”的集合，并实现对应的UI测试按钮&lt;br /&gt;
• {ModelName}Config.cs&lt;br /&gt;
• 运动参数&lt;br /&gt;
• AGV.cs&lt;br /&gt;
• 对接调度系统的接口（若干函数）&lt;br /&gt;
&lt;br /&gt;
'''• {ModelName}cDef.cs'''&lt;br /&gt;
• 重新声明C中需要用到的信号&lt;br /&gt;
• 声明静态成员self&lt;br /&gt;
• 重载Init()函数：初始化时调用。一般需写self = this; ClumsyLib.Capture();&lt;br /&gt;
• 定义Drive类型，重载Write()函数。例如DifferentialWriterClass，WriteLR&lt;br /&gt;
• 重载DriveStop()函数：刹车时调用的函数&lt;br /&gt;
ClumsyAdapter运动适配&lt;br /&gt;
&lt;br /&gt;
'''• Movements.cs'''&lt;br /&gt;
• 定义“单元动作”MovementDefinition。主要是重载Get()函数&lt;br /&gt;
（Generator Function，返回迭代器）&lt;br /&gt;
• 定义“动作测试按钮”MovementTest。重载Test()函数和TestStop()&lt;br /&gt;
函数&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''• AGV.cs'''&lt;br /&gt;
• 定义若干函数，对应Simple调度时下发的动作命令。主要使用&lt;br /&gt;
Movements.cs中定义的“单元动作”MovementDefinition&lt;br /&gt;
&lt;br /&gt;
===== Simple建图 =====&lt;br /&gt;
'''• 添加车辆'''&lt;br /&gt;
• 将车开至业务站点所在位置，在UI上对应位置添加站点&lt;br /&gt;
• 添加路径，连接站点&lt;br /&gt;
• 编辑站点、路径的属性（与AMRScene中SiteFields和TrackFields对&lt;br /&gt;
应）&lt;br /&gt;
• 编辑Simple上的车辆属性（speed等）&lt;br /&gt;
&lt;br /&gt;
===== AMRScene业务场景适配 =====&lt;br /&gt;
'''• {ModelName}Car.cs'''&lt;br /&gt;
• 定义SiteFields和TrackFields&lt;br /&gt;
• 定义若干TemplateTrackCoderSettings&lt;br /&gt;
• 定义若干TemplateSiteCoderSettings&lt;br /&gt;
• 其中：&lt;br /&gt;
• priority：值越大者越先检查&lt;br /&gt;
• useVerb：定义触发所需满足的条件&lt;br /&gt;
• blockVerb：终止符。为true则屏蔽剩下未检查的coder&lt;br /&gt;
• templateString：满足条件时编译生成的命令&lt;br /&gt;
&lt;br /&gt;
===== 雷达适配 =====&lt;br /&gt;
• 雷达驱动类派生于Lidar2DIOObject&lt;br /&gt;
• 将点云数据整理为LidarPoint2D格式&lt;br /&gt;
• th：-180度~180度，逆时针为角度正方向，x轴正方向为0度&lt;br /&gt;
• d：距离，单位mm&lt;br /&gt;
• intensity：强度，0到1&lt;br /&gt;
• 提交每帧数据时：&lt;br /&gt;
• 将数据存至LidarPoint2D[] cachedLidar&lt;br /&gt;
• 更新scanC（帧号），同时frame += 1&lt;br /&gt;
• output()将数据同步至共享内存&lt;br /&gt;
&lt;br /&gt;
[[文件:Qwe119.png]]&lt;/div&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%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E&amp;diff=475</id>
		<title>使用手册 - MDCS适配流程说明</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%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E&amp;diff=475"/>
		<updated>2023-12-15T06:17:41Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​创建页面，内容为“== 配置流程 ==  文件:Qwe1.png  缩略图  文件:车体配置流程 00.png  ==== MedullaAdapter车体适配-目录 ==== • {ModelName}Cart.cs • 定义车体信号（AsUpperIO、AsLowerIO、IOObjectMonitor），重载Init • 若干Routine.cs • 通常包括MotorRoutine、IORoutine、BatteryRoutine等 • 通信协议文件（PLC、ModBus、CAN等） • {ModelName}Remote.cs • 遥控器，用于测…”&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 配置流程 ==&lt;br /&gt;
&lt;br /&gt;
[[文件:Qwe1.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:MDCS部署方法介绍-PPT 03.png|缩略图]]&lt;br /&gt;
&lt;br /&gt;
[[文件:车体配置流程 00.png]]&lt;br /&gt;
&lt;br /&gt;
==== MedullaAdapter车体适配-目录 ====&lt;br /&gt;
• {ModelName}Cart.cs&lt;br /&gt;
• 定义车体信号（AsUpperIO、AsLowerIO、IOObjectMonitor），重载Init&lt;br /&gt;
• 若干Routine.cs&lt;br /&gt;
• 通常包括MotorRoutine、IORoutine、BatteryRoutine等&lt;br /&gt;
• 通信协议文件（PLC、ModBus、CAN等）&lt;br /&gt;
• {ModelName}Remote.cs&lt;br /&gt;
• 遥控器，用于测试运动控制是否正确（控制权限相当于Clumsy）&lt;br /&gt;
&lt;br /&gt;
==== MedullaAdapter车体适配 ====&lt;br /&gt;
'''• {ModelName}Cart.cs'''&lt;br /&gt;
• 重载Init()函数：初始化时调用，通常对通信接口进行初始化&lt;br /&gt;
• 定义以下public member：&lt;br /&gt;
• AsUpperIO：上位向硬件发送的信号&lt;br /&gt;
• AsLowerIO：硬件向上位发送的信号&lt;br /&gt;
• IOObjectMonitor：其他通信协议中包含的信号，无需与上位交互&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''• 若干Routine.cs'''&lt;br /&gt;
• 重载Operation()函数：指定scanInterval，以该周期重复执行&lt;br /&gt;
Operation中读写信号的代码&lt;br /&gt;
 &lt;br /&gt;
• {ModelName}Remote.cs&lt;br /&gt;
• 重载Operation()函数：使用Throttle、DPad、Button等预定义好&lt;br /&gt;
的遥控器元件，实现对车体信号的遥控逻辑。可使用Medulla内&lt;br /&gt;
置的remote简单遥控器界面，也可以使用NetRemote界面&lt;br /&gt;
&lt;br /&gt;
==== Detour建图 ====&lt;br /&gt;
&lt;br /&gt;
• 里程计-&amp;gt;添加里程计-&amp;gt;2D激光 Odometry_0-&amp;gt;启动&lt;br /&gt;
• 单线激光SLAM-&amp;gt;添加图层-&amp;gt;mainmap-&amp;gt;闭环检测开启-&amp;gt;建图模式&lt;br /&gt;
• 概览-&amp;gt;车体布局-&amp;gt;编辑-&amp;gt;选中单线雷达frontlidar-&amp;gt;根据实际雷达更&lt;br /&gt;
改以下参数：&lt;br /&gt;
• angleSgn：1为逆时针，-1为顺时针&lt;br /&gt;
• endAngle：扫描结束角度&lt;br /&gt;
• rangeStartAngle：有效扫描角度起始位置&lt;br /&gt;
• rangeEndAngle：有效扫描角度结束位置&lt;br /&gt;
• x，y，th：相对于轮轴中心的偏移量&lt;br /&gt;
• 在场地中移动车辆&lt;br /&gt;
• 完成建图后：&lt;br /&gt;
• 单线激光SLAM-&amp;gt;mainmap-&amp;gt;另存图层&lt;br /&gt;
• 主菜单-&amp;gt;导航配置-&amp;gt;保存&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ClumsyAdapter运动适配-目录 ====&lt;br /&gt;
'''• {ModelName}cDef.cs'''&lt;br /&gt;
• 定义车体信号（AsUpperIO、AsLowerIO），重载Init、DriveStop&lt;br /&gt;
• Movements.cs&lt;br /&gt;
• 定义“单元动作”的集合，并实现对应的UI测试按钮&lt;br /&gt;
• {ModelName}Config.cs&lt;br /&gt;
• 运动参数&lt;br /&gt;
• AGV.cs&lt;br /&gt;
• 对接调度系统的接口（若干函数）&lt;br /&gt;
&lt;br /&gt;
'''• {ModelName}cDef.cs'''&lt;br /&gt;
• 重新声明C中需要用到的信号&lt;br /&gt;
• 声明静态成员self&lt;br /&gt;
• 重载Init()函数：初始化时调用。一般需写self = this; ClumsyLib.Capture();&lt;br /&gt;
• 定义Drive类型，重载Write()函数。例如DifferentialWriterClass，WriteLR&lt;br /&gt;
• 重载DriveStop()函数：刹车时调用的函数&lt;br /&gt;
ClumsyAdapter运动适配&lt;br /&gt;
&lt;br /&gt;
'''• Movements.cs'''&lt;br /&gt;
• 定义“单元动作”MovementDefinition。主要是重载Get()函数&lt;br /&gt;
（Generator Function，返回迭代器）&lt;br /&gt;
• 定义“动作测试按钮”MovementTest。重载Test()函数和TestStop()&lt;br /&gt;
函数&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''• AGV.cs'''&lt;br /&gt;
• 定义若干函数，对应Simple调度时下发的动作命令。主要使用&lt;br /&gt;
Movements.cs中定义的“单元动作”MovementDefinition&lt;br /&gt;
&lt;br /&gt;
===== Simple建图 =====&lt;br /&gt;
'''• 添加车辆'''&lt;br /&gt;
• 将车开至业务站点所在位置，在UI上对应位置添加站点&lt;br /&gt;
• 添加路径，连接站点&lt;br /&gt;
• 编辑站点、路径的属性（与AMRScene中SiteFields和TrackFields对&lt;br /&gt;
应）&lt;br /&gt;
• 编辑Simple上的车辆属性（speed等）&lt;br /&gt;
&lt;br /&gt;
===== AMRScene业务场景适配 =====&lt;br /&gt;
'''• {ModelName}Car.cs'''&lt;br /&gt;
• 定义SiteFields和TrackFields&lt;br /&gt;
• 定义若干TemplateTrackCoderSettings&lt;br /&gt;
• 定义若干TemplateSiteCoderSettings&lt;br /&gt;
• 其中：&lt;br /&gt;
• priority：值越大者越先检查&lt;br /&gt;
• useVerb：定义触发所需满足的条件&lt;br /&gt;
• blockVerb：终止符。为true则屏蔽剩下未检查的coder&lt;br /&gt;
• templateString：满足条件时编译生成的命令&lt;br /&gt;
&lt;br /&gt;
===== 雷达适配 =====&lt;br /&gt;
• 雷达驱动类派生于Lidar2DIOObject&lt;br /&gt;
• 将点云数据整理为LidarPoint2D格式&lt;br /&gt;
• th：-180度~180度，逆时针为角度正方向，x轴正方向为0度&lt;br /&gt;
• d：距离，单位mm&lt;br /&gt;
• intensity：强度，0到1&lt;br /&gt;
• 提交每帧数据时：&lt;br /&gt;
• 将数据存至LidarPoint2D[] cachedLidar&lt;br /&gt;
• 更新scanC（帧号），同时frame += 1&lt;br /&gt;
• output()将数据同步至共享内存&lt;br /&gt;
&lt;br /&gt;
[[文件:Qwe119.png]]&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qwe119.png&amp;diff=474</id>
		<title>文件:Qwe119.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qwe119.png&amp;diff=474"/>
		<updated>2023-12-15T06:14:52Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:MDCS%E9%83%A8%E7%BD%B2%E6%96%B9%E6%B3%95%E4%BB%8B%E7%BB%8D-PPT_03.png&amp;diff=473</id>
		<title>文件:MDCS部署方法介绍-PPT 03.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:MDCS%E9%83%A8%E7%BD%B2%E6%96%B9%E6%B3%95%E4%BB%8B%E7%BB%8D-PPT_03.png&amp;diff=473"/>
		<updated>2023-12-15T06:13:41Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:%E8%BD%A6%E4%BD%93%E9%85%8D%E7%BD%AE%E6%B5%81%E7%A8%8B_00.png&amp;diff=472</id>
		<title>文件:车体配置流程 00.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:%E8%BD%A6%E4%BD%93%E9%85%8D%E7%BD%AE%E6%B5%81%E7%A8%8B_00.png&amp;diff=472"/>
		<updated>2023-12-15T06:10:12Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qwe1.png&amp;diff=471</id>
		<title>文件:Qwe1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qwe1.png&amp;diff=471"/>
		<updated>2023-12-15T06:08:45Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E9%A6%96%E9%A1%B5&amp;diff=470</id>
		<title>首页</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E9%A6%96%E9%A1%B5&amp;diff=470"/>
		<updated>2023-12-15T06:07:50Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​/* 使用手册 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[文件:MDCS-2023.png|缩略图|159x159像素|MDCS logo 2023]]&lt;br /&gt;
MDCS is a robot fleet developing platform, including the following components:&lt;br /&gt;
&lt;br /&gt;
[[Medulla]]: Efficient hardware communication and control platform.&lt;br /&gt;
&lt;br /&gt;
Detour: Positioning system, built-in Lidar and Visual SLAM&lt;br /&gt;
&lt;br /&gt;
Clumsy: Robot movement instruction platform, built-in typical movements for AGV/AMR.&lt;br /&gt;
&lt;br /&gt;
Simple: Robot fleet management including traffic control system.&lt;br /&gt;
&lt;br /&gt;
CycleGUI: Cycle based GUI framework, use co-routine to host GUI in an immediate-mode fashion. the co-routine is invoked only when a GUI refresh is needed.&lt;br /&gt;
&lt;br /&gt;
== 基本概念介绍 ==&lt;br /&gt;
定位：AGV的定位是由独立模块【Detour】完成。Detour支持激光雷达和视觉的各类SLAM算法，包括[[具有高鲁棒性的激光SLAM算法|具有高鲁棒性的2D激光SLAM算法]]、[[地纹SLAM]]、[[天花板SLAM]]、[[二维码识别导航|二维码导航]]等。Detour可以使用Medulla提供的数据来源、也可以自行获取。整套MDCS实施时一般使用Medulla提供的数据来源。&lt;br /&gt;
&lt;br /&gt;
AGV车载功能定义系统：由Medulla（硬件抽象逻辑）、Clumsy（车体运动抽象）组成；二者原理见[[车体抽象原理]]。Medulla+Clumsy可实现各类车体动作，最简单诸如[[巡线行走]]、[[绕障行走]]等，复杂一些的例子如[[自动识别工位并取放货]]、[[自动识别托盘取放货]]、[[识别料框并堆垛拆垛]]、[[联动天眼系统进行装卸车]]等。车载软件定义了AGV的能力集以及测试方法，并可由调度软件做动作组合从而完成整套任务。&lt;br /&gt;
&lt;br /&gt;
调度：交管、包络、寻路等内核算法由SimpleCore提供，其原理参见[[内核运行原理]]，SimpleCore提供编程接口使得用户可对具体车型或业务场景设置包络。对调度的运行原理参见：[[AGV任务运行逻辑]] 。MDCS提供一个简单的壳层称为SimpleComposer，其提供UI和基础的车辆通信定义，在此之上还支持插件进一步定义车辆具体细节和业务逻辑。&lt;br /&gt;
&lt;br /&gt;
== 使用手册 ==&lt;br /&gt;
[[MDCS-Walkthrough]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - MDCS简介]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 定位导航]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 分析定位问题]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 车队管控]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 激光+纹理导航|使用手册 - 激光 纹理导航]]  &lt;br /&gt;
&lt;br /&gt;
[[使用手册-routing字段：设置车辆必经点（必不经点）逻辑]]  &lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Simple:从使用到开发]]  &lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Simple:coder（路径编译器）机制详解]]  &lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Simple:包络如何定义]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Medulla:相机使用方法 Camera Data Access Guide]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Detour车体编辑器使用教学]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 双雷达标定手册]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 在地纹导航中使用二维码快速找回定位]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - MDCS软件部署方法介绍]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Simple软件文件管理标准化作业]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - MDCS适配流程说明]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - MDCS适配详细说明]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 有反+SLAM建图手册]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Linux MDCS部署&amp;amp;配置&amp;amp;操作说明]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - 数据录制与回放手册]]&lt;br /&gt;
&lt;br /&gt;
[[使用手册 - Simple图层合并手册]]&lt;br /&gt;
&lt;br /&gt;
== 开发手册 ==&lt;br /&gt;
[[开发手册 - 轨迹跟踪]]&lt;br /&gt;
&lt;br /&gt;
[[开发手册 - 目标跟踪]]&lt;br /&gt;
&lt;br /&gt;
[[FAQ]] &amp;amp; Cheat sheet&lt;br /&gt;
&lt;br /&gt;
[[待整理的杂项内容]]&lt;br /&gt;
&lt;br /&gt;
== 接口 ==&lt;br /&gt;
[[Medulla-API|Medulla]]&lt;br /&gt;
&lt;br /&gt;
[[Detour-API|Detour]]&lt;br /&gt;
&lt;br /&gt;
[[Clumsy-API|Clumsy]]&lt;br /&gt;
&lt;br /&gt;
[[Simple-API|Simple]]&lt;br /&gt;
&lt;br /&gt;
== 术语和约定 ==&lt;br /&gt;
[[通用约定|MDCS开发通用约定]]&lt;br /&gt;
&lt;br /&gt;
[[定位导航]]&lt;br /&gt;
&lt;br /&gt;
[[MDCS参数表:Medulla]]&lt;br /&gt;
&lt;br /&gt;
[[MDCS参数表:Detour]]&lt;br /&gt;
&lt;br /&gt;
[[MDCS参数表:Clumsy]]&lt;br /&gt;
&lt;br /&gt;
[[MDCS参数表:Simple]]&lt;br /&gt;
&lt;br /&gt;
== 链接 ==&lt;br /&gt;
* [https://dl.lessokaji.com MDCS下载站]：MDCS的各类程序可在该站上下载&lt;br /&gt;
* [https://dev.lessokaji.com 技术讨论站]：包含FAQ、需求讨论、AGV项目实施经验等技术讨论&lt;br /&gt;
* [https://nuget.lessokaji.com MDCS专用Nuget源]：MDCS主要使用c#进行开发，该源包括主要会用的库&lt;br /&gt;
* [https://git.lessokaji.com MDCS代码库]：git源&lt;br /&gt;
* [https://auth.lessokaji.com MDCS授权站]：License授权、代码阅读和编译权限授权站&lt;/div&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=469</id>
		<title>使用手册 - MDCS适配详细说明</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"/>
		<updated>2023-12-15T06:05:10Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​/* = */&lt;/p&gt;
&lt;hr /&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;
&amp;lt;nowiki&amp;gt;=====四，Detour 定位接口 =====&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&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>
	<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</id>
		<title>使用手册 - MDCS适配详细说明</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"/>
		<updated>2023-12-15T06:04:25Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​创建页面，内容为“==== 一、介绍 ==== MDCS（Medulla,Detour,Clumsy ,Simple ）是一套完整的 AGV（Automated Guided Vehicle）小车自动驾驶模型与控制架构，它由以下 4 个软件组成：  Medulla：硬件适配软件，针对不同的硬件进行通讯以及驱动适配；  Detour：AGV 导航定位软件，可以进行 SLAM、二维码或 UWB 定位等；  Clumsy：自动驾驶软件，定义了 AGV 的基本动作单元，例如转向/差动驱…”&lt;/p&gt;
&lt;hr /&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>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:QW21.png&amp;diff=467</id>
		<title>文件:QW21.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:QW21.png&amp;diff=467"/>
		<updated>2023-12-15T06:04:04Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:QW20.png&amp;diff=466</id>
		<title>文件:QW20.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:QW20.png&amp;diff=466"/>
		<updated>2023-12-15T06:03:30Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:QW19.png&amp;diff=465</id>
		<title>文件:QW19.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:QW19.png&amp;diff=465"/>
		<updated>2023-12-15T06:03:14Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw18.png&amp;diff=464</id>
		<title>文件:Qw18.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw18.png&amp;diff=464"/>
		<updated>2023-12-15T06:01:51Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw17.png&amp;diff=463</id>
		<title>文件:Qw17.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw17.png&amp;diff=463"/>
		<updated>2023-12-15T06:01:33Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw16.png&amp;diff=462</id>
		<title>文件:Qw16.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw16.png&amp;diff=462"/>
		<updated>2023-12-15T06:00:23Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;11&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw15.png&amp;diff=461</id>
		<title>文件:Qw15.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw15.png&amp;diff=461"/>
		<updated>2023-12-15T06:00:08Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw14.png&amp;diff=460</id>
		<title>文件:Qw14.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw14.png&amp;diff=460"/>
		<updated>2023-12-15T05:59:09Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;11&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw13.png&amp;diff=459</id>
		<title>文件:Qw13.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw13.png&amp;diff=459"/>
		<updated>2023-12-15T05:58:12Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw12.png&amp;diff=458</id>
		<title>文件:Qw12.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw12.png&amp;diff=458"/>
		<updated>2023-12-15T05:57:26Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw11.png&amp;diff=457</id>
		<title>文件:Qw11.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw11.png&amp;diff=457"/>
		<updated>2023-12-15T05:55:50Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw10.png&amp;diff=456</id>
		<title>文件:Qw10.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw10.png&amp;diff=456"/>
		<updated>2023-12-15T05:55:30Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw9.png&amp;diff=455</id>
		<title>文件:Qw9.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw9.png&amp;diff=455"/>
		<updated>2023-12-15T05:54:38Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw8.png&amp;diff=454</id>
		<title>文件:Qw8.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw8.png&amp;diff=454"/>
		<updated>2023-12-15T05:50:56Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw7.png&amp;diff=453</id>
		<title>文件:Qw7.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw7.png&amp;diff=453"/>
		<updated>2023-12-15T05:50:35Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw6.png&amp;diff=452</id>
		<title>文件:Qw6.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw6.png&amp;diff=452"/>
		<updated>2023-12-15T05:49:33Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw5.png&amp;diff=451</id>
		<title>文件:Qw5.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw5.png&amp;diff=451"/>
		<updated>2023-12-15T05:48:15Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw4.png&amp;diff=450</id>
		<title>文件:Qw4.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw4.png&amp;diff=450"/>
		<updated>2023-12-15T05:47:35Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw3.png&amp;diff=449</id>
		<title>文件:Qw3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw3.png&amp;diff=449"/>
		<updated>2023-12-15T05:46:56Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw2.png&amp;diff=448</id>
		<title>文件:Qw2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw2.png&amp;diff=448"/>
		<updated>2023-12-15T05:43:56Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw1.png&amp;diff=447</id>
		<title>文件:Qw1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Qw1.png&amp;diff=447"/>
		<updated>2023-12-15T05:42:13Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&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_-_%E6%BF%80%E5%85%89SLAM%EF%BC%8B%E5%8F%8D%E5%85%89%E6%9D%BF%E5%BB%BA%E5%9B%BE%E6%89%8B%E5%86%8C&amp;diff=446</id>
		<title>使用手册 - 激光SLAM＋反光板建图手册</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_-_%E6%BF%80%E5%85%89SLAM%EF%BC%8B%E5%8F%8D%E5%85%89%E6%9D%BF%E5%BB%BA%E5%9B%BE%E6%89%8B%E5%86%8C&amp;diff=446"/>
		<updated>2023-12-15T05:38:00Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​创建页面，内容为“===== 1．准备工作 ===== 1.打开Medulla，加载对应雷达插件，本手册以科力雷达举例，startup的配置方法如下  frontlidar=io load plugins/sdkeli.dll   //加载雷达驱动插件  frontlidar Start 192.168.2.1          //初始化雷达参数  frontlidar setReflexRange 0         //设置反光强度范围-用于筛选反光棒  2.打开Medulla.exe，找到对应雷达，打开可视化，找到对应合适的反光阈值区间  文件:…”&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===== 1．准备工作 =====&lt;br /&gt;
1.打开Medulla，加载对应雷达插件，本手册以科力雷达举例，startup的配置方法如下&lt;br /&gt;
 frontlidar=io load plugins/sdkeli.dll   //加载雷达驱动插件&lt;br /&gt;
 frontlidar Start 192.168.2.1          //初始化雷达参数&lt;br /&gt;
 frontlidar setReflexRange 0         //设置反光强度范围-用于筛选反光棒&lt;br /&gt;
&lt;br /&gt;
2.打开Medulla.exe，找到对应雷达，打开可视化，找到对应合适的反光阈值区间&lt;br /&gt;
&lt;br /&gt;
[[文件:As1.png]]&lt;br /&gt;
&lt;br /&gt;
3.打开Medulla命令行，输入frontlidar setReflexRange 100  ，看下雷达可视化界面的点，越红说明反光强度越高，设置这个值可以降低，红色点的判断条件是大于setReflexRange  越多，越红，因此我们只需要调节setReflexRange 大小，筛选出实际反光棒红色的点即可，保证只有有反光棒的点显示红色。&lt;br /&gt;
&lt;br /&gt;
[[文件:As2.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:As3.png]]&lt;br /&gt;
&lt;br /&gt;
4.记住当前设置的setReflexRange 的大小，把参数改到startup.ocmd中frontlidar setReflexRange xx&lt;br /&gt;
这样后续打开Medulla会自动加载这个反光强度范围值，至此我们Medulla的配置工作结束，下面就可以开始建图&lt;br /&gt;
&lt;br /&gt;
以上适用于2D雷达，3D雷达(暂时只有镭神）目前只需要加载最新的雷达驱动插件后即可使用。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 2．建图 =====&lt;br /&gt;
以上准备工作都完成后，开始建图工作&lt;br /&gt;
1.打开Detour.exe，打开车体编辑器，选择导航雷达-属性-useReflex设置为true-保存导航配置&lt;br /&gt;
&lt;br /&gt;
[[文件:As4.png]]&lt;br /&gt;
&lt;br /&gt;
[[文件:As5.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2.选择图层，开启建图模式，然后手动或者自动拉着小车建图即可。&lt;br /&gt;
&lt;br /&gt;
[[文件:As6.png]]&lt;br /&gt;
&lt;br /&gt;
3.锁定图层后，可以看到有反的黄色X标记，这就表示录入的一个个反光棒，如果有错误的，擦除即可，记得半径设置小一点，防止擦除过多                     &lt;br /&gt;
&lt;br /&gt;
[[文件:As7.png]]&lt;br /&gt;
&lt;br /&gt;
4.地图全部录好后，锁定图层，对需要进行有反导航的区域我们标记匹配困难区域，然后把对应区域涂抹成黄色即可，这样小车移动到此区域会进行有反匹配，非黄色区域还是会进行激光里程计匹配，涂抹OK后保存图层即可。&lt;br /&gt;
&lt;br /&gt;
[[文件:As8.png]]&lt;br /&gt;
&lt;br /&gt;
5，把车开到有反地图，可以看到紫色的点表示当前识别匹配的反光棒&lt;br /&gt;
&lt;br /&gt;
[[文件:As9.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 3．建图中的问题 =====&lt;br /&gt;
1.建图的时候如果地图上容易出现非反光棒的点，可能附近墙面或设备的反光强度也比较高，为了区分，可以把Detour-车体编辑器-frontlidar -调大reflexthres，这个是指点的强度要大于多少才算反光板，数值不要超过1。&lt;br /&gt;
&lt;br /&gt;
[[文件:As10.png]]&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As10.png&amp;diff=445</id>
		<title>文件:As10.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As10.png&amp;diff=445"/>
		<updated>2023-12-15T05:37:55Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As9.png&amp;diff=444</id>
		<title>文件:As9.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As9.png&amp;diff=444"/>
		<updated>2023-12-15T05:37:14Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As8.png&amp;diff=443</id>
		<title>文件:As8.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As8.png&amp;diff=443"/>
		<updated>2023-12-15T05:37:01Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As7.png&amp;diff=442</id>
		<title>文件:As7.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As7.png&amp;diff=442"/>
		<updated>2023-12-15T05:36:44Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As6.png&amp;diff=441</id>
		<title>文件:As6.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As6.png&amp;diff=441"/>
		<updated>2023-12-15T05:36:30Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As5.png&amp;diff=440</id>
		<title>文件:As5.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As5.png&amp;diff=440"/>
		<updated>2023-12-15T05:36:15Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;u&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As4.png&amp;diff=439</id>
		<title>文件:As4.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As4.png&amp;diff=439"/>
		<updated>2023-12-15T05:35:57Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As3.png&amp;diff=438</id>
		<title>文件:As3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As3.png&amp;diff=438"/>
		<updated>2023-12-15T05:35:35Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;4&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As2.png&amp;diff=437</id>
		<title>文件:As2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As2.png&amp;diff=437"/>
		<updated>2023-12-15T05:35:05Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;7&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As1.png&amp;diff=436</id>
		<title>文件:As1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:As1.png&amp;diff=436"/>
		<updated>2023-12-15T05:34:45Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&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_-_%E6%95%B0%E6%8D%AE%E5%BD%95%E5%88%B6%E4%B8%8E%E5%9B%9E%E6%94%BE%E6%89%8B%E5%86%8C&amp;diff=435</id>
		<title>使用手册 - 数据录制与回放手册</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_-_%E6%95%B0%E6%8D%AE%E5%BD%95%E5%88%B6%E4%B8%8E%E5%9B%9E%E6%94%BE%E6%89%8B%E5%86%8C&amp;diff=435"/>
		<updated>2023-12-15T05:30:43Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​创建页面，内容为“===== 一、简介 ===== Medulla数据录制：可以录制单个传感器数据或多个传感器数据。 ===== 二、录制方法 ===== 1，单个传感器数据录制 （1）打开Medulla.exe，找到需要录制数据的雷达，比如frontlidar,选中后，点击set_cap_dir，设置好录制的文件夹，然后点击start_capture即可开启录制，结束录制只需要点击stop_capture即可  文件:Zx1.png  （2）录制即可后可在设置的…”&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===== 一、简介 =====&lt;br /&gt;
Medulla数据录制：可以录制单个传感器数据或多个传感器数据。&lt;br /&gt;
===== 二、录制方法 =====&lt;br /&gt;
1，单个传感器数据录制&lt;br /&gt;
（1）打开Medulla.exe，找到需要录制数据的雷达，比如frontlidar,选中后，点击set_cap_dir，设置好录制的文件夹，然后点击start_capture即可开启录制，结束录制只需要点击stop_capture即可&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx1.png]]&lt;br /&gt;
&lt;br /&gt;
（2）录制即可后可在设置的文件夹中看到录制的数据。&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx2.png]]&lt;br /&gt;
&lt;br /&gt;
===== 2 多个传感器录制 =====&lt;br /&gt;
 （1），打开Medulla.exe，选中io,点击CapturePost，开始录制，结束录制在点击DumpPost即可。&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx3.png]]&lt;br /&gt;
&lt;br /&gt;
（2）在Medulla.exe同目录下会生成一个以时间命名的文件的dump文件&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx4.png|缩略图]]&lt;br /&gt;
&lt;br /&gt;
===== 三、回放数据 =====&lt;br /&gt;
需要加载虚拟雷达，具体见dev附件&lt;br /&gt;
 1 lidar回放&lt;br /&gt;
打开Medulla,加载雷达数据，打开附件的模拟雷达Medulla包即可，具体方法如下&lt;br /&gt;
 （1）打开Medulla.exe，点击init加载雷达数据，选择第一帧即可&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx5.png]]&lt;br /&gt;
&lt;br /&gt;
（2）点击switch_auto_next按钮，开启雷达数据回放&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx6.png]]&lt;br /&gt;
&lt;br /&gt;
（3）点击View 即可查看雷达点云了&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx7.png]]&lt;br /&gt;
&lt;br /&gt;
2 dump数据回放&lt;br /&gt;
（1）打开Medulla.exe，选择io-LoadPost，选择已录制好的传感器数据包，确定即可、&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx8.png]]&lt;br /&gt;
&lt;br /&gt;
（2）点击ReplayPost即可开启回放，可在Detour中直接回放现场录制的数据&lt;br /&gt;
&lt;br /&gt;
[[文件:Zx9.png]]&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx9.png&amp;diff=434</id>
		<title>文件:Zx9.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx9.png&amp;diff=434"/>
		<updated>2023-12-15T05:30:40Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx8.png&amp;diff=433</id>
		<title>文件:Zx8.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx8.png&amp;diff=433"/>
		<updated>2023-12-15T05:30:26Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;i&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx7.png&amp;diff=432</id>
		<title>文件:Zx7.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx7.png&amp;diff=432"/>
		<updated>2023-12-15T05:30:08Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx6.png&amp;diff=431</id>
		<title>文件:Zx6.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx6.png&amp;diff=431"/>
		<updated>2023-12-15T05:29:53Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx5.png&amp;diff=430</id>
		<title>文件:Zx5.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx5.png&amp;diff=430"/>
		<updated>2023-12-15T05:29:39Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx4.png&amp;diff=429</id>
		<title>文件:Zx4.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx4.png&amp;diff=429"/>
		<updated>2023-12-15T05:29:23Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx3.png&amp;diff=428</id>
		<title>文件:Zx3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx3.png&amp;diff=428"/>
		<updated>2023-12-15T05:29:03Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx2.png&amp;diff=427</id>
		<title>文件:Zx2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E6%96%87%E4%BB%B6:Zx2.png&amp;diff=427"/>
		<updated>2023-12-15T05:28:46Z</updated>

		<summary type="html">&lt;p&gt;Cola ding：​&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;2&lt;/div&gt;</summary>
		<author><name>Cola ding</name></author>
	</entry>
</feed>