以下是学习笔记:
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;
}
}
}
