这个平台采用的开源的GRBL,基于单片机Arduino,三个轴的设备。
支持G代码,也就是CNC上面用的G代码。
这个平台如下面所示:
你可以用它来写字,效果还不错。
控制程序实现了基础的功能:
示教点
步进调试位置
回原点的控制功能
由于这个平台没有源点感应开关,因此它所谓的原点, 是在开机那一刻的当前位置设置为原点.
因此这个机器不能中途断电, 否则你得重新设置原点.
并且每次结束程序前都会自动回一次原点, 才能断电.
下面列出核心类的代码, 方便大家参考.
代码是需要netMarketing类的支持的.
using netMarketing.automation.communication; using netMarketing.dataType; using netMarketing.http; using sharClass; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace xyzControlPanel { public struct ptStruct { public string x; public string y; public string z; public string u; public string explain; } public struct ptListStruct { public string ptName; public string x; public string y; public string z; public string u; public string explain; } public struct axisPosStruct { public double x; public double y; public double z; public double u; } public class motionControl : Settings { [Config, Description("串口名称,例如COM7"), Category("xyz平台参数"), DefaultValue("")] public string 串口名称 { get; set; } [Config, Description("步进距离x,单位mm"), Category("xyz平台参数"), DefaultValue("")] public double 步进距离x { get; set; } [Config, Description("步进距离y,单位mm"), Category("xyz平台参数"), DefaultValue("")] public double 步进距离y { get; set; } [Config, Description("步进距离z,单位mm"), Category("xyz平台参数"), DefaultValue("")] public double 步进距离z { get; set; } [Config, Description("步进距离u,单位deg"), Category("xyz平台参数"), DefaultValue("")] public double 步进距离u { get; set; } [Config, Description("连续运动增量,x,y,z, 单位mm"), Category("xyz平台参数"), DefaultValue("")] public double 连续运动增量 { get; set; } [Config, Description("连续运动角度增量,只能轴u, 单位deg"), Category("xyz平台参数"), DefaultValue("")] public double 连续运动角度增量 { get; set; } [Config, Description("步进模式,0连续运动,1步进运动"), Category("xyz平台参数"), DefaultValue("")] public int 步进模式 { get; set; } [Config, Description("步进速度"), Category("xyz平台参数"), DefaultValue("")] public int 步进速度 { get; set; } [Config, Description("示教点列表,每行之间用|分隔"), Category("xyz平台参数"), DefaultValue("")] public string 示教点列表 { get; set; } private CommPort serial = null; private bool isInitFlag = false; private Dictionary<string, ptStruct> ptList = new Dictionary<string,ptStruct>(); public axisPosStruct workPos = default(axisPosStruct); private axisPosStruct orgiPos = default(axisPosStruct); public motionControl() { try { init(); isInitFlag = true; InitCMD(); } catch(Exception ex) { throw ex; } } /// <summary> /// 外部更新点列表 /// </summary> /// <param name="data"></param> public void updatePtList(List<ptListStruct> data) { StringBuilder sb1 = new StringBuilder(); if (data.Count > 0) { ptList.Clear(); foreach (var m in data) { ptList.Add(m.ptName, new ptStruct() { x = m.x, y = m.y, z = m.z, u = m.u, explain = m.explain }); } } Save(); } /// <summary> /// 返回点列表,按数据结构 List<ptListStruct> ,主要给外部改新点列表使用。 /// </summary> /// <returns></returns> public List<ptListStruct> getPtList() { var res = new List<ptListStruct>(); foreach(var m in ptList) { res.Add(new ptListStruct() { ptName = m.Key, x=m.Value.x, y=m.Value.y, z=m.Value.z, u=m.Value.u, explain=m.Value.explain }); } return res; } /// <summary> /// 取指定示教点信息 /// </summary> /// <param name="ptName">示教点的名字</param> /// <returns></returns> public ptStruct getPosInfo(string ptName) { if (ptList.ContainsKey(ptName)) return ptList[ptName]; return default(ptStruct); } public new void Save() { try { if (ptList.Count > 0) { StringBuilder sb1 = new StringBuilder(); var list1 = new List<string>(); foreach (var m in ptList) { list1.Clear(); list1.Add(m.Key); list1.Add(m.Value.x); list1.Add(m.Value.y); list1.Add(m.Value.z); list1.Add(m.Value.u); list1.Add(m.Value.explain); sb1.Append(list1.createCSVRow()); sb1.Append("|"); } 示教点列表 = sb1.ToString(); if (示教点列表.Length > 2) { 示教点列表 = 示教点列表.Substring(0, 示教点列表.Length - 1); } } base.Save(); } catch(Exception ex) { int k1 = 0; } } public new void Load() { try { base.Load(); if (示教点列表.Length > 0) { ptList.Clear(); var ary1 = 示教点列表.Split('|'); foreach (var m in ary1) { var ary2 = m.Split(','); if (ary2.Length == 6) ptList.Add(ary2[0], new ptStruct() { x = ary2[1], y = ary2[2], z = ary2[3], u = ary2[4], explain = ary2[5] }); } } } catch(Exception ex) { int k1 = 0; } } /// <summary> /// 把当前机器位置设置为原点位置,指令 /// </summary> public void setOriPosCMD() { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { var cmd = "G10 P0L20 X0.0Y0.0Z0.0\r"; serial.Write(binHelper.toBin<string>(cmd),cmd.Length); orgiPos = getAxisMacPosCMD(); } catch (Exception ex) { throw ex; } } /// <summary> /// SLP指令,关闭电机 /// </summary> public void SLPCMD() { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { var cmd = "SLP\r"; serial.Write(binHelper.toBin<string>(cmd), cmd.Length); } catch (Exception ex) { throw ex; } } /// <summary> /// x,y,z平台初始化指令 /// </summary> public void InitCMD() { try { var buff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var msg = binHelper.toBin<string>("$X\r"); serial.Write(msg,msg.Length); Thread.Sleep(50); serial.Read(ref buff, buff.Length); msg = binHelper.toBin<string>("G10 P0L20 X0.0Y0.0Z0.0\r"); serial.Write(msg,msg.Length); Thread.Sleep(50); //机器初始化时,把当前位置设置为原点位置 orgiPos = getAxisMacPosCMD(); serial.Read(ref buff, buff.Length); msg = binHelper.toBin<string>("$ZL00418467\r"); serial.Write(msg,msg.Length); Thread.Sleep(50); serial.Read(ref buff, buff.Length); } catch(Exception ex) { throw ex; } } /// <summary> /// 解锁指令 /// </summary> public void unlockCMD() { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { var msg = binHelper.toBin<string>("$X\r"); serial.Write(msg,msg.Length); } catch (Exception ex) { throw ex; } } /// <summary> /// 所有轴停止运动 /// </summary> public void axisStopCMD() { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); } /// <summary> /// 去原点指令 /// </summary> public void goOrgiCMD() { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { var msg = binHelper.toBin<string>("G01 X0Y0Z0F20000\r"); serial.Write(msg, msg.Length); } catch (Exception ex) { throw ex; } } /// <summary> /// 示教用x轴步进运动 /// </summary> /// <param name="供给量"></param> /// <returns></returns> public void tMoveXCMD(int speed,bool isForward=true, double 供给量= 0.08333) { //$J=G21G91X0Y0.08333Z0F500 if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { if (!isForward) 供给量 = 供给量 * -1; string msg = string.Format("$J=G21G91X{0}Y0Z0F{1}\r",供给量, speed); var strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); Stopwatch sw1 = new Stopwatch(); sw1.Start(); while (true) { Thread.Sleep(10); var recvBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; serial.Read(ref recvBuff, 10); if (binHelper.InBin(recvBuff, new byte[] { (byte)'o', (byte)'k' }) >= 0) break; if (sw1.ElapsedMilliseconds >2000) { break; } } sw1.Stop(); } catch (Exception ex) { throw ex; } } /// <summary> /// 示教用y轴步进运动 /// </summary> /// <param name="供给量"></param> /// <returns></returns> public void tMoveYCMD(int speed, bool isForward = true, double 供给量 = 0.08333) { //$J=G21G91X0Y0.08333Z0F500 if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { if (!isForward) 供给量 = 供给量 * -1; string msg = string.Format("$J=G21G91X0Y{0}Z0F{1}\r", 供给量, speed); var strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); Stopwatch sw1 = new Stopwatch(); sw1.Start(); while (true) { Thread.Sleep(10); var recvBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; serial.Read(ref recvBuff, 10); if (binHelper.InBin(recvBuff, new byte[] { (byte)'o', (byte)'k' }) >= 0) break; if (sw1.ElapsedMilliseconds > 2000) { break; } } sw1.Stop(); } catch (Exception ex) { throw ex; } } /// <summary> /// 示教用Z轴步进运动 /// </summary> /// <param name="供给量"></param> /// <returns></returns> public void tMoveZCMD(int speed, bool isForward = true, double 供给量 = 0.08333) { //$J=G21G91X0Y0.08333Z0F500 if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { if (!isForward) 供给量 = 供给量 * -1; string msg = string.Format("$J=G21G91X0Y0Z{0}F{1}\r", 供给量, speed); var strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); Stopwatch sw1 = new Stopwatch(); sw1.Start(); while (true) { Thread.Sleep(10); var recvBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; serial.Read(ref recvBuff, 10); if (binHelper.InBin(recvBuff, new byte[] { (byte)'o', (byte)'k' }) >= 0) break; if (sw1.ElapsedMilliseconds > 2000) { break; } } sw1.Stop(); } catch (Exception ex) { throw ex; } } public bool tMoveUCMD(int speed, bool isForward = true, double 供给量 = 0.018) { return true; } public bool helpCMD() { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { string msg = string.Format("$\r"); var strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); while (true) { Thread.Sleep(10); var recvBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; serial.Read(ref recvBuff, 10); break; } return true; } catch (Exception ex) { throw ex; } } /// <summary> /// 取轴的工作位置 /// </summary> /// <returns></returns> public axisPosStruct getAxisWorkPosCMD() { axisPosStruct axispos = default(axisPosStruct); var macpos = getAxisMacPosCMD(); axispos.x = macpos.x - orgiPos.x; axispos.y = macpos.y - orgiPos.y; axispos.z = macpos.z - orgiPos.z; axispos.u = macpos.u - orgiPos.u; return axispos; } /// <summary> /// 取轴的机器位置 /// </summary> /// <returns></returns> public axisPosStruct getAxisMacPosCMD() { axisPosStruct axispos=default(axisPosStruct); if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { string msg = string.Format("?\r"); var strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); Stopwatch sw1 = new Stopwatch(); sw1.Start(); while (true) { Thread.Sleep(10); var recvBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; serial.Read(ref recvBuff, recvBuff.Length); if (binHelper.InBin(recvBuff, new byte[] { (byte)'P', (byte)'o', (byte)'s', (byte)':' }) >= 0) { var txt=Encoding.Default.GetString(recvBuff); var ary1 = stringHelper.getMidString(txt, "MPos:", "|Bf:").Split(','); if(ary1.Length==3) { axispos.x = double.Parse(ary1[0]); axispos.y = double.Parse(ary1[1]); axispos.z = double.Parse(ary1[2]); axispos.u = 0; } break; } if (sw1.ElapsedMilliseconds > 2000) { sw1.Stop(); return axispos; } } sw1.Stop(); return axispos; } catch (Exception ex) { throw ex; } } /// <summary> /// xy轴以指定速度移动到绝对位置 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="speed"></param> public bool goxyzCMD(double x, double y,double z, int speed) { if (!isInit()) throw new ArgumentException("运动模板没有初始化(或者没有初始化成功!)"); try { //使用绝对坐标 string msg = string.Format("G90\r"); var strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); //齐步走 msg = string.Format("G1 X{0}Y{1}Z{2}F{3}\r", x.ToString("0.000"), y.ToString("0.000"),z.ToString("0.000"), speed); strmsg = binHelper.toBin<string>(msg); serial.Write(strmsg, strmsg.Length); Stopwatch sw1 = new Stopwatch(); sw1.Start(); while (true) { Thread.Sleep(10); var recvBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; serial.Read(ref recvBuff, recvBuff.Length); if (binHelper.InBin(recvBuff, new byte[] { (byte)'o', (byte)'k' }) >= 0) break; if (sw1.ElapsedMilliseconds > 10000) { sw1.Stop(); return false; } } sw1.Stop(); return true; } catch (Exception ex) { throw ex; } } /// <summary> /// 运动控制类初始化成功标志 /// </summary> /// <returns></returns> public bool isInit() { return isInitFlag; } /// <summary> /// 初始化运动控制类 /// </summary> public void init() { try { serial = new CommPort(串口名称); serial.Open(); 示教点列表 = ""; } catch(Exception ex) { throw ex; } } } }
有空勇哥会把程序完善一下,写成一个tcp服务器的服务模块, 以方便视觉程序通讯调用.
目前只能用程序的调试运动功能来配合视觉模块做测试了.
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

