PCB Milling Feed Rate issue

Moderators: TomKerekes, dynomotion

jpbarad7
Posts: 21
Joined: Wed Dec 07, 2022 6:25 pm

PCB Milling Feed Rate issue

Post by jpbarad7 » Sat Mar 22, 2025 5:17 pm

Tom,

I’ve been using my SuperMax knee mill with KFLOP and closed-loop steppers to CNC mill printed circuit boards. I’m running the spindle at 2500 RPM with carbide end mills and drills. At a feed rate of 1 inch per minute, the results are very acceptable (photo attached).
1 ipm.JPG
However, as I increase the feed rate, the circular pads become increasingly irregular — I’ve attached photos at 5 IPM and 20 IPM for comparison.
5 ipm.JPG
20 ipm.JPG
I’ve tried a variety of adjustments but haven’t found anything that allows for higher feed rates without compromising quality.

While I’m fine working at 1 IPM since I don’t plan to produce a large number of PCBs, it would be nice to improve the feed rate if possible.

I suspect this may be a limitation of my hardware, but I’m also curious if there might be something in the configuration or software contributing to the issue.

I’d appreciate any thoughts or suggestions.

Best regards,
Jim

User avatar
TomKerekes
Posts: 2811
Joined: Mon Dec 04, 2017 1:49 am

Re: PCB Milling Feed Rate issue

Post by TomKerekes » Sat Mar 22, 2025 5:52 pm

Hi Jim,

Hmmm, maybe a lag in the axis positions?

Are the Steppers Closed loop in KFLOP or the Drives?

Please post your Configuration file GCodeConfigCNC.txt, the Initialization C Program, and the GCode and we can look into it.
Regards,

Tom Kerekes
Dynomotion, Inc.

jpbarad7
Posts: 21
Joined: Wed Dec 07, 2022 6:25 pm

Re: PCB Milling Feed Rate issue

Post by jpbarad7 » Sun Mar 23, 2025 8:29 pm

Thanks for your willingness to help.

My mill uses closed loop steppers controlled only by KFLOP, not by the stepper drivers.

I am using the Mach3 plug in, not KmotionCNC, however, I experience the same issues using KmotionCNC.

This is the GCodeConfigCNC.txt file from the Kmotion data folder:

Code: Select all

