1. 添加标定操作及界面
2. 修改配置界面方法调用参数
3. SeerAGV添加电池信息监听
4. 添加AGV电池充电操作
5. 修改AGV状态变化操作,添加操作锁
| | |
| | | { |
| | | InitialCalibrationMethod(); |
| | | InitialAllTestMethod(); |
| | | |
| | | InitialDevices(); |
| | | } |
| | | } |
| | | } |
| | |
| | | private void btnStartCalibration_Click(object sender, EventArgs e) |
| | | { |
| | | btnStartCalibration.Enabled = false; |
| | | |
| | | IDevice device = cboCalibDevices.SelectedItem as IDevice; |
| | | try |
| | | { |
| | | IOperationConfig config = propCalibrationConfig.SelectedObject as IOperationConfig; |
| | |
| | | config.InputPara = null; |
| | | } |
| | | |
| | | _calibrationMethod.Invoke(Process, new object[] { config }); |
| | | _calibrationMethod.Invoke(Process, new object[] { config, device }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | #region Test |
| | | Dictionary<ProcessMethodAttribute, MethodInfo> _allTestMethod = new Dictionary<ProcessMethodAttribute, MethodInfo>(); |
| | | MethodInfo _testMethod = null; |
| | | |
| | | List<IDevice> _deviceList = new List<IDevice>(); |
| | | private void InitialDevices() |
| | | { |
| | | _deviceList = (Process as ProcessControl).GetDeviceList(); |
| | | |
| | | List<ISimpleDevice> list = _deviceList.Select(u => u as ISimpleDevice).ToList(); |
| | | UIHelper.SetCombo(cboCalibDevices, list, "Name", "Id"); |
| | | UIHelper.SetCombo(cboDevices, list, "Name", "Id"); |
| | | } |
| | | |
| | | private void InitialAllTestMethod() |
| | | { |
| | |
| | | |
| | | private void cboTestMethod_SelectedIndexChanged(object sender, EventArgs e) |
| | | { |
| | | //if (cboTestMethod.SelectedIndex >= 0) |
| | | //{ |
| | | // string methodCode = cboTestMethod.SelectedValue.ToString(); |
| | | // var attr = _allTestMethod.Keys.FirstOrDefault(u => u.MethodCode == methodCode); |
| | | // if (attr == null) |
| | | // return; |
| | | if (cboTestMethod.SelectedIndex >= 0) |
| | | { |
| | | string methodCode = cboTestMethod.SelectedValue.ToString(); |
| | | var attr = _allTestMethod.Keys.FirstOrDefault(u => u.MethodCode == methodCode); |
| | | if (attr == null) |
| | | return; |
| | | |
| | | // _testMethod = _allTestMethod[attr]; |
| | | _testMethod = _allTestMethod[attr]; |
| | | |
| | | // if (Process.StationConfig.ProcessOpConfigDict.Keys.Contains(methodCode)) |
| | | // { |
| | | // propGridTestMethod.SelectedObject = Process.StationConfig.ProcessOpConfigDict[methodCode]; |
| | | // } |
| | | // else |
| | | // { |
| | | // MessageBox.Show(@"Config of " + methodCode + @" is not found"); |
| | | // } |
| | | //} |
| | | if (Process.StationConfig.ProcessOpConfigDict.Keys.Contains(methodCode)) |
| | | { |
| | | propGridTestMethod.SelectedObject = Process.StationConfig.ProcessOpConfigDict[methodCode]; |
| | | } |
| | | else |
| | | { |
| | | MessageBox.Show(@"Config of " + methodCode + @" is not found"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void btnManualTrigger_Click(object sender, EventArgs e) |
| | | { |
| | | IDevice device = cboDevices.SelectedItem as IDevice; |
| | | new Task((m) => |
| | | { |
| | | MethodInfo method = m as MethodInfo; |
| | |
| | | invokeTimes = 1; |
| | | } |
| | | ProcessResponse response = null; |
| | | |
| | | if (invokeTimes == 1) |
| | | { |
| | | try |
| | | { |
| | | Stopwatch sw = new Stopwatch(); |
| | | sw.Start(); |
| | | response = method.Invoke(Process, new object[] { propGridTestMethod.SelectedObject as IOperationConfig }) as ProcessResponse; |
| | | response = method.Invoke(Process, new object[] { propGridTestMethod.SelectedObject as IOperationConfig, device }) as ProcessResponse; |
| | | sw.Stop(); |
| | | |
| | | //RecordMsg($"{method.Name}调用耗时:{sw.ElapsedMilliseconds}ms"); |
| | |
| | | this.cboProductionCode = new System.Windows.Forms.ComboBox(); |
| | | this.statusStrip1 = new System.Windows.Forms.StatusStrip(); |
| | | this.tsslLoginStatus = new System.Windows.Forms.ToolStripStatusLabel(); |
| | | this.cboDevices = new System.Windows.Forms.ComboBox(); |
| | | this.label5 = new System.Windows.Forms.Label(); |
| | | this.label6 = new System.Windows.Forms.Label(); |
| | | this.cboCalibDevices = new System.Windows.Forms.ComboBox(); |
| | | this.tabControl1.SuspendLayout(); |
| | | this.tbConfig.SuspendLayout(); |
| | | this.tbCalibration.SuspendLayout(); |
| | |
| | | // |
| | | // tbCalibration |
| | | // |
| | | this.tbCalibration.Controls.Add(this.label6); |
| | | this.tbCalibration.Controls.Add(this.cboCalibDevices); |
| | | this.tbCalibration.Controls.Add(this.label1); |
| | | this.tbCalibration.Controls.Add(this.propCalibrationConfig); |
| | | this.tbCalibration.Controls.Add(this.btnStartCalibration); |
| | |
| | | // label1 |
| | | // |
| | | this.label1.AutoSize = true; |
| | | this.label1.Location = new System.Drawing.Point(22, 20); |
| | | this.label1.Location = new System.Drawing.Point(262, 12); |
| | | this.label1.Name = "label1"; |
| | | this.label1.Size = new System.Drawing.Size(53, 12); |
| | | this.label1.TabIndex = 7; |
| | |
| | | | System.Windows.Forms.AnchorStyles.Right))); |
| | | this.cboCalibrationMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; |
| | | this.cboCalibrationMethod.FormattingEnabled = true; |
| | | this.cboCalibrationMethod.Location = new System.Drawing.Point(12, 41); |
| | | this.cboCalibrationMethod.Location = new System.Drawing.Point(252, 33); |
| | | this.cboCalibrationMethod.Name = "cboCalibrationMethod"; |
| | | this.cboCalibrationMethod.Size = new System.Drawing.Size(185, 20); |
| | | this.cboCalibrationMethod.TabIndex = 4; |
| | |
| | | // |
| | | this.tbTest.Controls.Add(this.label3); |
| | | this.tbTest.Controls.Add(this.txtInvokeTimes); |
| | | this.tbTest.Controls.Add(this.label5); |
| | | this.tbTest.Controls.Add(this.label2); |
| | | this.tbTest.Controls.Add(this.propGridTestMethod); |
| | | this.tbTest.Controls.Add(this.cboDevices); |
| | | this.tbTest.Controls.Add(this.btnTrigger); |
| | | this.tbTest.Controls.Add(this.cboTestMethod); |
| | | this.tbTest.Location = new System.Drawing.Point(4, 22); |
| | |
| | | // label2 |
| | | // |
| | | this.label2.AutoSize = true; |
| | | this.label2.Location = new System.Drawing.Point(21, 13); |
| | | this.label2.Location = new System.Drawing.Point(262, 12); |
| | | this.label2.Name = "label2"; |
| | | this.label2.Size = new System.Drawing.Size(53, 12); |
| | | this.label2.TabIndex = 11; |
| | |
| | | | System.Windows.Forms.AnchorStyles.Right))); |
| | | this.cboTestMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; |
| | | this.cboTestMethod.FormattingEnabled = true; |
| | | this.cboTestMethod.Location = new System.Drawing.Point(11, 34); |
| | | this.cboTestMethod.Location = new System.Drawing.Point(252, 33); |
| | | this.cboTestMethod.Name = "cboTestMethod"; |
| | | this.cboTestMethod.Size = new System.Drawing.Size(185, 20); |
| | | this.cboTestMethod.TabIndex = 9; |
| | |
| | | this.tsslLoginStatus.Text = "未登录"; |
| | | this.tsslLoginStatus.Click += new System.EventHandler(this.tsslLoginStatus_Click); |
| | | // |
| | | // cboDevices |
| | | // |
| | | this.cboDevices.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; |
| | | this.cboDevices.FormattingEnabled = true; |
| | | this.cboDevices.Location = new System.Drawing.Point(21, 33); |
| | | this.cboDevices.Name = "cboDevices"; |
| | | this.cboDevices.Size = new System.Drawing.Size(185, 20); |
| | | this.cboDevices.TabIndex = 9; |
| | | this.cboDevices.SelectedIndexChanged += new System.EventHandler(this.cboTestMethod_SelectedIndexChanged); |
| | | // |
| | | // label5 |
| | | // |
| | | this.label5.AutoSize = true; |
| | | this.label5.Location = new System.Drawing.Point(31, 12); |
| | | this.label5.Name = "label5"; |
| | | this.label5.Size = new System.Drawing.Size(53, 12); |
| | | this.label5.TabIndex = 11; |
| | | this.label5.Text = "选择设备"; |
| | | // |
| | | // label6 |
| | | // |
| | | this.label6.AutoSize = true; |
| | | this.label6.Location = new System.Drawing.Point(31, 12); |
| | | this.label6.Name = "label6"; |
| | | this.label6.Size = new System.Drawing.Size(53, 12); |
| | | this.label6.TabIndex = 13; |
| | | this.label6.Text = "选择设备"; |
| | | // |
| | | // cboCalibDevices |
| | | // |
| | | this.cboCalibDevices.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; |
| | | this.cboCalibDevices.FormattingEnabled = true; |
| | | this.cboCalibDevices.Location = new System.Drawing.Point(21, 33); |
| | | this.cboCalibDevices.Name = "cboCalibDevices"; |
| | | this.cboCalibDevices.Size = new System.Drawing.Size(185, 20); |
| | | this.cboCalibDevices.TabIndex = 12; |
| | | // |
| | | // ConfigFrm |
| | | // |
| | | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); |
| | |
| | | private System.Windows.Forms.StatusStrip statusStrip1; |
| | | private System.Windows.Forms.ToolStripStatusLabel tsslLoginStatus; |
| | | private System.Windows.Forms.CheckBox chkHardwareTrigger; |
| | | private System.Windows.Forms.Label label5; |
| | | private System.Windows.Forms.ComboBox cboDevices; |
| | | private System.Windows.Forms.Label label6; |
| | | private System.Windows.Forms.ComboBox cboCalibDevices; |
| | | } |
| | | } |
| | | |
| | |
| | | //TaskList.CollectionChanged += TaskList_CollectionChanged; |
| | | } |
| | | |
| | | object agvStatusLock = new object(); |
| | | public bool SetAGVStatus(TaskStatus status) |
| | | { |
| | | lock (agvStatusLock) |
| | | { |
| | | switch (status) |
| | | { |
| | | case TaskStatus.Available: |
| | | break; |
| | | case TaskStatus.Running: |
| | | if (AGVStatus == TaskStatus.Available) |
| | | { |
| | | AGVStatus = status; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | case TaskStatus.Warning: |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | AGVStatus = status; |
| | | return true; |
| | | } |
| | | } |
| | | //private void TaskList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) |
| | | //{ |
| | | // if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) |
| | |
| | | { |
| | | ProcessConfig config = scope.Resolve<ProcessConfig>(); |
| | | |
| | | config.RobotConfigCollection.ForEach(plc => |
| | | config.RobotConfigCollection.ForEach(robot => |
| | | { |
| | | _hash[plc.ID] = plc.Name; |
| | | _hash[robot.ID] = robot.Name; |
| | | }); |
| | | } |
| | | } |
| | |
| | | { |
| | | ProcessConfig config = scope.Resolve<ProcessConfig>(); |
| | | |
| | | config.CameraConfigCollection.ForEach(plc => |
| | | config.CameraConfigCollection.ForEach(camera => |
| | | { |
| | | _hash[plc.ID] = plc.Name; |
| | | _hash[camera.ID] = camera.Name; |
| | | }); |
| | | } |
| | | } |
| | |
| | | LoadFullTray = 3, |
| | | [Description("卸载满Tray地点")] |
| | | UnloadFullTray = 4, |
| | | [Description("充电地点")] |
| | | Charge = 5, |
| | | } |
| | | |
| | | public class PathPosition : IComplexDisplay |
| | |
| | | [Description("该位置标准点位信息")] |
| | | [TypeConverter(typeof(ComplexObjectConvert))] |
| | | [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))] |
| | | public CustomizedPoint StandardPoint { get; set; } = new CustomizedPoint(); |
| | | public CustomizedPointWithAngle StandardPoint { get; set; } = new CustomizedPointWithAngle(); |
| | | |
| | | [Category("视觉配置")] |
| | | [Description("该位置拍摄配置")] |
| | |
| | | |
| | | config.PositionCollection.ForEach(p => |
| | | { |
| | | _hash[p.PositionCode] = $"{p.PositionCode}-{p.Description.GetEnumDescription()}"; |
| | | _hash[p.PositionCode] = $"{p.PositionCode}-{p.PositionNo}-{p.Description.GetEnumDescription()}"; |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public class PositionNoConverter : ComboBoxItemTypeConvert |
| | | { |
| | | public override void GetConvertHash() |
| | | { |
| | | using (var scope = GlobalVar.Container.BeginLifetimeScope()) |
| | | { |
| | | var config = scope.Resolve<ProcessConfig>(); |
| | | |
| | | config.PositionCollection.ForEach(p => |
| | | { |
| | | _hash[p.PositionNo] = $"{p.PositionNo}-{p.PositionCode}-{p.Description.GetEnumDescription()}"; |
| | | }); |
| | | } |
| | | } |
| | |
| | | using Bro.Common.Base; |
| | | using Bro.Common.Helper; |
| | | using Bro.Common.Model; |
| | | using Bro.Common.Model.Interface; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | | using System.Collections.Generic; |
| | |
| | | namespace A032.Process.Calibration |
| | | { |
| | | [Device("CalibrationCollection", "多步标定配置", EnumHelper.DeviceAttributeType.OperationConfig)] |
| | | public class CalibrationConfigCollection : OperationConfigBase |
| | | public class CalibrationConfigCollection : OperationConfigBase, IComplexDisplay,IHalconToolPath |
| | | { |
| | | [Category("关联配置")] |
| | | [Description("位置代码")] |
| | | [TypeConverter(typeof(PositionCodeConverter))] |
| | | public string PositionCode { get; set; } |
| | | [Description("位置序号")] |
| | | [TypeConverter(typeof(PositionNoConverter))] |
| | | public int PositionNo { get; set; } |
| | | |
| | | [Category("关联配置")] |
| | | [Description("适用相机编号")] |
| | |
| | | [TypeConverter(typeof(CollectionCountConvert))] |
| | | [Editor(typeof(ComplexCollectionEditor<CalibrationConfig>), typeof(UITypeEditor))] |
| | | public List<CalibrationConfig> Configs { get; set; } = new List<CalibrationConfig>(); |
| | | |
| | | [Category("显示配置")] |
| | | [Description("是否显示UI,从UI启动标定")] |
| | | public bool IsStartedFromUI { get; set; } = false; |
| | | |
| | | public string GetDisplayText() |
| | | { |
| | | return $"PositionNo:{PositionNo}; Configs:{Configs.Count}"; |
| | | } |
| | | |
| | | public List<string> GetHalconToolPathList() |
| | | { |
| | | return Configs.SelectMany(c => c.GetHalconToolPathList()).ToList(); |
| | | } |
| | | } |
| | | |
| | | //[Device("Calibration", "单步标定配置", EnumHelper.DeviceAttributeType.OperationConfig)] |
| | | public class CalibrationConfig : OperationConfigBase, IComplexDisplay, INotifyPropertyChanged |
| | | public class CalibrationConfig : OperationConfigBase, IComplexDisplay, INotifyPropertyChanged, IHalconToolPath |
| | | { |
| | | private Bitmap image = null; |
| | | [JsonIgnore] |
| | |
| | | [Description("图像标准点坐标")] |
| | | [TypeConverter(typeof(ComplexObjectConvert))] |
| | | [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))] |
| | | public CustomizedPoint ImageMarkPoint { get; set; } = new CustomizedPoint(); |
| | | public CustomizedPointWithAngle ImageMarkPoint { get; set; } = new CustomizedPointWithAngle(); |
| | | |
| | | [Category("相机配置")] |
| | | [Description("相机操作配置")] |
| | |
| | | { |
| | | return JsonConvert.SerializeObject(this); |
| | | } |
| | | |
| | | public List<string> GetHalconToolPathList() |
| | | { |
| | | return CameraOpConfig.GetHalconToolPathList(); |
| | | } |
| | | } |
| | | } |
| | |
| | | namespace A032.Process.Calibration |
| | | { |
| | | [Device("Calibration_9P_Dynamic", "动态9点标定", EnumHelper.DeviceAttributeType.OperationConfigCtrl)] |
| | | public partial class CtrlCalib9PDynamic : UserControl, IConfigCtrl<CameraBase, CalibrationConfigCollection> |
| | | public partial class CtrlCalib9PDynamic : UserControl//, IConfigCtrl<CameraBase, CalibrationConfigCollection> |
| | | { |
| | | PubSubCenter PubSubCenter = PubSubCenter.GetInstance(); |
| | | AutoResetEvent _confirmHandle = new AutoResetEvent(false); |
| | |
| | | InitializeComponent(); |
| | | } |
| | | |
| | | public CtrlCalib9PDynamic(ProcessControl process, IDevice device, IOperationConfig config, Action<List<CalibrationConfig>> finalCalculation) |
| | | public CtrlCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<AGVBindUnit, int, int> commuAction, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation) |
| | | { |
| | | InitializeComponent(); |
| | | |
| | | ProcessControl = process; |
| | | Camera = device as CameraBase; |
| | | Config = config as CalibrationConfigCollection; |
| | | |
| | | Config = calibConfig as CalibrationConfigCollection; |
| | | |
| | | Camera = bind.Camera as CameraBase; |
| | | |
| | | Bind = bind; |
| | | Position = position; |
| | | CommuAction = commuAction; |
| | | FinalCalculation = finalCalculation; |
| | | } |
| | | |
| | | public CalibrationConfigCollection Config { get; set; } |
| | | public CameraBase Camera { get; set; } |
| | | public ProcessControl ProcessControl { get; set; } |
| | | public Action<List<CalibrationConfig>> FinalCalculation { get; set; } |
| | | AGVBindUnit Bind { get; set; } |
| | | PathPosition Position { get; set; } |
| | | Action<AGVBindUnit, int, int> CommuAction; |
| | | CalibrationConfigCollection Config { get; set; } |
| | | CameraBase Camera { get; set; } |
| | | ProcessControl ProcessControl { get; set; } |
| | | Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> FinalCalculation { get; set; } |
| | | |
| | | public CalibrationConfigCollection GetConfig() |
| | | { |
| | |
| | | |
| | | if (chkManualConfirm.Checked) |
| | | { |
| | | this.Invoke(new Action(() => btnContinueCalib.Visible = true)); ; |
| | | this.Invoke(new Action(() => btnContinueCalib.Visible = true)); ; |
| | | _confirmHandle.WaitOne(); |
| | | } |
| | | |
| | |
| | | |
| | | private void btnStartCalib_Click(object sender, EventArgs e) |
| | | { |
| | | if (chkOfflineCalib.Checked) |
| | | { |
| | | //ProcessControl.Calibration_Pick_9P_Dynamic_Offline(Config.Configs); |
| | | } |
| | | else |
| | | { |
| | | //ProcessControl.SendCalibStartSignal(Config.TriggerAddress); |
| | | } |
| | | //if (chkOfflineCalib.Checked) |
| | | //{ |
| | | // //ProcessControl.Calibration_Pick_9P_Dynamic_Offline(Config.Configs); |
| | | //} |
| | | //else |
| | | //{ |
| | | // //ProcessControl.SendCalibStartSignal(Config.TriggerAddress); |
| | | //} |
| | | |
| | | ProcessControl.MultipleStepsProcess(Config, Bind, CommuAction); |
| | | } |
| | | |
| | | private void btnLoadOfflineImages_Click(object sender, EventArgs e) |
| | |
| | | |
| | | private void btnStepRun_Click(object sender, EventArgs e) |
| | | { |
| | | //CalibrationConfig config = propGridConfig.SelectedObject as CalibrationConfig; |
| | | CalibrationConfig config = propGridConfig.SelectedObject as CalibrationConfig; |
| | | //if (!chkOfflineRun.Checked) |
| | | //{ |
| | | // ProcessControl.CalibMarkPoint(Camera, config, _selectedStepIndex + 1); |
| | |
| | | //} |
| | | |
| | | //tsslInfo.Text = $"单步运算完成。标记点坐标:{config.ImageMarkPoint.X},{config.ImageMarkPoint.Y}"; |
| | | |
| | | ProcessControl.SingleStepProcess(config, CommuAction, Bind, Position.PositionNo, _selectedStepIndex); |
| | | tsslInfo.Text = $"单步运算完成。标记点坐标:{config.ImageMarkPoint.X},{config.ImageMarkPoint.Y}"; |
| | | } |
| | | |
| | | private void btnCalcuMatrix_Click(object sender, EventArgs e) |
| | | { |
| | | FinalCalculation.Invoke(Config.Configs); |
| | | FinalCalculation.Invoke(Config, Bind, Position); |
| | | } |
| | | |
| | | private void btnSnap_Click(object sender, EventArgs e) |
| | |
| | | { |
| | | public partial class FrmCalib9PDynamic : Form |
| | | { |
| | | //private CalibrationConfigCollection calibConfig; |
| | | //private AGVBindUnit bind; |
| | | //private PathPosition position; |
| | | //private Action<AGVBindUnit, int, int> sendMessageToRobot_Calibration; |
| | | //private Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> calculateMatrix; |
| | | |
| | | public FrmCalib9PDynamic() |
| | | { |
| | | InitializeComponent(); |
| | | } |
| | | |
| | | public FrmCalib9PDynamic(ProcessControl process, IDevice device, IOperationConfig config, Action<List<CalibrationConfig>> finalCalculation) |
| | | //public FrmCalib9PDynamic(ProcessControl process, IDevice device, IOperationConfig config, Action<List<CalibrationConfig>> finalCalculation) |
| | | //{ |
| | | // InitializeComponent(); |
| | | |
| | | // Device = device as CameraBase; |
| | | // Config = config as CalibrationConfigCollection; |
| | | // FinalCalculation = finalCalculation; |
| | | // CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, device, config, finalCalculation); |
| | | //} |
| | | |
| | | public FrmCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<AGVBindUnit, int, int> commuAction, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation) |
| | | { |
| | | InitializeComponent(); |
| | | |
| | | Device = device as CameraBase; |
| | | Config = config as CalibrationConfigCollection; |
| | | FinalCalculation = finalCalculation; |
| | | CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, device, config, finalCalculation); |
| | | //Config = calibConfig; |
| | | //Bind = bind; |
| | | //Camera = Bind.Camera; |
| | | //Position = position; |
| | | //CommuAction = commuAction; |
| | | //FinalCalculation = finalCalculation; |
| | | |
| | | CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, calibConfig, bind, position, commuAction, finalCalculation); |
| | | } |
| | | |
| | | CameraBase Device { get; set; } |
| | | CalibrationConfigCollection Config { get; set; } |
| | | //AGVBindUnit Bind { get; set; } |
| | | //CameraBase Camera { get; set; } |
| | | //CalibrationConfigCollection Config { get; set; } |
| | | //PathPosition Position { get; set; } |
| | | //Action<AGVBindUnit, int, int> CommuAction; |
| | | //Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> FinalCalculation { get; set; } |
| | | |
| | | CtrlCalib9PDynamic CtrlCalib9PDynamic { get; set; } |
| | | Action<List<CalibrationConfig>> FinalCalculation { get; set; } |
| | | |
| | | private void FrmCalib9PDynamic_Load(object sender, EventArgs e) |
| | | { |
| | |
| | | using Bro.Common.Base; |
| | | using Bro.Common.Factory; |
| | | using A032.Process; |
| | | using Bro.Common.Model; |
| | | using Autofac; |
| | | |
| | | namespace Bro.Device.Station.Forms |
| | | { |
| | |
| | | |
| | | private void LoadMethodCodes() |
| | | { |
| | | IStationProcess sp = new ProcessControl(); |
| | | //switch (StationCode) |
| | | //{ |
| | | // case "S1": |
| | | // sp = new StationProcess_S1(false); |
| | | // break; |
| | | // case "S2": |
| | | // sp = new StationProcess_S2(false); |
| | | // break; |
| | | // case "S3": |
| | | // sp = new StationProcess_S3(false); |
| | | // break; |
| | | // case "S4": |
| | | // sp = new StationProcess_S4(false); |
| | | // break; |
| | | // case "S5": |
| | | // sp = new StationProcess_S5(false); |
| | | // break; |
| | | // case "S6": |
| | | // sp = new StationProcess_S6(false); |
| | | // break; |
| | | // case "S7": |
| | | // sp = new StationProcess_S7(false); |
| | | // break; |
| | | // //case "S0": |
| | | // // sp = new StationProcess_S0(false); |
| | | // // break; |
| | | //} |
| | | |
| | | OpBinds = new Dictionary<string, IOperationConfig>(); |
| | | |
| | | ProcessMethodList = sp.CollectProcessMethods(); |
| | | using (var scope = GlobalVar.Container.BeginLifetimeScope()) |
| | | { |
| | | ProcessMethodList = scope.Resolve<List<ProcessMethodAttribute>>(); |
| | | } |
| | | |
| | | ProcessMethodList.ForEach(u => |
| | | { |
| | |
| | | }); |
| | | } |
| | | |
| | | Dictionary<string, MethodInfo> InvokeMethodDict = new Dictionary<string, MethodInfo>(); |
| | | //Dictionary<string, MethodInfo> InvokeMethodDict = new Dictionary<string, MethodInfo>(); |
| | | public List<ProcessMethodAttribute> CollectProcessMethods() |
| | | { |
| | | List<ProcessMethodAttribute> resultList = new List<ProcessMethodAttribute>(); |
| | |
| | | if (attr != null) |
| | | { |
| | | resultList.Add(attr); |
| | | InvokeMethodDict[attr.MethodCode] = m; |
| | | //InvokeMethodDict[attr.MethodCode] = m; |
| | | } |
| | | }); |
| | | |
| | |
| | | StationConfig = LoadStationConfig(configPath); |
| | | |
| | | #region 个别配置的特别处理 |
| | | |
| | | #endregion |
| | | |
| | | _warningRemains.CollectionChanged -= _warningRemains_CollectionChanged; |
| | | _warningRemains.CollectionChanged += _warningRemains_CollectionChanged; |
| | | |
| | | InitialPLCs(); |
| | | InitialRobots(); |
| | | InitialAGVs(); |
| | | InitialRobots(); |
| | | InitialCameras(); |
| | | |
| | | InitialAGVBindUnit(); |
| | | |
| | | InitialMachineTrayNums(); |
| | | |
| | | AutoFacRegister(); |
| | |
| | | |
| | | agv.OnAGVPositoinChanged = OnAGVPositionChanged; |
| | | agv.OnAGVTaskStatusChanged = OnAGVTaskStatusChanged; |
| | | agv.OnAGVBatteryLvlChanged = OnAGVBatterLvlChanged; |
| | | }); |
| | | } |
| | | |
| | |
| | | { |
| | | InitialHalconTool(c as IHalconToolPath); |
| | | }); |
| | | |
| | | Config.ProcessOpConfigDict.Values.ToList().ForEach(c => |
| | | { |
| | | InitialHalconTool(c as IHalconToolPath); |
| | | }); |
| | | #endregion |
| | | } |
| | | |
| | |
| | | using Bro.Common.Helper; |
| | | using Bro.Common.Interface; |
| | | using Bro.Common.Model; |
| | | using HalconDotNet; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | using static Bro.Common.Helper.EnumHelper; |
| | | |
| | | namespace A032.Process |
| | | { |
| | | public partial class ProcessControl |
| | | { |
| | | CalibReplyMsg _calibReply = new CalibReplyMsg(); |
| | | |
| | | [ProcessMethod("CalibrationCollection", "RobotCalibration", "机器人9点标定", true)] |
| | | public ProcessResponse RobotCalibration(IOperationConfig config) |
| | | public ProcessResponse RobotCalibration(IOperationConfig config, IDevice device) |
| | | { |
| | | CalibrationConfigCollection calibConfig = config as CalibrationConfigCollection; |
| | | |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.CameraId == calibConfig.CameraId); |
| | | if (bind == null) |
| | | { |
| | | throw new ProcessException("未能获取绑定设备信息"); |
| | | } |
| | | |
| | | PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == calibConfig.PositionNo); |
| | | if (position == null) |
| | | { |
| | | throw new ProcessException("未能获取正确位置信息"); |
| | | } |
| | | |
| | | if (calibConfig.Configs.Count < 9) |
| | | { |
| | | throw new ProcessException("请至少配置9个标定点位"); |
| | | } |
| | | |
| | | if (calibConfig.IsStartedFromUI) |
| | | { |
| | | FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, SendMessageToRobot_Calibration, CalculateMatrix); |
| | | frm.ShowDialog(); |
| | | } |
| | | else |
| | | { |
| | | MultipleStepsProcess(calibConfig, bind, SendMessageToRobot_Calibration); |
| | | |
| | | CalculateMatrix(calibConfig, bind, position); |
| | | } |
| | | |
| | | //for (int i = 0; i < calibConfig.Configs.Count; i++) |
| | | //{ |
| | | // bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, calibConfig.PositionNo, new List<float>() { i + 1 }); |
| | | |
| | | // _calibReply.CalibHandle.WaitOne(); |
| | | |
| | | // if (_calibReply.CalibIndex != (i + 1) || _calibReply.CalibPositionNo != calibConfig.PositionNo) |
| | | // { |
| | | // throw new ProcessException("标定反馈的索引或位置信息不一致"); |
| | | // } |
| | | |
| | | // calibConfig.Configs[i].CurrentPlatPoint = new CustomizedPoint(_calibReply.RobotPosition.X, _calibReply.RobotPosition.Y); |
| | | |
| | | // using (HObject hImage = CollectHImage(bind.Camera, calibConfig.Configs[i].CameraOpConfig, "RobotCalibration")) |
| | | // { |
| | | // var tool = _halconToolDict[calibConfig.Configs[i].CameraOpConfig.AlgorithemPath]; |
| | | |
| | | // tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } }); |
| | | // tool.RunProcedure(); |
| | | |
| | | // float x = (float)tool.GetResultTuple("OUTPUT_X").D; |
| | | // float y = (float)tool.GetResultTuple("OUTPUT_Y").D; |
| | | // float angel = (float)tool.GetResultTuple("OUTPUT_Angle").D; |
| | | // if (x < 0 || y < 0) |
| | | // { |
| | | // throw new ProcessException("获取点位信息不正确"); |
| | | // } |
| | | |
| | | // calibConfig.Configs[i].ImageMarkPoint = new CustomizedPointWithAngle(x, y, angel); |
| | | // } |
| | | //} |
| | | |
| | | //HOperatorSet.VectorToHomMat2d(new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.Y).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.Y).ToArray()), out HTuple matrix); |
| | | |
| | | //var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode); |
| | | //if (visionConfig != null) |
| | | //{ |
| | | // visionConfig.Matrix = new List<double>() { matrix[0], matrix[1], 0, matrix[3], matrix[4], 0 }; |
| | | //} |
| | | //else |
| | | //{ |
| | | // Config.VisionConfigCollection.Add(new PositionVisionConfig() |
| | | // { |
| | | // CameraId = bind.CameraId, |
| | | // PositionCode = position.PositionCode, |
| | | // Matrix = new List<double>() { matrix[0], matrix[1], 0, matrix[3], matrix[4], 0 }, |
| | | // }); |
| | | //} |
| | | |
| | | return new ProcessResponse(true); |
| | | } |
| | | |
| | | [ProcessMethod("CalibrationCollection", "StandardPointCalibration", "标准点位标定", true)] |
| | | public ProcessResponse StandardPointCalibration(IOperationConfig config) |
| | | public ProcessResponse StandardPointCalibration(IOperationConfig config, IDevice device) |
| | | { |
| | | return new ProcessResponse(true); |
| | | } |
| | | CalibrationConfigCollection calibConfig = config as CalibrationConfigCollection; |
| | | |
| | | public void SendCalibrationStartSignal(int stepNum) |
| | | { |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.CameraId == calibConfig.CameraId); |
| | | if (bind == null) |
| | | { |
| | | throw new ProcessException("未能获取绑定设备信息"); |
| | | } |
| | | |
| | | } |
| | | PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == calibConfig.PositionNo); |
| | | if (position == null) |
| | | { |
| | | throw new ProcessException("未能获取正确位置信息"); |
| | | } |
| | | |
| | | private int MultipleStepsCalibration(CalibrationConfigCollection configs, Action<List<CalibrationConfig>> FinalCalculation) |
| | | { |
| | | throw new NotImplementedException(); |
| | | if (calibConfig.Configs.Count < 1) |
| | | { |
| | | throw new ProcessException("请至少配置1个标定点位"); |
| | | } |
| | | |
| | | //configs.Configs.ForEach(c => |
| | | if (calibConfig.IsStartedFromUI) |
| | | { |
| | | FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, SendMessageToRobot_Standard, CalculateStandardPoint); |
| | | frm.ShowDialog(); |
| | | } |
| | | else |
| | | { |
| | | MultipleStepsProcess(calibConfig, bind, SendMessageToRobot_Standard); |
| | | |
| | | CalculateStandardPoint(calibConfig, bind, position); |
| | | } |
| | | |
| | | //for (int i = 0; i < calibConfig.Configs.Count; i++) |
| | | //{ |
| | | // c.Image = null; |
| | | //}); |
| | | // bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, calibConfig.PositionNo, new List<float>() { i + 1 }); |
| | | |
| | | //if (string.IsNullOrWhiteSpace(configs.CameraId) || !CameraDict.ContainsKey(configs.CameraId)) |
| | | //{ |
| | | // throw new ProcessException("标定配置未配置正确的相机编号"); |
| | | //} |
| | | // _calibReply.CalibHandle.WaitOne(); |
| | | |
| | | //if (string.IsNullOrWhiteSpace(configs.PositionCode)) |
| | | //{ |
| | | // throw new ProcessException("标定配置未指定路径位置"); |
| | | //} |
| | | |
| | | //CameraBase camera = CameraDict[configs.CameraId]; |
| | | //FrmCalib9PDynamic frm9PDynamic = new FrmCalib9PDynamic(this, camera, configs, FinalCalculation); |
| | | //frm9PDynamic.ShowDialog(); |
| | | |
| | | //if (configs.InputPara == null || configs.InputPara.Count <= 0) |
| | | //{ |
| | | // return (int)PLCReplyValue.NG; |
| | | //} |
| | | |
| | | //if (configs.InputPara[0] <= 0 || configs.InputPara[0] > configs.Configs.Count) |
| | | //{ |
| | | // configs.InputPara = null; |
| | | // return (int)PLCReplyValue.IGNORE; |
| | | //} |
| | | |
| | | //int sequence = configs.InputPara[0]; |
| | | |
| | | ////第一次 |
| | | //if (sequence == 1) |
| | | //{ |
| | | // configs.Configs.ForEach(c => |
| | | // if (_calibReply.CalibPositionNo != calibConfig.PositionNo) |
| | | // { |
| | | // c.Image = null; |
| | | // c.OfflineImagePath = ""; |
| | | // c.CurrentPlatPoint = new CustomizedPoint(); |
| | | // c.ImageMarkPoint = new CustomizedPoint(); |
| | | // throw new ProcessException("标定反馈的位置信息不一致"); |
| | | // } |
| | | |
| | | // calibConfig.Configs[i].CurrentPlatPoint = new CustomizedPoint(_calibReply.RobotPosition.X, _calibReply.RobotPosition.Y); |
| | | |
| | | // using (HObject hImage = CollectHImage(bind.Camera, calibConfig.Configs[i].CameraOpConfig, "RobotCalibration")) |
| | | // { |
| | | // var tool = _halconToolDict[calibConfig.Configs[i].CameraOpConfig.AlgorithemPath]; |
| | | |
| | | // tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } }); |
| | | // tool.RunProcedure(); |
| | | |
| | | // float x = (float)tool.GetResultTuple("OUTPUT_X").D; |
| | | // float y = (float)tool.GetResultTuple("OUTPUT_Y").D; |
| | | // float angel = (float)tool.GetResultTuple("OUTPUT_Angle").D; |
| | | // if (x < 0 || y < 0) |
| | | // { |
| | | // throw new ProcessException("获取点位信息不正确"); |
| | | // } |
| | | |
| | | // calibConfig.Configs[i].ImageMarkPoint = new CustomizedPointWithAngle(x, y, angel); |
| | | // } |
| | | //} |
| | | |
| | | //CustomizedPointWithAngle markPoint = calibConfig.Configs[0].ImageMarkPoint; |
| | | //var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode); |
| | | //if (visionConfig != null) |
| | | //{ |
| | | // visionConfig.StandardPoint = new CustomizedPointWithAngle(markPoint.X, markPoint.Y, markPoint.Angle); |
| | | //} |
| | | //else |
| | | //{ |
| | | // Config.VisionConfigCollection.Add(new PositionVisionConfig() |
| | | // { |
| | | // CameraId = bind.CameraId, |
| | | // PositionCode = position.PositionCode, |
| | | // StandardPoint = new CustomizedPointWithAngle(markPoint.X, markPoint.Y, markPoint.Angle), |
| | | // }); |
| | | //} |
| | | |
| | | //CalibrationConfig stepConfig = configs.Configs[sequence - 1]; |
| | | return new ProcessResponse(true); |
| | | } |
| | | |
| | | //HDevEngineTool tool = _halconToolDict[] |
| | | public void CalculateMatrix(CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position) |
| | | { |
| | | //HOperatorSet.VectorToHomMat2d(new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.Y).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.Y).ToArray()), out HTuple matrix); |
| | | |
| | | //CalibMarkPoint(camera, stepConfig, sequence); |
| | | List<double> matrix = GetMovementMatrix(calibConfig.Configs.Select(u => u.ImageMarkPoint as CustomizedPoint).ToList(), calibConfig.Configs.Select(u => u.CurrentPlatPoint).ToList(), out string msg); |
| | | |
| | | ////获取当前平台点位 |
| | | //stepConfig.CurrentPlatPoint = new CustomizedPoint(_monitorList.Skip(locationStartIndex).Take(4).ToList()); |
| | | ////stepConfig.CurrentPlatPoint = new CustomizedPoint(configs.InputPara.Skip(1).Take(4).ToList()); |
| | | var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode); |
| | | if (visionConfig != null) |
| | | { |
| | | visionConfig.Matrix = new List<double>() { matrix[0], matrix[1], 0, matrix[3], matrix[4], 0 }; |
| | | } |
| | | else |
| | | { |
| | | Config.VisionConfigCollection.Add(new PositionVisionConfig() |
| | | { |
| | | CameraId = bind.CameraId, |
| | | PositionCode = position.PositionCode, |
| | | Matrix = new List<double>() { matrix[0], matrix[1], 0, matrix[3], matrix[4], 0 }, |
| | | }); |
| | | } |
| | | |
| | | ////最后一次 |
| | | //if (sequence == configs.Configs.Count) |
| | | PubSubCenter.Publish(PubTag.CalibAllDone.ToString(), "", msg, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取标定点的转换矩阵 |
| | | /// </summary> |
| | | /// <param name="points"></param> |
| | | /// <returns></returns> |
| | | protected List<double> GetMovementMatrix(List<CustomizedPoint> imagePoints, List<CustomizedPoint> platPoints, out string msg) |
| | | { |
| | | HTuple uList, vList, xList, yList, matrix; |
| | | |
| | | ConvertPointToHTuple(imagePoints, out uList, out vList); |
| | | ConvertPointToHTuple(platPoints, out xList, out yList); |
| | | |
| | | HOperatorSet.VectorToHomMat2d(uList, vList, xList, yList, out matrix); |
| | | |
| | | double sum = 0; |
| | | for (int i = 0; i < imagePoints.Count; i++) |
| | | { |
| | | HOperatorSet.AffineTransPoint2d(matrix, imagePoints[i].X, imagePoints[i].Y, out HTuple m, out HTuple n); |
| | | |
| | | sum += Math.Sqrt((Math.Pow((m.D - platPoints[i].X), 2) + Math.Pow((n.D - platPoints[i].Y), 2))); |
| | | } |
| | | |
| | | //sum = ((sum / (double)Config.LengthPulseRatio) * 100.0) / ((double)imagePoints.Count); |
| | | sum = sum / (double)imagePoints.Count; |
| | | |
| | | msg = $"标定点数量:{imagePoints.Count};单点误差:{sum.ToString()}脉冲"; |
| | | |
| | | return matrix.DArr.ToList(); |
| | | } |
| | | |
| | | private void ConvertPointToHTuple(List<CustomizedPoint> point, out HTuple x, out HTuple y) |
| | | { |
| | | x = new HTuple(point.Select(p => p.X).ToArray()); |
| | | y = new HTuple(point.Select(p => p.Y).ToArray()); |
| | | } |
| | | |
| | | public void CalculateStandardPoint(CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position) |
| | | { |
| | | //var bind = Config.AGVBindCollection.FirstOrDefault(u => u.CameraId == calibConfig.CameraId); |
| | | //if (bind == null) |
| | | //{ |
| | | // FinalCalculation?.Invoke(configs.Configs); |
| | | // throw new ProcessException("未能获取绑定设备信息"); |
| | | //} |
| | | |
| | | //configs.InputPara = null; |
| | | //return (int)PLCReplyValue.OK; |
| | | //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == calibConfig.PositionNo); |
| | | //if (position == null) |
| | | //{ |
| | | // throw new ProcessException("未能获取正确位置信息"); |
| | | //} |
| | | |
| | | CustomizedPointWithAngle markPoint = calibConfig.Configs[0].ImageMarkPoint; |
| | | var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode); |
| | | if (visionConfig != null) |
| | | { |
| | | visionConfig.StandardPoint = new CustomizedPointWithAngle(markPoint.X, markPoint.Y, markPoint.Angle); |
| | | } |
| | | else |
| | | { |
| | | Config.VisionConfigCollection.Add(new PositionVisionConfig() |
| | | { |
| | | CameraId = bind.CameraId, |
| | | PositionCode = position.PositionCode, |
| | | StandardPoint = new CustomizedPointWithAngle(markPoint.X, markPoint.Y, markPoint.Angle), |
| | | }); |
| | | } |
| | | |
| | | PubSubCenter.Publish(PubTag.CalibAllDone.ToString(), "", $"标定完成,标准点:{markPoint.GetDisplayText()}", true); |
| | | } |
| | | |
| | | public void MultipleStepsProcess(CalibrationConfigCollection calibConfig, AGVBindUnit bind, Action<AGVBindUnit, int, int> sendMessageToRobot) |
| | | { |
| | | for (int i = 0; i < calibConfig.Configs.Count; i++) |
| | | { |
| | | SingleStepProcess(calibConfig.Configs[i], sendMessageToRobot, bind, calibConfig.PositionNo, i); |
| | | } |
| | | } |
| | | |
| | | public void SendMessageToRobot_Calibration(AGVBindUnit bind, int positionNo, int index) |
| | | { |
| | | bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, positionNo, new List<float>() { index + 1 }); |
| | | |
| | | _calibReply.CalibHandle.WaitOne(); |
| | | |
| | | if (_calibReply.CalibIndex != (index + 1) || _calibReply.CalibPositionNo != positionNo) |
| | | { |
| | | throw new ProcessException("标定反馈的索引或位置信息不一致"); |
| | | } |
| | | } |
| | | |
| | | public void SendMessageToRobot_Standard(AGVBindUnit bind, int positionNo, int index) |
| | | { |
| | | bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.StandardPoint, Bro.Device.AuboRobot.RobotMsgParas.None, positionNo); |
| | | |
| | | _calibReply.CalibHandle.WaitOne(); |
| | | |
| | | if (_calibReply.CalibPositionNo != positionNo) |
| | | { |
| | | throw new ProcessException("标定反馈的位置信息不一致"); |
| | | } |
| | | } |
| | | |
| | | //PubSubCenter.Subscribe(PubTag.CalibStepDone.ToString(), CalibStepDone); |
| | | //PubSubCenter.Subscribe(PubTag.CalibAllDone.ToString(), CalibAllDone); |
| | | public void SingleStepProcess(CalibrationConfig config, Action<AGVBindUnit, int, int> sendMessageToRobot, AGVBindUnit bind, int positionNo, int index) |
| | | { |
| | | sendMessageToRobot.Invoke(bind, positionNo, index); |
| | | |
| | | config.CurrentPlatPoint = new CustomizedPoint(_calibReply.RobotPosition.X, _calibReply.RobotPosition.Y); |
| | | |
| | | using (HObject hImage = CollectHImage(bind.Camera, config.CameraOpConfig, "RobotCalibration")) |
| | | { |
| | | var tool = _halconToolDict[config.CameraOpConfig.AlgorithemPath]; |
| | | |
| | | tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } }); |
| | | tool.RunProcedure(); |
| | | |
| | | float x = (float)tool.GetResultTuple("OUTPUT_X").D; |
| | | float y = (float)tool.GetResultTuple("OUTPUT_Y").D; |
| | | float angel = (float)tool.GetResultTuple("OUTPUT_Angle").D; |
| | | if (x < 0 || y < 0) |
| | | { |
| | | throw new ProcessException("获取点位信息不正确"); |
| | | } |
| | | |
| | | config.ImageMarkPoint = new CustomizedPointWithAngle(x, y, angel); |
| | | } |
| | | |
| | | PubSubCenter.Publish(PubTag.CalibStepDone.ToString(), index, "", true); |
| | | } |
| | | } |
| | | |
| | | public class CalibReplyMsg |
| | | { |
| | | public AutoResetEvent CalibHandle { get; set; } = new AutoResetEvent(false); |
| | | |
| | | public int CalibIndex { get; set; } = 0; |
| | | |
| | | public int CalibPositionNo { get; set; } |
| | | |
| | | public CustomizedPoint RobotPosition { get; set; } = new CustomizedPoint(); |
| | | } |
| | | } |
| | |
| | | { |
| | | public partial class ProcessControl |
| | | { |
| | | const int WAITTIME = 5000; |
| | | |
| | | Dictionary<int, int> machineFullTrayDict = new Dictionary<int, int>(); |
| | | Dictionary<int, int> machineEmptyTrayDict = new Dictionary<int, int>(); |
| | | List<TaskAssignInfo> taskAssignedList = new List<TaskAssignInfo>(); |
| | | |
| | | #region AGV事件 |
| | | private void OnAGVBatterLvlChanged(SeerAGVDriver agv, float batterLvl) |
| | | { |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id); |
| | | SeerAGVInitialConfig iConfig = agv.InitialConfig as SeerAGVInitialConfig; |
| | | if (batterLvl <= iConfig.BatteryLvlToCharge) |
| | | { |
| | | Task.Run(() => |
| | | { |
| | | var position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.Charge); |
| | | |
| | | if (position == null) |
| | | { |
| | | throw new ProcessException("未找到充电地点"); |
| | | } |
| | | |
| | | while (bind.UnitStatus != TaskStatus.Available) |
| | | { |
| | | if (bind.SetAGVStatus(TaskStatus.Running)) |
| | | { |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | break; |
| | | } |
| | | |
| | | Thread.Sleep(WAITTIME); |
| | | } |
| | | }); |
| | | |
| | | return; |
| | | } |
| | | |
| | | if (batterLvl >= iConfig.BatteryLvlChargeDone) |
| | | { |
| | | bind.SetAGVStatus(TaskStatus.Available); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | private void OnAGVTaskStatusChanged(SeerAGVDriver agv, AGVTaskStatus taskStatus) |
| | | { |
| | |
| | | // bind.RobotStatus = TaskStatus.Running; |
| | | //} |
| | | |
| | | bind.AGVStatus = TaskStatus.Available; |
| | | bind.SetAGVStatus(TaskStatus.Available); |
| | | } |
| | | } |
| | | |
| | |
| | | // bind.RobotStatus = TaskStatus.Running; |
| | | //} |
| | | |
| | | bind.AGVStatus = TaskStatus.Available; |
| | | bind.SetAGVStatus(TaskStatus.Available); |
| | | |
| | | PathPosition position = Config.PositionCollection.FirstOrDefault(p => p.PositionCode == bind.AGVDest); |
| | | switch (position.Description) |
| | |
| | | } |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | private void OnRobotMsgReceived(DateTime dt, AuboRobotDriver robot, RobotMsg msg) |
| | | { |
| | |
| | | break; |
| | | case RobotMsgAction.Calibration: |
| | | { |
| | | _calibReply.CalibIndex = int.Parse(msg.Datas[4]); |
| | | _calibReply.CalibPositionNo = msg.Para2; |
| | | _calibReply.RobotPosition = new CustomizedPoint(float.Parse(msg.Datas[0]), float.Parse(msg.Datas[1])); |
| | | |
| | | _calibReply.CalibHandle.Set(); |
| | | } |
| | | break; |
| | | case RobotMsgAction.StandardPoint: |
| | | { |
| | | |
| | | _calibReply.CalibPositionNo = msg.Para2; |
| | | _calibReply.CalibHandle.Set(); |
| | | } |
| | | break; |
| | | default: |
| | |
| | | while (bind.IsEmptyTrayEmpty && !bind.IsEmptyTrayTaskAssigned) |
| | | { |
| | | //if (bind.TaskList.Count == 0) |
| | | if (bind.AGVStatus == TaskStatus.Available && bind.RobotStatus == TaskStatus.Available) |
| | | if (bind.UnitStatus == TaskStatus.Available) |
| | | { |
| | | //List<AGVTaskModel> models = new List<AGVTaskModel>(); |
| | | //models.Add(new AGVTaskModel(TaskAvailableLevel.Both, "AGV_LoadEmptyTray")); |
| | |
| | | |
| | | //AddNewTaskToBind(device.Id, models); |
| | | |
| | | AGV_LoadEmptyTray(bind.Id); |
| | | bind.IsEmptyTrayTaskAssigned = true; |
| | | if (AGV_LoadEmptyTray(bind.Id)) |
| | | { |
| | | bind.IsEmptyTrayTaskAssigned = true; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Thread.Sleep(500); |
| | | Thread.Sleep(WAITTIME); |
| | | } |
| | | } |
| | | }); |
| | |
| | | while (bind.IsFullTrayFull && !bind.IsFullTrayTaskAssigned) |
| | | { |
| | | //if (bind.TaskList.Count == 0) |
| | | if (bind.AGVStatus == TaskStatus.Available && bind.RobotStatus == TaskStatus.Available) |
| | | if (bind.UnitStatus == TaskStatus.Available) |
| | | { |
| | | //List<AGVTaskModel> models = new List<AGVTaskModel>(); |
| | | //models.Add(new AGVTaskModel(TaskAvailableLevel.Both, "AGV_UnloadFullTray")); |
| | |
| | | |
| | | //AddNewTaskToBind(device.Id, models); |
| | | |
| | | AGV_UnloadFullTray(bind.Id); |
| | | |
| | | bind.IsFullTrayTaskAssigned = true; |
| | | if (AGV_UnloadFullTray(bind.Id)) |
| | | { |
| | | bind.IsFullTrayTaskAssigned = true; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Thread.Sleep(500); |
| | | Thread.Sleep(WAITTIME); |
| | | } |
| | | } |
| | | }); |
| | |
| | | // return new ProcessResponse(true); |
| | | //} |
| | | |
| | | public void AGV_LoadEmptyTray(string bindId) |
| | | public bool AGV_LoadEmptyTray(string bindId) |
| | | { |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId); |
| | | PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray); |
| | |
| | | throw new ProcessException("路径配置未设置空Tray上料点"); |
| | | } |
| | | |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | if (bind.SetAGVStatus(TaskStatus.Running)) |
| | | { |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | |
| | | bind.AGVStatus = TaskStatus.Running; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | //[ProcessMethod("", "AfterEmptyTrayPositionArrived", "到达空Tray上料点", true)] |
| | |
| | | //bind.AddTask(model_AGV); |
| | | //bind.AddTask(model_Robot); |
| | | |
| | | AGV_UnloadEmptyTray(bind.Id, position); |
| | | |
| | | taskStatus.IsTaskAssgined = true; |
| | | taskStatus.AgvId = bind.AGVId; |
| | | if (AGV_UnloadEmptyTray(bind.Id, position)) |
| | | { |
| | | taskStatus.IsTaskAssgined = true; |
| | | taskStatus.AgvId = bind.AGVId; |
| | | } |
| | | } |
| | | } |
| | | |
| | | Thread.Sleep(300); |
| | | Thread.Sleep(WAITTIME); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | //[ProcessMethod("", "AGV_UnloadEmptyTray", "AGV去往卸载空Tray料位置", true)] |
| | | public void AGV_UnloadEmptyTray(string bindId, PathPosition position) |
| | | public bool AGV_UnloadEmptyTray(string bindId, PathPosition position) |
| | | { |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId); |
| | | |
| | |
| | | throw new ProcessException("路径配置未设置空Tray下料点"); |
| | | } |
| | | |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | if (bind.SetAGVStatus(TaskStatus.Running)) |
| | | { |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | |
| | | bind.AGVStatus = TaskStatus.Running; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | //[ProcessMethod("", "Robot_UnloadEmptyTray", "机器人运动至空Tray拍照位置", true)] |
| | |
| | | |
| | | adjust_X = (float)dx_Robot.D; |
| | | adjust_Y = (float)dy_Robot.D; |
| | | adjust_Angle = angle; |
| | | adjust_Angle = visionConfig.StandardPoint.Angle - angle; |
| | | } |
| | | |
| | | //bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.EmptyTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle }); |
| | |
| | | //bind.AddTask(model_AGV); |
| | | //bind.AddTask(model_Robot); |
| | | |
| | | AGV_LoadFullTray(bind.Id, position); |
| | | |
| | | taskStatus.IsTaskAssgined = true; |
| | | taskStatus.AgvId = bind.AGVId; |
| | | if (AGV_LoadFullTray(bind.Id, position)) |
| | | { |
| | | taskStatus.IsTaskAssgined = true; |
| | | taskStatus.AgvId = bind.AGVId; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | //[ProcessMethod("", "AGV_LoadFullTray", "AGV去往满Tray上料位置", true)] |
| | | public void AGV_LoadFullTray(string bindId, PathPosition position) |
| | | public bool AGV_LoadFullTray(string bindId, PathPosition position) |
| | | { |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId); |
| | | |
| | |
| | | throw new ProcessException("路径配置未设置满Tray上料点"); |
| | | } |
| | | |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | if (bind.SetAGVStatus(TaskStatus.Running)) |
| | | { |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | |
| | | bind.AGVStatus = TaskStatus.Running; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | //return new ProcessResponse(true); |
| | | } |
| | |
| | | |
| | | adjust_X = (float)dx_Robot.D; |
| | | adjust_Y = (float)dy_Robot.D; |
| | | adjust_Angle = angle; |
| | | adjust_Angle = visionConfig.StandardPoint.Angle - angle; |
| | | } |
| | | |
| | | //bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.FullTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle }); |
| | |
| | | // return new ProcessResponse(true); |
| | | //} |
| | | |
| | | public void AGV_UnloadFullTray(string bindId) |
| | | public bool AGV_UnloadFullTray(string bindId) |
| | | { |
| | | var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId); |
| | | PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray); |
| | |
| | | throw new ProcessException("路径配置未设置满Tray下料点"); |
| | | } |
| | | |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | if (bind.SetAGVStatus(TaskStatus.Running)) |
| | | { |
| | | bind.AGVDest = position.PositionCode; |
| | | bind.AGV.TaskOrder(position.PositionCode); |
| | | |
| | | bind.AGVStatus = TaskStatus.Running; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | //[ProcessMethod("", "Robot_UnloadFullTray", "机器人卸载满Tray", true)] |
| | |
| | | { |
| | | cbo.DataSource = dataSource; |
| | | cbo.DisplayMember = display; |
| | | cbo.ValueMember = value; |
| | | if (!string.IsNullOrWhiteSpace(value)) |
| | | { |
| | | cbo.ValueMember = value; |
| | | } |
| | | } |
| | | |
| | | public static void SetCombo(ToolStripComboBox cbo, object dataSource, string display, string value) |
| | | { |
| | | cbo.ComboBox.DataSource = dataSource; |
| | | cbo.ComboBox.DisplayMember = display; |
| | | cbo.ComboBox.ValueMember = value; |
| | | if (!string.IsNullOrWhiteSpace(value)) |
| | | { |
| | | cbo.ComboBox.ValueMember = value; |
| | | } |
| | | } |
| | | |
| | | public static void SetCombo(DataGridViewComboBoxColumn cbo, object dataSource, string display, string value) |
| | | { |
| | | cbo.DataSource = dataSource; |
| | | cbo.DisplayMember = display; |
| | | cbo.ValueMember = value; |
| | | if (!string.IsNullOrWhiteSpace(value)) |
| | | { |
| | | cbo.ValueMember = value; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | /// 操作配置的字典集合 |
| | | /// Key:MethodCode,Value:操作配置 |
| | | /// </summary> |
| | | //Dictionary<string, IOperationConfig> ProcessOpConfigDict { get; set; } |
| | | Dictionary<string, IOperationConfig> ProcessOpConfigDict { get; set; } |
| | | |
| | | ///// <summary> |
| | | ///// 仰拍相机标定矩阵 |
| | |
| | | ///// 仰拍相机拍摄的夹具工件的旋转中心图像坐标 |
| | | ///// </summary> |
| | | //CustomizedPoint RotationCenter { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 是否输出CSV文件 |
| | | /// </summary> |
| | |
| | | [Category("监听配置")] |
| | | [Description("是否采用简单监听模式。true:简单模式,只获取任务状态;false:全部模式,获取任务所有信息")] |
| | | public bool IsSimpleMonitor { get; set; } = true; |
| | | |
| | | private float batteryLvlToCharge = 0.1f; |
| | | [Category("充电配置")] |
| | | [Description("充电电池容量,电池容量低于该值时需要充电")] |
| | | public float BatteryLvlToCharge |
| | | { |
| | | get => batteryLvlToCharge; |
| | | set |
| | | { |
| | | if (value >= 1 || value <= 0) |
| | | { |
| | | value = 0.1f; |
| | | } |
| | | batteryLvlToCharge = value; |
| | | } |
| | | } |
| | | |
| | | private float batteryLvlChargeDone = 0.9f; |
| | | [Category("充电配置")] |
| | | [Description("充电完成电池容量,电池容量高于该值时确认充电完成")] |
| | | public float BatteryLvlChargeDone |
| | | { |
| | | get => batteryLvlChargeDone; |
| | | set |
| | | { |
| | | if (value >= 1 || value <= 0) |
| | | { |
| | | value = 0.9f; |
| | | } |
| | | batteryLvlChargeDone = value; |
| | | } |
| | | } |
| | | } |
| | | |
| | | [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.OperationConfig)] |
| | |
| | | CancelTask = 0x0BBB, |
| | | PauseTask = 0x0BB9, |
| | | TaskOrder = 0x0BEB, |
| | | |
| | | QueryBattery = 0x2AFF, |
| | | } |
| | | |
| | | public enum AGVTaskStatus |
| | |
| | | { |
| | | public Action<SeerAGVDriver, string> OnAGVPositoinChanged; |
| | | public Action<SeerAGVDriver, AGVTaskStatus> OnAGVTaskStatusChanged; |
| | | public Action<SeerAGVDriver, float> OnAGVBatteryLvlChanged; |
| | | |
| | | SeerAGVInitialConfig IConfig |
| | | { |
| | |
| | | { |
| | | msg_Position = new SeerMessage((int)AGVCode.QueryPosition, SID); |
| | | msg_GuideStatus = new SeerMessage((int)AGVCode.QueryTaskStatus, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : ""); |
| | | msg_Battery = new SeerMessage((int)AGVCode.QueryBattery, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : ""); |
| | | |
| | | Task.Run(() => |
| | | { |
| | |
| | | if (client_Guide != null && client_Guide.Connected) |
| | | { |
| | | CancelTask(); |
| | | client_Guide.Close(); |
| | | client_Guide.Close(); |
| | | client_Guide = null; |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | float batteryLvl = 0; |
| | | public float BatteryLvl |
| | | { |
| | | get => batteryLvl; |
| | | set |
| | | { |
| | | if (batteryLvl != value) |
| | | { |
| | | batteryLvl = value; |
| | | OnAGVBatteryLvlChanged?.Invoke(this, batteryLvl); |
| | | } |
| | | } |
| | | } |
| | | |
| | | SeerMessage msg_Position = new SeerMessage(); |
| | | SeerMessage msg_GuideStatus = new SeerMessage(); |
| | | SeerMessage msg_Battery = new SeerMessage(); |
| | | private void MonitorAGV() |
| | | { |
| | | while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) |
| | |
| | | SendMsg(client_State, IConfig.StatusPort, msg_Position); |
| | | Thread.Sleep(IConfig.ScanInterval); |
| | | SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus); |
| | | Thread.Sleep(IConfig.ScanInterval); |
| | | SendMsg(client_State, IConfig.StatusPort, msg_Battery); |
| | | Thread.Sleep(IConfig.ScanInterval); |
| | | } |
| | | catch (Exception ex) |
| | |
| | | case (int)AGVCode.QueryTaskStatus: |
| | | TaskStatus = (AGVTaskStatus)recMsg.JValues.Value<int>("task_status"); |
| | | break; |
| | | case (int)AGVCode.QueryBattery: |
| | | BatteryLvl = recMsg.JValues.Value<float>("battery_level"); |
| | | break; |
| | | default: |
| | | break; |
| | | } |