4.6 Connect Spindles

Hardware Connection · on-board relay, PWM spindle, laser, 0–10 V VFD and RS485 VFD
A VFD runs on mains power and stays dangerous after switch-off. Only the low-voltage signal wires shown here go to the controller, and mains loads belong on the contact side of a relay, in a rated enclosure. Wire and earth the VFD according to its own manual, and test every control signal with the spindle or laser still disconnected.
ToolOutputPinSpeed rangeBench test
M6 T0On-board relay (on/off spindle)GPIO.26on above S02.4
M6 T1PWM spindleGPIO.4S0S100002.5
M6 T2LaserGPIO.12S0S2552.6
M6 T30–10 V VFDGPIO.13 + OPT-io.15/OPT-io.14S0S240002.7
M6 T4RS485 Modbus VFD (YL620 profile)A / BS0S240003.2
The 5 V pins are signal outputs, not power outputs. The Outputs (5v) header brings out GPIO.4, GPIO.12, GPIO.14 and GPIO.13 plus GND. They drive the input of a driver, laser module or VFD. GPIO.4 and GPIO.12 are also wired to the two MOSFET channels (1.5 A each, light loads only); anything heavier needs a relay or SSR.
Pick the spindle type that matches your hardware
What you are connectingFluidNC sectionV4.96 Pro outputHere
Spindle or router that is only on or offrelayon-board relay, driven by GPIO.26E
Spindle controller with a PWM / 0–5 V speed inputpwmGPIO.4 on the Outputs (5v) headerA
Laser module with a TTL / PWM inputLaserGPIO.12B
VFD with an analog speed input and terminal run commands10V0–10V terminal — GPIO.13, OPT-io.15, OPT-io.14C
VFD with an RS485 / Modbus portYL620 or another named profileA / B terminalsD
Brushless motor through an ESC, or an RC servoBESCGPIO.4 / GPIO.12 (raw PWM)F
DC motor through an H-bridge moduleHBridgeGPIO.4 + GPIO.12G
Plasma torchPlasmaa relay contact + one optocoupler inputH
No spindle at allNoSpindle — created automatically
💡 FluidNC also has a DAC spindle type that uses the ESP32's built-in digital-to-analog converter on gpio.25 / gpio.26, at 8-bit resolution into 0–3.3 V. On the V4.96 Pro those two pins already have jobs in the test YAML (the pendant UART and the on-board relay), and the 0–10 V circuit (C) gives a better signal for a VFD anyway.
A
PWM spindle — M6 T1
pwm:
  pwm_hz: 5000
  output_pin: gpio.4
  enable_pin: NO_PIN
  disable_with_s0: false
  s0_with_disable: true
  tool_num: 1
  speed_map: 0=0.000% 10000=100.000%
  off_on_alarm: false
If the board will not start with your laser or drive connected. GPIO.12 and GPIO.15 are two of the pins the ESP32 reads at the instant it powers up, to decide how to start — after that they are ordinary outputs. A device whose input has its own pull-up or pull-down can hold one of them at the wrong level during those first milliseconds. The tell-tale sign: the controller starts fine with the device unplugged, and refuses to start (or refuses a firmware upload) with it connected. Power the controller first, or move that signal to another output pin in your YAML.
B
Laser — M6 T2
PiBot V4.96 Pro wired to a laser module: PWM/TTL+ and GND to the Outputs 5v header, 12V from the module's own supply
Figure B1 — a laser module has three leads. PWM/TTL+ and GND go to the Outputs (5v) header; 12V+/VCC comes from the module's own supply and never touches the controller — but that supply's negative must sit on the same ground as the controller, or the TTL signal has no return path. The test YAML puts the laser on GPIO.12. Click the image to view it full size.
ModeBehaviourTypical use
M3Constant power. Stays at the full S value whenever a feed move is active, including a dwell. Turn it off with M5, G0 or S0.Cutting through material
M4Dynamic power. Scales with feed rate during acceleration and deceleration so corners do not burn darker, and stays off when there is no motion.Engraving
Laser:
  pwm_hz: 5000
  output_pin: gpio.12
  enable_pin: NO_PIN
  disable_with_s0: false
  s0_with_disable: true
  tool_num: 2
  speed_map: 0=0.000% 255=100.000%
  off_on_alarm: true