m_SetupFile=DefaultKeepOffsetsInches.set
m_ToolFile=Default.tbl
m_GeoFile=
m_Button0=INIT
m_Button1=
m_Button2=
m_Button3=
m_Button4=
m_Button5=
m_Button6=
m_Button7=
m_Button8=
m_Button9=
CommandHistory[0]=g0x0
CommandHistory[1]=g1x3f5
CommandHistory[2]=g1x0f5
CommandHistory[3]=g1x5f5
CommandHistory[4]=m30
CommandHistory[5]=m3s50
CommandHistory[6]=m8
CommandHistory[7]=m7
CommandHistory[8]=m3s100
CommandHistory[9]=m5
m_CommandString=g0x0
m_BreakAngle=  9.000000000000000e+01
m_CollinearTol=  1.000000000000000e-03
m_CornerTol=  1.000000000000000e-03
m_FacetAngle=  1.000000000000000e+00
m_JogSpeed[0]=  1.000000000000000e+00
m_JogSpeed[1]=  1.000000000000000e+00
m_JogSpeed[2]=  1.000000000000000e+00
m_JogSpeed[3]=  1.000000000000000e+01
m_JogSpeed[4]=  1.000000000000000e+01
m_JogSpeed[5]=  1.000000000000000e+01
m_JogSpeed[6]=  1.000000000000000e+00
m_JogSpeed[7]=  1.000000000000000e+00
m_JogSlowPercent=  2.500000000000000e+01
m_HardwareFRORange=  1.000000000000000e+00
m_MaxRapidFRO=  1.000000000000000e+00
m_ArcRadiusTol=  7.000000000000000e-04
m_ArcRSmallTol=  1.000000000000000e-12
m_TPLookahead=  5.000000000000000e-02
m_RadiusC=  0.000000000000000e+00
m_RadiusB=  0.000000000000000e+00
m_RadiusA=  0.000000000000000e+00
m_MaxAccelC=  1.400000000000000e-01
m_MaxAccelB=  1.000000000000000e+01
m_MaxAccelA=  1.000000000000000e+01
m_MaxAccelX=  4.280000000000000e+00
m_MaxAccelY=  4.480000000000000e+00
m_MaxAccelZ=  4.280000000000000e+00
m_MaxAccelU=  1.000000000000000e-02
m_MaxAccelV=  1.000000000000000e-02
m_MaxVelC=  2.900000000000000e-01
m_MaxVelB=  1.000000000000000e+01
m_MaxVelA=  1.000000000000000e+01
m_MaxVelX=  8.500000000000000e-01
m_MaxVelY=  8.500000000000000e-01
m_MaxVelZ=  1.110000000000000e+00
m_MaxVelU=  1.000000000000000e+01
m_MaxVelV=  1.000000000000000e+01
m_CountsPerInchC=  4.270000000000000e+05
m_CountsPerInchB=  1.000000000000000e+02
m_CountsPerInchA=  1.000000000000000e+02
m_CountsPerInchX=  2.335000000000000e+05
m_CountsPerInchY=  2.335000000000000e+05
m_CountsPerInchZ=  1.800000000000000e+05
m_CountsPerInchU=  1.000000000000000e+02
m_CountsPerInchV=  1.000000000000000e+02
m_Step0=  1.000000000000000e-04
m_Step1=  1.000000000000000e-03
m_Step2=  1.000000000000000e-02
m_Step3=  1.000000000000000e-01
m_Step4=  1.000000000000000e+00
m_Step5=  1.000000000000000e+01
m_ReverseRZ=0
m_EnableGamePad=0
m_ZeroUsingFixtures=0
m_ToolLengthImmediately=0
m_ToolTableDoM6=0
m_ConfirmExit=1
m_ArcsToSegs=0
m_DisplayEncoder=0
m_Lathe=0
m_DoRapidsAsFeeds=0
m_DiameterMode=0
m_XPosFront=0
m_SpindleType=1
m_SpindleAxis=3
m_SaveFixtureOnOK=1
m_SpindleUpdateTime=  2.000000000000000e-01
m_SpindleTau=  1.000000000000000e-01
m_SpindleCntsPerRev=  3.200000000000000e+03
Interpreter->McodeActions[0].Action=0
Interpreter->McodeActions[0].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[0].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[0].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[0].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[0].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[0].String=
Interpreter->McodeActions[1].Action=0
Interpreter->McodeActions[1].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[1].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[1].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[1].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[1].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[1].String=
Interpreter->McodeActions[2].Action=0
Interpreter->McodeActions[2].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[2].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[2].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[2].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[2].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[2].String=
Interpreter->McodeActions[3].Action=2
Interpreter->McodeActions[3].dParams[0]=  1.510000000000000e+02
Interpreter->McodeActions[3].dParams[1]=  1.000000000000000e+00
Interpreter->McodeActions[3].dParams[2]=  1.500000000000000e+02
Interpreter->McodeActions[3].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[3].dParams[4]=  1.000000000000000e+02
Interpreter->McodeActions[3].String=C:\Users\jpbar\Documents\JPB-SuperMax-CNC-Mill\JPB SpindleMach3DAC.c
Interpreter->McodeActions[4].Action=2
Interpreter->McodeActions[4].dParams[0]=  1.510000000000000e+02
Interpreter->McodeActions[4].dParams[1]=  1.000000000000000e+00
Interpreter->McodeActions[4].dParams[2]=  1.500000000000000e+02
Interpreter->McodeActions[4].dParams[3]=  1.000000000000000e+00
Interpreter->McodeActions[4].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[4].String=
Interpreter->McodeActions[5].Action=2
Interpreter->McodeActions[5].dParams[0]=  1.510000000000000e+02
Interpreter->McodeActions[5].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[5].dParams[2]=  1.500000000000000e+02
Interpreter->McodeActions[5].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[5].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[5].String=SpindleUsingJogs\CSS\OffJog.c
Interpreter->McodeActions[6].Action=0
Interpreter->McodeActions[6].dParams[0]=  4.000000000000000e+00
Interpreter->McodeActions[6].dParams[1]=  9.000000000000000e+00
Interpreter->McodeActions[6].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[6].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[6].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[6].String=ToolChange.c
Interpreter->McodeActions[7].Action=1
Interpreter->McodeActions[7].dParams[0]=  1.530000000000000e+02
Interpreter->McodeActions[7].dParams[1]=  1.000000000000000e+00
Interpreter->McodeActions[7].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[7].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[7].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[7].String=
Interpreter->McodeActions[8].Action=1
Interpreter->McodeActions[8].dParams[0]=  1.520000000000000e+02
Interpreter->McodeActions[8].dParams[1]=  1.000000000000000e+00
Interpreter->McodeActions[8].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[8].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[8].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[8].String=
Interpreter->McodeActions[9].Action=2
Interpreter->McodeActions[9].dParams[0]=  1.520000000000000e+02
Interpreter->McodeActions[9].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[9].dParams[2]=  1.530000000000000e+02
Interpreter->McodeActions[9].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[9].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[9].String=
Interpreter->McodeActions[10].Action=3
Interpreter->McodeActions[10].dParams[0]=  7.000000000000000e+00
Interpreter->McodeActions[10].dParams[1]= -2.000000000000000e+01
Interpreter->McodeActions[10].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[10].dParams[3]= -2.000000000000000e+03
Interpreter->McodeActions[10].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[10].String=C:\Users\jpbar\Documents\JPB-SuperMax-CNC-Mill\JPB SpindleMach3DAC.c
Interpreter->McodeActions[11].Action=4
Interpreter->McodeActions[11].dParams[0]=  1.000000000000000e+00
Interpreter->McodeActions[11].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[11].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[11].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[11].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[11].String=KStep\InitKStep3Axis.c
Interpreter->McodeActions[12].Action=0
Interpreter->McodeActions[12].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[12].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[12].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[12].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[12].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[12].String=Add.scr
Interpreter->McodeActions[13].Action=0
Interpreter->McodeActions[13].dParams[0]=  2.000000000000000e+00
Interpreter->McodeActions[13].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[13].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[13].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[13].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[13].String=BlinkKFLOP.c
Interpreter->McodeActions[14].Action=0
Interpreter->McodeActions[14].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[14].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[14].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[14].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[14].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[14].String=
Interpreter->McodeActions[15].Action=0
Interpreter->McodeActions[15].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[15].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[15].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[15].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[15].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[15].String=
Interpreter->McodeActions[16].Action=0
Interpreter->McodeActions[16].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[16].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[16].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[16].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[16].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[16].String=
Interpreter->McodeActions[17].Action=0
Interpreter->McodeActions[17].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[17].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[17].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[17].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[17].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[17].String=
Interpreter->McodeActions[18].Action=0
Interpreter->McodeActions[18].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[18].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[18].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[18].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[18].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[18].String=
Interpreter->McodeActions[19].Action=0
Interpreter->McodeActions[19].dParams[0]=  4.600000000000000e+01
Interpreter->McodeActions[19].dParams[1]=  1.000000000000000e+00
Interpreter->McodeActions[19].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[19].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[19].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[19].String=
Interpreter->McodeActions[20].Action=0
Interpreter->McodeActions[20].dParams[0]=  4.600000000000000e+01
Interpreter->McodeActions[20].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[20].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[20].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[20].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[20].String=
Interpreter->McodeActions[21].Action=0
Interpreter->McodeActions[21].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[21].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[21].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[21].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[21].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[21].String=
Interpreter->McodeActions[22].Action=0
Interpreter->McodeActions[22].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[22].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[22].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[22].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[22].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[22].String=
Interpreter->McodeActions[23].Action=0
Interpreter->McodeActions[23].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[23].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[23].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[23].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[23].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[23].String=
Interpreter->McodeActions[24].Action=0
Interpreter->McodeActions[24].dParams[0]=  2.000000000000000e+00
Interpreter->McodeActions[24].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[24].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[24].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[24].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[24].String=
Interpreter->McodeActions[25].Action=0
Interpreter->McodeActions[25].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[25].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[25].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[25].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[25].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[25].String=
Interpreter->McodeActions[26].Action=0
Interpreter->McodeActions[26].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[26].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[26].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[26].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[26].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[26].String=
Interpreter->McodeActions[27].Action=0
Interpreter->McodeActions[27].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[27].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[27].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[27].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[27].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[27].String=
Interpreter->McodeActions[28].Action=0
Interpreter->McodeActions[28].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[28].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[28].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[28].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[28].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[28].String=
Interpreter->McodeActions[29].Action=0
Interpreter->McodeActions[29].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[29].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[29].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[29].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[29].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[29].String=
Interpreter->McodeActions[30].Action=0
Interpreter->McodeActions[30].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[30].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[30].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[30].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[30].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[30].String=
Interpreter->McodeActions[31].Action=0
Interpreter->McodeActions[31].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[31].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[31].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[31].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[31].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[31].String=
Interpreter->McodeActions[32].Action=0
Interpreter->McodeActions[32].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[32].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[32].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[32].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[32].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[32].String=
Interpreter->McodeActions[33].Action=0
Interpreter->McodeActions[33].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[33].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[33].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[33].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[33].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[33].String=
Interpreter->McodeActions[34].Action=0
Interpreter->McodeActions[34].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[34].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[34].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[34].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[34].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[34].String=
Interpreter->McodeActions[35].Action=0
Interpreter->McodeActions[35].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[35].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[35].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[35].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[35].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[35].String=
Interpreter->McodeActions[36].Action=0
Interpreter->McodeActions[36].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[36].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[36].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[36].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[36].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[36].String=
Interpreter->McodeActions[37].Action=0
Interpreter->McodeActions[37].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[37].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[37].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[37].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[37].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[37].String=
Interpreter->McodeActions[38].Action=0
Interpreter->McodeActions[38].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[38].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[38].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[38].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[38].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[38].String=
Interpreter->McodeActions[39].Action=0
Interpreter->McodeActions[39].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[39].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[39].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[39].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[39].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[39].String=
Interpreter->McodeActions[40].Action=0
Interpreter->McodeActions[40].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[40].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[40].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[40].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[40].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[40].String=
Interpreter->McodeActions[41].Action=2
Interpreter->McodeActions[41].dParams[0]=  1.510000000000000e+02
Interpreter->McodeActions[41].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[41].dParams[2]=  1.500000000000000e+02
Interpreter->McodeActions[41].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[41].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[41].String=
Interpreter->McodeActions[42].Action=0
Interpreter->McodeActions[42].dParams[0]=  1.000000000000000e+00
Interpreter->McodeActions[42].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[42].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[42].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[42].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[42].String=C:\KMotionSrc\C Programs\HaltGCode.c
Interpreter->McodeActions[43].Action=0
Interpreter->McodeActions[43].dParams[0]=  4.600000000000000e+01
Interpreter->McodeActions[43].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[43].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[43].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[43].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[43].String=C:\KMotionSrc\C Programs\Safe Z on Halt Carl.c
Interpreter->McodeActions[44].Action=2
Interpreter->McodeActions[44].dParams[0]=  1.550000000000000e+02
Interpreter->McodeActions[44].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[44].dParams[2]=  1.510000000000000e+02
Interpreter->McodeActions[44].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[44].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[44].String=
Interpreter->McodeActions[45].Action=0
Interpreter->McodeActions[45].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[45].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[45].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[45].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[45].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[45].String=
Interpreter->McodeActions[46].Action=0
Interpreter->McodeActions[46].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[46].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[46].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[46].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[46].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[46].String=
Interpreter->McodeActions[47].Action=0
Interpreter->McodeActions[47].dParams[0]=  3.000000000000000e+00
Interpreter->McodeActions[47].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[47].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[47].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[47].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[47].String=C:\KMotionSrc\C Programs\BlinkKFLOP.c
Interpreter->McodeActions[48].Action=0
Interpreter->McodeActions[48].dParams[0]=  0.000000000000000e+00
Interpreter->McodeActions[48].dParams[1]=  0.000000000000000e+00
Interpreter->McodeActions[48].dParams[2]=  0.000000000000000e+00
Interpreter->McodeActions[48].dParams[3]=  0.000000000000000e+00
Interpreter->McodeActions[48].dParams[4]=  0.000000000000000e+00
Interpreter->McodeActions[48].String=
m_DialogFace=1
m_SafeZ=  0.000000000000000e+00
m_SafeRelAbs=0
m_DegreesA=1
m_DegreesB=1
m_DegreesC=0
m_UserButtonKeys[0]=120
m_UserButtonKeys[1]=121
m_UserButtonKeys[2]=-1
m_UserButtonKeys[3]=123
m_UserButtonKeys[4]=-1
m_UserButtonKeys[5]=-1
m_UserButtonKeys[6]=-1
m_UserButtonKeys[7]=-1
m_UserButtonKeys[8]=116
m_UserButtonKeys[9]=117
m_VarsFile=
m_ScreenScriptFile=3AxisNoJog.scr
m_DisplayGViewer=1
m_ConfigCheckWord=12345678
/code]



