C#--運動控制--運動暫停思路--檢測沿信號方法


以下是學習筆記:

1.思路分析:

【1.1】運動的兩種方式:

相對運動:相對於現在的位置走一段距離,相對運動走暫停比較麻煩,某一瞬間按了暫停,可能不知道走了多少,恢復比較麻煩。

絕對運動:回原點,相對於原點的位置,相對運動做暫停簡單些。

【1.2】暫停按鈕放在哪里?

查看說明書:給軸運動指令號,暫停按鈕應該放在等待停止的中。

 

 

 2,封裝的運動控制方法

【2.1】Motion.cs中:封裝的單軸絕對定位的方法:就是發一個運動指令

        #region 單軸絕對定位

        /// <summary>
        /// 單軸絕對定位
        /// </summary>
        /// <param name="axis">軸號</param>
        /// <param name="pos">位置</param>
        /// <param name="vel">速度</param>
        /// <param name="acc">加減速度</param>
        /// <returns></returns>
        public OperationResult MoveAbs(short axis, double pos, double vel = 10, double acc = 0.0125)
        {
            //通用運動初始化驗證

            OperationResult result = CommonMotionValidate(axis);
            if (!result.IsSuccess) return result;

            short error = 0;

            try
            {
                //清除標志
                error = gts.GT_ClrSts(axis, 1);
                ErrorHandler("GT_ClrSts", error);

                // 將軸設為點動模式
                error = gts.GT_PrfTrap(axis);
                ErrorHandler("GT_PrfTrap", error);

                //創建一個TJboPra對象
                gts.TTrapPrm trap;

                //讀取點位運動參數
                error = gts.GT_GetTrapPrm(axis,out trap);
                ErrorHandler("GT_GetTrapPrm", error);

                trap.acc = acc;
                trap.dec = acc;
                trap.smoothTime = 25;//[0,50]

                //設置點位運動參數
                error = gts.GT_SetTrapPrm(axis, ref trap);
                ErrorHandler("GT_SetTrapPrm", error);

                int posPulse = 0;

                if (axis == advancedParameter.Axis_X)
                {
                    posPulse = Convert.ToInt32(Math.Round(pos * advancedParameter.Scale_X));
                }
                else if (axis == advancedParameter.Axis_Y)
                {
                    posPulse = Convert.ToInt32(Math.Round(pos * advancedParameter.Scale_Y));
                }
                else if (axis == advancedParameter.Axis_Z)
                {
                    posPulse = Convert.ToInt32(Math.Round(pos * advancedParameter.Scale_Z));
                }
                else
                {
                    posPulse = Convert.ToInt32(pos);
                }

                //設置AIXS軸的目標位置
                error = gts.GT_SetPos(axis, posPulse);
                ErrorHandler("GT_SetPos", error);
                //設置AIXS軸的目標速度
                error = gts.GT_SetVel(axis, vel);
                ErrorHandler("GT_SetVel", error);
                //【上面的代碼,都是設置參數的,GT_Update之前都是不動的】
                //設置AIXS軸的的運動【調用GT_Update就是發運動指令,發完運動指令就開始運動的,發完運動指令后代碼就結束了,不等待的】
                error = gts.GT_Update(1<<(axis-1));
                ErrorHandler("GT_Update", error);

            }
            catch (Exception e)
            {
                result.IsSuccess = false;
                result.ErrorMsg = e.Message;
                return result;
            }

            return OperationResult.CreateSuccessResult();
        }

        /// <summary>
        /// 單軸絕對定位,方法的重載
        /// </summary>
        /// <param name="axis">軸相關信息類</param>
        /// <returns></returns>
        public OperationResult MoveAbs(Axis axis)
        {
            return MoveAbs(axis.AxisNo, axis.AxisDestPos, axis.AxisDestVel, axis.AxisDestAcc);
        }
        #endregion

 

