模糊逻辑-穿越障碍

"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开源机器学习框架。这是一个很好的框架，它展示了使用推理引擎完成任务是多么容易。

在这一章中，我们将讨论:

1. 模糊逻辑

2. 避障与识别

3. AGV

模糊逻辑

#region 创建两个模糊集来表示凉和暖的温度
#region
TrapezoidalFunction function1 = new TrapezoidalFunction(13, 18, 23, 28);
FuzzySet fsCool = new FuzzySet("", function1);
double[,] coolValues = new double[20, 2];
for (int i = 10; i < 30; i++)
{
coolValues[i - 10, 0] = i;
coolValues[i - 10, 1] = fsCool.GetMembership(i);
}
chart?.UpdateDataSeries("", coolValues);
#endregion#region
TrapezoidalFunction function2 = new TrapezoidalFunction(23, 28, 33, 38);
FuzzySet fsWarm = new FuzzySet("", function2);
double[,] warmValues = new double[20, 2];
for (int i = 20; i < 40; i++)
{
warmValues[i - 20, 0] = i;
warmValues[i - 20, 1] = fsWarm.GetMembership(i);
}
chart?.UpdateDataSeries("", warmValues);
#endregion 暖
#endregion 创建两个模糊集来表示凉和暖的温度

LinguisticVariable lvTemperature = new LinguisticVariable("温度", 0, 80);
TrapezoidalFunction function1 = new TrapezoidalFunction(10, 15, TrapezoidalFunction.EdgeType.Right);
FuzzySet fsCold = new FuzzySet("", function1);
TrapezoidalFunction function2 = new TrapezoidalFunction(10, 15, 20, 25);
FuzzySet fsCool = new FuzzySet("", function2);
TrapezoidalFunction function3 = new TrapezoidalFunction(20, 25, 30, 35);
FuzzySet fsWarm = new FuzzySet("", function3);
TrapezoidalFunction function4 = new TrapezoidalFunction(30, 35, TrapezoidalFunction.EdgeType.Left);
FuzzySet fsHot = new FuzzySet("", function4);
double[][,] chartValues = new double[4][,];
for (int i = 0; i < 4; i++)
chartValues[i] = new double[160, 2];

#region 语言变量的形状——它的标签从开始到结束的形状
int j = 0;
for (float x = 0; x < 80; 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[0][j, 0] = x;
chartValues[0][j, 1] = y1;
chartValues[1][j, 0] = x;
chartValues[1][j, 1] = y2;
chartValues[2][j, 0] = x;
chartValues[2][j, 1] = y3;
chartValues[3][j, 0] = x;
chartValues[3][j, 1] = y4;
}
chart.UpdateDataSeries("", chartValues[0]);
chart.UpdateDataSeries("", chartValues[1]);
chart.UpdateDataSeries("", chartValues[2]);
chart.UpdateDataSeries("", chartValues[3]);
#endregion 语言变量的形状——它的标签从开始到结束的形状

模糊的自主移动小车

让我先来解释下什么是模糊推理系统。模糊推理系统是一种能够进行模糊计算的模型。这是使用数据库、语言变量和规则库完成的，所有这些都可以存储在内存中。

模糊推理系统的典型操作如下：

1. 获取数字输入
2. 结合激活规则的结果得到一个模糊输出
3. 验证输入激活了来自规则库的哪些规则
4. 利用带有语言变量的数据库获取每个数字输入的语言意义

#region 构成这些距离的语言标签(模糊集)

FuzzySet fsNear = new FuzzySet("Near", new TrapezoidalFunction(15, 50, TrapezoidalFunction.EdgeType.Right));

FuzzySet fsMedium = new FuzzySet("Medium", new TrapezoidalFunction(15, 50, 60, 100));

FuzzySet fsFar = new FuzzySet("Far", new TrapezoidalFunction(60, 100, TrapezoidalFunction.EdgeType.Left));

#endregion 构成这些距离的语言标签(模糊集)

#region 右侧测量距离（输入）

LinguisticVariable lvRight = new LinguisticVariable("RightDistance", 0, 120);

