Jelajahi Sumber

优化运动超时检测与批量参数设置安全性

- 缩短机器人运动超时时间,增加各轴实时位置监控,超时无变化自动停止并记录日志,提升异常检测与容错能力
- 批量设置供料器编号、速度、深度等参数前增加有效性校验,参数异常时弹窗确认,防止误操作
- 设置起始Z坐标后校验终点坐标合理性,异常时警告用户
- 相机自动矫正前增加用户确认弹窗
- 整体提升系统健壮性与用户交互体验
孝锋 徐 8 bulan lalu
induk
melakukan
dba2c60216

+ 80 - 7
TeamAAS-VM/Core/Robots/XYZU_Robot.cs

@@ -171,7 +171,7 @@ namespace TeamAAS_VP.Core.Robots
             }
         }
 
-        public int Timeout { get; set; } = 120000;
+        public int Timeout { get; set; } = 5000;
 
         private bool _CanExecute = true;
 
@@ -483,9 +483,7 @@ namespace TeamAAS_VP.Core.Robots
                 CanExecute = false;
                 Dictionary<string, object> keyValues = new Dictionary<string, object>();
 
-                // 1. 复位所有轴的开始移动命令
-                //StopMove();
-
+                // 1. 写入目标位置到各轴的 ManuPositionNode
                 keyValues = new Dictionary<string, object>();
                 foreach (var axis in Axes)
                 {
@@ -514,12 +512,84 @@ namespace TeamAAS_VP.Core.Robots
                     return false;
                 }
 
-                // 4. 等待移动完成
+                // 准备停滞检测:收集所有实际位置节点
+                var actNodes = Axes.Where(a => !string.IsNullOrWhiteSpace(a.State.ActPositionNode))
+                                   .Select(a => a.State.ActPositionNode)
+                                   .Distinct()
+                                   .ToArray();
+
+                // lastPos 存储上一次读取到的位置,lastChange 存储上次发生“实质性”变化的时间
+                Dictionary<string, float> lastPos = new Dictionary<string, float>();
+                Dictionary<string, DateTime> lastChange = new Dictionary<string, DateTime>();
+                foreach (var node in actNodes)
+                {
+                    lastPos[node] = float.NaN;
+                    lastChange[node] = DateTime.UtcNow;
+                }
+
+                const float movementThreshold = 0.01f; // 判断位置变化的阈值,避免噪声
                 Stopwatch sw = new Stopwatch();
                 sw.Start();
                 while (true)
                 {
-                    //检查各轴是否到位和目标位置一致
+                    // 先读取各轴的实际位置,用于停滞检测
+                    Dictionary<string, object> posRead = new Dictionary<string, object>();
+                    try
+                    {
+                        if (actNodes.Length > 0)
+                        {
+                            posRead = Plc.ReadNodes(actNodes);
+                        }
+                    }
+                    catch
+                    {
+                        // 如果读取失败,继续让 CheckMoveFinished 来处理状态或超时
+                    }
+
+                    var now = DateTime.UtcNow;
+
+                    // 更新每个节点的变化时间:只要任意一个轴在最近 Timeout 时间内有变化,就视为系统仍在运动
+                    foreach (var node in actNodes)
+                    {
+                        float actual = 0;
+                        if (posRead != null && posRead.ContainsKey(node))
+                        {
+                            var raw = posRead[node];
+                            if (raw != null)
+                            {
+                                try { actual = Convert.ToSingle(raw); } catch { /* 保持 actual = 0 */ }
+                            }
+                        }
+
+                        if (float.IsNaN(lastPos[node]))
+                        {
+                            lastPos[node] = actual;
+                            lastChange[node] = now;
+                        }
+                        else
+                        {
+                            if (Math.Abs(actual - lastPos[node]) > movementThreshold)
+                            {
+                                // 有实质性变化,更新记录时间和值
+                                lastPos[node] = actual;
+                                lastChange[node] = now;
+                            }
+                            // 否则保持 lastChange 不变(表示该轴最近一次变化的时间)
+                        }
+                    }
+
+                    // 判断是否至少有一个轴在最近 Timeout 时间内发生过变化(即认为还在运动)
+                    bool anyAxisMovedRecently = actNodes.Any(node => (now - lastChange[node]).TotalMilliseconds <= Timeout);
+
+                    // 如果没有任何轴在最近 Timeout 时间内发生变化,则认为出现停滞异常
+                    if (!anyAxisMovedRecently && actNodes.Length > 0)
+                    {
+                        StopMove();
+                        LogHelper.WriteLogInfo($"轴停滞超时(整体判定),目标位置:X={position.X},Y={position.Y},Z={position.Z},U={position.U},超时阈值(ms)={Timeout}");
+                        return false;
+                    }
+
+                    // 检查是否整体到位或有错误(保留原有逻辑)
                     var (isFinished, isError) = CheckMoveFinished(position);
                     if (isFinished)
                     {
@@ -531,12 +601,15 @@ namespace TeamAAS_VP.Core.Robots
                         }
                         return true;
                     }