C
0–10 V VFD spindle — M6 T3
Check what your drive's +10V terminal actually is. On the drive in both drawings below it is the reference supply for a manual speed potentiometer, not an input — which is why the figures mark it with a red ×. The V4.96 Pro generates its own 0–10 V, so nothing goes there. Terminal names are not standardised, though — on another brand a terminal printed 10V may be the analog input itself. Identify the analog voltage input in your own manual (it carries a name such as VI, AVI or AI), then take GPIO.13 to it and GND to the analog common (GND / ACM).
C1
Five wires, plus the on-board relay as the start / enable contact
PiBot V4.96 Pro wired to a 0-10V VFD: OPT-io.15 and OPT-io.14 to X1 and X2, OPT-Common to COM, GPIO.13 and GND to VI and GND, and the on-board relay across COM and X3
Figure C1 — the V4.96 Pro carries its own relay, so the enable contact costs no extra hardware: COMMON goes to the drive's COM and Normal Open to X3. The optocoupler pair still does forward and reverse, and the analog pair still does speed. If your drive needs no enable contact, leave the relay out and set enable_pin: NO_PIN. Click the image to view it full size.
V4.96 Pro terminal→ VFD terminalFunction
GPIO.13 (0–10V)analog voltage input (VI / AVI / AI)speed reference
GNDanalog common (GND / ACM)analog return
OPT-io.15 (Out1/Fwd)forward digital input (X1 / DI1)run forward
OPT-io.14 (Out2/Rev)reverse digital input (X2 / DI2)run reverse
OPT-Commondigital common (COM / DCM)shared return for Fwd and Rev
on-board relay COMMON / NOdigital common (COM) and X3 (STOP / enable)the maintained start / enable contact
💡 This page uses the 10V spindle type rather than plain PWM because 10V has separate forward_pin and reverse_pin and releases them on M5. A drive that holds a minimum frequency at 0 V would keep turning if its direction input stayed closed.
💡 A concrete example. On a Huanyang drive, PD001 = 1 takes the run command from the external terminals and PD002 = 1 takes the frequency from the external analog input. Other brands use different numbers for the same two choices — find them in your own manual.
10V:
  forward_pin: gpio.15         # OPT-io.15 Out1/Fwd - X1   (also RS485 TX - pick one)
  reverse_pin: gpio.14         # OPT-io.14 Out2/Rev - X2   (also RS485 direction - pick one)
  output_pin: gpio.13          # 0-10V - VI, GND - analog common
  enable_pin: gpio.26          # on-board relay COMMON-NO across COM and X3
  direction_pin: NO_PIN
  pwm_hz: 5000
  disable_with_s0: false
  s0_with_disable: true
  spinup_ms: 0
  spindown_ms: 0
  tool_num: 3
  speed_map: 0=0.000% 1000=0.000% 24000=100.000%
  off_on_alarm: false
C2
Three external contacts — forward, reverse and start/stop
PiBot V4.96 Pro driving a PiBot IsoSwitch V4 relay board, whose three contacts go to the VFD X1, X2 and X3 inputs
Figure C2 — three relay contacts do forward, reverse and start/stop, driven from I2SO.23 / I2SO.21 / I2SO.20 plus GND. Those I2SO signals only reach the green terminal when the jumper caps are fitted in that driver slot — a driver module must not be plugged in there. The 0–10 V pair is wired exactly as in C1. Click the image to view it full size.
RelayInputV4.96 signal→ VFD terminalYAML key
K3S3I2SO.20X1 (FWD)forward_pin
K2S2I2SO.21X2 (REV)reverse_pin
K1S1I2SO.23X3 (STOP / enable)enable_pin
10V:
  forward_pin: I2SO.20         # K3 - X1 (FWD)
  reverse_pin: I2SO.21         # K2 - X2 (REV)
  enable_pin: I2SO.23          # K1 - X3 (STOP / enable)
  output_pin: gpio.13          # 0-10V - VI, GND - analog common
  direction_pin: NO_PIN
  pwm_hz: 5000
  disable_with_s0: false
  s0_with_disable: true
  spinup_ms: 0
  spindown_ms: 0
  tool_num: 3
  speed_map: 0=0.000% 1000=0.000% 24000=100.000%
  off_on_alarm: false