#endregion 右侧测量距离（输入）

#region 左侧测量距离（输入）

LinguisticVariable lvLeft = new LinguisticVariable("LeftDistance", 0, 120);

#endregion 左侧测量距离（输入）

#region 前方测量距离（输入）

LinguisticVariable lvFront = new LinguisticVariable("FrontalDistance", 0, 120);

#endregion 前方测量距离（输入）

#region 组成角度的语言标签(模糊集)

FuzzySet fsVN = new FuzzySet("VeryNegative", new TrapezoidalFunction(-40, -35, TrapezoidalFunction.EdgeType.Right));

FuzzySet fsN = new FuzzySet("Negative", new TrapezoidalFunction(-40, -35, -25, -20));

FuzzySet fsLN = new FuzzySet("LittleNegative", new TrapezoidalFunction(-25, -20, -10, -5));

FuzzySet fsZero = new FuzzySet("Zero", new TrapezoidalFunction(-10, 5, 5, 10));

FuzzySet fsLP = new FuzzySet("LittlePositive", new TrapezoidalFunction(5, 10, 20, 25));

FuzzySet fsP = new FuzzySet("Positive", new TrapezoidalFunction(20, 25, 35, 40));

FuzzySet fsVP = new FuzzySet("VeryPositive", new TrapezoidalFunction(35, 40, TrapezoidalFunction.EdgeType.Left));

#endregion 组成角度的语言标签(模糊集)

#region

LinguisticVariable lvAngle = new LinguisticVariable("Angle", -50, 50);

#endregion 角

#region 数据库

Database fuzzyDB = new Database();

#endregion 数据库

// 创建推理系统
IS = new InferenceSystem(fuzzyDB, new CentroidDefuzzifier(1000));

// 直走
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);
}

/// <summary>
/// 得到传感器的测量结果
/// </summary>
private void GetMeasures()

{
#region 获得自主移动小车的位置

pbTerrain.Image = CopyImage(OriginalMap);

Bitmap b = (Bitmap)pbTerrain.Image;

Point pPos = new Point(pbRobot.Left - pbTerrain.Left + 5, pbRobot.Top - pbTerrain.Top + 5);

#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, -1, 0);

Point pLeftObstacle = GetObstacle(pPos, b, 1, 90);

Point pRightObstacle = GetObstacle(pPos, b, 1, -90);

#region 显示线束

Graphics g = Graphics.FromImage(b);

if (cbLasers.Checked)
{
g.DrawLine(new Pen(Color.Red, 1), pFrontObstacle, pPos);

g.DrawLine(new Pen(Color.Red, 1), pLeftObstacle, pPos);

g.DrawLine(new Pen(Color.Red, 1), pRightObstacle, pPos);
}

#endregion 显示线束

#region 绘制AGV

if (btnRun.Text != RunLabel)
{
g.FillEllipse(new SolidBrush(Color.Blue), pPos.X - 5, pPos.Y - 5, 10, 10);
}

g.DrawImage(b, 0, 0);

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 + 90) * Math.PI) / 180;

int Offset = 0;

int Inc = -4;

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 / 2, pbRobot.Top - pbTerrain.Top + pbRobot.Height / 2);

Point p2 = new Point(p1.X + IncX, p1.Y + IncY);

g.DrawLine(new Pen(new SolidBrush(Color.Green)), p1, p2);

g.DrawImage(OriginalMap, 0, 0);

g.Dispose();
}

pbRobot.Top = pbRobot.Top + IncY;

pbRobot.Left = pbRobot.Left + IncX;
}

总结

在这一章中，我们学习了各种类型的模糊逻辑实现，并看到了使用AForge.NET将这种逻辑添加到我们的应用程序中是多么的容易。在我们的下一章中，我们将开始深入研究自组织地图，将我们的机器学习技能提升到一个新的层次。如果你还记得小学时上的美术课，这一章一定会给你带来回忆。

posted @ 2019-01-13 18:04  王振耀  阅读(...)  评论(...编辑  收藏