Table of contents |

KMotionCNC Spindle Control


KMotionCNC allows the User to configure how the Spindle is to be be controlled. Four basic actions that need to be defined are:

To configure what action is to take place for each of the four functions the Tool Setup must be configured to either do the operations directly, or by invoking a KFLOP User C Program.

For the most basic cases where only one or two control IO bits are required for On/Off/Direction the IO operations can be configured directly. If Speed can be controlled by simple open loop scaling/limiting of a DAC output then speed control can also be configured directly.

For more complex cases and to allow control of virtually any type of Spindle, through any type of interface, KMotionCNC can be configured to invoke User programs to perform the four tasks listed above. Spindles might need to be controlled in a variety of different ways: Open Loop, Closed Loop, DACs, PWMs, Step/Dir, ModBus, Rs232, etc...Although this requires a small program to be written, it provides maximal flexibility and full control to the system designer. Usually with only a few lines of code the desired task may be performed. Common examples are provided.

For G96/G97 - CSS (Constant Surface Speed) an additional program is required to run continuously in KFLOP which changes spindle speed continuously as a function of X position (radius). See the CSSJog.c example.

If a quadrature encoder is installed on the spindle it may be used for Spindle Speed Measurement and Display. See the Threading Configuration described here.

Basic Configuration

For basic configurations where the spindle CW/CCW/OFF can be controlled with one or two IO bits (normally Kanalog Relay Driver or Opto Outputs) and with speed control from a Kanalog DAC then no C programming is required. An example configuration is shown below. Note the S action is mapped to Kanalog DAC #7 with a negative scale of -2.047. Kanalog DAC outputs are inverting such that negative DAC counts result in a positive voltage. The assumption in this case is that an S value of 1000RPM would correspond to -2047 DAC counts or +10V. And the allowed range is from -2047 to 0 counts (0V to +10V).

An additional advantage to using I/O bits rather than C Programs is that they I/O commands will be embedded within the motion stream and will occur synchronously with the motion and without any pause in the motion. This is especially useful for faster systems with Lasers/Engravers/Extruders instead of a traditional Spindle. For more information on buffered IO commands see here.

Tool Setup Screen

User Program Configuration

For more advanced functionality User C Programs may be assigned for each of the spindle actions. For systems that have a spindle that can be controlled with an axis channel the C Programs listed below can be used directly with little or no modification. Note if your Spindle speed is controlled by a DAC an Axis channel can be configured to output open loop to a DAC, see here for how. This assumes that axis channel has already been configured much like the other axes in the system and can be moved using Axis Jog Commands. Spindles such as this are types that can be driven like a servo with feedback, or as an open loop Step/Dir drive. The only requirement is that a KFLOP axis channel can be used for control. This also allows acceleration (and Jerk) to be controlled by the axis channel for smooth speed changes.

The example configuration below shows the four spindle tasks assigned to four C programs. Each of the programs run temporarily to perform their function and should never execute concurrently so each can use the same Thread. See here for more information on Threads. M3, M4, and M5 do not pass any parameter so the VAR should be assigned to ay unused Variable such as #1. For S the speed value is passed in the VAR parameter. If G96/G97 CSS is to be used then the same VAR should be used as the G96 speed is passed. This VAR number is defined in PC-DSP.h as

	#define PC_COMM_CSS_S 113 // S speed setting in inches/sec

Spindle CSS

In most cases the four C programs can be used without any modification. The programs all include a common file called MySpindleDefs.h that contain settings that are likely to require customization for any particular system. The file and parameters are defined and described below. Each of the four C programs includes this file with an include statement of: #include "MySpindleDefs.h". This should be placed immediately after the #include "KMotionDef.h" (which includes and defines all the standard KFLOP definitions).

Some Spindle controls/interfaces can accept a positive and negative command to drive in CW and CCW directions. Others require inputs (relays) to switch the directions and the speed is always set as a positive command. If your system is capable of accepting positive and negative commands then define USE_POS_NEG_VOLTAGE as 1 otherwise define it as 0.


	#define SPINDLEAXIS 6 		// Axis Channel to Jog to rotate Spindle
	#define FACTOR (1000/60.0)	// to convert RPM to counts/sec (counts/rev / 60.0sec)
	#define SPINDLECW_BIT 154 	// bit to activate to cause CW rotation
	#define SPINDLECCW_BIT 155 	// bit to activate to cause CCW rotation
	#define SPEEDVAR 99 		// global persistant variable to store latest speed
	#define STATEVAR 98 		// global persistant variable to store latest state (-1=CCW,0=off,1=CW)
	#define KMVAR PC_COMM_CSS_S 	// variable KMotionCNC will pass speed parameter (113)
	#define USE_POS_NEG_VOLTAGE 0 	// 0 = output Magnitude, 1 = output positive and negative speed