This is my initialization program:

[code]#include "KMotionDef.h"

// Defines KFLOP channels 0-4 as axes X-C
// Disables and Zeros all axes
// Defines axis parameters
// Enables all axes and sets positions to Zero
// Sets them as an XYZAC coordinate system for GCode
// Watchenable loop turns servos ON/OFF when axes are ENABLED/DISABLED
// or when Control Program (i.e. Mach3) is loaded/ended
// Each axis is disabled when a limit switch is tripped
// To reactivate, manually move axis away from switch then reload Control Program

void ServiceWatchdogStatus(void);
void WatchdogTripped(void);
void WatchdogOK(void);
void WatchLimits(void);

#define X 0
#define Y 1
#define Z 2					// Quill
#define C 3					// Knee
#define A 4					// Rotary

#define WATCHDOG_DELAY 2.0 	// Script to disable drives if/when Control Program is closed

int ControlProgramActive = 1;

int XLimit;
int YLimit;
int ZLimit;
int CLimit;

int main() 
{
	DisableAxis(X);
	Zero(X);

	DisableAxis(Y);
	Zero(Y);

	DisableAxis(Z);
	Zero(Z);

	DisableAxis(C);
	Zero(C);

	DisableAxis(A);
	Zero(A);	

FPGA(STEP_PULSE_LENGTH_ADD)=32 + 0x40 + 0x80;	

	ch0->InputMode=ENCODER_MODE;
	ch0->OutputMode=CL_STEP_DIR_MODE;
	ch0->Vel=200000;
	ch0->Accel=1e+06;
	ch0->Jerk=1e+07;
	ch0->P=0;
	ch0->I=0.001;
	ch0->D=0;
	ch0->FFAccel=0;
	ch0->FFVel=0;
	ch0->MaxI=1e+06;
	ch0->MaxErr=1e+09;
	ch0->MaxOutput=1e+06;
	ch0->DeadBandGain=1;
	ch0->DeadBandRange=0;
	ch0->InputChan0=0;
	ch0->InputChan1=0;
	ch0->OutputChan0=56;
	ch0->OutputChan1=0;
	ch0->MasterAxis=-1;
	ch0->LimitSwitchOptions=0x120;
	ch0->LimitSwitchNegBit=136;
	ch0->LimitSwitchPosBit=136;
	ch0->SoftLimitPos=1e+09;
	ch0->SoftLimitNeg=-1e+09;
	ch0->InputGain0=-46;
	ch0->InputGain1=1;
	ch0->InputOffset0=0;
	ch0->InputOffset1=0;
	ch0->OutputGain=-1;
	ch0->OutputOffset=0;
	ch0->SlaveGain=1;
	ch0->BacklashMode=BACKLASH_OFF;
	ch0->BacklashAmount=0;
	ch0->BacklashRate=0;
	ch0->invDistPerCycle=1;
	ch0->Lead=0;
	ch0->MaxFollowingError=5000;
	ch0->StepperAmplitude=20;

	ch0->iir[0].B0=1;
	ch0->iir[0].B1=0;
	ch0->iir[0].B2=0;
	ch0->iir[0].A1=0;
	ch0->iir[0].A2=0;

	ch0->iir[1].B0=1;
	ch0->iir[1].B1=0;
	ch0->iir[1].B2=0;
	ch0->iir[1].A1=0;
	ch0->iir[1].A2=0;

	ch0->iir[2].B0=0.00075647;
	ch0->iir[2].B1=0.00151294;
	ch0->iir[2].B2=0.00075647;
	ch0->iir[2].A1=1.88998;
	ch0->iir[2].A2=-0.89301;
	


	ch1->InputMode=ENCODER_MODE;
	ch1->OutputMode=CL_STEP_DIR_MODE;
	ch1->Vel=200000;
	ch1->Accel=1e+06;
	ch1->Jerk=1e+07;
	ch1->P=0;
	ch1->I=0.001;
	ch1->D=0;
	ch1->FFAccel=0;
	ch1->FFVel=0;
	ch1->MaxI=1e+06;
	ch1->MaxErr=1e+09;
	ch1->MaxOutput=1e+06;
	ch1->DeadBandGain=1;
	ch1->DeadBandRange=0;
	ch1->InputChan0=1;
	ch1->InputChan1=0;
	ch1->OutputChan0=57;
	ch1->OutputChan1=0;
	ch1->MasterAxis=-1;
	ch1->LimitSwitchOptions=0x120;
	ch1->LimitSwitchNegBit=137;
	ch1->LimitSwitchPosBit=137;
	ch1->SoftLimitPos=1e+09;
	ch1->SoftLimitNeg=-1e+09;
	ch1->InputGain0=46;
	ch1->InputGain1=1;
	ch1->InputOffset0=0;
	ch1->InputOffset1=0;
	ch1->OutputGain=-1;
	ch1->OutputOffset=0;
	ch1->SlaveGain=1;
	ch1->BacklashMode=BACKLASH_OFF;
	ch1->BacklashAmount=0;
	ch1->BacklashRate=0;
	ch1->invDistPerCycle=1;
	ch1->Lead=0;
	ch1->MaxFollowingError=2500;
	ch1->StepperAmplitude=20;

	ch1->iir[0].B0=1;
	ch1->iir[0].B1=0;
	ch1->iir[0].B2=0;
	ch1->iir[0].A1=0;
	ch1->iir[0].A2=0;

	ch1->iir[1].B0=1;
	ch1->iir[1].B1=0;
	ch1->iir[1].B2=0;
	ch1->iir[1].A1=0;
	ch1->iir[1].A2=0;

	ch1->iir[2].B0=0.779671;
	ch1->iir[2].B1=-1.55685;
	ch1->iir[2].B2=0.779671;
	ch1->iir[2].A1=1.55685;
	ch1->iir[2].A2=-0.559341;



	ch2->InputMode=ENCODER_MODE;
	ch2->OutputMode=CL_STEP_DIR_MODE;
	ch2->Vel=200000;
	ch2->Accel=1e+06;
	ch2->Jerk=1e+07;
	ch2->P=0;
	ch2->I=0.001;
	ch2->D=0;
	ch2->FFAccel=0;
	ch2->FFVel=0;
	ch2->MaxI=1e+06;
	ch2->MaxErr=1e+09;
	ch2->MaxOutput=1e+06;
	ch2->DeadBandGain=1;
	ch2->DeadBandRange=0;
	ch2->InputChan0=2;
	ch2->InputChan1=0;
	ch2->OutputChan0=58;
	ch2->OutputChan1=0;
	ch2->MasterAxis=-1;
	ch2->LimitSwitchOptions=0x120;
	ch2->LimitSwitchNegBit=138;
	ch2->LimitSwitchPosBit=138;
	ch2->SoftLimitPos=1e+09;
	ch2->SoftLimitNeg=-1e+09;
	ch2->InputGain0=-35.45;
	ch2->InputGain1=1;
	ch2->InputOffset0=0;
	ch2->InputOffset1=0;
	ch2->OutputGain=-1;
	ch2->OutputOffset=0;
	ch2->SlaveGain=1;
	ch2->BacklashMode=BACKLASH_OFF;
	ch2->BacklashAmount=0;
	ch2->BacklashRate=0;
	ch2->invDistPerCycle=1;
	ch2->Lead=0;
	ch2->MaxFollowingError=2500;
	ch2->StepperAmplitude=20;

	ch2->iir[0].B0=1;
	ch2->iir[0].B1=0;
	ch2->iir[0].B2=0;
	ch2->iir[0].A1=0;
	ch2->iir[0].A2=0;

	ch2->iir[1].B0=1;
	ch2->iir[1].B1=0;
	ch2->iir[1].B2=0;
	ch2->iir[1].A1=0;
	ch2->iir[1].A2=0;

	ch2->iir[2].B0=0.000768809;
	ch2->iir[2].B1=0.00153762;
	ch2->iir[2].B2=0.000768809;
	ch2->iir[2].A1=1.92081;
	ch2->iir[2].A2=-0.923885;
	


	ch3->InputMode=ENCODER_MODE;
	ch3->OutputMode=CL_STEP_DIR_MODE;
	ch3->Vel=100000;
	ch3->Accel=75000;
	ch3->Jerk=1e+06;
	ch3->P=0;
	ch3->I=0.001;
	ch3->D=0;
	ch3->FFAccel=0;
	ch3->FFVel=0;
	ch3->MaxI=1e+06;
	ch3->MaxErr=1e+09;
	ch3->MaxOutput=1e+06;
	ch3->DeadBandGain=1;
	ch3->DeadBandRange=0;
	ch3->InputChan0=3;
	ch3->InputChan1=0;
	ch3->OutputChan0=59;
	ch3->OutputChan1=0;
	ch3->MasterAxis=-1;
	ch3->LimitSwitchOptions=0x120;
	ch3->LimitSwitchNegBit=139;
	ch3->LimitSwitchPosBit=139;
	ch3->SoftLimitPos=1e+09;
	ch3->SoftLimitNeg=-1e+09;
	ch3->InputGain0=-85.3;
	ch3->InputGain1=1;
	ch3->InputOffset0=0;
	ch3->InputOffset1=0;
	ch3->OutputGain=-1;
	ch3->OutputOffset=0;
	ch3->SlaveGain=1;
	ch3->BacklashMode=BACKLASH_OFF;
	ch3->BacklashAmount=0;
	ch3->BacklashRate=0;
	ch3->invDistPerCycle=1;
	ch3->Lead=0;
	ch3->MaxFollowingError=10000;
	ch3->StepperAmplitude=20;

	ch3->iir[0].B0=1;
	ch3->iir[0].B1=0;
	ch3->iir[0].B2=0;
	ch3->iir[0].A1=0;
	ch3->iir[0].A2=0;

	ch3->iir[1].B0=1;
	ch3->iir[1].B1=0;
	ch3->iir[1].B2=0;
	ch3->iir[1].A1=0;
	ch3->iir[1].A2=0;

	ch3->iir[2].B0=0.000768809;
	ch3->iir[2].B1=0.00153762;
	ch3->iir[2].B2=0.000768809;
	ch3->iir[2].A1=1.92081;
	ch3->iir[2].A2=-0.923885;
	

	
	ch4->InputMode=NO_INPUT_MODE;
	ch4->OutputMode=STEP_DIR_MODE;
	ch4->Vel=40000;
	ch4->Accel=400000;
	ch4->Jerk=4e+06;
	ch4->P=0.2;
	ch4->I=0;
	ch4->D=0;
	ch4->FFAccel=0;
	ch4->FFVel=0;
	ch4->MaxI=200;
	ch4->MaxErr=200;
	ch4->MaxOutput=200;
	ch4->DeadBandGain=1;
	ch4->DeadBandRange=0;
	ch4->InputChan0=4;
	ch4->InputChan1=1;
	ch4->OutputChan0=63;
	ch4->OutputChan1=1;
	ch4->MasterAxis=-1;
	ch4->LimitSwitchOptions=0x120;
	ch4->LimitSwitchNegBit=0;
	ch4->LimitSwitchPosBit=0;
	ch4->SoftLimitPos=1e+09;
	ch4->SoftLimitNeg=-1e+09;
	ch4->InputGain0=0;
	ch4->InputGain1=1;
	ch4->InputOffset0=0;
	ch4->InputOffset1=0;
	ch4->OutputGain=1;
	ch4->OutputOffset=0;
	ch4->SlaveGain=1;
	ch4->BacklashMode=BACKLASH_OFF;
	ch4->BacklashAmount=0;
	ch4->BacklashRate=0;
	ch4->invDistPerCycle=1;
	ch4->Lead=0;
	ch4->MaxFollowingError=1000000000;
	ch4->StepperAmplitude=250;

	ch4->iir[0].B0=1;
	ch4->iir[0].B1=0;
	ch4->iir[0].B2=0;
	ch4->iir[0].A1=0;
	ch4->iir[0].A2=0;

	ch4->iir[1].B0=1;
	ch4->iir[1].B1=0;
	ch4->iir[1].B2=0;
	ch4->iir[1].A1=0;
	ch4->iir[1].A2=0;

	ch4->iir[2].B0=1;
	ch4->iir[2].B1=0;
	ch4->iir[2].B2=0;
	ch4->iir[2].A1=0;
	ch4->iir[2].A2=0;


	EnableAxisDest(X,0);
	EnableAxisDest(Y,0);
	EnableAxisDest(Z,0);
	EnableAxisDest(C,0);
	EnableAxisDest(A,0);
	
	DefineCoordSystem6(0,1,2,4,-1,3);
	
	
	for (;;)  							// loop forever
	{
		XLimit = ReadBit(136);
		YLimit = ReadBit(137);
		ZLimit = ReadBit(138);
		CLimit = ReadBit(139);
		
		if (!XLimit || !YLimit || !ZLimit || !CLimit)
		{
			WatchLimits();
		}

		WaitNextTimeSlice();
		ServiceWatchdogStatus();
				
		if  (ControlProgramActive &&	// ControlProgramActive when loaded
		    (ch0->Enable) &&
		    (ch1->Enable) &&
		    (ch2->Enable) &&		    		    
		    (ch3->Enable) &&
		    (ch4->Enable))				// Enables stepper drivers IF ALL axes are enabled
		
			SetBit(155);		
		else
			ClearBit(155);				// Disables stepper drivers if ANY axis is disabled
	}
		
	return 0;
}