【2.1】Motion.cs中:封裝的2單軸絕對定位的方法,就是調用上一個方法,實際自動流程中就是調用這里的方法。

 

        #region 2軸絕對定位

        /// <summary>
        /// 2軸絕對定位
        /// </summary>
        /// <param name="axis">軸號</param>
        /// <param name="pos">位置</param>
        /// <param name="vel">速度</param>
        /// <param name="acc">加減速度</param>
        /// <returns>操作結果</returns>
        public OperationResult Move2DAbs(short[] axis, double[] pos,double[] vel,double[] acc)
        {
            if (axis.Length == 2 && pos.Length == 2 && vel.Length == 2 && acc.Length == 2)//保證是2軸的2個參數
            {
                //通用運動初始化驗證
                OperationResult result = CommonMotionValidate(axis[0]);
                if (!result.IsSuccess) return result;

                result = CommonMotionValidate(axis[1]);
                if (!result.IsSuccess) return result;

                Axis axisInfoX=new Axis();
                axisInfoX.AxisNo = axis[0];
                axisInfoX.AxisDestPos = pos[0];
                axisInfoX.AxisDestVel = vel[0];
                axisInfoX.AxisDestAcc = acc[0];

                Axis axisInfoY = new Axis();
                axisInfoY.AxisNo = axis[1];
                axisInfoY.AxisDestPos = pos[1];
                axisInfoY.AxisDestVel = vel[1];
                axisInfoY.AxisDestAcc = acc[1];

                //絕對定位
                result = MoveAbs(axisInfoX);
                if (!result.IsSuccess) return result;

                result = MoveAbs(axisInfoY);
                if (!result.IsSuccess) return result;

                //【分析】上面的“絕對定位”的代碼只是發了一個運動指令就結束了,就開始運動了,不費時間的
                //【分析】費時間的是下面的“等待停止”的代碼,軸運動了之后就一直等,一直在循環等待運動到位后軸停止

                //等待停止
                result = WaitStop(new List<Axis>(){ axisInfoX, axisInfoY });
                if (!result.IsSuccess) return result;



                return OperationResult.CreateSuccessResult();
            }
            return new OperationResult()
            {
                IsSuccess = false,
                ErrorMsg = "傳遞參數長度不正確"
            };
        }

        #endregion

 

【2.3】Motion.cs中:封裝的等待軸正常停止的方法,只要把判斷暫停放在這里就可以了。

 

 

 

 

 

        #region 等待軸正常停止

        /// <summary>
        /// 等待軸正常停止
        /// </summary>
        /// <param name="axis">軸號</param>
        /// <returns>操作結果</returns>
        public OperationResult WaitStop(Axis axis)
        {
            //通用運動初始化驗證
            OperationResult result = CommonMotionValidate(axis.AxisNo);
            if (!result.IsSuccess) return result;

            short error = 0;
            //軸狀態
            int sts;

            do
            {
                //如果isPause==True有人按了暫停
                if (isPause)
                {
                    StopAxis(axis.AxisNo);
                    while (true)
                    {
                        if (isPause)
                        {
                            Thread.Sleep(10);
                        }
                        else
                        {
                            //恢復指令
                            MoveAbs(axis);

                            //繼續走
                            break;
                            
                        }
                    }
                }

                try
                {

                    error = gts.GT_GetSts(axis.AxisNo, out sts,1,out uint pClock);
                    ErrorHandler("GT_GetSts", error);
                }
                catch (Exception e)
                {
                    result.IsSuccess = false;
                    result.ErrorMsg = e.Message;
                    return result;
                }
            } while ((sts&0x400)!=0);

            return OperationResult.CreateSuccessResult();
        }

        /// <summary>
        /// 等待2軸正常停止
        /// </summary>
        /// <param name="axis">軸號</param>
        /// <returns>操作結果</returns>
        public OperationResult WaitStop(List<Axis> axis)
        {
            if (axis.Count != 2)
            {
                return new OperationResult()
                {
                    IsSuccess = false,
                    ErrorMsg = "傳遞對象集合數量不為2"
                };
            }
            //通用運動初始化驗證
            OperationResult result = CommonInitedValidate();
            if (!result.IsSuccess) return result;

            short error = 0;
            //軸狀態
            int sts0;
            int sts1;

            do
            {
                //如果isPause==True有人按了暫停
                if (isPause)
                {
                    //先停止
                    StopAxis(axis[0].AxisNo);
                    StopAxis(axis[1].AxisNo);

                    //再一直等
                    while (true)
                    {
                        //如果按鈕還是按下的狀態
                        if (isPause)
                        {
                            Thread.Sleep(10);
                        }
                        //如果有人回復的暫停按鈕
                        else
                        {
                            //恢復指令
                            MoveAbs(axis[0]);
                            MoveAbs(axis[1]);

                            //繼續走,跳出循環
                            break;
                        }
                    }
                }

                try
                {
                    error = gts.GT_GetSts(axis[0].AxisNo, out sts0, 1, out uint pClock0);
                    error = gts.GT_GetSts(axis[1].AxisNo, out sts1, 1, out uint pClock1);
                    ErrorHandler("GT_GetSts", error);
                }
                catch (Exception e)
                {
                    result.IsSuccess = false;
                    result.ErrorMsg = e.Message;
                    return result;
                }
            } while ((sts0 & 0x400) != 0|| (sts1 & 0x400) != 0);

            return OperationResult.CreateSuccessResult();
        }

        #endregion