These C Programs (located in the <Install Directory>\C Programs\SpindleUsingJogs\CSS directory) are written in a manner to handle a common issue with Spindles which is that a Speed change while the Spindle is commanded off should not be immediately applied. The four programs use two global variables to maintain the latest state and speed. This allows a speed change (when off) to be delayed until the spindle is turned on, but also be applied immediately if already on. In the example above VARs 99 and 98 are used for this purpose.

CSS - Constant Surface Speed

Constant Surface Speed allows a lathe cutting tool to maintain a constant linear rate regardless of the current radius (or diameter) as the spindle RPM is continuously adjusted as a function of the radius.

Here is a simple GCode Program that uses G96 CSS mode

	G90 G21			(Absolute mm)
	G00 X50.8 Y0 Z50.8	(Rapid to starting position)
	G96 M3 D2500 S159.6 	(CSS should be 1000RPM at R=25.4mm)
	G1 X2.54 Z25.4 F350 	(Change X - radius)
	G1 X50.8 Z0
	G1 X2.54 F5000 		(Change X - radius faster)
	G1 X50.8 Z0
	G1 X2.54 		(Change X - radius faster)
	G1 X50.8 Z0
	M05 			(Spindle off)
	G0 Z50.8
	G97 M3 S500 		(Run at normal RPM Mode)
	G4 P3

G96/G97 CSS requires some additional C Program functionality to be running within KFLOP. When KMotionCNC decodes a G96 command to enter CSS mode it does so by setting a number of VAR parameters within KFLOP. A program continuously running within KFLOP will detect the CSS mode and set the Spindle RPM as a function of the X axis position (radius) and requested surface speed. The five variables set by KMotionCNC to control CSS are listed in the shared header file PC-DSP.h as and define which persist variables the data will be placed:

	// Persist Variable used with CSS Constant Surface speed for Spindle
	// These parameters will be set when GCode switches to G97 CSS mode
	// A User program in KFLOP must be running to monitor the mode an x position
	// and alter the spindle RPM appropriately.
	#define PC_COMM_CSS_MODE 110 		// Mode 1=Normal RPM mode. 2=CSS
	#define PC_COMM_CSS_X_OFFSET 111 	// X axis counts for Radius zero
	#define PC_COMM_CSS_X_FACTOR 112 	// X axis factor to convert counts to inches
	#define PC_COMM_CSS_S 113 			// S speed setting in inches/sec
	#define PC_COMM_CSS_MAX_RPM 114 	// Limit max RPM to this value as Radius approaches zero

MODE: defines whether CSS is active or not. G96 sets all CSS parameters and then switches the mode to 2. G97 (normal fixed RPM Mode) sets the Mode to 1. On Power up the Mode will be 0. X_OFFSET allows KFLOP to relate a position in counts to a radius from the spindle axis. It consists of all GCode Offsets converted to X axis counts. X_FACTOR is the inverse of the X axis resolution which allows KFLOP to do a simple multiplication to convert X axis counts to inches. S: is the desired surface speed in inches/sec (converted from GCode units of feet/min or meters/min). MAX_RPM: specifies the maximum allowed RPM. As the radius approaches zero the required RPM to maintain a specified surface speed will approach infinity. Any computed RPM beyond this value will be limited to this value. The max RPM may be specified on the line of GCode with the D word. If no D word is specified on the same line as the G96 then the limit will be sent as 1e9 RPM.