void ServiceWatchdogStatus(void)
{
	static int Alive=FALSE;
	static int PrevStatusRequestCounter=-1;
	static double WatchdogTime=0;
	double T=Time_sec();
	
	// check if Host is requesting Status
	if (StatusRequestCounter != PrevStatusRequestCounter)
	{
		// yes, save time 
		WatchdogTime = T + WATCHDOG_DELAY;
		PrevStatusRequestCounter=StatusRequestCounter;
		if (!Alive) WatchdogOK();
		Alive=TRUE;
	}
	else
	{
		if (T > WatchdogTime) 	 // time to trigger?
		{
			if (Alive) WatchdogTripped();
			Alive=FALSE; 
		}
	}
}


void WatchdogOK(void)			// Trips when Mach3/KMotionCNC is open
{
	ClearBit(47);  				// KFLOP LED off
	Delay_sec(1);
	SetBit(47);
	Delay_sec(1);
	
	ControlProgramActive = 1;
}


void WatchdogTripped(void)		// Trips when Mach3/KMotionCNC is closed 
{	
	ClearBit(46);  				// KFLOP LED off
	Delay_sec(1);
	SetBit(46);
	Delay_sec(1);
	
	ControlProgramActive = 0;	// Keeps forever loop from re-enabling drives 
								// with 'SetBit(155)'
}


