Sic.Framework/SimulatorCore/Robots/BrooksMag7RobotSimulator.cs

455 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Timers;
using MECF.Framework.Simulator.Core.SubstrateTrackings;
namespace MECF.Framework.Simulator.Core.Robots
{
public class BrooksMag7RobotSimulator : RobotSimulator
{
protected Random _rd = new Random();
public bool Failed { get; set; }
public string ErrorCode { get; set; }
public bool EventChecked { get; set; }
public string EventCode { get; set; }
public override Dictionary<string, double> MoveTimes
{
get { return moveTimes; }
set { moveTimes = value; }
}
public override ReadOnlyCollection<string> Arms
{
get { return arms; }
}
//private static string source = "BrooksMag7";
private static string msgDone = "_RDY";
private static string msgError = "_ERR";
private readonly string armAPan1 = "VTM.ArmA.Left";
private readonly string armAPan2 = "VTM.ArmA.Right";
private readonly string armBPan1 = "VTM.ArmB.Left";
private readonly string armBPan2 = "VTM.ArmB.Right";
private System.Timers.Timer timer;
private string currentStation;
private string newLocation;
private string currentArm;
private string newArm = "";
private string lastMsg;
private Dictionary<string, double> moveTimes;
private ReadOnlyCollection<string> arms;
public BrooksMag7RobotSimulator() : base(1102, 0, "\r", ' ', 5)
{
List<string> armsList = new List<string>();
armsList.Add(armAPan1);
armsList.Add(armAPan2);
armsList.Add(armBPan1);
armsList.Add(armBPan2);
arms = new ReadOnlyCollection<string>(armsList);
// create the message handling dictionary
AddCommandHandler("HOME", HandleHome);
AddCommandHandler("PICK", HandlePick);
AddCommandHandler("PLACE", HandlePlace);
AddCommandHandler("GOTO", HandleGoto);
AddCommandHandler("SWAP", HandleExchange);
AddCommandHandler("RQ", HandleRequest);
AddCommandHandler("Unknown", HandleUnknown);
//AddCommandHandler("SVON", HandleSVON);
// AddCommandHandler("SVOFF", HandleSVOFF);
timer = new System.Timers.Timer();
timer.Enabled = false;
timer.AutoReset = false;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
// Default move times based on Brooks spreadsheet
moveTimes = new Dictionary<string, double>();
moveTimes["PickPlace"] = 2.8;
moveTimes["Move90Degrees"] = 1.69;
moveTimes["Move180Degrees"] = 2.11;
moveTimes["HeightAdjust"] = 0.9;
moveTimes["ExtendRetract"] = 1.3;
moveTimes["WaferFactor"] = 1.0;
moveTimes["SwapAtPM"] = 7.3;
// Original default times based on Brooks log files
//moveTimes["PickPlace"] = 3.2;
//moveTimes["Move90Degrees"] = 1.5;
//moveTimes["Move180Degrees"] = 1.9;
//moveTimes["HeightAdjust"] = 0.9;
//moveTimes["ExtendRetract"] = 1.2;
//moveTimes["WaferFactor"] = 1.15;
currentArm = "A";
currentStation = "Unknown";
}
internal void HandleSVON(string msg)
{
if (ErrorMessage == "SVON Failed")
{
HandleError(ErrorMessage);
return;
}
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 1)
{
HandleError("Invalid SVON command (arguments)");
return;
}
HandleMove(RobotStateEnum.SVON, cmdComponents);
}
internal void HandleSVOFF(string msg)
{
if (ErrorMessage == "SVOFF Failed")
{
HandleError(ErrorMessage);
return;
}
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 1)
{
HandleError("Invalid SVOFF command (arguments)");
return;
}
HandleMove(RobotStateEnum.SVOFF, cmdComponents);
}
internal void HandleHome(string msg)
{
if (ErrorMessage == "Home Failed")
{
HandleError(ErrorMessage);
return;
}
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 2)
{
HandleError("Invalid homing command (arguments)");
return;
}
HandleMove(RobotStateEnum.Homing, cmdComponents);
}
internal void HandlePick(string msg)
{
msg = msg.Trim();
if (ErrorMessage == "Pick Failed")
{
HandleError(ErrorMessage);
return;
}
if (Failed && !string.IsNullOrEmpty(ErrorCode))
{
HandleError(ErrorMessage);
return;
}
if (EventChecked && !string.IsNullOrEmpty(EventCode))
{
HandleEvent(EventCode);
return;
}
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 6 && cmdComponents.Length != 8 && cmdComponents.Length != 10)
{
HandleError("Invalid pick command (arguments)");
return;
}
RobotStateEnum rs = RobotStateEnum.Picking;
if (cmdComponents.Length > 6 && cmdComponents[6] == "ENRT")
rs = RobotStateEnum.Extending;
else if (cmdComponents.Length > 6 && cmdComponents[6] == "STRT")
rs = RobotStateEnum.Retracting;
lastMsg = msg;
HandleMove(rs, cmdComponents);
}
internal void HandlePlace(string msg)
{
msg = msg.Trim();
if (ErrorMessage == "Place Failed")
{
HandleError(ErrorMessage);
return;
}
if (Failed && !string.IsNullOrEmpty(ErrorCode))
{
HandleError(ErrorMessage);
return;
}
if (EventChecked && !string.IsNullOrEmpty(EventCode))
{
HandleEvent(EventCode);
return;
}
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 6 && cmdComponents.Length != 8 && cmdComponents.Length != 10)
{
HandleError("Invalid place command (arguments)");
return;
}
RobotStateEnum rs = RobotStateEnum.Placing;
if (cmdComponents.Length > 6 && cmdComponents[6] == "ENRT")
rs = RobotStateEnum.Extending;
else if (cmdComponents.Length > 6 && cmdComponents[6] == "STRT")
rs = RobotStateEnum.Retracting;
lastMsg = msg;
HandleMove(rs, cmdComponents);
}
internal void HandleExchange(string msg)
{
if (ErrorMessage == "Swap Failed" || ErrorMessage == "Place Failed" || ErrorMessage == "Pick Failed")
{
HandleError(ErrorMessage);
return;
}
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 4)
{
HandleError("Invalid swap command (arguments)");
return;
}
lastMsg = msg;
HandleMove(RobotStateEnum.Exchanging, cmdComponents);
}
internal void HandleRequest(string msg)
{
string[] components = msg.Split(_msgDelimiter);
string reply = components[1];
if (components[1] == "WAFER" && components[2] == "PRESENT")
reply += " " + components[2] + GetArmStates();
else if (components[1] == "ERRMSG")
reply = LookupError(components[2]);
OnWriteMessage(reply);
OnWriteMessage(msgDone);
}
internal void HandleUnknown(string msg)
{
OnWriteMessage(msgDone);
}
internal void HandleGoto(string msg)
{
string[] cmdComponents = msg.Split(_msgDelimiter);
if (cmdComponents.Length != 11)
{
HandleError("Invalid move command (arguments)");
return;
}
HandleMove(RobotStateEnum.Approaching, cmdComponents);
}
private bool HandleMove(RobotStateEnum action, string[] cmdComponents)
{
if (robotStateArgs.State != RobotStateEnum.Idle &&
(action == RobotStateEnum.Homing && robotStateArgs.State != RobotStateEnum.Errored)) // allow homes when in error, but not other moves
{
HandleError("Already moving");
return false;
}
newLocation = "Unknown";
switch (action)
{
case RobotStateEnum.Picking:
case RobotStateEnum.Placing:
case RobotStateEnum.Approaching:
case RobotStateEnum.Extending:
case RobotStateEnum.Retracting:
case RobotStateEnum.Exchanging:
case RobotStateEnum.SVON:
case RobotStateEnum.SVOFF:
break;
default:
break;
}
if (ErrorMessage != "Pick Failed" && ErrorMessage != "Place Failed" && ErrorMessage != "Home Failed" &&
ErrorMessage != "Swap Failed" && !string.IsNullOrEmpty(ErrorMessage))
{
HandleError(ErrorMessage);
return false;
}
double delay = GetMoveTime(action);
timer.Interval = delay * 1000;
timer.Enabled = true;
return true;
}
private double GetMoveTime(RobotStateEnum action)
{
double rotationTime = 0;
double zMoveTime = 0;
if (newLocation != currentStation)
{
if (currentStation == "LL1" || currentStation == "LL2")
rotationTime = newLocation == "PM2" ? moveTimes["Move180Degrees"] : moveTimes["Move90Degrees"];
else
rotationTime = currentStation == "PM2" ? moveTimes["Move180Degrees"] : moveTimes["Move90Degrees"];
double factor = 1.0;
if (WaferTrack.Instance.IsOccupied(armAPan1) || WaferTrack.Instance.IsOccupied(armAPan2) ||
WaferTrack.Instance.IsOccupied(armBPan1) || WaferTrack.Instance.IsOccupied(armBPan2))
{
factor = moveTimes["WaferFactor"];
}
rotationTime *= factor;
}
else if (newArm != currentArm)
zMoveTime = moveTimes["HeightAdjust"];
switch (action)
{
case RobotStateEnum.Approaching:
if (newLocation == currentStation)
return moveTimes["HeightAdjust"];
return rotationTime;
case RobotStateEnum.Extending:
case RobotStateEnum.Retracting:
return moveTimes["ExtendRetract"] + rotationTime + zMoveTime;
case RobotStateEnum.Picking:
return moveTimes["PickPlace"] + zMoveTime;
case RobotStateEnum.Placing:
if (newLocation.StartsWith("PM"))
return moveTimes["PickPlace"] + zMoveTime;
else
return moveTimes["ExtendRetract"] + rotationTime + zMoveTime;
case RobotStateEnum.Exchanging:
return moveTimes["SwapAtPM"];
default:
return moveTimes["Move90Degrees"];
}
}
private void HandleError(string msg)
{
string errorCode = string.Format("0x{0}", lastError.ToString("x8"));
lastError++;
errorLookup[errorCode] = msg;
OnWriteMessage(msgError + " " + ErrorCode);
OnWriteMessage(msgDone);
}
private void HandleEvent(string msg)
{
// string errorCode = string.Format("0x{0}", lastError.ToString("x8"));
//lastError++;
//errorLookup[errorCode] = msg;
OnWriteMessage(msg);
OnWriteMessage(msgDone);
}
private string GetArmStates()
{
return " N N";
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
currentStation = newLocation;
currentArm = newArm;
if (robotStateArgs.State == RobotStateEnum.Picking || robotStateArgs.State == RobotStateEnum.Placing ||
robotStateArgs.State == RobotStateEnum.Extending || robotStateArgs.State == RobotStateEnum.Exchanging)
{
lastMsg = "";
}
SetRobotState(RobotStateEnum.Idle);
timer.Enabled = false;
OnWriteMessage(msgDone);
}
}
}