【红色飓风Nano二代测评】Verilog实现直线插补
0赞既然要用Nano2打造一个数控平台,那么插补就是必不可少的,那么我们就从“插补”开始。
首先,任意一条直线都是X和Y分量组成的,而我们的X,Y分量是有两个步进电机控制的。如上图所示,原点O和点A构成直线。
想象一下,现在我们的XY平台已经搭建好了。
平台的控制端点上有一支画笔,X轴的步进电机转一下,画笔就会在X方向上走一步;Y轴的步进电机转一下,画笔就会在Y方向上走一步。
(要是能有个这样的数控平台就爽了,哈哈~)
假设,现在假设画笔就在原点O,A的坐标是(4,3),现在我们要求控制步进电机,使画笔从原点O移到A。如果不考虑插补的话,我可以控制X电机先移动4个单位,再让Y电机移动3个单位。那么画笔移动到的A点没错,再从宏观上看画笔的运动轨迹:
它是由两条相互垂直的直线组成的折线。但是如果我们要求画笔的运动轨迹看上去就是直线OA,那这个如何实现呢?
先抛开上面这个问题不管,我们继续假设,画笔在原点O,A的坐标是(3,3),我们要求控制步进电机,使画笔从原点O移到A。当然我们可以效仿上面的方法,可以先控制X电机移动3个单位,再让Y电机移动3个单位。紧接着,提高要求:要求画笔的运动轨迹看上去就是直线OA。
那似乎也不难,只要我们要求X轴和Y轴步骤电机“步伐保持一致”同时移动3个单位,那么画笔的运动轨迹就是直线OA。回头再之前的问题,看似否能解决:画笔就在原点O,A的坐标是(4,3),要求画笔的运动轨迹看上去就是直线OA。感觉依然没有办法。原因是应为之前A点的坐标比较特殊(3,3)导致直线OA的X和Y轴的分量是相等的,很容易保证在相同时间内XY轴步进电机同时完成各种的任务。
但是如果直线OA的X和Y轴的分量不等,如何保证画笔的运动轨迹看上去就是直线OA呢?这就要借助插补的力量了~~
插补的思路就是,让X和Y电机“同时工作”,在适当的时机走出自己的一步。
在理想的数学是世界里,直线是由无数细化的点构成的,但是在真实的的世界,没有什么是无限的,就拿步进电机驱动的器的而言它的细分数是有限的,也就是说步进电机每一步的距离不可能是无穷小的。所以我们数控世界的“直线”往往是由很多细小直线段构成的“折线”如下图:
左图的,直线经过局部放大后,我们发现它是一条类似楼梯的折线,用插补的思想去解读它,就感觉是;“X电机走一步,紧接着Y电机走一步,然后X电机走2步,紧接着Y电机走一步”循环往复,一条“直线就出来了”现在思路出来了,如何将一条直线细化,并且将任务分配给X,Y电机,它们之间如何做出配合,在适当的时间走出自己的一步,就是问题的关键。
现在就介绍一种,十分简单的直线插补方法:
还是以画直线(4,3)为例,我们需要建立一个定时器,用来控制画直线的数度,还需要建立两个计数器来匹配XY轴的速度。很明显计数器的大小是有“讲究”的。首先直线(4,3)X轴的分量是4,Y轴的分量是3,而计数器的大小正好反过来,X轴的计数器大小是3,Y轴的计数器大小是4。为什么要这么做,看着下图,想必您也猜的八九不离十了,那我就说说具体实现过程:
当数度计时器溢出时,同通知X,Y计数器计数加一,当某个计数器计满后,就通知所对应的电机走一步,并且清空该计数器。如此往复,当走到合适的长度就让其停下来。
我们可先不让其停止,让其一直这么循环下去,看看斜率对不对即可。
从仿真图上看当X走完4步,Y轴正好完成3步,正好满足(4,3)这条直线的分量,如果对应到实际再来看看。
那就是X走一步,Y走一步,X走一步,Y走一步,XY同时走一步:
如果多叠加几次,看看是什么效果:
有没有发现,我们走的这条折线,已近非常的接近OA这条直线了,也就是斜边“弦五”,说明一下,真正的数控中,步进电机加上机械结构,轻松达到了每步0.1mm的精度,人眼更本看不出来,这是一条折线~~
最后奉上代码:
module Pulse ( input CLK, input RSTn, input Pu_Sig,//该信号为高时,表示要发脉冲~~ output reg pulse ); parameter ON = 1'b1; parameter OFF = 1'b0; reg[7:0] C0; reg [3:0]i; always @(posedge CLK or negedge RSTn) if(!RSTn) begin C0 <= 8'd0; pulse <= OFF; i <= 4'd0; end else case(i) 0://判断是否发脉冲 begin if(Pu_Sig)begin i <= i + 1'b1;end else begin pulse <= OFF; i <= i;end end 1: begin if(C0 == 10)//脉冲宽度控制 begin pulse <= OFF; C0 <= 8'd0; i <= 4'd0; end else begin pulse <= ON; C0 <= C0 + 1'b1; i <= i; end end endcase endmodule
module test ( input CLK, input RSTn, output X_pulse, output Y_pulse ); //速度控制器 reg [9:0]Cnt; always @(posedge CLK or negedge RSTn) if(!RSTn) begin Cnt <= 10'd0; end else begin if(Cnt == 10'd1000) Cnt <= 10'd0; else Cnt <= Cnt + 1'b1; end //X轴计数器 reg [9:0]Cx; reg X_Pu_Sig; always @(posedge CLK or negedge RSTn) if(!RSTn) begin Cx <= 10'd0; X_Pu_Sig <= 1'b0; end else begin if(Cx == 3) begin Cx <= 10'd0; X_Pu_Sig <= 1'b1;end else if(Cnt == 10'd1000) begin Cx <= Cx + 1'b1; X_Pu_Sig <= 1'b0;end else begin Cx <= Cx; X_Pu_Sig <= 1'b0;end end //Y轴计数器 reg [9:0]Cy; reg Y_Pu_Sig; always @(posedge CLK or negedge RSTn) if(!RSTn) begin Cy <= 10'd0; Y_Pu_Sig <= 1'b0; end else begin if(Cy == 4) begin Cy <= 10'd0; Y_Pu_Sig <= 1'b1; end else if(Cnt == 10'd1000) begin Cy <= Cy + 1'b1; Y_Pu_Sig <= 1'b0;end else begin Cy <= Cy; Y_Pu_Sig <= 1'b0;end end //--发脉冲模块例化 Pulse PulseX ( .CLK(CLK), .RSTn(RSTn), .Pu_Sig(X_Pu_Sig),//该信号为高时,表示要发脉冲~~ .pulse(X_pulse) ); Pulse PulseY ( .CLK(CLK), .RSTn(RSTn), .Pu_Sig(Y_Pu_Sig),//该信号为高时,表示要发脉冲~~ .pulse(Y_pulse) ); endmodule这是顶层模块,实现一个定时器,两个计数器,并且例化两个Pulse模块,一个X轴,一个Y轴。
TestBeach如下:
module test_vlg(); reg CLK; reg RSTn; wire X_pulse; wire Y_pulse; test i1 ( .CLK(CLK), .RSTn(RSTn), .X_pulse(X_pulse), .Y_pulse(Y_pulse) ); initial begin RSTn = 0; #10 RSTn = 1; CLK = 1; forever #5 CLK = ~CLK; end
接下来,我将用Nano2实现——通过插补在TFT上画任意直线,并且同步驱动电机。敬请期待~~
技术讨论欢迎加群~~电子技术协会 362584474