void WatchLimits(void)
{
	if (XLimit == 0)
	{
		ClearBit(155);
		DisableAxis(X);
	}
	
	if (YLimit == 0)
	{
		ClearBit(155);
		DisableAxis(Y);
	}
	
	if (ZLimit == 0)
	{
		ClearBit(155);
		DisableAxis(Z);
	}
	
	if (CLimit == 0)
	{
		ClearBit(155);
		DisableAxis(C);
	}

	ClearBit(150);				// Disables VFD and stops spindle motor
	ClearBit(151);
}
/code]


Lastly, this is the Gcode file for the program used to mill the speed test PCB file shown in the previous photos:

[code](SPEED TEST)
(MACHINE)
(  DESCRIPTION JPB SUPERMAX)
(T9 D=0.02 CR=0.1 TAPER=10DEG - ZMIN=-0.007 - TAPERED MILL)
G90 G94 G91.1 G40 G49 G17
G0 Z0.4

(CONTOUR 1)
S100 M3
G4 P10
G90
G54
M7
M8
G0 X0.6839 Y0.1161
G43 Z0.4 H9
G0 Z0.2
G1 Z0.004 F1.
Z-0.007
X0.4339 Y-0.1339
G2 X0.3661 Y-0.0661 I-0.0339 J0.0339
G1 X0.6661 Y0.2339
G2 X0.7339 I0.0339 J-0.0339
Y0.1661 I-0.0339 J-0.0339
G1 X0.6839 Y0.1161
G0 Z0.2
X0.7525 Y0.0932
G1 Z0.004 F1.
Z-0.007
X0.7521 Y0.0966
X0.752 Y0.1
Y0.2
G2 X0.848 I0.048 J0.
G1 Y0.1
G2 X0.7525 Y0.0932 I-0.048 J0.
G0 Z0.2
X0.7713 Y-0.0385
G1 Z0.004 F1.
Z-0.007
G2 X0.8287 Y0.0385 I0.0287 J0.0385
X0.7713 Y-0.0385 I-0.0287 J-0.0385
G0 Z0.2
X0.7659 Y-0.1341
G1 Z0.004 F1.
Z-0.007
G2 X0.8341 Y-0.0665 I0.0341 J0.0338
X0.7659 Y-0.1341 I-0.0341 J-0.0338
G0 Z0.2
Y-0.1659
G1 Z0.004 F1.
Z-0.007
G2 X0.8341 Y-0.2334 I0.0341 J-0.0338
X0.7659 Y-0.1659 I-0.0341 J0.0338
G0 Z0.2
X0.7339 Y-0.166
G1 Z0.004 F1.
Z-0.007
G2 X0.7321 Y-0.2357 I-0.0339 J-0.034
X0.6625 Y-0.23 I-0.0321 J0.0357
G1 X0.6375
G2 X0.5625 I-0.0375 J0.03
G1 X0.4375
G2 X0.3625 Y-0.17 I-0.0375 J0.03
X0.4375 I0.0375 J-0.03
G1 X0.5625
G2 X0.6375 I0.0375 J-0.03
G1 X0.6625
G2 X0.7339 Y-0.166 I0.0375 J-0.03
G0 Z0.2
Y-0.134
G1 Z0.004 F1.
Z-0.007
G2 X0.7 Y-0.148 I-0.0339 J0.034
G1 X0.6
G2 Y-0.052 I0. J0.048
G1 X0.642
G3 X0.652 Y-0.042 I0. J0.01
G1 Y0.
G2 X0.748 I0.048 J0.
G1 Y-0.1
G2 X0.7339 Y-0.134 I-0.048 J0.
G0 Z0.2
X0.4932 Y0.1525
G1 Z0.004 F1.
Z-0.007
G2 X0.4625 Y0.17 I0.0068 J0.0475
G1 X0.4375
G2 X0.43 Y0.1625 I-0.0375 J0.03
G1 Y0.1375
G2 X0.37 Y0.0625 I-0.03 J-0.0375
Y0.1375 I0.03 J0.0375
G1 Y0.1625
G2 X0.3661 Y0.2339 I0.03 J0.0375
X0.4375 Y0.23 I0.0339 J-0.0339
G1 X0.4625
G2 X0.5375 Y0.17 I0.0375 J-0.03
X0.4932 Y0.1525 I-0.0375 J0.03
G0 Z0.4

