Commit 089dc454 SK

AGV架构

1 个父辈 773dbccc
using System;
using Acc.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AgvManager
namespace Acc.AgvManager
{
public class AgvManager{
......@@ -12,9 +13,34 @@ namespace AgvManager
public static Dictionary<string,AgvBean> agvBeanMap = new Dictionary<string, AgvBean>();
public static Node GetNode(string nodeName)
{
nodeMap.TryGetValue(nodeName, out Node node);
return node;
}
public static void UpdateNode(Node node)
{
string nodeName = node.GetNodeName();
if (nodeMap.ContainsKey(nodeName))
{
nodeMap.Add(nodeName, node);
}
else
{
nodeMap[nodeName] = node;
}
}
public static void UpdateNodeStatus(string nodeName, NodeStatus nodeStatus)
{
nodeMap.TryGetValue(nodeName, out Node node);
if(node != null)
{
node.UpdateNodeStatus(nodeStatus);
nodeMap[nodeName] = node;
}
}
public static void UpdateAgvStatus(string agvName, AgvStatus agvStatus)
......@@ -24,17 +50,18 @@ namespace AgvManager
public void onTimer()
{
foreach (var agvName in agvBeanMap)
foreach (AgvBean agvBean in agvBeanMap.Values)
{
AgvBean agvBean = agvBeanMap[agvName];
if (agvBean.isIdle() || agvBean.isInCharge())
if (agvBean.IsIdle() || agvBean.IsInCharge())
{
//空闲,判断电量,是否要进行充电
if (agvBean.needCharge())
if (agvBean.NeedCharge())
{
if (!agvBean.isInCharge())
if (!agvBean.IsInCharge())
{
//充电
LogUtil.info("AGV["+agvBean.Name+"]电量过低,执行充电任务");
}
}
......@@ -42,13 +69,12 @@ namespace AgvManager
{
//执行优先级最高的新任务
Job jobToExecute = null;
foreach (var nodeName in agvBeanMap)
foreach (Node node in nodeMap.Values)
{
Node node = nodeMap[nodeName];
Job job = node.GetNewJob(agvBean, nodeMap, agvBeanMap);
if (job != null)
{
if (jobToExecute == null || job.priority > jobToExecute.priority)
if (jobToExecute == null || job.GetPriority() > jobToExecute.GetPriority())
{
jobToExecute = job;
}
......@@ -57,15 +83,14 @@ namespace AgvManager
if (jobToExecute != null)
{
if (agvBean.isInCharge())
if (agvBean.IsInCharge())
{
//充电取消
LogUtil.info("AGV[" + agvBean.Name + "]充电任务中断");
}
agvBean.executeNewJob(jobToExecute);
LogUtil.info("AGV[" + agvBean.Name + "]开启新的任务"+ jobToExecute.ToString());
agvBean.ExecuteNewJob(jobToExecute);
}
}
}
else
......
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>42a5cbfa-785a-41f8-8e6c-3988db9eb07c</ProjectGuid>
<ProjectGuid>{42A5CBFA-785A-41F8-8E6C-3988DB9EB07C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AgvManager</RootNamespace>
<RootNamespace>Acc.AgvManager</RootNamespace>
<AssemblyName>AgvManager</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
......@@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
......@@ -29,26 +30,40 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>
<Reference Include="System.Core"/>
<Reference Include="System.Xml.Linq"/>
<Reference Include="System.Data.DataSetExtensions"/>
<Reference Include="Microsoft.CSharp"/>
<Reference Include="System.Data"/>
<Reference Include="System.Net.Http"/>
<Reference Include="System.Xml"/>
<Reference Include="log4net">
<HintPath>..\..\BOSCHStore\dll\log4net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="AgvManager.cs" />
<Compile Include="bean\AgvApi.cs" />
<Compile Include="bean\AgvBean.cs" />
<Compile Include="bean\AgvStatus.cs" />
<Compile Include="bean\Job.cs" />
<Compile Include="bean\JobStep.cs" />
<Compile Include="bean\Node.cs" />
<Compile Include="bean\NodeStatus.cs" />
<Compile Include="bean\PriorityLevel.cs" />
<Compile Include="demo\DoubleLineInNode.cs" />
<Compile Include="demo\LineNode.cs" />
<Compile Include="demo\NodePlace.cs" />
<Compile Include="demo\TakeEmptyShelfJob.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="util\LogUtil.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
\ No newline at end of file
using System;
public interface AgvApi
namespace Acc.AgvManager
{
public interface AgvApi
{
}
}
using System;
using Acc.Common;
using System;
using System.Collections.Generic;
public class AgvBean
namespace Acc.AgvManager
{
public AgvStatus agvStatus;
public AgvApi AgvApi;
public Job job;
public bool isIdle()
public class AgvBean
{
return false;
}
public AgvStatus agvStatus;
public AgvApi AgvApi;
public Job job;
public bool needCharge()
{
return false;
}
public string Name;
public void ExecuteNewJob(Job newJob)
{
job = newJob;
}
public bool IsIdle()
{
return false;
}
public void JobContinue(AgvBean currentAgvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap)
{
if(job != null)
public bool NeedCharge()
{
return false;
}
public void ExecuteNewJob(Job newJob)
{
job = newJob;
}
public void JobContinue(AgvBean currentAgvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap)
{
job.execute(agvBean, nodeMap, agvBeanMap);
if (job.IsEnd())
if (job != null)
{
//添加任务已经完成日志
job = null;
if (!job.IsProcess)
{
try
{
job.IsProcess = true;
job.Execute(currentAgvBean, nodeMap, agvBeanMap);
}catch(Exception e)
{
LogUtil.error("AGV["+Name+"]执行任务["+job.ToString()+"]出错",e);
}
finally
{
job.IsProcess = false;
}
}
if (job.IsEnd())
{
//添加任务已经完成日志
job = null;
}
}
}
}
internal bool IsInCharge()
{
throw new NotImplementedException();
}
}
}
using System;
namespace Acc.AgvManager
{
}
public class AgvStatus
{
public AgvStatus()
......
using System;
using System.Collections.Generic;
public interface Job
namespace Acc.AgvManager
{
/// <summary>
/// 任务优先级
/// </summary>
/// <returns></returns>
public virtual int GetPriority();
public abstract class Job
{
/// <summary>
/// 是否任务正在执行,防止任务执行时间过长产生多线程问题
/// </summary>
public bool IsProcess { get; set; }
/// <summary>
/// 任务是否已经结束
/// </summary>
/// <returns></returns>
public virtual bool IsEnd();
/// <summary>
/// 任务优先级
/// </summary>
/// <returns></returns>
public abstract int GetPriority();
/// <summary>
/// 根据任务状态继续执行任务
/// </summary>
public virtual void execute(AgvBean agvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap);
/// <summary>
/// 任务是否已经结束
/// </summary>
/// <returns></returns>
public abstract bool IsEnd();
/// <summary>
/// 根据任务状态继续执行任务
/// </summary>
public abstract void Execute(AgvBean agvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acc.AgvManager
{
public class JobStep<T> where T : Enum
{
private T step;
private string msg = "";
public string Msg
{
get { return msg; }
set
{
if (!string.IsNullOrEmpty(value))
{
//不为空,且与上一个消息不一样才打印
if (!value.Equals(msg))
{
LogUtil.info(value);
}
}
msg = value;
}
}
private DateTime startTime = DateTime.Now;
public JobStep(T initStep)
{
this.step = initStep;
this.msg = "";
}
/// <summary>
/// 当前步骤是否是某个步骤
/// </summary>
/// <param name="step"></param>
/// <returns></returns>
public bool IsStep(T step)
{
return this.step.Equals(step);
}
/// <summary>
/// 是否超时
/// </summary>
/// <param name="timeOutMilliseconds"></param>
/// <returns></returns>
public bool IsTimeOut(int timeOutMilliseconds)
{
TimeSpan span = DateTime.Now - startTime;
if (span.TotalMilliseconds > timeOutMilliseconds)
{
return true;
}
return false;
}
/// <summary>
/// 进入下一个步骤
/// </summary>
/// <param name="nextStep"></param>
public void ToNextStep(T nextStep)
{
step = nextStep;
startTime = DateTime.Now;
}
public string StatusStr()
{
return step.ToString();
}
}
}
using System;
using System.Collections.Generic;
public interface Node{
public string nodeName;
namespace Acc.AgvManager
{
public abstract class Node
{
protected NodeStatus nodeStatus = new NodeStatus();
public virtual Job GetNewJob(AgvBean currentAgvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap);
public abstract string GetNodeName();
public void UpdateNodeStatus(NodeStatus status)
{
nodeStatus = status;
}
public virtual Job GetNewJob(AgvBean currentAgvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap)
{
return null;
}
}
}
using System;
/// <summary>
/// 节点状态
/// </summary>
public class NodeStatus
namespace Acc.AgvManager
{
/// <summary>
/// 节点状态
/// </summary>
public class NodeStatus
{
public bool CanEnter = false;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acc.AgvManager
{
public class PriorityLevel
{
public static readonly int HIGH = 100;
public static readonly int MIDDLE = 50;
public static readonly int LOW = 1;
}
}
using Acc.AgvManager;
using Acc.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 双层线空料架Node
/// </summary>
namespace Acc.AgvManager.demo
{
public class DoubleLineInNode : Node
{
public override Job GetNewJob(AgvBean currentAgvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap)
{
//状态为未放满,且有解绑任务,如果没有其他小车执行回收空料架任务,分配一个任务
foreach(AgvBean agvBean in agvBeanMap.Values)
{
//已经有小车在执行了
if(agvBean.job is TakeEmptyShelfJob)
{
return null;
}
}
foreach(Node node in nodeMap.Values)
{
if(node is LineNode)
{
LineNode lineNode = (LineNode)node;
bool hasShelfToTake = lineNode.HasShelfToTake();
if (hasShelfToTake)
{
string nodeName = node.GetNodeName();
Job job = new TakeEmptyShelfJob(nodeName, PriorityLevel.MIDDLE);
}
}
}
return null;
}
public override string GetNodeName()
{
return PLACE.DOUBLE_LINE_IN;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acc.AgvManager.demo
{
/// <summary>
/// 产线
/// </summary>
public class LineNode : Node
{
private string _place;
/// <summary>
/// 解绑的RFID列表
/// </summary>
private List<String> unBindRfidList = new List<string>();
/// <summary>
/// 正在执行此任务的AGV,拉上料架后从列表中清除,同时ShelfTakeCount + 1
/// </summary>
private List<String> taskAgvList = new List<string>();
/// <summary>
/// 添加解绑料架
/// </summary>
/// <param name="rfid"></param>
public void AddUnBindRfid(string rfid)
{
if (!unBindRfidList.Contains(rfid))
{
Common.LogUtil.info("添加解绑料架["+rfid+"]");
unBindRfidList.Add(rfid);
}
else
{
Common.LogUtil.info("添加解绑料架[" + rfid + "]失败,该料架已经解绑过");
}
}
/// <summary>
/// 已经拉走了几个空料架
/// </summary>
public int AlreadyTakeCount { get; set; }
public LineNode(string place)
{
this._place = place;
}
public override string GetNodeName()
{
return _place;
}
/// <summary>
/// AGV已经拉上料架
/// </summary>
/// <returns></returns>
public void FinishedOneShelfTask(string agvName)
{
if (taskAgvList.Contains(agvName))
{
Common.LogUtil.info("AGV[" + agvName + "]已将[" + _place + "]的一个空料架拉上车,解除任务锁定");
taskAgvList.Remove(agvName);
AlreadyTakeCount = AlreadyTakeCount + 1;
if (AlreadyTakeCount == unBindRfidList.Count)
{
Common.LogUtil.info("[" + _place + "]的解绑的空料架已全部拉走");
AlreadyTakeCount = 0;
unBindRfidList = new List<string>();
}
}
}
/// <summary>
/// 是否有空料架需要回收
/// </summary>
/// <returns></returns>
public bool HasShelfToTake()
{
int remainUnBindShelf = unBindRfidList.Count - taskAgvList.Count - AlreadyTakeCount;
return remainUnBindShelf > 0;
}
/// <summary>
/// 开始一辆车去拉料架
/// </summary>
public bool StartOneTask(string agvName)
{
if(HasShelfToTask())
{
if (!taskAgvList.Contains(agvName))
{
taskAgvList.Add(agvName);
Common.LogUtil.info("AGV["+ agvName + "]锁定["+ _place + "]一个空料架任务");
}
}
return false;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acc.AgvManager.demo
{
public class PLACE
{
public static readonly string NONE = "";
/// <summary>
/// 待机点
/// </summary>
public static readonly string STAND_UP = "STAND_UP";
public static readonly string DOUBLE_LINE_IN = "A1";
public static readonly string LINE_C1 = "C1";
public static readonly string LINE_D1 = "D1";
}
}
using Acc.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acc.AgvManager.demo
{
/// <summary>
/// 回收空料架任务
/// </summary>
public class TakeEmptyShelfJob : Job
{
public TakeEmptyShelfJob(string palce, int priority)
{
emptyShelfPlace = palce;
_priority = priority;
}
/// <summary>
/// 空料架位置点
/// </summary>
private string emptyShelfPlace = PLACE.NONE;
/// <summary>
/// 优先级
/// </summary>
private int _priority;
private JobStep<TAKE_EMPTY_STEP> TakeEmptyStep = new JobStep<TAKE_EMPTY_STEP>(TAKE_EMPTY_STEP.NONE);
public override void Execute(AgvBean agvBean, Dictionary<string, Node> nodeMap, Dictionary<string, AgvBean> agvBeanMap)
{
if (TakeEmptyStep.IsStep(TAKE_EMPTY_STEP.NONE))
{
LogUtil.info("开始执行回收空料架任务,发送到AGV");
TakeEmptyStep.ToNextStep(TAKE_EMPTY_STEP.WAIT_AGV_START_TAKE_TASK);
Node node = AgvManager.GetNode(emptyShelfPlace);
if(node != null)
{
if(node is LineNode)
{
LineNode lineNode = (LineNode)node;
lineNode.StartOneTask(agvBean.Name);
AgvManager.UpdateNode(node);
}
}
}
else if (TakeEmptyStep.IsStep(TAKE_EMPTY_STEP.WAIT_AGV_START_TAKE_TASK))
{
//判断小车是否开始执行任务
bool isTaskStart = false;
if (isTaskStart)
{
LogUtil.info("AGV已接收并开始执行回收空料架任务,等待到达取架点");
TakeEmptyStep.ToNextStep(TAKE_EMPTY_STEP.WAIT_REACH_TAKE_PLACE);
}
}
}
public override int GetPriority()
{
return _priority;
}
public override bool IsEnd()
{
return TakeEmptyStep.IsStep(TAKE_EMPTY_STEP.END);
}
}
/// <summary>
/// AGV离开A4
/// </summary>
public enum TAKE_EMPTY_STEP
{
NONE,
/// <summary>
/// 等待AGV开始执行去取架点任务
/// </summary>
WAIT_AGV_START_TAKE_TASK,
/// <summary>
/// 等待AGV到达取架点
/// </summary>
WAIT_REACH_TAKE_PLACE,
/// <summary>
/// AGV到达取架点
/// </summary>
REACH_TAKE_PLACE,
/// <summary>
/// 送上双层线
/// </summary>
END
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using System.Reflection;
using System.Drawing;
namespace Acc.Common
{
public class LogUtil
{
public static readonly ILog AIOLog = LogManager.GetLogger("AIOBOXLog");
private static LogUtil instance = new LogUtil();
public delegate void ShowLog(string msg, Color color);
public static readonly ILog LOGGER = LogManager.GetLogger("RollingLogFileAppender");
public static readonly ILog rfidLog = LogManager.GetLogger("RfidLog");
public static Dictionary<int, DateTime> lastErrorLogTime = new Dictionary<int, DateTime>();
public static System.Windows.Forms.RichTextBox logBox = null;
public static int showCount = 25;
public static bool debug_opened = false;
public static void info(ILog log, string msg)
{
if (log == null)
{
return;
}
log.Info(msg);
AddToBox(msg, Color.Black);
//clear();
}
public static void info(ILog log, string msg, Color color)
{
log.Info(msg);
AddToBox(msg, color);
}
public static void debug(ILog log, string msg, Color color)
{
log.Debug(msg);
if (debug_opened)
{
AddToBox(msg, color);
}
}
public static void debug(ILog log, string msg)
{
log.Debug(msg);
if (debug_opened)
{
AddToBox(msg, Color.Gray);
}
}
public static void RfidLog(string msg)
{
rfidLog.Debug(msg);
}
public static void error(string errorMsg, int type, int seconds = 10)
{
if (lastErrorLogTime.ContainsKey(type))
{
TimeSpan span = DateTime.Now - lastErrorLogTime[type];
if (span.TotalSeconds > seconds)
{
lastErrorLogTime.Remove(type);
lastErrorLogTime.Add(type, DateTime.Now);
error(LOGGER, errorMsg);
}
}
else
{
lastErrorLogTime.Add(type, DateTime.Now);
error(LOGGER, errorMsg);
}
}
public static void error(ILog log, string errorMsg, Exception ex = null)
{
if (errorMsg.Trim().Equals("") && (ex == null))
{
return;
}
if (ex == null)
{
log.Error(errorMsg);
}
else
{
log.Error(errorMsg, ex);
}
AddToBox(errorMsg, Color.Red);
}
private static void AddToBox(string msg, Color color)
{
try
{
ShowLogPro(msg, color);
}
catch (Exception ex)
{
LOGGER.Error("出错:", ex);
}
}
private static List<string> logList = new List<string>();
public static string LastText = "";
private static void ShowLogPro(string msg, Color color)
{
try
{
if (logList.Count > 0)
{
// logList.RemoveAt(0);
}
if (logList.Count >= showCount)
{
logList.RemoveAt(0);
}
string text = "";
foreach (string str in logList)
{
text += str;
}
System.DateTime now = System.DateTime.Now;
logList.Add(now.ToLongTimeString() + " " + msg + Environment.NewLine);
if (logBox == null)
{
return;
}
LastText = text;
if (logBox.Visible)
{
logBox.Text = text;
// logBox.Focus(); //使文本框获取焦点
logBox.AppendText(now.ToLongTimeString() + " " + msg + Environment.NewLine); //增加文本
TimeSpan span = DateTime.Now - lastTime;
if (span.TotalSeconds > 3000000)
{
lastTime = DateTime.Now;
logBox.Select(logBox.Text.Length, 0); //设置光标的位置到文本尾
logBox.ScrollToCaret(); //滚动到控件光标处
}
}
}
catch (Exception ex)
{
LOGGER.Error("出错:" + ex.ToString());
}
}
private static DateTime lastTime = DateTime.Now;
public static void UpdateLogbox(System.Windows.Forms.RichTextBox box)
{
logBox = box;
if (logBox != null && logBox.Visible)
{
logBox.Text = LastText;
TimeSpan span = DateTime.Now - lastTime;
if (span.TotalSeconds > 3000000)
{
lastTime = DateTime.Now;
logBox.Select(logBox.Text.Length, 0); //设置光标的位置到文本尾
logBox.ScrollToCaret(); //滚动到控件光标处
}
}
}
public static void ClearLog()
{
if (logBox != null)
{
LastText = "";
logList.Clear();
logBox.Text = "";
}
}
public static void debug(string msg)
{
debug(LOGGER, msg);
}
public static void error(string errorMsg, Exception ex = null)
{
error(LOGGER, errorMsg, ex);
}
public static void info(string msg)
{
info(LOGGER, msg);
}
}
}
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!