Electronics ยท Firmware ยท Making

GRBL Board Upgrade ๐Ÿ”ฅ engraving + remote monitoring

Three sessions to get it engraving, then a fourth to make it actually nice: a rigid aluminum base, a proper enclosure for the Pi, an Inkscape extension, and a webcam stream that made "headless" stop meaning "blind."
Status
โœ… Fully working, engraving & monitored
Board
GRBL 1.1f ยท ATMega2560
Sessions
Sept 9 ยท 12 ยท 13 ยท finishing touches
Final calibration
87.4 steps/mm
Workflow
Inkscape (J Tech / custom script) โ†’ CNCjs, webcam-monitored

๐Ÿ”ฅ A laser cutter dead since 2017, actually engraving again

ATMega2560 ยท GRBL 1.1f ยท CNCjs on a Pi 4 ยท SVG-to-G-code, homegrown
GRBL 1.1f ATMega2560 A4988 drivers CNCjs on Pi 4 Inkscape J Tech Laser Tool Custom svg_to_gcode.py 12V 2-pin laser module mjpg-streamer systemd

Session 1 (Sept 9): wiring and the first freeze

The replacement board arrived โ€” GRBL 1.1f on an ATMega2560, three A4988 stepper drivers, running off the existing 12V supply. Motors and endstops wired first; the laser itself deliberately left for later once the right connector was actually in hand.

01Motors & endstops

Straightforward remapping โ€” X and Y motor coil pairs onto the new board's A/B terminals, endstop signal and ground onto their matching pins. Nothing exotic yet.

02GRBL speaks a different dialect than Marlin

Two small but important differences from the old Marlin/mLaser stack: GRBL fires the laser with M3/M5, not Marlin's M4 โ€” and laser power is a S0โ€“1000 range, not Marlin's P0โ€“255. Every G-code habit from the old machine needed a small mental remap.

03Automatic homing freezes the board โ€” work around it

The standard $H homing cycle reliably hung the controller โ€” an endstop-interrupt issue with this specific board, not a wiring fault. Rather than chase the root cause immediately, a manual homing procedure (jog toward the endstops with short relative moves, watch for both Pn:XY flags, then G92 X0 Y0 to zero the origin) became the standing workaround for the rest of the project.

โœ… Movement directions confirmed: X+ moves left, Y+ moves back, home is the front-right corner โ€” both axes correct with zero direction-invert needed at this stage.

Session 2 (Sept 12): the laser actually fires

04Finding the real connector

The board turned out to be an Annoy Tools GRBL board, offering four different laser output options (12V 2-pin, 12V 3-pin, 12V 4-pin, 24V 3-pin). The Makeblock laser module needed the simple 12V 2-pin white JST โ€” once identified, wiring was trivial.

05A genuine "oh, that's how laser mode works" moment

With $32=1 (laser mode) enabled, GRBL only fires the laser while the machine is actually moving โ€” G1 X.. Y.. F.. S.. moves and fires together; a stationary M3 alone does nothing. Not a bug, just a genuinely different mental model from a simple on/off laser control.

06Two more wiring mistakes, both mechanical rather than logical

X and Y motor connectors had been swapped, and the X motor's direction wires needed a red/blue swap. Both fixed, both axes homing cleanly to the front-right corner.

โœ… First confirmed laser engraving. The machine that sat dead since 2017 physically marked something again.

Session 3 (Sept 13): calibration and a real workflow

07Steps/mm, hunted down by iteration

A commanded 50ร—30mm rectangle first came out at 104ร—62mm โ€” the inherited 177.8 steps/mm value from the old Marlin setup was nowhere close to correct for this board's drivers and pulley ratio. Measured, corrected, re-tested, repeated:

177.8
inherited guess
85.5
first correction
89.1
second correction
87.4
final โ€” perfect 50ร—30mm
1
week, start to finish
8
years the machine sat dead

08A real SVG-to-engraving pipeline

Design in Inkscape, save as Plain SVG, convert with a small custom svg_to_gcode.py script, upload the result to CNCjs running on the Pi 4, hit Cycle Start. Laser power tuned by result: 150 engraves paper without cutting through; 400 cuts through thin paper cleanly.

"From Marlin 2016 to GRBL 2026 โ€” one USB hub caused most of the problems!"
โ€” session notes, September 9

Session 4: the finishing touches

09Frame fixed to a real base

The frame's slight out-of-true wobble is gone โ€” the whole machine is now mounted to a 5mm aluminum plate base. Genuine mechanical rigidity, not a workaround.

10The Pi 4 gets a proper home

Relocated onto the frame itself, right next to the GRBL board, inside a yellow 3D-printed housing sourced from Printables โ€” which happens to match the machine's blue frame nicely. No more loose electronics hanging off the side.

11A proper Inkscape laser extension

Installed and tested the J Tech Photonics Laser Tool extension for Inkscape โ€” a purpose-built plugin for exactly this workflow, working alongside the custom svg_to_gcode.py script from Session 3.

12The real hammer: streaming a webcam into CNCjs

The situation: a USB webcam (HD 720P, /dev/video0) on a headless Pi running CNCjs, needing to be viewed from a completely different machine's browser โ€” direct browser camera access doesn't work here at all; what's actually needed is a real network video stream.

Solution: mjpg-streamer

sudo apt install -y cmake build-essential libjpeg-dev v4l-utils

Identify the real camera device โ€” USB webcams show up cleanly; ignore the Pi's internal bcm2835-codec ISP nodes, which aren't real cameras:

v4l2-ctl --list-devices

Manual test run first:

export LD_LIBRARY_PATH=/usr/local/lib/mjpg-streamer
mjpg_streamer -i "input_uvc.so -d /dev/video0" -o "output_http.so -w /usr/local/share/mjpg-streamer/www -p 8080"

Made persistent with a systemd unit โ€” /etc/systemd/system/mjpg-streamer.service:

[Unit]
Description=MJPG Streamer for webcam
After=network.target

[Service]
Environment=LD_LIBRARY_PATH=/usr/local/lib/mjpg-streamer
ExecStart=/usr/local/bin/mjpg_streamer -i "input_uvc.so -d /dev/video0" -o "output_http.so -w /usr/local/share/mjpg-streamer/www"
Restart=on-failure
RestartSec=5
User=brain

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mjpg-streamer.service
sudo systemctl status mjpg-streamer.service   # confirmed: active (running)
โœ… Stream persists across reboots at http://<pi-ip>:8080/?action=stream. In CNCjs: Webcam widget โ†’ settings โ†’ URL/streaming mode โ†’ paste that URL. Remote job monitoring, actually working.

Troubleshooting notes, kept for next time:

What was actually achieved

The fully upgraded Makeblock laser engraving a test pattern

Still on the list

One honest item left, and it's the one that actually matters for safety:

From broken, brittle plastic and a protocol nobody else ever learned to speak, to a laser that fires exactly where it's told, calibrated to the tenth of a millimeter. Eight years dead, one week to bring back.
โ€” September 2026