M9
M5
G0 Z0.4
G0 X0 Y0
M30
/code]

Thank you again!

Jim

User avatar
TomKerekes
Posts: 2811
Joined: Mon Dec 04, 2017 1:49 am

Re: PCB Milling Feed Rate issue

Post by TomKerekes » Sun Mar 23, 2025 10:36 pm

Hi Jim,

Here are some thoughts:

The Look ahead/Buffer time is only 0.05 seconds. This should normally be at least 1 second.

The Max Following error setting of 5000 counts corresponds to ~0.02 inches. This is relatively large so if the axes aren't following the trajectory precisely there wouldn't be an error. I'm guessing the errors are on the order of 0.005 inches? That would be around 1200 counts. How low can you set the Max Following error before you detect errors?

You might check the Servo Tuning using the Step Response Screen at similar conditions. Such as:

Feedrate 5ipm -> 20,000 counts/sec
Accel 4.28 inches/sec2 -> 1,000,000 counts/sec2
Jerk infinity 1e8
Move size 0.1 inches -> 23,350 counts

You might consider using lower accelerations. For example a motion of 0.1 inches at 5ipm takes about 1.25 seconds. While the acceleration to 5ipm takes only ~0.02 seconds. So the acceleration could be reduced without significantly reducing throughput.

You might capture the motion with a C Program like CaptureXYMotionPosDest.c to analyze exactly how well the servo is following.

HTH
Regards,

Tom Kerekes
Dynomotion, Inc.

jpbarad7
Posts: 21
Joined: Wed Dec 07, 2022 6:25 pm

Re: PCB Milling Feed Rate issue

Post by jpbarad7 » Tue Apr 01, 2025 4:21 pm

Tom,

Thank you VERY much for this information.

Unfortunately, I have not been able to get back into the shop to test anything yet. When I do, I will report back.

Before emailing you, I experimented quite a bit with acceleration, reducing it considerably without noticable effect.

I have the Max following errors set high to allow for rapid jogging during set up and tool changes - well beyond any feedrate that I might use within a program. It doesn't seem to cause any measurable issues with straight movements and larger arcs. I will reduce it and see what happens.

I have also played with look ahead within Mach3, but didn't notice it was so short in KmotionCNC. I'll reset that to 1 sec.

Whenever I compare my commanded moves with actual graphically, the two curves follow each other exactly, except for a 'spike' when movement is first initiated. I wondered if this could be the cause of the irregularities in the small circles I am milling. I thought maybe it was caused by lag when the steppers initially overcome friction?

When tuning a closed loop stepper system, is only the integrator value adjusted? Should I have to mess with P or D?

Thanks again!

Jim

User avatar
TomKerekes
Posts: 2811
Joined: Mon Dec 04, 2017 1:49 am

Re: PCB Milling Feed Rate issue

Post by TomKerekes » Tue Apr 01, 2025 5:19 pm

Hi Jim,
Before emailing you, I experimented quite a bit with acceleration, reducing it considerably without noticable effect.
To what value was it reduced?

I have the Max following errors set high to allow for rapid jogging during set up and tool changes - well beyond any feedrate that I might use within a program. It doesn't seem to cause any measurable issues with straight movements and larger arcs. I will reduce it and see what happens.
Max Following Error doesn't have any effect on how the motion is performed, rather it just determines if there will be a fault or not. The idea was to use it for diagnostic purposes. You might need reduce your rapids in order to set it small enough to check for errors during feeds.

I have also played with look ahead within Mach3, but didn't notice it was so short in KmotionCNC. I'll reset that to 1 sec.
Are the motion parameters set the same?

Whenever I compare my commanded moves with actual graphically, the two curves follow each other exactly, except for a 'spike' when movement is first initiated. I wondered if this could be the cause of the irregularities in the small circles I am milling. I thought maybe it was caused by lag when the steppers initially overcome friction?
Please post the data or a plot.

When tuning a closed loop stepper system, is only the integrator value adjusted? Should I have to mess with P or D?
Yes all the parameters are available to improve performance. Including Filters and Feed Forwards.
Regards,

Tom Kerekes
Dynomotion, Inc.

jpbarad7
Posts: 21
Joined: Wed Dec 07, 2022 6:25 pm

Re: PCB Milling Feed Rate issue

Post by jpbarad7 » Tue Jul 29, 2025 7:53 pm

Tom,

I just wanted to follow up and 'close the loop' on the issue I was having machining small circles.

The problem, as you suspected, was with improper acceleration and PID values. I had experimented for countless hours, unrewardingly, until deciding to ask ChatGPT for help. After gathering basic information about my system (controller, drives, motors, etc.), it had me input starting values for P and I, run a test, then upload the raw data. It analyzed the data in that and in many subsequently submitted files, then made suggestions for changes to enhance performance. After several tuning sessions, during which it had me clear filters, add FFVel and FFAccel values, set proper max limits for output, integrator, and error, and adjusting backlash settings for my only non ball-screwed axis (knee), I am now able to machine very acceptable 0.076" copper pads at speeds up to 15 ipm. I suspect I could go even faster on long runs, but the small distances involved in PCB manufacturing of most boards doesn't allow the machine to reach its max speeds.

