以下是學習筆記:
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; } } }