In most cases the supplied function ServiceCSS() shown below can be used. See C Program comments below on how to include this file into your Initialization C file and add a call to it in a continuous loop. If you already have a continuous loop in your Initialization C File then add a call ServiceCSS() within it. If there is not already an loop add one as shown in the comments below.

	// Handle CSS (Constant Surface Speed) messages from KMotionCNC)
	// This code assumes you have an Axis Channel Configured to control
	// Spindle speed and Jog Calls can be made to control speed
	// Include this function into your main Init Thead code and call it
	// continuously from a forever loop similar to that shown here

	//#include "KMotionDef.h"
	//#include "MySpindleDefs.h"
	//#include "CSSJog.c"
	// 	for (;;)
	// 	{
	// 		WaitNextTimeSlice();
	// 		ServiceCSS();
	// 	}

	int *css_mode = &persist.UserData[PC_COMM_CSS_MODE];			// Mode 1=Normal RPM mode. 2=CSS
	float *css_xoff = &persist.UserData[PC_COMM_CSS_X_OFFSET];		// X axis counts for Radius zero
	float *css_xfactor = &persist.UserData[PC_COMM_CSS_X_FACTOR];	// X axis factor to convert counts to inches
	float *css_s = &persist.UserData[PC_COMM_CSS_S];				// S speed setting in inches/sec
	float *css_max_rpm = &persist.UserData[PC_COMM_CSS_MAX_RPM];	// Limit max RPM to this value as Radius approaches zero
	double css_T=0; 	// update only every so often
	#define CSS_UPDATE_DT 0.05
	void ServiceCSS(void)
		float rpm;
		double T=Time_sec();

		if (*css_mode == 2 && T > css_T) 	// check if we are in CSS mode and it is time to update
			css_T=T+CSS_UPDATE_DT;	// determine next time to update

			// convert axis position to distance from center in inches
			float radius = fast_fabs((chan[CS0_axis_x].Dest - *css_xoff) * *css_xfactor);

			if (radius > 0.0f)
				rpm = *css_s / (radius * (TWO_PI_F/60.0f));
				rpm = *css_max_rpm;
			if (rpm > *css_max_rpm) rpm = *css_max_rpm;

			if (persist.UserData[STATEVAR]!=0) 	// if spindle is already on, ramp to new speed
					Jog(SPINDLEAXIS,rpm * FACTOR * persist.UserData[STATEVAR]);
			// printf("xoff=%f radius= %f xfactor=%f s=%f(ips) maxrpm=%f rpm=%f\n",*css_xoff,radius,*css_xfactor,*css_s,*css_max_rpm,rpm);


Step-by-step Recap

This sequence is applicable for Spindles that can be driven with a KFLOP Axis Channel:

  1. - Electrically Interface your spindle
  2. - Using KMotion.exe configure your Spindle Axis Channel and test that KMotion Console Screen Jog commands can successfully control it.
  3. - Modify MySpindleDefs.h with settings that apply for your system.
  4. - Configure KMotionCNC | Tool Setup | M3 - M9| M3, M4, M5, and S
  5. - If Spindle encoder feedback is available, configure KMotionCNC | Tool Setup | Trajectory Planner | Threading.
  6. - if CSS is desired, include and add ServiceCSS() to a continuous loop in your Initialization C File.


Simple demo Video of final GCode running CSS GCode.

User Video using CSS.

Configuring an Axis to Control a DAC open Loop

For Spindles that are controlled open loop with a 0-10V signal it is possible to configure an Axis Channel to output current Speed directly to a DAC. There a several advantages to configuring in this manner. First, the Spindle can be controlled using Jog Speed Commands in exactly the same manner as a closed loop servo (or any other) type of Axis Channel. And second the Axis Motion Profile Parameters (Acceleration and Jerk) can be used to ramp the speed up and down.

The configuration is the same as a DAC Servo with no Feedback (PID all zero) and with Velocity Feed Forward. The Servo diagram shows how the Motion Profile can be routed directly o the output using the Velocity Feedforward path:

Servo Flow Diagram

The Screens below show such a configuration. This configuration can be loaded from AxisAsDAC7.mot

No Input, DAC Output, Negative Gain, Infinite Following error:

Open Loop Configuration

Filters all cleared to have Flat DC Gain=1

Open Loop - No Filters

PID Zero, Max Output = full DAC Range of 2047 counts, Max Error Infinity, Feed Forward 2047 so that a velocity of 1 count/sec will generate full dac output.

Acceleration = 1 count/s2 so that full speed will ramp up in 1 second, Jerk=5 counts/s3 (Acceleration is "smoothed" over 1/5th second). This demonstration Move profile moves at 0.5 counts/sec which results in half of the full DAC output range (1023 counts or 5V analog). Note the output (green plot) follows the Commanded Velocity (blue) in perfect proportion. Any Velocity Range could be used because this is only a theoretical velocity profile and can be scaled to any proportion by the Velocity FeedForward. 1.0 counts/s is used to keep the math simple and to allow Jogging continuously for years without exceeding the Max error or Max Following Error limits.

Open Loop DAC Step Response

You may also test your Spindle Axis using Console Screen Jog commands. For example Jog7=0.25 should drive the spindle at 25% full speed.

If your Spindle can accept a +/-10V signal to drive both directions then Jog7 = -0.25 should drive in the negative direction.

The standard SpindleUsingJogs examples can now be used for an open loop DAC controlled Spindle.

To determine the proper FACTOR in the MySpindleDefs.h file you will need to know what RPM your Spindle runs at when the full 10V analog signal is applied. This will correspond to the RPM where a full Jog Speed of 1.0 will be required. So for example if your RPM reading at 10V is 2500 RPM then configure:

	#define FACTOR (1.0/2500.0)	// to convert RPM to counts/sec