After proper tuning, ChatGPT even helped me optimize the settings in KmotionCNC and my Mach3 plugin (Look ahead, CV distances, etc.).

I don't know how you feel about AI, but it made short work of a problem that as been an issue for me for several years!

Thanks again for your excellent service and support over the years.

Jim

User avatar
TomKerekes
Posts: 2811
Joined: Mon Dec 04, 2017 1:49 am

Re: PCB Milling Feed Rate issue

Post by TomKerekes » Thu Jul 31, 2025 9:53 pm

Hi Jim,

That's quite amazing. Thanks for sharing.

What level of ChatGPT did you use? Free, Plus, or Pro?
Regards,

Tom Kerekes
Dynomotion, Inc.

jpbarad7
Posts: 21
Joined: Wed Dec 07, 2022 6:25 pm

Re: PCB Milling Feed Rate issue

Post by jpbarad7 » Fri Aug 01, 2025 2:58 pm

Tom,

I have the plus plan.

The free version does not allow access to ChatGPT 4o, which is the most advanced version at this time. Nor does it allow for file uploads, which is the thing that really made the difference for me. I had a great deal of difficulty identifying changes (positive or negative) in the plots produced on the step response screen. I was erroneously making changes based on stepper/machine sounds and perceived smoothness of motion, which lead me down a rabbit hole of frustration and disappointment. After saving and uploading the file to ChatGPT, it was able to tell me what difference the changes made and provided additional suggestions. It even told me when tuning was complete!

Now my system can produce very acceptable PCBs with the Mach3 plugin. Using the same settings in KmotionCNC yielded equal results - no better/no worse. ChatGPT told me because KMotionCNC was far better than Mach3 with motion control and trajectory planning, I could be certain that the residual imperfections I was seeing in milling the small circles were due to machine limitations rather than tuning issues.

It did occasionally take me in a wrong direction - even AI stumbles into a rabbit hole once in a while, apparently. When it happened, I closed the chat and opened another.

It would be interesting to hear what a person with your knowledge/experience felt about the way ChatGPT approached the tuning process.

I have a few remaining questions, if you have time to comment:

Even though I have tested the system with CaptureXYZPosDestToFile and found the errors to be minimal (again, by ChatGPT analysis) and can run all axes from limit to limit at a rapid rate (G0), if/when I tried to run a test on the step response screen of >250000 moves, it would move forward to completion, but stop on the return path with 1000+ counts still on the axis counter. The system didn't crash, it just didn't complete the run. This was very confusing to me. I suspected I was exceeding some limit within Kmotion but could never identify it.

Is there a way to limit max travel speeds of jogging in KmotionCNC? My system can't keep up with the high jog rate - I think because it uses the max vel, accel, and jerk settings in the config file. Thinking my V, A, and J were set to high, I experimented with lowering them repeatedly but found that there is a lower limit to each, afterwhich PID tuning is no longer effective. In the Mach3 plug in I was able to get around this by reducing the V and A values until I could move at rapid rate without crashing.

There's still a lot I don't know, and probably never will know about tuning, but am happy to be where I am at this point.

Thanks again!

Jim

User avatar
TomKerekes
Posts: 2811
Joined: Mon Dec 04, 2017 1:49 am

Re: PCB Milling Feed Rate issue

Post by TomKerekes » Fri Aug 01, 2025 9:01 pm

Hi Jim,

Thanks for the info.
I had a great deal of difficulty identifying changes (positive or negative) in the plots produced on the step response screen.
The simple idea is to have the measured position accurately follow the commanded trajectory with the least error. When plotting Position and Command the red plot should match/overlay the blue plot. Once they start matching very well it may be hard to see how much error there is so plot the error instead. In this case the goal is to reduce the error to zero. Its good to know the resolution of your system so you can convert errors to actual distance. For example if your system has a resolution of 20,000 counts/inch and you see errors of 100 counts you would understand this is 100/20000 = 0.005 inches.

It even told me when tuning was complete
Did you tell it your accuracy and speed requirements?

ChatGPT told me because KMotionCNC was far better than Mach3 with motion control and trajectory planning, I could be certain that the residual imperfections I was seeing in milling the small circles were due to machine limitations rather than tuning issues.
I'm not sure that would necessarily be true. The same bad tuning applied to both would be likely to give similar results. I'm not saying this is the case.

Even though I have tested the system with CaptureXYZPosDestToFile and found the errors to be minimal (again, by ChatGPT analysis) and can run all axes from limit to limit at a rapid rate (G0), if/when I tried to run a test on the step response screen of >250000 moves, it would move forward to completion, but stop on the return path with 1000+ counts still on the axis counter. The system didn't crash, it just didn't complete the run. This was very confusing to me. I suspected I was exceeding some limit within Kmotion but could never identify it.
It's not clear what you mean. After the move and move back is the position physically off by 1000 counts? On KMotion's Axis Screen does the Position and Destination match? Are both values the same as before the movements?

Is there a way to limit max travel speeds of jogging in KmotionCNC? My system can't keep up with the high jog rate
Yes on Tool Setup | Trajectory Planner | Jog Speeds. See here.

I think because it uses the max vel, accel, and jerk settings in the config file.
It uses the Acceleration and Jerk for Jogging but the Jog Speed for the Velocity. G0 Rapids use all 3.

I experimented with lowering them repeatedly but found that there is a lower limit to each, afterwhich PID tuning is no longer effective.
I don't understand what you mean. "Not effective"? PID should work the same at all speeds.


It would be helpful if you post your Initialization C Program and KMotion CNC Settings.

Sounds like you are doing very well.
Regards,

Tom Kerekes
Dynomotion, Inc.

Post Reply