Ages ago I bought an EleksMaker plotter. The basic idea is to use a couple of stepper motors to move a pen across paper, and a servo to lift it. That’s enough to draw things!

I think it’s fair to say the EleksMaker is at least heavily inspired by the AxiDraw1 from Evil Mad Scientist Labs2, though it’s much cheaper and less polished. Perhaps inevitably I think the documentation has rotted since the device was released: these are my brief notes on how to get it all working.

These days, I think most people building the Eleksmaker tend to install a laser rather than a pen, which can be rather confusing. For example the software goes to some length to avoid firing the laser continuously at the same spot because it might cause a fire.

Hardware

The machine came as a kit which was fairly easy to build. Two static stepper motors drive a belt, which is looped in a clever way to move the pen arbitrarily in a plane. In CNC circles it’s refered to as a CoreXY3 design.

Vertical motion is controlled by a servo. There’s not a direct linkage between the servo arm and the pen: rather the servo arm can lift the pen away from the paper, but when the servo arm swings out of the way gravity pulls the pen down. In practice I found this didn’t work very well, but adding a spring to pull the pen down solved the problem.

It is tempting to replace this part of the mechanism. However, it’s not entirely trivial: it is hard to align the machine such that it moves the head parallel to the paper, so you either need some sort of springiness in the pen holder, or use a pen which can tolerate the variation. This is essentially the bed-levelling problem well-known to the owners of 3D-printers, but tolerances here are much less precise.

When connecting a servo with the usual brown-orange-yellow colours, the brown goes closest to the micro-USB port.

Firmware

The EleksMaker is controlled by an Arduino Nano running grbl4. Both firmware and hardware are essentially obsolete but are still available. Oddly most of the grbl code lives in a library: the grblUpload.ino file which you compile to make the firmware has but a single include:

 #include <grbl.h>

Configuring grbl

By default grbl assumes that there are independent X- and Y-axis motors. To support the CoreXY geometry it’s enough edit config.h and

#define COREXY

Firmware size

When compiled my grbl firmware was 31,320 bytes long, which is too big for the default Arduino Nano settings (30,720 bytes). Annoyingly, the problem isn’t with the bootloader, but rather with the fuses that set how much flash is available for user (i.e. non-bootloader) code. This issue5 comes up repeatedly on the Arduino forum

So the first step in uploading firmware to a new board is to fix the fuses: the easiest way to do this is to burn a new bootloader pretending that the Nano is a Uno. The Uno has the same processor but sane fuse and bootloader settings. Happily you only have to entertain this deception once.

Servo control

Originally in grbl the servo output was used to control the speed of a spindle on a CNC machine. As mentioned above, these days people typically put a laser, rather than a pen, on the plotter, and use the servo output to modulate its intensity. In both cases, the servo output is a PWM signal, which is good for RC servo control, but the parameters need to be changed.

To control a RC servo6 we need a frequency of 50Hz with a pulse length of 1–2ms, which we can achieve by changing this definition (which occurs twice) in cpu_map.h:

#define SPINDLE_TCCRB_INIT_MASK ((1<<CS22)|(1<<CS21) | (1<<CS20))
    // 1/1024 prescaler ~60Hz for servo

Once patched thus, on-times of 19–31 move the servo to sensible places.

grbl implements safety interlocks which couple the servo output to the motion. This makes sense when driving a spindle or laser, but can be confusing when you’re just moving a pen up and down.

grbl settings

grbl has a number of configuration parameters. These are the settings I’m using:

>>> $I
[VER:1.1h.20190825:]
[OPT:VC,15,128]
ok
>>> $$
$0 = 10    (Step pulse time, microseconds)
$1 = 25    (Step idle delay, milliseconds)
$2 = 0    (Step pulse invert, mask)
$3 = 1    (Step direction invert, mask)
$4 = 0    (Invert step enable pin, boolean)
$5 = 0    (Invert limit pins, boolean)
$6 = 0    (Invert probe pin, boolean)
$10 = 1    (Status report options, mask)
$11 = 0.010    (Junction deviation, millimeters)
$12 = 0.002    (Arc tolerance, millimeters)
$13 = 0    (Report in inches, boolean)
$20 = 0    (Soft limits enable, boolean)
$21 = 0    (Hard limits enable, boolean)
$22 = 0    (Homing cycle enable, boolean)
$23 = 0    (Homing direction invert, mask)
$24 = 25.000    (Homing locate feed rate, mm/min)
$25 = 500.000    (Homing search seek rate, mm/min)
$26 = 250    (Homing switch debounce delay, milliseconds)
$27 = 1.000    (Homing switch pull-off distance, millimeters)
$30 = 255    (Maximum spindle speed, RPM)
$31 = 0    (Minimum spindle speed, RPM)
$32 = 1    (Laser-mode enable, boolean)
$100 = 100.000    (X-axis travel resolution, step/mm)
$101 = 100.000    (Y-axis travel resolution, step/mm)
$102 = 100.000    (Z-axis travel resolution, step/mm)
$110 = 5000.000    (X-axis maximum rate, mm/min)
$111 = 5000.000    (Y-axis maximum rate, mm/min)
$112 = 5000.000    (Z-axis maximum rate, mm/min)
$120 = 200.000    (X-axis acceleration, mm/sec^2)
$121 = 200.000    (Y-axis acceleration, mm/sec^2)
$122 = 200.000    (Z-axis acceleration, mm/sec^2)
$130 = 200.000    (X-axis maximum travel, millimeters)
$131 = 200.000    (Y-axis maximum travel, millimeters)
$132 = 200.000    (Z-axis maximum travel, millimeters)
ok
>>> $G
[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0 S0]
ok

Some of these set scale sizes. For example $30 and $31 control the mapping between the spindle speed set in G-code and the value poked into the PWM peripheral.

G-code

To control the plotter we send it G-code7. G-code covers all sorts of machines, but we only need a small subset here.

Preamble

G28             ; XXXXX
G53             ; XXXXX
M03 S17         ; lift the pen
G1 X0 Y0 F1000  ; move to the origin and set default speed

Epilogue

M03 S17         ; lift the pen
G28             ; XXXXX

Movement

This moves us to (123,45) measured in mm at the default speed.

G1 X123 Y45

Pen control

To move the pen up:

M03 S17         ; lift the pen

and to move it down:

M03 S31         ; drop the pen

Set coordinate origin

Sometimes it’s helpful to move the coordinate origin. Usually I want to tell the machine to use the current position as the origin in future.

G92 X0 Y0       ; Set (0,0) to current location

Useful links

Universal G-code Sender

To control the machine the Universal G-code Sender8 was very useful.

Other Eleksmaker articles

Generating G-code

There are numerous tools to convert SVG to G-code. Here are a few I found useful: