C#--运动控制--运动暂停思路--检测沿信号方法
以下是学习笔记:
1.思路分析:
【1.1】运动的两种方式:
相对运动:相对于现在的位置走一段距离,相对运动走暂停比较麻烦,某一瞬间按了暂停,可能不知道走了多少,恢复比较麻烦。
绝对运动:回原点,相对于原点的位置,相对运动做暂停简单些。
【1.2】暂停按钮放在哪里?
查看说明书:给轴运动指令号,暂停按钮应该放在等待停止的中。
2,封装的运动控制方法
【2.1】Motion.cs中:封装的单轴绝对定位的方法:就是发一个运动指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #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单轴绝对定位的方法,就是调用上一个方法,实际自动流程中就是调用这里的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #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中:封装的等待轴正常停止的方法,只要把判断暂停放在这里就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | #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】变量:
1 2 3 4 5 | //创建暂停按钮上升沿的缓存值 private bool PauseRiseCache = false ; //创建暂停按钮下降沿的缓存值 private bool PauseFallCache = true ; |
【3.2】创建自动循环流程,一直检测暂停按钮的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 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】检测沿信号的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /// <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 ; } } } |
分类:
C#--运动控制
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构