Close
0%
0%

Limn: Pen Plotter with Toolchanger

Building a Pen Plotter with automatic toolchanger with components from an old RepRap style 3D Printer. Runs on Klipper.

Similar projects worth following
I've always wanted to build my own Pen Plotter that can change tools automatically. I've reached the version 2 of my design. Inspired from E3D, the toolchanger uses another small stepper motor to actuate a rotating key to lock in the tool. Due to the size of the stepper we currently need high precision and have to tinker a bit for successful lock. It will be an open source and open hardware project once I've reached a stable design.

Initial hardware were obtained from a Tronxy 3D Printer, namely:

- Melzi V2 control board (modified to have 5V stepper voltage on two axes)

- 2x NEMA 17 Stepper Motors

- 8mm rods for the edges (Size can be variable, but need 2x of same length for X axis)

- 2x 6mm rods for the Y axis

- 6 & 8 mm linear bearings

- Idler pulleys

Apart from this plenty of screws, bearings, and belts are needed.

The design uses CoreXY framework.

The Z axis is belted and integral to the toolhead. I chose to use a fixed max-Z endstop and BLTouch both.

The toolchanger "locking" system uses a tiny linear stepper motor found on Aliexpress, which drives a rack to turn a gear on which the key is mounted. The torque is VERY low and is making it quite challenging to have a successful coupling.

We needed low wobble and low friction, so the rest of the design has to maintain precision for this to work. Also a bit of PTFE lube worked wonders!

I attach a couple of pics of the toolhead.

The extra wires are conected to the screws and were intended to power/communicate with the tool in future. I've discovered since that the resistance is too high. Will retry or switch to pogo pins later after eliminating the coupling reliability.

