基于C#的机器学习--模糊逻辑-穿越障碍
模糊逻辑-穿越障碍
模糊逻辑。另一个我们经常听到的术语。但它的真正含义是什么?它是否意味着不止一件事?我们马上就会知道答案。
我们将使用模糊逻辑来帮助引导一辆自动驾驶汽车绕过障碍,如果我们做得正确,我们将避开沿途的障碍。我们的自动导航车辆(AGV)将在障碍物周围导航,感知其路径上的障碍物。它将使用一个推理系统来帮助引导它前进。你或者用户将能够创造障碍或通过的方式,AGV必须避开或通过。你可以观察跟踪光束的工作,以及跟踪AGV的路径沿其路线。AGV所采取的每一步都将在用户界面上进行更新,这样您就可以看到发生了什么。
在布尔逻辑中,事物或真或假,或黑或白。许多人不知道的是,还有一种被称为多值逻辑的东西,它的真实值介于和之间。模糊逻辑是处理部分真理的多值逻辑的概念实现。例如很多人也不知道的著名的sigmoid函数,它是一种模糊化的方法。
维基百科(建议大家多使用这个百科,百度百科真的只能用呵呵来形容)对此有很好的描述,如下:
维基百科:
"In this image, the meanings of the expressions cold, warm, and hot are represented by functions mapping a temperature scale. A point on that scale has three "truth values"-one for each of the three functions. The vertical line in the image represents a particular temperature that the three arrows (truth values) gauge. Since the red arrow points to zero,this temperature may be interpreted as "not hot". The orange arrow (pointing at 0.2) may describe it as "slightly warm" and the blue arrow (pointing at 0.8) "fairly cold"."
在这幅图中,cold(冷)、warm(暖)和hot(热)表达式的含义由映射一个温标的函数表示。这个尺度上的一个点有三个“真值”,三个函数各有一个。图像中的垂直线表示三个箭头(真值)测量的特定温度。由于红色箭头指向零,这个温度可以解释为“不热”。 橙色的箭头(指向0.2)可以描述为“轻微温暖”,蓝色的箭头(指向0.8)可以描述为“轻微温暖”或“很冷”。
我们为什么要展示这个?因为,这个图表和描述非常准确地描述了什么是模糊逻辑。我们将使用AForge.NET开源机器学习框架。这是一个很好的框架,它展示了使用推理引擎完成任务是多么容易。
在这一章中,我们将讨论:
模糊逻辑
避障与识别
AGV
模糊逻辑
我们的应用程序将有两个简单的按钮,一个用于运行模糊集测试,另一个用于运行语言变量测试。下面是示例应用程序的快速快照:
创建此示例的代码相对较小且简单。这是当我们点击Run Fuzzy Set Test按钮时的样子。我们将创建两个模糊集(一个用于凉爽,一个用于温暖),并为每个模糊集添加一些成员数据值,然后绘制它们:
#region 创建两个模糊集来表示凉和暖的温度
#region 凉
TrapezoidalFunction function1 = new TrapezoidalFunction(, , , );
FuzzySet fsCool = new FuzzySet("凉", function1);
double[,] coolValues = new double[, ];
for (int i = ; i < ; i++)
{
coolValues[i - , ] = i;
coolValues[i - , ] = fsCool.GetMembership(i);
}
chart?.UpdateDataSeries("凉", coolValues);
#endregion 凉
#region 暖
TrapezoidalFunction function2 = new TrapezoidalFunction(, , , );
FuzzySet fsWarm = new FuzzySet("暖", function2);
double[,] warmValues = new double[, ];
for (int i = ; i < ; i++)
{
warmValues[i - , ] = i;
warmValues[i - , ] = fsWarm.GetMembership(i);
}
chart?.UpdateDataSeries("暖", warmValues);
#endregion 暖
#endregion 创建两个模糊集来表示凉和暖的温度
运行语言变量测试的代码如下。同样,我们创建模糊集,但这次我们创建个而不是个。与我们的第一个测试一样,我们首先添加成员数据,然后绘图:
LinguisticVariable lvTemperature = new LinguisticVariable("温度", , );
TrapezoidalFunction function1 = new TrapezoidalFunction(, , TrapezoidalFunction.EdgeType.Right);
FuzzySet fsCold = new FuzzySet("冷", function1);
lvTemperature.AddLabel(fsCold);
TrapezoidalFunction function2 = new TrapezoidalFunction(, , , );
FuzzySet fsCool = new FuzzySet("凉", function2);
lvTemperature.AddLabel(fsCool);
TrapezoidalFunction function3 = new TrapezoidalFunction(, , , );
FuzzySet fsWarm = new FuzzySet("暖", function3);
lvTemperature.AddLabel(fsWarm);
TrapezoidalFunction function4 = new TrapezoidalFunction(, , TrapezoidalFunction.EdgeType.Left);
FuzzySet fsHot = new FuzzySet("热", function4);
lvTemperature.AddLabel(fsHot);
double[][,] chartValues = new double[][,];
for (int i = ; i < ; i++)
chartValues[i] = new double[, ];
最后我们画出这些值:
#region 语言变量的形状——它的标签从开始到结束的形状
int j = ;
for (float x = ; x < ; x += 0.5f, j++)
{
double y1 = lvTemperature.GetLabelMembership("冷", x);
double y2 = lvTemperature.GetLabelMembership("凉", x);
double y3 = lvTemperature.GetLabelMembership("暖", x);
double y4 = lvTemperature.GetLabelMembership("热", x); chartValues[][j, ] = x;
chartValues[][j, ] = y1;
chartValues[][j, ] = x;
chartValues[][j, ] = y2;
chartValues[][j, ] = x;
chartValues[][j, ] = y3;
chartValues[][j, ] = x;
chartValues[][j, ] = y4;
}
chart.UpdateDataSeries("冷", chartValues[]);
chart.UpdateDataSeries("凉", chartValues[]);
chart.UpdateDataSeries("暖", chartValues[]);
chart.UpdateDataSeries("热", chartValues[]);
#endregion 语言变量的形状——它的标签从开始到结束的形状
语言变量的形状:
正如所看到的,我们能够很容易地展示出维基百科定义所展示的视觉定义。
模糊的自主移动小车
在我们继续之前,先看一下我们的应用程序将是什么样子的,然后对推理引擎进行简要的解释:
尽管AForge.NET使得我们很容易和透明的创建一个InferenceSystem(推理系统)对象。
让我先来解释下什么是模糊推理系统。模糊推理系统是一种能够进行模糊计算的模型。这是使用数据库、语言变量和规则库完成的,所有这些都可以存储在内存中。
模糊推理系统的典型操作如下:
- 获取数字输入
- 结合激活规则的结果得到一个模糊输出
- 验证输入激活了来自规则库的哪些规则
- 利用带有语言变量的数据库获取每个数字输入的语言意义
对于我们来讲,大部分工作将在初始化我们的模糊逻辑系统时进行。让我们将其分解为前面概述的各个步骤。
首先,我们需要准备语言标签(模糊集)组成的距离。他们分别是Near(近)、Medium(中)和Far(远)。
#region 构成这些距离的语言标签(模糊集) FuzzySet fsNear = new FuzzySet("Near", new TrapezoidalFunction(, , TrapezoidalFunction.EdgeType.Right)); FuzzySet fsMedium = new FuzzySet("Medium", new TrapezoidalFunction(, , , )); FuzzySet fsFar = new FuzzySet("Far", new TrapezoidalFunction(, , TrapezoidalFunction.EdgeType.Left)); #endregion 构成这些距离的语言标签(模糊集)
接下来,我们初始化所需的语言变量。第一个是lvRight,它将是右侧测量距离的变量:
#region 右侧测量距离(输入) LinguisticVariable lvRight = new LinguisticVariable("RightDistance", , ); lvRight.AddLabel(fsNear); lvRight.AddLabel(fsMedium); lvRight.AddLabel(fsFar); #endregion 右侧测量距离(输入)
现在,我们对左侧测量距离的变量做同样的操作:
#region 左侧测量距离(输入) LinguisticVariable lvLeft = new LinguisticVariable("LeftDistance", , ); lvLeft.AddLabel(fsNear); lvLeft.AddLabel(fsMedium); lvLeft.AddLabel(fsFar); #endregion 左侧测量距离(输入)
最后一个语言变量是前方测量距离:
#region 前方测量距离(输入) LinguisticVariable lvFront = new LinguisticVariable("FrontalDistance", , ); lvFront.AddLabel(fsNear); lvFront.AddLabel(fsMedium); lvFront.AddLabel(fsFar); #endregion 前方测量距离(输入)
现在我们关注组成这个角度的语言标签(模糊集)。我们需要完成这一步,这样才能创建最终的语言变量:
#region 组成角度的语言标签(模糊集) FuzzySet fsVN = new FuzzySet("VeryNegative", new TrapezoidalFunction(-, -, TrapezoidalFunction.EdgeType.Right)); FuzzySet fsN = new FuzzySet("Negative", new TrapezoidalFunction(-, -, -, -)); FuzzySet fsLN = new FuzzySet("LittleNegative", new TrapezoidalFunction(-, -, -, -)); FuzzySet fsZero = new FuzzySet("Zero", new TrapezoidalFunction(-, , , )); FuzzySet fsLP = new FuzzySet("LittlePositive", new TrapezoidalFunction(, , , )); FuzzySet fsP = new FuzzySet("Positive", new TrapezoidalFunction(, , , )); FuzzySet fsVP = new FuzzySet("VeryPositive", new TrapezoidalFunction(, , TrapezoidalFunction.EdgeType.Left)); #endregion 组成角度的语言标签(模糊集)
现在我们可以创建角度的最终语言变量:
#region 角 LinguisticVariable lvAngle = new LinguisticVariable("Angle", -, ); lvAngle.AddLabel(fsVN); lvAngle.AddLabel(fsN); lvAngle.AddLabel(fsLN); lvAngle.AddLabel(fsZero); lvAngle.AddLabel(fsLP); lvAngle.AddLabel(fsP); lvAngle.AddLabel(fsVP); #endregion 角
现在我们可以继续创建我们的模糊数据库。对于我们的应用程序,这是一个语言变量的内存字典,如果您愿意的话可以将其实现为SQL、NoSQL或任何其他类型的具体数据库。
#region 数据库 Database fuzzyDB = new Database(); fuzzyDB.AddVariable(lvFront); fuzzyDB.AddVariable(lvLeft); fuzzyDB.AddVariable(lvRight); fuzzyDB.AddVariable(lvAngle); #endregion 数据库
接下来,我们将创建主推理引擎。下一行代码中最有趣的是CentroidDifuzzifier。在推理过程的最后,我们需要一个数值来控制过程的其他部分。为了得到这个数字,我们采用了一种去模糊化的方法。
我们的模糊推理系统的输出是一组点火强度大于零的规则。这种点火强度对随后的模糊规则集施加了约束。当我们把这些模糊集合放在一起时,它们会形成一个形状,这就是语言输出的意义。重心法将计算我们的形状面积的中心,以获得输出的数值表示。它使用近似数,所以会选择几个区间进行计算。随着时间间隔的增加,输出的精度也会增加:
// 创建推理系统
IS = new InferenceSystem(fuzzyDB, new CentroidDefuzzifier());
接下来,我们可以开始向我们的推理系统添加规则:
// 直走
IS.NewRule("规则 1", "IF FrontalDistance IS Far THEN Angle IS Zero"); // 直走(如果可以走到任何地方)
IS.NewRule("规则 2", "IF FrontalDistance IS Far AND RightDistance IS Far AND LeftDistance IS Far THEN Angle IS Zero"); // 右侧有墙
IS.NewRule("规则 3", "IF RightDistance IS Near AND LeftDistance IS Not Near THEN Angle IS LittleNegative"); // 左侧有墙
IS.NewRule("规则 4", "IF RightDistance IS Not Near AND LeftDistance IS Near THEN Angle IS LittlePositive"); // 前方有墙 - 房间在右侧
IS.NewRule("规则 5", "IF RightDistance IS Far AND FrontalDistance IS Near THEN Angle IS Positive"); // 前方有墙 - 房间在左侧
IS.NewRule("规则 6", "IF LeftDistance IS Far AND FrontalDistance IS Near THEN Angle IS Negative"); // 前方有墙 -两边都是房间 - 向右走
IS.NewRule("规则 7", "IF RightDistance IS Far AND LeftDistance IS Far AND FrontalDistance IS Near THEN Angle IS Positive");
经过所有这些工作,我们的推理系统就已经准备好了!
if (FirstInference)
GetMeasures(); try
{
DoInference(); MoveAGV(); GetMeasures();
} catch (Exception ex)
{
Debug.WriteLine(ex);
}
应用程序的主代码循环如下所示。我们将详细描述每个功能:
让我们快速看一下GetMeasures函数。获取当前地图以及AGV的位置后,调用HandleAGVOnWall函数,用于处理AGV碰到墙壁无法移动的情况。在这之后,DrawAGV在地图中绘制AGV。最后,RefreshTerrain 刷新地图:
/// <summary>
/// 得到传感器的测量结果
/// </summary>
private void GetMeasures() {
#region 获得自主移动小车的位置 pbTerrain.Image = CopyImage(OriginalMap); Bitmap b = (Bitmap)pbTerrain.Image; Point pPos = new Point(pbRobot.Left - pbTerrain.Left + , pbRobot.Top - pbTerrain.Top + ); #endregion 获得自主移动小车的位置 HandleAGVOnWall(b, pPos); DrawAGV(pPos, b); RefreshTerrain();
}
DrawAGV向左和向右遇到任何障碍时,如果选中Show beam复选框,就会看到前面、左边和右边的避束检测器显示:
/// <summary>
/// 绘制AGV
/// </summary>
/// <param name="pPos">坐标</param>
/// <param name="b">位图</param>
private void DrawAGV(Point pPos, Bitmap b)
{
Point pFrontObstacle = GetObstacle(pPos, b, -, ); Point pLeftObstacle = GetObstacle(pPos, b, , ); Point pRightObstacle = GetObstacle(pPos, b, , -); #region 显示线束 Graphics g = Graphics.FromImage(b); if (cbLasers.Checked)
{
g.DrawLine(new Pen(Color.Red, ), pFrontObstacle, pPos); g.DrawLine(new Pen(Color.Red, ), pLeftObstacle, pPos); g.DrawLine(new Pen(Color.Red, ), pRightObstacle, pPos);
} #endregion 显示线束 #region 绘制AGV if (btnRun.Text != RunLabel)
{
g.FillEllipse(new SolidBrush(Color.Blue), pPos.X - , pPos.Y - , , );
} g.DrawImage(b, , ); g.Dispose(); #endregion 绘制AGV #region 更新显示的距离 txtFront.Text = GetDistance(pPos, pFrontObstacle).ToString(); txtLeft.Text = GetDistance(pPos, pLeftObstacle).ToString(); txtRight.Text = GetDistance(pPos, pRightObstacle).ToString(); #endregion 更新显示的距离
}
DoInference函数运行我们的模糊推理系统的一个历元(实例、生成等等)。最终,它负责确定AGV的下一个角度。
/// <summary>
/// 运行模糊推理系统的一个纪元
/// </summary>
private void DoInference()
{
// 输入设置
IS?.SetInput("RightDistance", Convert.ToSingle(txtRight.Text)); IS?.SetInput("LeftDistance", Convert.ToSingle(txtLeft.Text)); IS?.SetInput("FrontalDistance", Convert.ToSingle(txtFront.Text)); // 输出设置
try
{
double NewAngle = IS.Evaluate("Angle"); txtAngle.Text = NewAngle.ToString("##0.#0"); Angle += NewAngle;
}
catch (Exception)
{
}
}
MoveAGV函数负责将AGV移动一步。如果您检查了跟踪路径的话,会发现这个函数中大约50%的代码时用于绘制AGV的历史轨迹的。
/// <summary>
/// 移动AGV
/// </summary>
private void MoveAGV()
{
double rad = ((Angle + ) * Math.PI) / ; int Offset = ; int Inc = -; Offset += Inc; int IncX = Convert.ToInt32(Offset * Math.Cos(rad)); int IncY = Convert.ToInt32(Offset * Math.Sin(rad)); if (cbTrajeto.Checked)
{
Graphics g = Graphics.FromImage(OriginalMap); Point p1 = new Point(pbRobot.Left - pbTerrain.Left + pbRobot.Width / , pbRobot.Top - pbTerrain.Top + pbRobot.Height / ); Point p2 = new Point(p1.X + IncX, p1.Y + IncY); g.DrawLine(new Pen(new SolidBrush(Color.Green)), p1, p2); g.DrawImage(OriginalMap, , ); g.Dispose();
} pbRobot.Top = pbRobot.Top + IncY; pbRobot.Left = pbRobot.Left + IncX;
}
主要应用与显示光束的选择:
随着应用程序的运行,AGV成功导航障碍物,显示路径和光束。角度是AGV当前所面对的角度,传感器读数与前、左、右波束传感器有关:
我们的AGV成功地完成了穿越障碍,并继续运行:
轨迹路径和显示光束可单独选择:
总结
在这一章中,我们学习了各种类型的模糊逻辑实现,并看到了使用AForge.NET将这种逻辑添加到我们的应用程序中是多么的容易。在我们的下一章中,我们将开始深入研究自组织地图,将我们的机器学习技能提升到一个新的层次。如果你还记得小学时上的美术课,这一章一定会给你带来回忆。
基于C#的机器学习--模糊逻辑-穿越障碍的更多相关文章
- 基于C#的机器学习--目录
转载请注明出处:https://www.cnblogs.com/wangzhenyao1994/p/10223666.html 文章发表的另一个地址:https://blog.csdn.net/wyz ...
- UVA 1600 Patrol Robot(机器人穿越障碍最短路线BFS)
UVA 1600 Patrol Robot Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu ...
- 基于Python的机器学习实战:KNN
1.KNN原理: 存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系.输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应 ...
- Spark学习之基于MLlib的机器学习
Spark学习之基于MLlib的机器学习 1. 机器学习算法尝试根据训练数据(training data)使得表示算法行为的数学目标最大化,并以此来进行预测或作出决定. 2. MLlib完成文本分类任 ...
- 基于python的机器学习开发环境安装(最简单的初步开发环境)
一.安装Python 1.下载安装python3.6 https://www.python.org/getit/ 2.配置环境变量(2个) 略...... 二.安装Python算法库 安装顺序:Num ...
- 基于Apache Spark机器学习的客户流失预测
流失预测是个重要的业务,通过预测哪些客户可能取消对服务的订阅来最大限度地减少客户流失.虽然最初在电信行业使用,但它已经成为银行,互联网服务提供商,保险公司和其他垂直行业的通用业务. 预测过程是大规模数 ...
- 基于C#的机器学习--惩罚与奖励-强化学习
强化学习概况 正如在前面所提到的,强化学习是指一种计算机以“试错”的方式进行学习,通过与环境进行交互获得的奖赏指导行为,目标是使程序获得最大的奖赏,强化学习不同于连督学习,区别主要表现在强化信号上,强 ...
- 基于C#的机器学习--贝叶斯定理-执行数据分析解决肇事逃逸之谜
贝叶斯定理-执行数据分析解决肇事逃逸之谜 在这一章中,我们将: 应用著名的贝叶斯定理来解决计算机科学中的一个非常著名的问题. 向您展示如何使用贝叶斯定理和朴素贝叶斯来绘制数据,从真值表中发现异常值 ...
- 基于C#的机器学习--面部和动态检测-图像过滤器
在本章中,我们将展示两个独立的例子,一个用于人脸检测,另一个用于动态检测,以及如何快速地将这些功能添加到应用程序中. 在这一章中,我们将讨论: 面部检测 动态检测 将检测添加到应用程序中 面部检测 人 ...
随机推荐
- Content Editor Webpart(三)使用JSOM
JSOM是SharePoint 提供的一种clientAPI.开发者仅仅须要使用Javescript.就能够实现和SharePoint的交互.很方便. 首先依照 (Content Editor Web ...
- Java I/O系列(二)ByteArrayInputStream与ByteArrayOutputStream源码分析及理解
1. ByteArrayInputStream 定义 继承了InputStream,数据源是内置的byte数组buf,那read ()方法的使命(读取一个个字节出来),在ByteArrayInputS ...
- ios开发者较为好用的工具
移动应用世界发生了巨大的变化,无论是在风格上还是在市场竞争上,消费者意识都推动了移动应用开发公司的崛起. 新的应用以及新的功能的出现 Apple IOS是为用户提供最新工具和升级的平台之一,它为iPh ...
- Mysql-多表连接的操作和用法
一 .介绍 二 .多表连接查询 三 .符合条件连接查询 四 .子查询 一.介绍 本节主题 多表连接查询 复合条件连接查询 子查询 准备表 #建表 create table dep( id int, n ...
- linux 学习第十二天(网络会话connection、bond、ssh配置)
一.网络会话 使用 con-name 参数指定公司所使用的网络会话名称company,然后依次用ifname 参 数指定本机的网卡名称,用autoconnect no 参数设置该网络会话默认不被自动激 ...
- 阿里云CentOS7部署MySql8.0
本文主要介绍了阿里云CentOS7如何安装MySql8.0,并对所踩的坑加以记录; 环境.工具.准备工作 服务器:阿里云CentOS 7.4.1708版本; 客户端:Windows 10; SFTP客 ...
- 企业案例:查找当前目录下所有文件,并把文件中的https://www.cnblogs.com/zhaokang2019/字符串替换成https://www.cnblogs.com/guobaoyan2019/
企业案例:查找当前目录下所有文件,并把文件中的https://www.cnblogs.com/zhaokang2019/字符串替换成https://www.cnblogs.com/guobaoyan2 ...
- Vue.js——十分钟入门Vuex
一. 什么是Vuex? Vuex Vuex是一个专门为Vue.js应用程序开发的状态管理模式, 它采用集中式存储管理所有组件的公共状态, 并以相应的规则保证状态以一种可预测的方式发生变化. Vue ...
- laravel5.5源码笔记(六、中间件)
laravel中的中间件作为一个请求与响应的过滤器,主要分为两个功能. 1.在请求到达控制器层之前进行拦截与过滤,只有通过验证的请求才能到达controller层 2.或者是在controller中运 ...
- 使用PHP生成二维码支持自定义logo
require_once 'phpqrcode/phpqrcode.php'; //引入类库 $text = "https://www.baidu.com/";//要生成二维码的文 ...