FluidNC supports 12 motors on 6 axes. This page details the different ways steps are generated, settings and integration with different hardware.
This is an important section for the motors.
Type: Enumeration
Range: RMT| TIMED| I2S_STATIC | I2S_STREAM
Default: RMT
Details: This determines the method used to generate the steps in firmware. Controller board hardware is designed for either RMT or I2S stepping so you must choose a method that your controller board hardware uses. It is not possible to mix and match stepping types on different motors. The supported types are:
People often ask if the I2S method could be used for input expansion. While it is theoretically possible, there are complications that make it less attractive than other input expansion methods. We do not plan to implement I2S input. For input expansion, we recommend and support using an auxiliary MCU that communicates with the FluidNC ESP32 over a UART connection.
Example
stepping:
engine: I2S_static
idle_ms: 250
pulse_us: 4
dir_delay_us: 4
disable_delay_us: 0
segments: 6
Step signals are sent as pulses. Each pulse has a duration as described above. The pulse_us is the "on" duration of the pulse. It typically needs an equal "off" duration. Other parameters like dir_delay_us also can contribute to the total duration of each pulse. The absolute maximum number of pulses you can send per second (Hz) is 1/(total pulse time). This has nothing to due with the speed of the processor, it is just math. Realistically the fastest you can go is in the 100kHz-125kHz range. This will be slower if you are using long pulse durations.
The config items that set this rate are steps_per_mm and maximum pulse rate. Here is the equation to find this rate.
(steps_per_mm * (max_rate_mm_per_min) / 60)
Therefore, you can see that steps_per_mm has a big impact. Do not use a larger number than you need, or max speed will suffer. Consider lowering your microstepping to get a lower steps_per_mm.
Some of this math is checked with this formula when the config file is loaded. You may get errors if rates are exceeded, you may also get crashes.
1000000 / ((2 * pulse_us) + dir_delay_us)
The speed of the processor can also come into play if a lot of processor time is required per step. High density laser engraving is one example.
if you exceed the max rate you will get an error like this: "[MSG:ERR: Initialization error at /axes/y: Stepping rate 157750 steps/sec exceeds the maximum rate 125000]"
Example
axes:
shared_stepper_disable_pin: NO_PIN
shared_stepper_reset_pin: NO_PIN
homing_runs: 2
axes:
[x:|y:|z:|a:|b:|c:]
The axes must be used in order. If using an XZ machine, a Y axis must still be declared. If the Y axis is not defined, FluidNC will define a virtual one without any outputs. This requirement is due to a reporting issue. The reporting sends values like 000.000, 000.000, 000.000. The axes are not labeled, so you assume they are in XYZABC order. The minimum axis count is 3. If you only define X and Y a virtual Z will be created.
ABC axis will not report position in inches:
XYZ are traditionally linear axes and ABC are considered rotary axes. ABC axis can be used as linear axes with a catch; they do not report units in inches. FluidNC uses millimeters internally and scales to inches for reporting XYZ axis. However it will not scale ABC because it assumes they are a universal scale like degrees or radians that do not change for inches.
Example:
axes:
x:
steps_per_mm: 800.000
max_rate_mm_per_min: 4500.000
acceleration_mm_per_sec2: 100.000
max_travel_mm: 180.000
soft_limits: true
These keys are for the homing at the axis letter level. Even if an axis has more than one motor, it still homes towards one end and at a specific speed.
$H
. Anything lower than 1 will be an inactive cycle and no physical homing will occur for that axis.$H
, but you can still home it with $H<axis>
cycle: 1
and the other axes on higher cycles.true
$HX
to home the X axis).Some closed loop motors like servos home themselves and will ignore many of settings like the pulloff and speeds
Example:
axes:
x:
homing:
cycle: 2
allow_single_axis: true
positive_direction: false
mpos_mm: 1.000
seek_mm_per_min: 200
feed_mm_per_min: 50
seek_scaler: 1.5
feed_scaler: 1.5
axes:
x:
motor0:
limit_neg_pin: gpio.33
limit_pos_pin: NO_PIN
limit_all_pin: NO_PIN
hard_limits: true
pulloff_mm: 1.000
Use this one for external drivers or when only step direction and enable are needed.
example
motor0:
standard_stepper:
step_pin: I2SO.5
direction_pin: I2SO.4
disable_pin: gpio.16:low
See this page for important information step pulse timing
example
axes:
x:
motor0:
stepstick:
step_pin: I2SO.5
direction_pin: I2SO.4
disable_pin: gpio.16:low
ms1_pin: NO_PIN
ms2_pin: NO_PIN
ms3_pin: I2SO.6
reset_pin: NO_PIN
Available at Pololu. 3.3V-5V Compatible.
AGC is Automatic Gain Control (Like Trinamic Coolstep) This is typically the sleep pin on stepsticks. On the 6 Pack controller this can be controller via the TMC5160 jumper. Use the TMC5160 side to enable it.
DMODE0 through DMODE2 are typically MS1 through MS3 on steps stick. These pins are more commonly connected to jumpers rather than the controller.
TB67S249FTG example config
stepstick:
step_pin: I2SO.5
direction_pin: I2SO.4
disable_pin: I2SO.7:low
ms1_pin: NO_PIN
ms2_pin: NO_PIN
ms3_pin: I2SO.6:high
reset_pin: NO_PIN
Trinamic drivers have many features that can be set by FluidNC. These drivers are typically completely powered by the motor voltage. Vcc pins are only used for I/O voltage reference. Therefore, the motor voltage must be on at all times to use these. The ESP32 on the controller can often be powered by the USB connection, but the motors cannot. If the motor voltage is not present at turn and the ESP32 is powered by the USB, the drivers will not respond. If the drivers are failing the startup tests, try clicking the ESP32 reset button when the main power is on.
There is a command that allows you to run the motor driver initialization at any time. It is $Motors/Init or $MI. If you forget to turn on the main power, you can turn on the power and then send the $MI command. A message will be sent regarding the the success or failure of that. You can send that command whenever you want to check the motor status (not in run mode)
Examples
[MSG:ERR: X Axis driver test failed. Check connection]
[MSG:ERR: Y Axis driver test failed. Check motor power]
[MSG:ERR: Z Axis driver test passed]
We are not experts on these drivers. We use a third party open source library (TMCStepper) to control them. We do not know the best register settings for them. Many of them will be specific to your machine and motors. You will have to experiment. They are generally great drivers, but temperamental. Please don't expect the FluidNC developers to solve your issues with these motors.
Note: You can buy some Trinamic drivers on modules in "stand alone" or "stepstick" mode. These cannot be setup by FluidNC and you should configure them as stepstick drivers.
Driver Not Detected: The drivers are detected using the UART or SPI connection. If you get this message, it is most likely a communication problem. Check the configuration and wiring.
SPI controlled drivers use SPI (Serial Peripheral Interface) to directly control the features and modes of the driver. SPI has 2 modes, independent and daisy chain mode. This depends on how the SPI is wired on the controller.
daisy chain
For independent mode each driver needs its own cs_pin:. They do not use a spi_index:, so each spi_index: should be set to -1.
In daisy chain mode they all use the same cs_pin:, but each requires it's own spi_index:. The spi_index: is a number from 1 to how many drivers you have. The spi_index: indicates the position of the driver on the SPI daisy chain. You must set the index based on the PCB design and axis letter order.
In a daisy chain arrangement, MOSI loops through all the motors, and then returns to the controller as MISO. To write to the second driver, you write to the first with the data for the second driver, then write dummy data to the first to push the first data to the second. Reading data has the same issue when you have to push the data through the drivers at the end of the chain. There the FluidNC needs to know about all drivers, even ones you are not using. You must define something for all drivers.
Links
Config Item
standard example
tmc_2130:
cs_pin: gpio.17
spi_index: -1
r_sense_ohms: 0.110
run_amps: 0.750
hold_amps: 0.250
microsteps: 32
stallguard: 0
stallguard_debug: false
toff_disable: 0
toff_stealthchop: 5
toff_coolstep: 3
run_mode: StealthChop
homing_mode: StealthChop
use_enable: false
step_pin: gpio.12
direction_pin: gpio.26
disable_pin: NO_PIN
Daisy chain example:
x:
steps_per_mm: 800.000
max_rate_mm_min: 5000.000
acceleration_mm_per_sec2: 100.000
max_travel_mm: 300.000
soft_limits: false
tmc_2130:
cs_pin: gpio.17
spi_index: 1
r_sense_ohms: 0.110
run_amps: 0.750
hold_amps: 0.750
microsteps: 16
stallguard: 0
stallguard_debug: false
toff_disable: 0
toff_stealthchop: 5
toff_coolstep: 3
run_mode: CoolStep
homing_mode: CoolStep
use_enable: true
step_pin: gpio.12
direction_pin: gpio.14
disable_pin: NO_PIN
y:
steps_per_mm: 800.000
max_rate_mm_min: 5000.000
acceleration_mm_per_sec2: 100.000
max_travel_mm: 300.000
soft_limits: false
homing:
cycle: 2
positive_direction: false
mpos_mm: 150.000
feed_mm_per_min: 100.000
seek_mm_per_min: 200.000
settle_ms: 500
seek_scaler: 1.100
feed_scaler: 1.100
motor0:
limit_neg_pin: NO_PIN
limit_pos_pin: NO_PIN
limit_all_pin: gpio.39
hard_limits: true
pulloff_mm: 1.000
tmc_2130:
spi_index: 2
r_sense_ohms: 0.110
run_amps: 0.750
hold_amps: 0.750
microsteps: 16
stallguard: 0
stallguard_debug: false
toff_disable: 0
toff_stealthchop: 5
toff_coolstep: 3
run_mode: CoolStep
homing_mode: CoolStep
use_enable: true
step_pin: gpio.27
direction_pin: gpio.26
disable_pin: NO_PIN
TMC2208 drivers can operate in standalone STEP/DIR mode . Values such as microstep, run current and hold current, amongst others, can also be configured via UART.
A step_pin and a direction_pin must always be defined in the motor config. Enabling the motor can be done either using a disable_pin: or enabled via UART with use_enable: true in the config file.
The TMC2208 drivers are not addressable. This means that when daisy chaining these drivers, config values will be passed to all drivers and it is not possible to configure parameters for individual drivers. It is important to note that the values that will be applied will be those defined in the last motor / axis listed in the config file. Values that are not defined in this final motor / axis config will fall back to default, overriding any values set in previous motor/ axis configurations.
Config Items:
Daisy chain example:
axes:
shared_stepper_disable_pin: gpio.1
x:
steps_per_mm: 400
max_rate_mm_per_min: 1500
acceleration_mm_per_sec2: 100
homing:
cycle: 2
allow_single_axis: true
positive_direction: false
mpos_mm: 0
feed_mm_per_min: 50
seek_mm_per_min: 400
motor0:
limit_all_pin: gpio.2:low
hard_limits: true
pulloff_mm: 1
tmc_2208:
step_pin: gpio.3
direction_pin: gpio.4:low
# THESE VALUES ARE OVERIDEN BY Y AS TMC2208 IS NOT ADDRESSABLE.
# ALL VALUES ARE TAKEN FROM LAST DEFINED MOTOR/AXIS
# run_amps: 1.5
# hold_amps: 0.5
# microsteps: 8
# disable_pin: 10
y:
steps_per_mm: 400
max_rate_mm_per_min: 1500
acceleration_mm_per_sec2: 100
homing:
cycle: 2
allow_single_axis: true
positive_direction: true
mpos_mm: 290
feed_mm_per_min: 50
seek_mm_per_min: 400
motor0:
limit_all_pin: gpio.5:low
hard_limits: true
pulloff_mm: 1
tmc_2208:
step_pin: gpio.6
direction_pin: gpio.7
# THESE ARE THE LAST DEFINED VALUES
# AND WILL BE THE VALUES APPLIED TO
# ALL DRIVERS IN THE DAISY CHAIN
microsteps: 16
r_sense_ohms: 0.110
# IF NOT DEFINED - DEFAULT VALUES WILL BE USED
# run_amps: 0.5
# hold_amps: 0.5
disable_pin: NO_PIN
uart:
txd_pin: gpio.8
rxd_pin: gpio.9
baud: 115200
mode: 8N1
tmc_5160:
step_pin: gpio.12
direction_pin: gpio.14
disable_pin: NO_PIN
cs_pin: gpio.17
r_sense_ohms: 0.050
run_amps: 1.800
hold_amps: 1.250
microsteps: 8
toff_disable: 0
toff_stealthchop: 5
use_enable: false
run_mode: CoolStep
homing_mode: CoolStep
stallguard: 16
stallguard_debug: false
toff_coolstep: 3
tpfd: 4
A lot of people have had trouble with these drivers. They are very advanced and the settings have to be finely tuned to your machine. They also can draw a lot of power. Make sure you have a power supply with a lot of extra capacity. We cannot provide too much support because we are not experts on the chip. Please respect our support time. For extra fine tuning see the "pro" versions lower on this page.
Potentiometers Many TMC5160 modules have potentiometers on them. The TMCStepper library we use sets TMC5160 chips in an *i_scale_analog" mode. This means the pot is used to scale that current value that is set digitally. You should turn these pots up to full or where they output 2.5V. This will allow you to use the full current range of the drivers.
Here is a chart for the current. Most modules use a 0.075Ohm resistor, so for those the maximum current is 3.1A
This section is for UART controlled chips. Each chip must have a hardware based addressing system. We do not support write only communication (1 way), because it is critical that we know the chips are responding to commands.
It is very difficult to use TMC2209 plug in modules or controllers that do not directly support Trinamic UART controlled chips. You must externally wire the UART and you must figure out how to wire the UART externally.
TMC2209 drivers need a step_pin and a direction_pin. They can either use an disable_pin: or enable via UART with a use_enable: true
in the config file.
You must define pins for the uart in a uart section of the config file. Each motor must have a uart_num:. This could allow multiple uarts to be used to get past the 4 address per uart limit.
motor0:
limit_neg_pin: gpio.36:low
tmc_2209:
uart_num: 1
addr: 0
cs_pin: NO_PIN
r_sense_ohms: 0.110
run_amps: 1.000
hold_amps: 0.500
microsteps: 16
stallguard: 0
stallguard_debug: false
toff_disable: 0
toff_stealthchop: 5
toff_coolstep: 3
run_mode: StealthChop
homing_mode: StealthChop
homing_amps: 0.50
use_enable: false
direction_pin: gpio.12
step_pin: gpio.14
disable_pin: NO_PIN
The UART is typically connected like this, with a single connection to all drivers. The drivers need the address (addr:
in config) set from 0 to 3 via the MSn_ADn pins via hardware connections.
The cs_pin can be used to control a chip to switch the UART. This can allow you to get around the the limit of 4 addresses for the chips. The address can be dynamic. You can also connect the cs_pin to an address pin.
The Vcc on the stepstick modules is used as the I/O reference. It should be 3.3V when directly connected to ESP32s. The driver Vcc is generated internally from VMot, so these chip will not communicate unless the VMot is connected.
The tmc_5160Pro and tmc_2160Pro motors are for advanced users who want direct control over the most important and commonly used registers of the driver. We can add more registers if they are needed.
Currently the driver uses the same register values for both normal and homing modes.
You will need the datasheet to understand these registers
Most registers are a number built up from many smaller values. There is a Google Sheet that can help you create the register values from these values. Make your own copy of the sheet to get edit rights.You will still need to use the datasheet to determine what values to use.
TMC5160 and TMC2160 work exactly the same. The only difference is the name in the config file.
tmc_5160Pro:
step_pin: I2SO.2
direction_pin: I2SO.1
disable_pin: I2SO.0
cs_pin: I2SO.3
spi_index: -1
use_enable: false
CHOPCONF: 373326168
COOLCONF: 0
THIGH: 0
TCOOLTHRS: 0
GCONF: 4
PWMCONF: 3289120798
IHOLD_IRUN: 3852
tmc_2160Pro:
step_pin: I2SO.2
direction_pin: I2SO.1
disable_pin: I2SO.0
cs_pin: I2SO.3
spi_index: -1
use_enable: false
CHOPCONF: 373326168
COOLCONF: 0
THIGH: 0
TCOOLTHRS: 0
GCONF: 4
PWMCONF: 3289120798
IHOLD_IRUN: 3852
If you have a working config from the normal tmc_5160 config item, you can use that as a starting point. If you set $message/level=debug, it will show you the current values of the registers.
If you are struggling to use this type of config, this might not be for you. The registers are very complex and not for newbies. Even the developers of FluidNC do not fully understand how to use them. Please don't expect support on register values. Ask TMC directly.
RC Servos have an internal control system that allows them to move to a specific location based on a PWM signal. There are analog and digital versions of these. They both use the same PWM input, but the digital ones use a more advanced control system. They use the width of the pulse to determine where to move. One end of the travel usually uses a 1ms pulse width and the other end uses a 2ms pulse width. There is no standard on the rotation range of motion and many can use a slightly wider pulse width range. If the PWM signal is removed the servo can often be turned by hand.
The PWM frequency for analog servos is typically 50Hz. If you increase that it changes the control loop and could overheat the servo. Digital servos can use a higher frequency, but typically never higher than 200 Hz. The PWM signal is only sent when the motors are enabled. Set idle_ms to 255 if you want the signal to always be on.
FluidNC creates a virtual stepper motor for the axis. You give it parameters for speed, acceleration, etc like normal motors. The servo range will be mapped to the max_travel of the axis. If your servo is not rotating the correct direction with respect to the virtual axis, you can swap the min_pulse_us/max_pulse_us key values.
Like a normal axis, they operate in machine space. You can still place a work zero wherever you like. Soft limits can be used. Homing works a little differently. They do not use switches because they always know where they are. If you put them on a homing cycle, they will immediately move to the end of travel in the direction in the direction specified in the homing: section. To give them enough time to get there. A time of max_travel: / speed: will be given.
At startup A servo will immediately move to machine position 0.0 or the closest point in the range if the range does not include 0.0. This will only occur when the motors are enabled. If the motors are not enabled at startup (idle_ms: not 255), then the servos will move to the current machine position as soon as any other axis moves.
Testing the RC Servo In the startup messages you will see the range like Axis Z (-5.000,0.000). Send G53G0Z-5 and G53G0Z0 to test that range.
Config file keys
example
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
example with rotation reversed
rc_servo:
pwm_hz: 60
output_pin: gpio.27
min_pulse_us: 2000
max_pulse_us: 1000
All servos have their own speed and acceleration. If you use faster motion values for the virtual axis than the servo can handle, it will not be able to follow accurately. FluidNC will not be able to detect this. You must experiment with values until you get the performance you like. The steps_per_mm key is used for the virtual axis. Most servos will only have 200-1000 units of accuracy across the entire range of motion. Double that higher end number and divide by the max_travel for the axis. Example: For a max_travel or 10mm, set you steps_per_mm to (2 * 1000 / 10) = 200 steps_per_mm.
Unlike stepper motors, RC servo have a fixed rotational range. That range is mapped to the machine coordinates using the max_travel, mpos_mm and homing direction config items (more details here). If you try to move outside the range the servo will stop at the end of travel, but the machine position will still increment. You can still jog the machine position outside the range, but the servo will not move until it is in the range. You can apply soft limits to the axis if you want to prevent this. Soft limits are strongly recommended for RC servos for this reason.
Pulse lengths vary by manufacturer. The default is 1000-2000 microseconds, but many manufacturers use a larger range. If you are trying get the FluidNC units to match specific locations in the servo travel you can tweak these values a little. Servo are not too accurate, so don't expect them to match stepper motors. Be sure to stay within the servo's range. Servo can be damaged by operating outside thier range.
Here is a complete axis RC servo axis definition. In this case the travel is 5mm, the machine position after homing is 5mm, so the range is 0mm to 5mm. You can test the motion on this axis with the following gcode commands. I use G53 to make sure the motion is in machine coordinates, overriding any work offsets you may have created.
G53 G0 Z5
G53 G0 Z0
z:
steps_per_mm: 100
max_rate_mm_per_min: 5000
acceleration_mm_per_sec2: 100
max_travel_mm: 5
homing:
cycle: 1
mpos_mm: 0
positive_direction: true
motor0:
rc_servo:
pwm_hz: 50
output_pin: gpio.27
min_pulse_us: 1000
max_pulse_us: 2000
This lets an Solenoid act like an axis. It will be active when the machine position of the axis is above 0.0. This can be inverted with the direction_invert: value. If inverted, it will active at below 0.0.
When active the PWM will come on at the pull_percent value. After pull_ms time, it will change to the hold_percent value. This can be used to keep the coil cooler.
The feature runs on a 50ms update timer. The solenoid should react within 50ms of the position. The pull_ms also used that 50ms update resolution. The PWM can be inverted using the :low attribute on the output pin. This inverts the signal in case you need it. It is not used to invert the direction logic.
The axis position still respects your speed and acceleration and other axis coordination. If you go from Z0 to Z5, it will activate as soon as it goes above 0. If you G0 from Z5 to Z0, it will not deactivate until it gets to Z0.
Example YAML
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: false
homing:
cycle: 1
positive_direction: true
mpos_mm: 5.000
motor0:
solenoid:
output_pin: gpio.26
pwm_hz: 5000
off_percent: 0.000
pull_percent: 100.000
hold_percent: 20.000
pull_ms: 1000
direction_invert: false
This allows Dynamixel Servo motors to be used as axis motors. This document was written assuming XL430-250T servos were used, but other servo types that use Robotis Protocol 2 can probably be used (not tested). The servo's count range is mapped to the axis machine position (mpos) range. If your X axis servo has a count range from 0-4095, that would be mapped across the mpos range. If the range is 0-300 and you send G0X150 it will be told to go to count 2047.
Servo setup The servos must be setup with Dynamixel software first. The easiest way is to use the Dynamixel Wizard software. Here are the registers you probably want to set.
Address | Name | Value | Description |
---|---|---|---|
7 | ID | 1-253 | Must be unique |
8 | Baud Rate | 3 (1000000) | |
9 | Return Time Delay | 100 | Faster |
24 | Moving Threshold | 1 | Most Accurate |
48 (optional) | Max Position | 0-4095 | Limits rotation |
52 (optional) | Min Position | 0-4095 | Limits rotation |
If you stall a Dynamixel motor it will likely go into a faulted mode. The only way to recover is to power cycle them.
config values
Direction reversal Swap the count_min: and count_max: values.
Homing The servo will immediately go to the homing/mpos_mm location of the axis.
Enable The servos will disable whenever the motors disable (see the idle_ms config value). When they are disabled, you can move them by hand and the mpos will track the movement.
Example config section
x:
steps_per_mm: 100.000
max_rate_mm_per_min: 5000.000
acceleration_mm_per_sec2: 50.000
max_travel_mm: 300.000
soft_limits: false
homing:
cycle: 2
positive_direction: false
mpos_mm: 0.000
feed_mm_per_min: 100.000
seek_mm_per_min: 200.000
settle_ms: 500
seek_scaler: 1.100
feed_scaler: 1.100
motor0:
limit_neg_pin: NO_PIN
limit_pos_pin: NO_PIN
limit_all_pin: NO_PIN
hard_limits: false
pulloff_mm: 1.000
dynamixel2:
id: 1
uart_num: 1
count_min: 1024
count_max: 3072