I was mainly inspired by https://www.printables.com/model/137147-ratrig-vcore-3-tool-changer design on Printables, which is where I discovered the term Kinematic coupling (a constraint model for mating parts). 

  • Interactive Plotting

    Prashant Sinha2 hours ago 0 comments

    I posted a quick video showing how I'm using the plotter currently. It's far from ideal but also quite efficient. Basically just dragging SVGs from Sketch to the slicer. As long as the paper doesn't move we can keep plotting at different areas.


    Apart from pen alignment, the core toolchanging part seems to work well now. Here are some plots I've done lately: 

    > An image vectorized in Inkscape, 0.05mm


    > Drawings from Wikimedia Commons, 0.7mm

    > Pioneer Plaque, Paris Metro map (using toolchanger, misaligned). 0.05mm

    The paper curled at certain points but overall I'm happy with the results.

    > Paris Metro, Pioneer Plaque, Telescope. 0.7mm

  • RFID Read, Source available on GitHub

    Prashant Sinha4 days ago 0 comments

    I posted a screencast where the plotter scans RFID tags on the tools. Still need to find out how to use the values read.

    Additionally, I was finally able to clean up a bit the klipper side of things. In the Limn repo I've published the current printer/toolchanger/rfid config. It's under MIT license. The README explains the contents.

    Link to Github

    This is my first time configuring klipper, so I'd be keen to know what could be done better!

  • Under the hood

    Prashant Sinha5 days ago 0 comments

    The plotter is designed to be scalable. Four components in each corners mate with variable lengths of rods/belts/base.

    A hard MDF board and the four steel rods on the edges together form a sufficiently rigid and square frame. I got the rods and bearings from a Tronxy 3D Printer Kit, as well as the driver PCB and XY Stepper Motors.

    The driver board uses 12V, and has 4 A4982 driver chips. Z axis is configured to drive dual Z axis motors so we have a different pinout here for the motors.

    I'd noticed the small SRM1509 and Linear motors get too hot on 12V regardless of proper VREF, so I cut the 12V trace and supplied external 5V to Z and K (the toolhead lock) axis drivers.



    When the belts are tensioned the frame is pulled inwards along the belt direction, which reduces the wobble. However it will likely deform when lifted in the current setup. There is not much to do unless we switch to a metal frame.

    The tool dock however needed special consideration as we need it to not move and survive the toolhead crashing into it. To keep it positioned the brackets (shown below) mate with a steel rod, and rest on the base. The middle one also acts as a hinge for the LCD.




    --

    I'm quite close to finishing the design. I've built a 1:1 model in Fusion360, and would just like to give a shout to amazing people on GrabCAD and Printables (and elsewhere) for sharing their models. I'll be posting the STEP files on Printables (about a week or so). There are many parts, with some parts such as the K axis requiring special considerations (and it's pretty specific to the hardware I had at hand) so there's a bit of work left to do to documenting them. Almost all parts print without supports. 


  • Detecting Tools, Tool Parameters, "Slicing"

    Prashant Sinha6 days ago 0 comments

    The tool docking mechanism relies on Maxwell Coupling for repeatability, however this repeatability only holds per tool. As such, different pens will land at varying positions on the paper for the same coordinate.

    My current understanding is that it will be too much effort to precisely align each tool, and rather it'd be easier to calibrate each tool against a reference tool (ideally the sharpest pen). Hence we need a way to configure the tool parameters (`{offset_x, offset_y, offset_z, depth...}`). 

    For the sake of simplicity it'd be good that the printer handles this at runtime. Any print file could be printed by any tool/tools. 

    I really did not want to reinvent any more wheels, so I stuck to PrusaSlicer. A new printer config, with custom gcode templates, multi-extruder toolhead, and some regex susbtitution later I can now drag an SVG file in the slicer, and generate the exact GCODE that klipper is expecting.

    Pen Up and Down motion is achieved by replacing `retraction` events. I chose to keep raw Z values here, and change Z-offset on klipper instead, so that the travel moves reflect actual pen moves in the preview. Similarly extrusions are kept only to have something in the preview, but are ignored by G1 macro.

    The slicer emits T0..T4 commands for each tool change. On klipper side custom macros translate these commands to actual movement.

    I still haven't figured out varying nozzle sizes while slicing but it should be possible. 


    Back to detecting tools: A basic detection can be done by physical contact with the coupling surface -- on the tool's side we can bridge two screws with a wire. I'm aware of 1Wire EEPROM being a thing but did not find any to buy. There seems to be several Spool detecting projects, such as OpenSpools, which can use RFID readers to detect the spools. We could use something like that.

    To set the parameters there's now a spring-loaded-retractable RFID sensor mounted near the first tool. It can be slid back by the Y axis. 

    (I did not realize that I wired the PN532 with I2C, but OpenSpools needs SPI connection. I'm too lazy to take it out so I'll likely have to figure out an alternative on this.)

    On the tools we stick a tag and the docking macro will eventually use the sensor for tool parameters. 

  • NEMA 8: No Go & Backlash Correction

    Prashant Sinha04/03/2026 at 15:46 0 comments

    I received the AliExpress NEMA 8 motors yesterday and replaced the SRM1509 for a test. After tightening the belts I can turn the axis manually but the stepper just buzzes. I tried upping the stepper current till 0.8A but I could stop the shaft with my fingers. Oh well. I went back to the previous motor.

    I wanted to make a note about the pulleys. Normally even if you make the shaft hole good size the pulley would not engage and the little flex it has will allow it to turn. I figured a good way to prevent this is by embedded nuts. Essentially a nut on the flat surface of the shaft, and a screw. 

    Since for now we have to live with the gear play I attempted correcting the backlash in software. Klipper allows you to override any macros, including G1, and with a macro variable one can keep track of the direction the motor was going in previously. If we are about to go in opposite direction then extra motor movement can correct for backlash IF it is stable (it is in my case). Only problem is that BED_CALIBRATE does not seem to be using a G1 command so the bed mesh is not corrected.

    For plotting without a bed mesh the backlash is not really a big deal. With bed mesh we need to just be careful to not overshoot the end positions on the axis. I haven't found a clean way to do this yet, but I'm looking at /extras dir in klipper right now.

    gcode_macro G1]
    rename_existing: G1.1 # Rename the existing G1 command to G1.1
    gcode:
      {% set is_abs = printer.gcode_move.absolute_coordinates %}
      {% set curr_z = printer.toolhead.position.z %}
      {% set param_z = params.Z|default(-42)|float %}
      {% set new_z = 0 %}
      {% if 'Z' in params %}
        {% set next_z = param_z if is_abs else (curr_z + param_z) %}
        {% set delta = next_z - curr_z %}
        {% set direction = (delta / delta|abs) if delta != 0 else last_dir %}
        {% set backlash = 1.8 if direction != last_dir else 0  %}
        {% set correction = backlash * direction %}
        SET_GCODE_VARIABLE MACRO=G1 VARIABLE=last_dir VALUE={direction}
        {% if correction %}
          {% set step_to = correction if not is_abs else (curr_z + correction) %}
          # SET_KINEMATIC_POSITION Z={curr_z - correction} SET_HOMED=''
          G92 Z{curr_z - correction}
          G1.1 Z{step_to}
          # SET_KINEMATIC_POSITION Z={curr_z} SET_HOMED=''
          G92 Z{curr_z}
          M118 Corrected: Backlash: {backlash} Direction: {direction}
        {% endif %}
      {% endif %}
      {% set p_x = ' X' ~ params.X if 'X' in params else '' %}
      {% set p_y = ' Y' ~ params.Y if 'Y' in params else '' %}
      {% set p_z = ' Z' ~ params.Z if 'Z' in params else '' %}
      {% set p_f = ' F' ~ params.F if 'F' in params else '' %}
      {% set ps = p_x + p_y + p_z + p_f %}
      G1.1 {ps}
    variable_last_dir: 1

    PS: The 3-point coupling seems to be good enough to pass some electricity, finally! 

  • Z Axis & Toolhead

    Prashant Sinha04/01/2026 at 18:50 0 comments

    For a plotter we do not really need large Z axis movement. Initial iterations used a MG14 servo motor for Pen Up/Pen Down motion. It worked but was loud, imprecise, and limited to flat bed.

    I found that SRM1509 stepper motors were just strong enough while being small and are what in use currently. These use a gearbox so some trial and error yielded a close but incorrect Z scaling. Additionally there is significant play due to gears and I had to account for the backlash.

    The motor module is designed separately so can be changed for a different system later. I plan to switch to NEMA8/NEMA11 motors soon. Currently the belt tension is achieved through three bolts that lift the entire motor and GT2 pulley assembly. 

    For the motion system 3mm/5cm dowels and bushings are used. Belt rides on 603ZZ bearings. When tensioned, the motor module and Y axis "rider" are rigid. Weighs about 250g!

    Attached some pictures.

  • First Steps

    Prashant Sinha03/31/2026 at 09:03 0 comments

    Magnets was the answer, as it turns out. For locking the tool, good alignment is necessary. I had planned for, but forgotten to put, magnets on the coupling screws to help the tool positioning. It does a "click" now when taken from the rack and then the lock can be closed.

    I posted a video here:

    Apologies for vertical orientation, I was too excited!

    Next steps: Working on the software stack to go from layered svg to mutli-tool gcode.

View all 7 project logs

Enjoy this project?

Share

Discussions

Joel wrote 6 days ago point

No comments on this awesome project?

Will definitely keep an eye on it, rock on! :)

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates