Servos are great to rotate/move things around, but they are limited in their capabilities. Steppers are more versatile and controlling them is not hard with the help of stepper driver modules. But since they do expect a fairly high rate of step pulses, a dedicated controller is needed. This is a solved problem though: GRBL takes care of that and it accepts G-Code which looks like this:
G0X100
To move the X axis to the position at 100mm. Generating movements are simply a stream of such strings. Sending a
G0X100.5
after 1 second will results in a moving speed of 0.5mm/s. A nice part of GRBL is that it also controls acceleration and deceleration. Important for moving heavy objects for long distances at high speed.
But traditional GRBL uses an Arduino which is not network connected. Luckily GRBL was ported to the ESP32 CPU with its WiFi interface. Even better: FluidNC was created improving on a lot of areas, like configuration (no need to recompile for a config change) and connectivity (IP or Bluetooth and of course serial).
Naturally that looked like an interesting thing to try out.
Hardware
- A NEMA17 stepper (200 steps/rotation) with a timing belt moving a slider along an aluminium profile
- A stepper driver (DRV8825 I think I use)
- Makerbase MKS DLC32
- A end-stop sensor (microswitch in my case)
Configuration
- Get the FluidNC firmware from here
- Erase the FLASH on the ESP32 with the included erase script (on Windows: run erase.bat)
- Flash the WiFi version (on Windows: run install-wifi.bat)
- You should now be able to connect via fluidterm.bat and for any debugging this is very helpful as you can see the boot process and early errors.
- Configure WiFi according to this. That should be it as most default are sensible and thus not much to configure beside the SSID and the password:
$Sta/SSID=myssid
$Sta/Password=mypasswordforthessid
- Reboot ($Bye) and check network parameters ($I):
$I
[VER:3.4 FluidNC v3.4.3:]
[OPT:PHS]
[MSG: Machine: Slider]
[MSG: Mode=STA:SSID=myssid:Status=Connected:IP=192.168.3.18:MAC=66-55-44-33-22-11]
ok
- Connect to the Web UI at http://192.168.3.18 (the IP you get via $I obviously)
- Upload a file for the configuration for the MKS DLC32 and the hardware setup you have. In my case: I only use the x-axis, so my config file looks like below. It’s almost 100% of the example config and the main changes are:
- idle_ms=255 which keeps the stepper powered forever so it can hold things in place
- steps_per_mm and max)travel_mm for the x-axis to match my hardware
- turn off homing for y and z axis since I don’t use them
board: MKS-DLC32 V2.1
name: Slider
meta: (01.01.2022) by Skorpi
kinematics:
Cartesian:
stepping:
engine: I2S_STREAM
idle_ms: 255
pulse_us: 4
dir_delay_us: 1
disable_delay_us: 0
axes:
shared_stepper_disable_pin: I2SO.0
x:
steps_per_mm: 40.7
max_rate_mm_per_min: 15000.000
acceleration_mm_per_sec2: 500.000
max_travel_mm: 440.000
soft_limits: true
homing:
cycle: 1
positive_direction: false
mpos_mm: 0.000
feed_mm_per_min: 300.000
seek_mm_per_min: 5000.000
settle_ms: 500
seek_scaler: 1.100
feed_scaler: 1.100
motor0:
limit_neg_pin: gpio.36
hard_limits: true
pulloff_mm: 2.000
stepstick:
step_pin: I2SO.1
direction_pin: I2SO.2
y:
steps_per_mm: 428.0
max_rate_mm_per_min: 12000.000
acceleration_mm_per_sec2: 300.000
max_travel_mm: 440.000
soft_limits: true
homing:
cycle: 0
positive_direction: false
mpos_mm: 0.000
feed_mm_per_min: 300.000
seek_mm_per_min: 5000.000
settle_ms: 500
seek_scaler: 1.100
feed_scaler: 1.100
motor0:
limit_neg_pin: gpio.35
hard_limits: false
pulloff_mm: 2.000
stepstick:
step_pin: I2SO.5
direction_pin: I2SO.6:low
z:
steps_per_mm: 157.750
max_rate_mm_per_min: 12000.000
acceleration_mm_per_sec2: 500.000
max_travel_mm: 80.000
soft_limits: true
homing:
cycle: 0
positive_direction: false
mpos_mm: 0.000
feed_mm_per_min: 300.000
seek_mm_per_min: 1000.000
settle_ms: 500
seek_scaler: 1.100
feed_scaler: 1.100
motor0:
limit_neg_pin: gpio.34
hard_limits: false
pulloff_mm: 1.000
stepstick:
step_pin: I2SO.3
direction_pin: I2SO.4
i2so:
bck_pin: gpio.16
data_pin: gpio.21
ws_pin: gpio.17
spi:
miso_pin: gpio.12
mosi_pin: gpio.13
sck_pin: gpio.14
sdcard:
cs_pin: gpio.15
card_detect_pin: NO_PIN
control:
safety_door_pin: NO_PIN
reset_pin: NO_PIN
feed_hold_pin: NO_PIN
cycle_start_pin: NO_PIN
macro0_pin: gpio.33:low:pu
macro1_pin: NO_PIN
macro2_pin: NO_PIN
macro3_pin: NO_PIN
macros:
startup_line0:
startup_line1:
macro0: $SD/Run=lasertest.gcode
macro1: $SD/Run=home.gcode
macro2:
macro3:
coolant:
flood_pin: NO_PIN
mist_pin: NO_PIN
delay_ms: 0
probe:
pin: gpio.22
check_mode_start: true
Laser:
pwm_hz: 5000
#L on Beeper / IN on TTL
output_pin: gpio.32
enable_pin: I2SO.7
disable_with_s0: false
s0_with_disable: false
tool_num: 0
speed_map: 0=0.000% 0=12.500% 1700=100.000%
# 135=0mA 270=5mA 400=10mA 700=16mA
user_outputs:
analog0_pin: NO_PIN
analog1_pin: NO_PIN
analog2_pin: NO_PIN
analog3_pin: NO_PIN
analog0_hz: 5000
analog1_hz: 5000
analog2_hz: 5000
analog3_hz: 5000
digital0_pin: NO_PIN
digital1_pin: NO_PIN
digital2_pin: NO_PIN
digital3_pin: NO_PIN
start:
must_home: false
- When done, name the file you just uploaded:
$Config/Filename=config2.yaml
- Then you have to “Home” once so the controller knows where everything is (using telnet for a change since network is up now):
❯ telnet 192.168.3.18 23
Trying 192.168.3.18...
Connected to 192.168.3.18.
Escape character is '^]'.
Grbl 3.4 [FluidNC v3.4.3 (wifi) '$' for help]
$H
ok
?
<Idle|MPos:0.000,0.000,0.000|FS:0,0|Pn:PYZ|Ov:100,100,100>
ok
- and now you should be able to move the slider via very simple G-Code (x axis to 100mm position):
G0X100
ok
- If you get an error for the $H command, it’s likely that you don’t have a working end-stop for the axis which are supposed to have one. A quick fix is to use $X to disable end-stop checks. It’ll allow axis movements, but it does no checks for movements.
Node.js sending commands
GRBL has no single command to do a slow controlled motion, so in order to do that, a program needs to send G-Code commands to it. Node.js to the rescue! Below test program moves the slider 2 times back and forth and when done, it closes the connection:
// Test to send commands to GRBL (FluidNC)
const net=require('net');
let stateIsIdle=false;
let statusLine='';
function gotALine(s) {
console.log('Got a line: '+s);
if (s.startsWith('<Idle|')) {
if (stateIsIdle==true) {
console.log('Idle detected again');
client.end();
process.exit(0);
} else {
stateIsIdle=true;
console.log('Idle detected');
}
}
}
let client=new net.Socket();
client.connect(23, '192.168.21.118', () => { console.log('Got connected'); });
client.on('data', (data) => {
let s=data.toString();
if (s.indexOf('\n') < 0) {
statusLine+=s;
} else {
statusLine+=s;
gotALine(statusLine.trim());
statusLine='';
}
});
client.on('close', () => { console.log('Closed connection'); });
function sendStatusRequest() {
if (client) client.write('?\n');
}
setInterval(sendStatusRequest, 1000);
for (let i=0; i<2; ++i) {
client.write('G0X0\n');
client.write('G0X400\n');
}
Problems
- When requesting a status via ‘?’, it seems the stepper steps take a short break which causes a jerky movement. This is very reproducible. Issue created for this. Using I2S_STREAM helps a lot, but it’s not 100% fixed. I2S_STREAM has another problem though…
- I2S_STREAM seems to be inaccurate: moving 4 times 100mm and then moving back to 0 leaves several mm missing. The same test with I2S_STATIC shows zero error.