C3
Two-wire or three-wire — match the drive's own parameter
Terminal control mode set in the driveWhat the drive expectsWiringYAML
Two-wire — X1 = run forward, X2 = run reversea closure held for as long as it should runFigure C1forward_pin + reverse_pin, enable_pin: NO_PIN
Two-wire — X1 = run, X2 = directionone held run contact plus one direction contactone contact on each inputenable_pin (run) + direction_pin (direction)
Three-wire — X1 / X2 = start, X3 = stopa start command plus a stop input held closedFigure C2enable_pin on the X3 contact — M5 stops the drive by releasing it
💡 FluidNC writes the direction contacts first and the enable contact last. A three-wire drive that latches on the rising edge of its start input can therefore miss the command. Prove your combination either way: send M3 S12000 and M5 ten times in a row and confirm every start and every stop. If a three-wire drive is unreliable, switch it to two-wire control.
Do not leave a manual pushbutton station wired across the same terminals. A controller contact in parallel with the panel's stop button bypasses that button. And the drive's STOP input is not a safety stop in any wiring: an emergency stop must remove power through a rated safety circuit, not through a terminal command.
D
RS485 Modbus VFD — M6 T4
uart1:
  txd_pin: gpio.15
  rxd_pin: gpio.16
  rts_pin: gpio.14
  baud: 9600
  mode: 8N1

YL620:
  uart_num: 1
  modbus_id: 1
  tool_num: 4
  speed_map: 0=0% 0=25% 6000=25% 24000=100%
  off_on_alarm: false
💡 The profile in the test configuration is one worked example. FluidNC also ships named profiles for other drives (Huanyang, H2A, YL620, NowForever…) — see the Modbus VFD page for the section your drive needs.
E
On-board relay — relay · M6 T0
relay:
  output_pin: gpio.26          # on-board relay - set the GPIO.26 jumper to relay output
  direction_pin: NO_PIN
  enable_pin: NO_PIN
  disable_with_s0: false
  s0_with_disable: true
  spinup_ms: 3000              # let the spindle reach speed before cutting
  spindown_ms: 3000
  tool_num: 0
  off_on_alarm: true
F
Brushless ESC or RC servo — BESC
5V hobby servo wired to the PiBot V4.96 Pro: signal to the Outputs 5v header, black to GND, red to a +5V pin on the board
Figure F1 — the wiring path for a 5 V hobby servo: signal (white) to a PWM pin on the Outputs (5v) header, black to that header's GND, and red to a +5V pin on the board. The servo in the photograph is there to show the three leads, not as a recommended size — see the note below. Click the image to view it full size.
Watch the servo's current. A servo draws far more while it moves — and more again if it stalls — than while it sits still. That +5V is the board's own regulated rail, produced by the on-board step-down converter from the main power input — so it shares its budget with the rest of the board. Treat it as a supply for a light servo — a pen lift, a tool-cover flap. Anything with real torque, including the class of servo in the photograph, and any ESC-driven motor, needs its own 5 V supply, with only the ground shared with the controller.
BESC:
  output_pin: gpio.4           # raw PWM pin - not the 0-10V terminal
  pwm_hz: 50                   # 20 ms period
  min_pulse_us: 1000           # ESC "off" pulse - check its datasheet
  max_pulse_us: 2000           # ESC full-power pulse
  tool_num: 5
  speed_map: 0=0% 1000=100%
G
DC motor through an H-bridge — HBridge
HBridge:
  pwm_hz: 5000
  output_cw_pin: gpio.4
  output_ccw_pin: gpio.12
  enable_pin: NO_PIN
  disable_with_s0: false
  spinup_ms: 1000
  spindown_ms: 1000
  tool_num: 6
  speed_map: 0=0.000% 10000=100.000%
  off_on_alarm: false
H
Plasma torch — Plasma
Plasma:
  enable_pin: gpio.26          # torch start through the on-board relay
  arc_ok_pin: gpio.39:low      # an optocoupler input you are not using for limits
  arc_wait_ms: 1000
  tool_num: 7
  off_on_alarm: true
I
Settings every spindle section shares
SettingWhat it doesNotes
tool_numWhere this spindle's tool range startsThe range runs until the next spindle's tool_num. One spindle must have tool_num: 0 so every tool number is valid.
speed_mapMaps the S value to the output0=0.000% 1000=0.000% 24000=100.000% means S below 1000 gives nothing — a minimum-speed floor. Full syntax on FluidNC's speed map page.
enable_pinA separate line held on while the spindle runsThe start / enable contact in C2. Affected by disable_with_s0.
direction_pinReverse signalM4 is only accepted when this — or forward_pin/reverse_pin in a 10V section — is assigned.
spinup_ms / spindown_msWait after a speed change before the next move runs0–60000 ms, scaled to the size of the change: half the range costs half the time.
disable_with_s0Also disable at S0, not only at M5Default false.
s0_with_disableDrive the speed output to its S0 value on M5Leave true so the analog or PWM output actually falls to zero when you stop.
off_on_alarmTurn the spindle off when an alarm occursRecommended true for a laser, and worth it for a torch.
atc / m6_macroAutomatic tool change, or a macro to run instead of the built-in M6Optional — see the FluidNC spindle configuration page.
J
Using more than one spindle
!
One pin, one job — what shares what on this board
SignalIts job in the test YAMLIf you want it for a spindle instead
GPIO.26The on-board relay as an on/off spindle (relay:, T0), only when its function jumper selects relay outputGive it to the 10V section as enable_pin instead (C1) — one or the other
GPIO.15 / GPIO.14RS485 TX and direction (uart1, YL620 profile)The same pins are the OPT-io.15 / OPT-io.14 Fwd/Rev optocouplers — use the Modbus path or the direction contacts, not both
GPIO.4 / GPIO.12PWM spindle (T1) and laser (T2); the same two pins drive the MOSFET channelsOne job each — a BESC or HBridge output takes the place of that spindle
I2SO.23 / I2SO.21 / I2SO.20Flood and mist coolant (M7/M8); reach the green terminal only with the jumper caps fitted in that driver slotGive them up and they drive the three relay inputs in C2
💡 The five paths in the test YAML (M6 T0 relay, T1 PWM, T2 laser, T3 0–10 V, T4 RS485) already follow these rules. Sections FH above use tool numbers 5–7 so you can add one without disturbing them — but check the table above first: on this board several pins wear two hats.
K
Also possible: an RC servo or solenoid as an axis
z:
  steps_per_mm: 100.000
  max_rate_mm_per_min: 5000.000
  acceleration_mm_per_sec2: 100.000
  max_travel_mm: 5.000
  soft_limits: true
  homing:
    cycle: 1
    positive_direction: true
    mpos_mm: 5.000

  motor0:
    rc_servo:
      pwm_hz: 50
      output_pin: gpio.27
      min_pulse_us: 1000
      max_pulse_us: 2000
rc_servo:
  pwm_hz: 60
  output_pin: gpio.27
  min_pulse_us: 2000
  max_pulse_us: 1000
💡 Full details on FluidNC's RC servo and axes pages. Check which pin your machine has free before copying gpio.27 — in the test YAML it is the pendant UART.

Quick troubleshooting