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