-                    if (sw.ElapsedMilliseconds > Timeout)
+
+                    // 检查整体超时(防止一直有抖动导致 anyAxisMovedRecently 一直为 true)
+                    if (sw.ElapsedMilliseconds > 60000) // 保守超时,一分钟,可根据需求调整
                     {
                         LogHelper.WriteLogInfo($"机器人执行移动超时,位置:X={position.X},Y={position.Y},Z={position.Z},U={position.U}");
                         StopMove();
                         return false;
                     }
+
                     Thread.Sleep(10);
                 }
             }

+ 57 - 0
TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs

@@ -924,6 +924,16 @@ namespace TeamAAS_VP.ViewModels.Product
         /// </summary>
         void ExecuteApplyLockPointFeederAndScrewProgramCommand()
         {
+            //检查供料器编号和螺丝程序编号是否大于0,如果小于等于0,则提示用户编号是否正确,是否继续写入
+            if (LockFeederNumber <= 0 || LockScrewProgramNumber <= 0)
+            {
+                var result = MessageBox.Show("供料器编号或螺丝程序编号小于等于0,是否继续写入?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                if (result != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+            }
+
             //遍历所有点位,设置供料器编号和螺丝程序编号
             foreach (var point in Points)
             {
@@ -937,6 +947,16 @@ namespace TeamAAS_VP.ViewModels.Product
         /// </summary>
         void ExecuteApplyLockPointSpeedCommand()
         {
+            //检查速度是否大于0,如果小于等于0,则提示用户速度是否正确,是否继续写入
+            if (LockXSpeed <= 0 || LockYSpeed <= 0 || LockZSpeed <= 0 || LockZDescendSpeed <= 0)
+            {
+                var result = MessageBox.Show("速度小于等于0,是否继续写入?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                if (result != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+            }
+
             //遍历所有点位,设置速度
             foreach (var point in Points)
             {
@@ -952,6 +972,16 @@ namespace TeamAAS_VP.ViewModels.Product
         /// </summary>
         void ExecuteApplyLockPointDepthCommand()
         {
+            //检查深度是否大于0,如果小于等于0,则提示用户深度是否正确,是否继续写入
+            if (LockZDepth <= 0)
+            {
+                var result = MessageBox.Show("深度小于等于0,是否继续写入?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                if (result != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+            }
+
             //遍历所有点位,设置Z深度
             foreach (var point in Points)
             {
@@ -964,11 +994,31 @@ namespace TeamAAS_VP.ViewModels.Product
         /// </summary>
         void ExecuteApplyLockPointStartZCommand()
         {
+            //检查起始Z坐标是否小于0,如果大于等于0,则提示用户坐标是否正确,是否继续写入
+            if (LockPointStartZ >= 0)
+            {
+                var result = MessageBox.Show("起始Z坐标大于等于0,是否继续写入?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                if (result != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+            }
+
             //遍历所有点位,设置起始Z坐标
             foreach (var point in Points)
             {
                 point.Z_Position_Start = LockPointStartZ;
             }
+
+            //检查终点坐标是否小于等于起始坐标,如果不是,则提示用户终点坐标大于等于起始坐标,用户需要去调整终点坐标
+            foreach (var point in Points)
+            {
+                if (point.Z_Position_Stop >= point.Z_Position_Start)
+                {
+                    MessageBox.Show($"点位编号 {point.Number} 的终点坐标大于等于起始坐标,请调整终点坐标!", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
+                }
+            }
+
         }
 
         /// <summary>
@@ -978,6 +1028,13 @@ namespace TeamAAS_VP.ViewModels.Product
         {
             try
             {
+                //弹窗提示用户是否确认要通过相机自动矫正锁附点位
+                var resultConfirm = MessageBox.Show("确认要通过相机自动矫正锁附点位吗?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                if (resultConfirm != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+
                 var view = new AutoCorrectLockPoint();
                 var vm = view.DataContext as AutoCorrectLockPointViewModel;
                 vm.Robot = Robot;