尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于雷赛运动控制卡与C#上位机的三轴写字机开发与调试

基于雷赛运动控制卡与C#上位机的三轴写字机开发与调试 简介本资源是一套基于C#与Visual Studio 2019开发的三轴运动控制平台写字系统源码面向本科毕业设计、自动化/机电类课程设计及初阶工业控制项目开发者解决鼠标轨迹实时映射为X-Y-Z三轴协同运动的核心问题适用于运动控制教学演示、机器人轨迹规划入门实践及雷赛MC系列控制卡的工程化应用验证。压缩包共51个文件含7个核心C#源码文件如Form1.cs、LTSMC.cs、1个VS解决方案文件.sln、1个工程配置文件.csproj、2个界面资源文件.resx、2张实机效果截图软件界面.png、写字效果图.png、1份Markdown格式用户手册README.md及若干编译产物.exe、.pdb、.dll等整体体积2.44MB结构清晰便于按模块理解通信驱动、轨迹插补与UI交互逻辑。已有55人学习下载提供完整可运行工程、硬件接口封装示例及图形化调试界面开箱即用支持在雷赛运动控制卡硬件平台上快速验证与二次开发。 一台三轴平台配上雷赛运动控制卡再用C#在VS2019里写一套上位机程序就能让一支笔在纸上写出标准字形——这个题目在毕业设计和课程设计里出现的频率非常高。我见过不少同学的实现电机能转、坐标能到但写出来的字不是抖、就是歪或者写到一半漏笔画。做这个项目的难点其实不在“让电机转”而在把文字从字符变成坐标、再把坐标变成平稳运动的这条完整链路。这篇文章就跟大家完整拆一遍三轴写字机项目从机械结构、运动学参数、VS2019工程搭建、雷赛控制卡SDK调用到字形提取、坐标变换、实测调试和答辩准备适合正在做毕设、或者想入门工控上位机开发的同学参考。1. 项目拆解三轴写字机从字符输入到笔尖出墨的完整链路1.1 系统架构六个环节各司其职先说清楚一台写字机到底由什么组成。很多人一上来就盯着控制卡和电机其实整个系统是一条完整的数据链路任何一个环节出问题写出来的字都不会好看。这条链路是字符输入 → 上位机解析 → 坐标生成 → 控制卡指令 → 驱动器 → 步进电机 → 机械平台 → 笔尖出墨。字符输入环节最常见的是在WinForms界面里写一个TextBox输入一个汉字或者一串字母。上位机要做的就是把这个字符转换成一系列坐标点这是整个项目里最有技术含量的部分。坐标点生成之后通过雷赛控制卡提供的API下发给运动控制器控制卡把这些坐标按照设定好的速度曲线转换成脉冲信号。脉冲信号经过步进驱动器放大驱动步进电机转动。电机通过联轴器带动丝杠丝杠再推动平台在X轴、Y轴上移动Z轴控制笔的抬落。最后笔尖在纸上留下轨迹整个过程完成。我强调这条链路是因为很多同学调试时容易陷入一个误区字写歪了第一反应是改代码。但字歪可能是因为机械装配时两轴不垂直也可能是因为坐标系没有统一还可能是脉冲当量算错了。你得先知道自己写的每行代码在链路里管的是哪一段出了故障才知道往哪个方向排查。1.2 为什么选雷赛控制卡加C#这套组合市面上能做三轴运动控制的方案不少有PLC加步进驱动器有开源的GRBL加Arduino也有直接用树莓派加Python的方案。很多同学纠结怎么选我说一下我这边的看法。PLC方案的优点是稳定、抗干扰强但它的软肋是界面和算法。你让PLC去做文字轮廓提取、贝塞尔曲线扁平化这种图形学处理效率太低而且PLC的HMI做写字机交互界面非常难受。开源GRBL方案便宜几百块就能搞定但GRBL的指令集偏向G代码要做精细的曲线控制、联动抬落笔你得自己封装一层协议。如果是课程设计老师问你“控制卡的作用是什么”你总不能说“我用的是开源程序”吧。雷赛控制卡加C#这套组合最大的优势在两点。第一雷赛是国内运动控制领域出货量很大的厂商中文资料齐全官方会提供C#的Demo和DLL很多型号在二手平台也能低价买到研发成本可控。第二C#加WinForms的开发效率高做界面、做调试工具、做演示都很顺手VS2019的断点调试在看坐标数据、排查指令问题时也比C友好得多。对毕设来说这套组合既有技术深度又好落地。2. 机械结构选型与运动学参数计算写出来好看的前提2.1 三种常见机械结构的取舍三轴平台的机械结构最常见的三种是龙门式、悬臂式和十字滑台式。龙门式是两个X轴立柱支撑横梁Y轴挂在横梁上Z轴再挂在Y轴上。这种结构刚度最好运动时横梁受力均匀写字精度高但成本也最高调试装配要花不少功夫。悬臂式是一个X轴底座加一个悬伸出去的Y轴Z轴装在Y轴末端。这种结构简单便宜很多淘宝上的桌面写字机就是这个方案。缺点是悬臂端在快速加减速时容易振动写大字、写连笔时轻则会抖重则失步。十字滑台式是X轴和Y轴上下层叠平台在下面走X上面的滑台走Y。这种结构重心低、稳定性好但占用空间大Z轴安装位置也受限制。如果是毕设选型我的建议是经费充足、有动手能力就上龙门式结构稳定答辩论据也充分时间和预算有限就选十字滑台式实用性好悬臂式也能用但要做好减振的心理准备速度参数要保守一些。Z轴这里我要多说一句很多同学忽略Z轴的刚度问题。写字时笔要跟纸面有接触力这个力不能太大也不能太小。如果Z轴直接用一根光轴加一个电磁铁去压笔结构太软写起来笔尖会飘。靠谱的做法是Z轴末端做一个弹簧笔夹让笔有一定的浮动行程靠弹簧力压在纸上这样下笔力量稳定出墨也均匀。2.2 雷赛控制卡的选型步骤与接线设计雷赛的运动控制卡产品线很多不同系列的轴数、接口总线、IO资源都不一样。选型时主要看三点轴数够不够、总线接口跟电脑匹不匹配、IO口够不够用。很多毕业设计项目用到的雷赛卡以PCI接口的DMC系列和USB接口的DMC2000系列为主。PCI卡稳定但要机箱里有空的PCI插槽USB卡方便笔记本也能用但要注意USB通信延迟和驱动稳定性。选卡时按自己的使用场景来实验室台式机、追求稳定选PCI要带着演示、用笔记本选USB。IO口这里容易踩坑。一套三轴系统X、Y、Z三个轴的脉冲和方向信号是必须的还需要限位开关输入、原点开关输入以及控制电磁铁或继电器抬落笔的输出口。所以要选的卡至少要有够用的通用输入输出口。雷赛卡的DSP在控制周期里会同时处理运动插补和IO扫描但写程序时还是要给IO操作留出合理的时序后面我会提到。接线层面有一个关键细节从控制卡到驱动器的信号线一定要用屏蔽双绞线而且屏蔽层要可靠接地。脉冲方向和使能信号是高速变化的方波如果不做屏蔽旁边电机一启动脉冲信号就容易被干扰表现出来的现象就是电机偶然丢一步写出来的字出现毛刺。这一点很多学生容易忽略。2.3 脉冲当量、电子齿轮与速度换算运动学参数是整个软件编程的基础而脉冲当量是这里面最重要的一个数。脉冲当量的物理含义是每发出一个脉冲平台实际移动多少毫米。两相步进电机的步距角通常是1.8度也就是200个脉冲转一圈。如果驱动器把细分倍数设为8那么电机转一圈需要200×81600个脉冲。假设丝杠的导程是5毫米意思是丝杠转一圈、滑块移动5毫米那么脉冲当量就是导程除以每圈脉冲数也就是5除以1600等于0.003125毫米每脉冲。换句话说平台走1毫米大约需要320个脉冲。这个数字一出来速度和加速度的换算都很直接。如果想写字速度为10毫米每秒那对应的脉冲频率就是10除以0.003125等于3200赫兹。加速度如果设定为0.2秒内从0加速到最大速度那API里设置加速时间时就有依据了。写大字和写小字的时候要考虑换算出合适的脉冲当量。如果丝杠导程大、细分又不高脉冲当量会偏大写小字时坐标点之间只有几个脉冲的差别平台根本走不出精细的曲线。反过来细分太高会降低电机高速时的扭矩影响运行稳定性。实际调试中写字机用8到16细分是一个比较平衡的范围。参数计算清楚之后还有一个映射工作了要做。上位机生成的是毫米或者像素坐标下发给控制卡之前要把它们换算成脉冲数这个换算关系在软件里最好定义一个全局常量或者配置项方便现场调参数。很多同学喜欢把换算系数散落在代码各处后面改丝杠、换细分时痛不欲生。3. VS2019工程搭建与雷赛SDK集成从空项目到电机转起来3.1 创建WinForms工程并解决DLL引用问题VS2019里新建一个C# Windows Forms应用工程名称建议别用中文避免一些历史遗留的编码问题。目标框架用.NET Framework 4.6或4.7都没有问题。雷赛官方提供的DLL一般区分32位和64位这个最容易踩坑的地方在编译目标平台。新建的工程默认是AnyCPU程序跑起来之后可能以64位模式运行。如果雷赛自带的DLL只有32位版本程序加载时就会抛DllNotFoundException或者BadImageFormatException界面都打不开。解决办法很简单在解决方案管理器里右键项目选择属性把生成目标平台改成x86。别小看这一步很多同学卡在“程序一运行就崩溃”这个环节其实就是位数不匹配。DLL的引入方式不用添加引用直接声明外部函数即可。雷赛的DLL通常安装后会在系统目录里或者随项目放在Debug目录下。C#里用DllImport声明调用函数例如雷赛控制卡提供的是dmc1000.dll。下面的代码是简化示意具体函数名以你手上那款卡的官方手册为准。using System.Runtime.InteropServices; public class LeadshineMotion { private const string DllName dmc1000.dll; [DllImport(DllName, EntryPoint dmc_board_init)] public static extern short BoardInit(); [DllImport(DllName, EntryPoint dmc_set_profile)] public static extern short SetProfile(short axis, int lowSpeed, int highSpeed, double accTime, double decTime); [DllImport(DllName, EntryPoint dmc_pmove)] public static extern short PMove(short axis, int position, short posMode); [DllImport(DllName, EntryPoint dmc_check_done)] public static extern short CheckDone(short axis); [DllImport(DllName, EntryPoint dmc_get_position)] public static extern int GetPosition(short axis); [DllImport(DllName, EntryPoint dmc_home_move)] public static extern short HomeMove(short axis, short moveMode, short dir, int vel); [DllImport(DllName, EntryPoint dmc_stop)] public static extern short Stop(short axis, short stopMode); [DllImport(DllName, EntryPoint dmc_set_do)] public static extern short SetDo(short ioIndex, short state); [DllImport(DllName, EntryPoint dmc_get_di)] public static extern short GetDi(short ioIndex); }这个声明的模式是所有控制卡调用的通用结构理解它之后不管换什么卡都能快速迁移。提示DllImport里的函数名必须跟DLL导出名完全一致大小写都不能错。如果函数名不对编译不会报错但运行到调用处就会抛MissingMethodException。3.2 板卡初始化、轴参数设置与回原点工程搭好之后第一个要跑通的流程是板卡初始化和回原点。初始化就是调用BoardInit通常是0表示成功非0表示失败。初始化失败的原因一般有两个一个是控制卡驱动没装好设备管理器里看不到设备另一个是DLL版本和驱动版本不匹配。这一步不需要写太多代码但要在日志里把返回码打出来方便定位。初始化通过之后要给每个轴设置运动参数。以雷赛的DMC系列为例SetProfile需要设置低速、高速和加减速时间。低速一般指启动速度高速指最大运行速度。写字机的X轴和Y轴运动建议起始速度在100到200赫兹左右最大速度在8000到12000赫兹左右加加速时间0.1到0.2秒。如果加速度设太大平台会剧烈抖动相当于开车猛踩油门机械结构受不了。Z轴的运动参数和XY轴不一样。Z轴负责抬落笔行程短、负载小但要求响应快。落笔时如果速度太高笔尖会撞击纸面容易溅墨抬笔速度太高又会导致平台振动。所以Z轴的加速时间也要设得平稳一些速度别超过XY轴的一半。接着是回原点。三轴写字机每次上电都要有一个基准位置不然坐标都是漂的。回原点的方式取决于机械结构有没有原点开关。如果有原点开关调用HomeMove控制卡会以设定速度找原点开关的边沿找到后停在原点位置如果没有原点开关只有限位开关也可以把限位触发后的点当成机械原点。值得注意的一点是回原点之后不要立刻开始写字。步进电机在找原点过程中可能有过冲控制卡虽然在硬件上会处理减速但实际位置和原点位置之间可能还有几十个脉冲的偏差。我的习惯是回完原点后手动让平台走一个固定的矩形轨迹确认坐标定位没有问题再继续。3.3 运动API调用的线程模型为什么不能在UI线程里跑运动控制这是新手最容易犯的错误直接在WinForms的按钮点击事件里写循环等待运动完成结果界面卡死鼠标都点不动。原因很简单WinForms的UI线程要持续处理窗口消息如果你的代码在UI线程里while循环等电机运动完窗口就无法响应用户操作了。我见过最极端的例子同学把整个写字流程全放在按钮事件里程序一运行界面假死半分钟只能强行结束进程。正确的做法是把写字流程放到后台线程里执行。可以在Task.Run里跑一个工作方法方法内部用轮询方式检查运动完成状态每隔几毫秒调用一次CheckDone运动完成后继续下一步。UI线程只负责接收用户输入和显示状态后台线程负责和运动控制卡交互。两个线程之间要传递进度或者日志时用Invoke或者Progress 回调回到UI线程更新界面。这里还要强调一个细节虽然用的是后台线程但不要一个点接一个点地粗暴执行。控制卡的运动指令是异步的PMove发出后立刻返回真正的运动在硬件层面进行。如果在代码里每个点之间都用Thread.Sleep固定延时不仅效率低而且运动不平滑。更合理的方式是等待控制卡返回“运动完成”状态再发下一条指令。4. 字形提取与坐标变换文字是怎么变成脉冲的4.1 两种主流方案对比位图点阵与矢量轮廓把文字变成坐标思路上有两类做法。第一类是把文字渲染成位图然后做点阵扫描用点阵坐标去驱动平台。这种方法实现简单但写出来的字本质上是一堆点笔要不停抬落速度慢而且字体边缘很难光滑。如果想让笔在纸上画出连续的笔画点阵方式不是最优解。第二类是用矢量轮廓提取。利用Windows平台自带的GDI字体引擎把文字轮廓转成一系列路径点然后让笔沿着路径描边。这种方式写出来的字是空心/轮廓风格的笔画连续、运动平滑观感好很多实现难度也在可接受范围内。还有进阶方案是把位图做细化骨架提取比如用Zhang-Suen细化算法把粗笔画的文字骨架化再沿着骨架连线写。这个方案从效果上说更接近真正的“写字”但它牵扯到图像处理知识工作量会大一截。对毕设来说如果时间和精力有限矢量轮廓方案已经足够展示技术能力。4.2 用GDI提取文字轮廓的实现GDI提取文字轮廓的核心是GraphicsPath对象。把文字添加到路径里然后获取路径上的点集。using System.Drawing; using System.Drawing.Drawing2D; public static ListListPointF GetCharOutline(char ch, FontFamily fontFamily, float fontSize) { var strokes new ListListPointF(); using (GraphicsPath path new GraphicsPath()) { path.AddString(ch.ToString(), fontFamily, (int)FontStyle.Regular, fontSize, new PointF(0, 0), StringFormat.GenericDefault); // 把贝塞尔曲线转成连续的直线段0.3是扁平化精度越小越密 path.Flatten(new Matrix(), 0.3f); PointF[] points path.PathPoints; byte[] types path.PathTypes; ListPointF current new ListPointF(); for (int i 0; i points.Length; i) { // PathTypes的低位是1表示这是一个新图形的起点 if ((types[i] 0x01) ! 0 current.Count 0) { strokes.Add(current); current new ListPointF(); } current.Add(points[i]); } if (current.Count 0) { strokes.Add(current); } } return strokes; }这段代码返回的是一个列表的列表每个内部列表代表一段闭合或开放的轮廓。Flatten方法很关键文字轮廓在字体引擎里是贝塞尔曲线表示的控制卡只认直线段所以必须把它扁平化成小线段。扁平化精度设得越小轮廓越接近原始形状但坐标点数量也会暴涨后面运动时耗时更长。0.3毫米左右是一个适合写字机的平衡值字小就可以再精细一些。有一点要提前说明用字体轮廓取出来的点和“笔顺”没有关系它只是外轮廓的几何描述。比如写“口”字你拿到的可能是内外两个闭合环。沿着这些环走写出来的是字形轮廓你在纸上看到的是空心字效果。它的优点是好实现、好看缺点是如果老师要求“一笔一画写出汉字笔顺”这个方法就不太够用需要在此基础上做骨架化处理或者引入笔画顺序数据。4.3 从像素坐标到运动平台脉冲坐标的变换拿到轮廓点之后下一步是把这些点的坐标换算成控制卡能用的脉冲数。这一步看起来简单实际最容易出bug。GDI的坐标系是左上角为原点X向右为正Y向下为正。也就是说文字在内存Bitmap里越靠下Y坐标越大。但三轴平台运动时Y轴通常是从前向后运动或者从下到上运动。如果你直接把GDI的Y坐标套到平台坐标里写出来的字就是上下镜像的。正确的坐标变换需要做三件事缩放、平移、镜像。缩放的公式是脉冲数等于像素坐标乘以缩放系数。缩放系数要从像素到毫米再换算到脉冲。比如设定字高是30毫米文字的GDI高度是100个像素那么每个像素对应0.3毫米再乘上脉冲当量320脉冲每毫米得到每像素96脉冲。平移是把字形摆到平台合适的起始位置。因为GDI字形是从左上角0,0点开始画的你需要给它加一个偏移量让文字出现在纸面的中间而不是角落。镜像处理很简单在Y方向取反即可。比如用yPluse (originY - yPixel) * scale或者yPluse (bitmapHeight - yPixel) * scale。具体用哪一种取决于你的平台Y轴正方向跟GDI的Y轴正方向是否相反。这也是为什么我建议先在界面上做一个“镜像”开关现场调试时按一下按钮就能切换方向比改代码重新编译快得多。还有一个细节缩放过程中尽量不要用整数除法先用double计算最后再四舍五入到整数脉冲数。因为平台分辨率是有限的你发过去的脉冲数只能是整数而四舍五入造成的误差在每一个点上都可能累积。好在单点误差最多半个脉冲对应的位置误差微乎其微实际写字效果不会受影响。5. 核心代码串联封装类、写字流程与三个容易忽略的细节5.1 运动控制封装类的关键实现把DLL函数包进一个类里是这个项目里非常值得做的工程化工作。不要在主窗体里到处裸调DLL函数后期一定要乱。封装类可以把轴参数、IO操作、运动状态这些逻辑集中起来。public class MotionController { private readonly short _axisX 0; private readonly short _axisY 1; private readonly short _axisZ 2; private double _pulsePerMm; // 脉冲当量的倒数即每毫米脉冲数 private double _scalePixelToPulse; private int _originX; // 写字区域左上角对应的平台坐标 private int _originY; public bool Initialize() { short result LeadshineMotion.BoardInit(); return result 0; } public void ConfigureAxes() { // 设置XY轴的加减速曲线 LeadshineMotion.SetProfile(_axisX, 100, 8000, 0.15, 0.15); LeadshineMotion.SetProfile(_axisY, 100, 8000, 0.15, 0.15); // Z轴抬落笔响应要求快速度保守但要干净利落 LeadshineMotion.SetProfile(_axisZ, 50, 3000, 0.1, 0.1); } public bool Home() { LeadshineMotion.HomeMove(_axisX, 0, 0, 3000); LeadshineMotion.HomeMove(_axisY, 0, 0, 3000); LeadshineMotion.HomeMove(_axisZ, 0, 0, 2000); return true; } public void MoveTo(double mmX, double mmY) { int pulseX _originX (int)Math.Round(mmX * _pulsePerMm); int pulseY _originY (int)Math.Round(mmY * _pulsePerMm); LeadshineMotion.PMove(_axisX, pulseX, 1); // 1表示绝对定位 LeadshineMotion.PMove(_axisY, pulseY, 1); while (LeadshineMotion.CheckDone(_axisX) 0 || LeadshineMotion.CheckDone(_axisY) 0) { System.Threading.Thread.Sleep(2); } } public void SetPen(bool down) { if (down) { LeadshineMotion.PMove(_axisZ, downPosition, 1); while (LeadshineMotion.CheckDone(_axisZ) 0) { } } else { LeadshineMotion.PMove(_axisZ, upPosition, 1); while (LeadshineMotion.CheckDone(_axisZ) 0) { } } } }这个类把“位置”的单位暴露成毫米内部再做脉冲换算。主程序里看起来直观逻辑也清晰。5.2 写字主流程与抬落笔时序写字的主流程我看很多同学的代码写得很随意点位运动、抬落笔、延时全堆在一起。我建议把它抽象成“笔画级”的任务一次处理一个轮廓段。private void RunWriteJob(ListListPointF strokes) { foreach (var stroke in strokes) { if (stroke.Count 2) { continue; } // 1. 抬笔移动到笔画起点 _motion.SetPen(false); MoveToPixel(stroke[0]); // 2. 落笔留一点出墨时间 _motion.SetPen(true); Thread.Sleep(80); // 3. 沿着笔画逐段运动 for (int i 1; i stroke.Count; i) { MoveToPixel(stroke[i]); } // 4. 写完这一笔之后抬笔 _motion.SetPen(false); } } private void MoveToPixel(PointF pixel) { // 像素转毫米再转脉冲 double mmX (pixel.X - originPixelX) * pixelToMm; double mmY (originPixelY - pixel.Y) * pixelToMm; // Y镜像在这里处理 _motion.MoveTo(mmX, mmY); }这个流程里最重要的时序是落笔之后的那段出墨延时。电磁铁或继电器驱动的Z轴从下达到动作到完全稳定需要几十毫秒。如果落笔后立刻开始横移笔尖还没压稳墨迹开头就会虚。这个延时时间可以在50到150毫秒之间调试取决于你用的Z轴执行机构和笔的类型。每写完一段、抬笔之后的那个瞬间同样建议给一点稳定时间。因为抬笔动作会引起平台轻微的振动如果立刻高速移动到下一笔起点笔尖可能拖着墨迹画出多余的线。5.3 代码层面容易忽略的三个细节第一个细节是运动完成判断。控制卡的CheckDone函数返回的是硬件层面的运动状态但不同系列的卡返回值含义不一样有的返回0表示运动中有的返回1表示运动中。写代码前一定要先看官方帮助文档或者写一个小Demo测试确认。第二个细节是坐标精度处理。像素点经过缩放、镜像、偏移后最后转成整数脉冲时要用Math.Round而不是直接强转int。直接强转会丢弃小数部分导致系统性的位置偏差。比如脉冲数都偏小0.5个脉冲左右对小字影响不大但写长直线时两端会明显偏短。第三个细节是线程安全。上位机的运动控制是后台线程在跑UI线程如果同时去查当前坐标或者在界面上修改参数可能读到中间状态。我习惯在封装类里加一个锁对象所有对板卡的操作都走同一把锁避免并发调用把控制卡的状态搞乱。6. 实测调试记录抖动、镜像、出水不稳的逐个排查6.1 平台抖动问题加减速参数和机械共振第一个要解决的通常是抖动问题。有同学调试时发现平台启动的时候明显顿了一下然后中段又嗡嗡响停下来的时候笔尖还会上下跳动。这个问题很大的概率出在加减速参数和细分数不匹配上。如果你把加速时间设得太短比如0.05秒从静止加速到12000赫兹步进电机会因为加速度过大而丢步机械结构也会因为惯性冲击而抖动。解决办法是把加速时间慢慢调大每次增加0.05秒观察抖动是否改善。还有一个容易被忽略的是步进驱动器的电流设置。驱动器的电流输出必须和电机的额定电流匹配电流过大电机会发热剧烈电流过小扭矩不够高速容易丢步。写字机这种轻载应用电流调到电机额定的80%左右通常比较稳妥。机械共振也会导致抖动。某些速度段下丝杠、联轴器、平台会产生共振。如果发现平台在某个速度下特别抖换个速度就安静了那就是共振。解决方法是避开这个速度范围或者换刚性更好的联轴器。6.2 字整体歪斜和镜像问题坐标系与原点设置第二次调试最常见的问题是字写出来是歪的或者上下颠倒。先说镜像问题。如果你确定代码里坐标变换已经做了Y轴取反但写出来还是镜像那就查一下机械装配方向。X轴和Y轴电机安装方向不同正方向可能是相反的。比如代码里认为Y轴正方向是远离操作者但实际上电机装反了Y轴正方向是朝操作者的。这时候不用改代码把坐标变换里Y轴的符号再反转一次就行。这也是为什么我建议界面上做一个镜像开关。字歪斜的原因通常是运动平台两轴不垂直。用直角尺测量一下如果X轴和Y轴装配偏差超过半个毫米写出来的字就会明显平行四边形化。这种纯机械问题再怎么调软件参数都没用只能松螺丝重新定位。如果装配没问题再检查回原点时两轴的坐标系原点是否一致。还有一个非常影响效果的问题控制卡断电后再上电如果没有回原点软件里的原点和你手放的纸的参考点就对不上。每次上电后第一件事必须是回原点并且回完原点后要把纸摆放固定好。很多现场翻车都是没回原点直接写字。6.3 Z轴抬落笔与出水不稳定字写出来不连续、有些地方墨色深浅不一问题往往出在Z轴和笔的配合上。如果用的是普通的中性笔或水性笔落笔时笔尖要跟纸面有一定的角度。如果笔杆完全是竖直的笔尖和纸张的接触面积变化会导致出墨不稳定。更好的做法是让笔杆有一个5到10度的倾角让笔尖的球珠稳定接触纸面。Z轴的落笔深度也要调到适中的位置。落笔过深笔尖会过度挤压墨迹变粗甚至笔尖堵塞落笔本文还有配套的精品资源点击获取
返回列表