所谓交通管控,很容易理解,就是在某个固定区域中,哪辆AGV小车先行,哪辆AGV小车后走的问题;
一、前提条件
要想系统进行管制,必须要有良好的网络条件(无论wifi或者射频),此外AGV的硬件一定要好,否则数据丢包会变成家常便饭;此外,一定要进行多测试,进行压力测试,场景越多越好,代码写的再好场景测试不足,再好的代码也是瞎的。之前我们公司的项目曾经在无线模块上吃过亏,1600元的模块和200元的模块差异还是很大的,不要轻易相信厂家所谓的“我们用的没有问题”,一定要进行现场实地测试;
二、算法分析
简单的交通管控,如下图所示:
以上区域就构成了一个简单的交通管控区域,A、D为入口点,C、B分别为出口点,简单的算法只要小车到入口点停止,然后系统判断该区域中是否有运行的小车即可,如果没有小车那么直接放行改agv即可;如果有小车那么需要,将小车加入等待队列,且用前一辆车进行管控,当且仅当前一辆车出管制区后才能放行;
此处建议大伙将程序写成单例的,否则太耗资源了,单例代码如下:
private static readonly AgvControlService instance = new AgvControlService();
private AgvControlService()
{
}
public static AgvControlService GetInstance()
{
return instance;
}
判断逻辑如下:(1)先校验是否需要进行管控,如果需要在判断是否在出口
//管控点是否需要管控
if (!checkNeedControl(currentLankMark))
{
logger.Info("[AGV-NO-NEED-CONTROL]:Landmarks:{0},AGV:{1}", currentLankMark, agv.Id);
return;
}
ControlPoint controlPoint = controlPointList.Where(m => m.LandMarkId == currentLankMark).FirstOrDefault();
if (controlPoint == null)
{
return;
}
#region 判断是出口
if (controlPoint.IsExported)
{
#region 将小车移除管制区
AgvControlGroupModelList.RemoveAll(m => m.Agv.Id == agv.Id && m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId);
#endregion
#region 遍历这个管制区是否有被该车管制住等待的小车 放行等待的车
AgvControlGroupModel currentControlGroupAgv = AgvControlGroupModelList.Where(m => m.ControlAgv == agv.Id && m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId).OrderBy(m => m.EnterTime).FirstOrDefault();
if (currentControlGroupAgv != null)
{
startAgv(currentControlGroupAgv.Agv);
AgvControlGroupModelList.Remove(currentControlGroupAgv);
currentControlGroupAgv.ControlState = ControlState.Entering;
AgvControlGroupModelList.Add(currentControlGroupAgv);
return;
}
#endregion
return;
}
#endregion
(2)判断是否在入口
#region 判断是入口
if (!controlPoint.IsExported)
{
#region 第一步 判断管制区有木有车?
//没有车直接放行
var enteringAGV = AgvControlGroupModelList.Where(m => m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId && m.ControlState == ControlState.Entering);
if (enteringAGV == null || enteringAGV.Count() < 1)
{
logger.Info("[AGV-CONTROL-MSG]NO CARS IN THIS AREA ,SO RELEASE THIS AGV[{0}]", agv.Id);
AgvControlGroupModel enterAgvControlGroupModel = new AgvControlGroupModel()
{
Agv = agv,
ControlPoint = controlPoint,
ControlState = ControlState.Entering,
EnterTime = DateTime.Now
};
AgvControlGroupModelList.RemoveAll(m => m.Agv.Id == agv.Id && m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId);
AgvControlGroupModelList.Add(enterAgvControlGroupModel);
startAgv(agv);
return;
}
#endregion
#region 第二步 判断正在运行的小车是否是这个
var list = enteringAGV.Where(m=>m.Agv.Id==agv.Id);
if (list!= null&&list.Count()>0)
{
logger.Info("[AGV-CONTROL-MSG]THIS CAR IS ENTERING CAR ,SO NO COMMAND AGV[{0}]", agv.Id);
startAgv(agv);
return;
}
#endregion
#region 第三步 判断正在等待的小车是否是这个
var waitAGV = AgvControlGroupModelList.Where(m => m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId && m.ControlState == ControlState.Wait);
if (waitAGV != null && waitAGV.Count() > 0)
{
List<AGV> waitList = waitAGV.Select(m => m.Agv).ToList();
if (waitList.FindAll(m => m.Id == agv.Id) != null)
{
logger.Info("[AGV-CONTROL-MSG]THIS CAR IS WAIT CAR ,SO NO COMMAND AGV[{0}]", agv.Id);
return;
}
// return;
}
#endregion
//先等待的车管制后进的小车
AgvControlGroupModel newWaitControlGroupModel = new AgvControlGroupModel()
{
Agv = agv,
ControlPoint = controlPoint,
ControlState = ControlState.Wait,
EnterTime = DateTime.Now,
ControlAgv = item.Agv.Id
};
AgvControlGroupModelList.RemoveAll(m => m.Agv.Id == agv.Id && m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId);
AgvControlGroupModelList.Add(newWaitControlGroupModel);
quickStopAgv(agv);
return;
}
#endregion
这样就可以实现一个最简单的交通管制了,但是此方法在业务层面上,效率不是很高;可能存在A->B或者D->C同时存在两辆车,如果后一辆车必须等着前一辆车出管制区,才能启动的话,效率就有点低了;为此我们可以认为A->B是同一类型的,D->C是同一类型的,如果此种情况同时出现,我们可以在放行前一辆车的同时放行后一辆车
var item = enteringAGV.OrderByDescending(m => m.EnterTime).FirstOrDefault();
if (!string.IsNullOrEmpty(controlPoint.Name) && !string.IsNullOrEmpty(item.ControlPoint.Name) && controlPoint.Name.Equals(item.ControlPoint.Name))
{
AgvControlGroupModel enterAgvControlGroupModel = new AgvControlGroupModel()
{
Agv = agv,
ControlPoint = controlPoint,
ControlState = ControlState.Entering,
EnterTime = DateTime.Now
};
AgvControlGroupModelList.RemoveAll(m => m.Agv.Id == agv.Id && m.ControlPoint.ControlGroupId == controlPoint.ControlGroupId);
AgvControlGroupModelList.Add(enterAgvControlGroupModel);
startAgv(agv);
return;
}
复杂的交通管制,会在管制区中嵌套多个管制区,或者再管制区中再对接其他的指令,这种情况就需要现场仔细调试了。