KMotionCNC Spindle Speed: Troubleshooting M3 and S

Tom Garrett4 min read
Motion ControlOther ManufacturerTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

An M3 S500 command can produce zero spindle output when the KMotionCNC S action writes the requested speed to one persistent variable but the M3 program reads another. Treat M3, M4, M5, and S as four separate actions: S receives and stores the speed; M3 and M4 apply that stored speed and direction; M5 stops the spindle.

Identify the variable mismatch

The working configuration passes the S value through persistent variable 1. The S program copies that value to persistent variable 99, and the M3/M4 programs read variable 99. A program that reads variable 97 instead can calculate zero counts per second even when KMotionCNC issued S500.

Action Purpose Required variable behavior
M3 Spindle clockwise Read saved speed from persist.UserData[99]
M4 Spindle counterclockwise Read saved speed from persist.UserData[99]
M5 Stop spindle No passed speed variable required; the configured variable may be -1
S Update commanded speed Receive speed in persist.UserData[1] and copy it to persist.UserData[99]

Configure the four spindle actions

  1. In KMotionCNC Tool Setup, assign separate C programs to the M3, M4, M5, and S actions.
  2. Configure the S action to pass its floating-point speed through persistent variable 1.
  3. Configure M3, M4, and M5 without a passed variable; -1 is acceptable for those action settings.
  4. In the S program, interpret persist.UserData[1] as a float and copy its raw stored value to persist.UserData[99].
  5. In both direction programs, interpret persist.UserData[99] as a float before calculating the jog rate.
#define SPINDLEAXIS 4
#define FACTOR (2048/60.0)
#define SPEEDVAR 99
#define STATEVAR 98
#define KMVAR 1

/* S action */
float speed = *(float *)&persist.UserData[KMVAR];
persist.UserData[SPEEDVAR] = persist.UserData[KMVAR];

/* M3 action */
float savedSpeed = *(float *)&persist.UserData[SPEEDVAR];
Jog(SPINDLEAXIS, savedSpeed * FACTOR);

The floating-point casts matter because the speed occupies the persistent storage as a float. Do not replace the stored value with an ordinary integer conversion.

Apply direction and state correctly

Use persistent variable 98 for spindle state: 0 for off, 1 for clockwise, and -1 for counterclockwise. When reversing direction, clear output bits 154 and 155, command Jog(4,0), and wait for CheckDone(4) before asserting the opposite direction output.

For the demonstrated positive factor, M3 commands speed * FACTOR and M4 commands -speed * FACTOR. M5 clears both direction bits, commands zero jog speed, records state 0, and waits for the axis to stop. The evidence also contains an alternative factor, -500.0/2007, tied to a different stated counts-to-RPM relationship. Do not combine the two factors; select and validate the factor that matches the installed step/direction scaling and required polarity.

Verify command flow and scaling

  1. Issue an S command and confirm that persistent variable 1 receives the requested floating-point speed.
  2. Confirm that the S program copies the value to persistent variable 99.
  3. Issue M3 and print the calculated jog command. With S500 and FACTOR = 2048/60.0, the derived command is approximately 17066.67 counts/sec.
  4. Confirm that channel 4 receives the jog command and that the VFD receives step/direction pulses.
  5. Repeat with M4 and verify that the commanded jog rate changes sign. Issue M5 and verify a zero jog command and cleared direction outputs.

If the printed rate remains zero, inspect variables 1 and 99 before investigating the VFD. If the rate is nonzero but measured RPM is wrong, verify the factor and pulse scaling instead of changing the persistent-variable mapping.

Separate speed-command errors from encoder noise

The reported VFD measurements closely followed the requested speeds: S300 produced 10.02 Hz and 299 RPM, S750 produced 25.09 Hz and 752 RPM, S1500 produced 50 Hz and 1499 RPM, and S3000 produced 100.14 Hz and 2999 RPM. KMotionCNC displayed lower values of approximately 261, 695, 1413, and 2910 RPM, with about ±10 RPM movement even at zero speed. This pattern separates a functioning VFD command path from a questionable encoder measurement path.

The installed encoder is single-ended, rated at 2500 PPR, and connected in parallel to the VFD feedback card and inputs IO38, IO39, and IO40; IO36 and IO37 carry step/direction to the VFD. Diagnose the feedback independently:

  1. Zero the reported encoder position and mark the physical spindle position.
  2. Rotate or run the spindle, then return it precisely to the mark.
  3. Check whether the final position lies within several counts of a multiple of 10000 counts.
  4. If the count does not return as expected or changes while stopped, inspect the single-ended signal path, grounding, shielding, shared loading, and noise before altering speed scaling.

FAQ

Why does KMotionCNC print zero counts per second after M3 S500?

The S action may be writing speed to persistent variable 1 while M3 reads the wrong saved-speed variable. Copy variable 1 to 99 in the S program and read variable 99 as a float in M3.

What variable should KMotionCNC use for the spindle S action?

Configure the S action to pass speed through persistent variable 1. M3, M4, and M5 do not require a passed speed variable and may use -1 in their action configuration.

How do I check a 2500 PPR spindle encoder in KMotion?

Zero the position, mark the spindle, move it, and return it to the same physical position. The final reading should be within several counts of a multiple of 10000; movement while stopped or a poor return result directs troubleshooting toward the encoder signal path.

Back to blog