3,主窗體實現運動暫停的方法(主要代碼)

【3.1】變量:

        //創建暫停按鈕上升沿的緩存值
        private bool PauseRiseCache = false;

        //創建暫停按鈕下降沿的緩存值
        private bool PauseFallCache = true;

  

【3.2】創建自動循環流程,一直檢測暫停按鈕的狀態

 

        private void FrmMain_Load(object sender, EventArgs e)
        {
            //導航按鈕事件綁定
            NaviButtonBind();

            //打開默認的窗體:實時監控窗體
            CommonNaviButton_ClickEvent(this.btn_monitor, null);

            //更新用戶
            this.lbl_user.Text = Program.GlobalSysAdmin.LoginName;

            //板卡初始化
            AddLog(0, "板卡正在初始化");
            var result = motionEx.InitCarl();

            if (!result.IsSuccess)
            {
                AddLog(1, "板卡初始化失敗:" + result.ErrorMsg);
            }
            else
            {
                AddLog(0, "板卡初始化成功");
            }

            //掃碼槍
            result = scanner.StartMonitor();
            SetScanner(result.IsSuccess);
            if (!result.IsSuccess)
            {
                AddLog(1, "掃碼槍連接失敗:" + result.ErrorMsg);
            }
            else
            {
                scanner.ScannerReceived += Scanner_ScannerReceived;
                AddLog(0, "掃碼槍連接成功");
            }

            //調用委托更新界面
            SetRowState();

            //測試
            SetSNCode("123123123");

            //創建自動流程線程
            cts = new CancellationTokenSource();

            Task MainTask = new Task(MainPorcess, cts.Token);

            //創建檢測暫停按鈕的線程
            Task CheckPause = new Task(CheckPauseProcess, cts.Token);//可以用同一個標志位Token

            //線程關閉時調用的方法【關閉運動控制卡】
            cts.Token.Register(() => { motionEx.CloseCard(); });

            //開啟線程
            MainTask.Start();
            CheckPause.Start();
        }

        #region 檢測暫停線程
  
        private void CheckPauseProcess()
        {
            while (!cts.IsCancellationRequested)
            {
                //獲取暫停按鈕的狀態(輸入)
                bool current = motionEx.GetPauseButton();
                //檢測上升沿信號
                if (CheckEdgeSingal(current, ref PauseRiseCache,true))
                {
                    //按下了按鈕
                    motionEx.IsPause = true;
                }
                //檢測下降沿信號
                if (CheckEdgeSingal(current, ref PauseFallCache,false))
                {
                    //松開了按鈕,恢復暫停
                    motionEx.IsPause = false;
                }
            }
        }

        #endregion

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            cts.Cancel();
        }

  

【3.3】檢測沿信號的方法

        /// <summary>
        /// 檢測沿信號
        /// </summary>
        /// <param name="current">當前值</param>
        /// <param name="cache">緩存值(上一次值)</param>
        /// <param name="isRsieOrFall">上升沿或下降沿,True為上升沿,False為下降沿</param>
        /// <returns>是否檢測到沿信號</returns>
        private bool CheckEdgeSingal(bool current, ref bool cache, bool isRsieOrFall = false)
        {
            //如果是上升沿
            if (isRsieOrFall)
            {
                //如果當前值為true並且上一次值為false,就說明是上升沿信號
                if (current && !cache)
                {
                    cache = current;
                    return true;
                }
                else
                {
                    cache = current;
                    return false;
                }
            }
            //否則是下降沿
            else
            {
                //如果當前值為false並且上一次值為true,就說明是下降沿信號
                if (!current && cache)
                {
                    cache = current;
                    return true;
                }
                else
                {
                    cache = current;
                    return false;
                }
            }
        }

  

  

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM