Skip to content

Latest commit

 

History

History

axidraw

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@thi.ng/axidraw

npm version npm downloads Mastodon Follow

This project is part of the @thi.ng/umbrella monorepo.

About

Minimal AxiDraw plotter/drawing machine controller for Node.js.

This package provides a super-lightweight alternative to control an AxiDraw plotter directly from Node.js, using a small custom set of medium/high-level drawing commands. Structurally, these custom commands are thi.ng/hiccup-like S-expressions, which can be easily serialized to/from JSON and are translated to the native EBB commands for the plotter.

Declarative vs. imperative

Due to AxiDraw's lack of G-Code support, most other available AxiDraw support libraries are providing only a purely imperative API to control the machine. In contrast, this package utilizes a more declarative approach, also very much following the pattern of other packages in the thi.ng/umbrella monorepo, which allows (geometry) data to be inspected, augmented, converted/transformed, serialized up until the very last moment before being sent to the machine for physical output...

Units, limits & clipping

This package performs no bounds checking nor clipping and expects all given coordinates to be valid and within machine limits. Coordinates can be given in any unit, but if not using millimeters (default), a conversion factor to inches (unitsPerInch) MUST be provided as part of the options object given to the AxiDraw constructor. Clipping can be handled by the geom or geom-axidraw packages (see below)...

Path planning

Path planning is considered a higher level operation than what's addressed by this package and is therefore out of scope. The thi.ng/geom-axidraw provides some configurable point & shape sorting functions, but this is an interim solution and a full path/route planning facility is currently still outstanding and awaiting to be ported from other projects.

thi.ng/geom support

The thi.ng/geom package provides numerous shape types & operations to generate & transform geometry. Additionally, thi.ng/geom-axidraw can act as bridge API and provides the polymorphic asAxiDraw() function to convert single shapes or entire shape groups/hierarchies directly into the draw commands used by this (axidraw) package. See package readme for more details and examples.

SVG support

This package does not provide any direct conversions from SVG or any other geometry format. But again, whilst not containing a full SVG parser (at current only single paths can be parsed), the family of thi.ng/geom packages provides numerous shape types & operations which can be directly utilized to output generated geometry together with this package...

The only built-in conversion provided here is the polyline() utility function to convert an array of points (representing a polyline) to an array of drawing commands (with various config options). All other conversions are out of scope for this package (& for now).

Serial port support

We're using the serialport NPM package to submit data directly to the drawing machine. That package includes native bindings for Linux, MacOS and Windows.

The AxiDraw.connect() function (see example below) attempts to find the drawing machine by matching a given regexp with available port names. The default regexp might only work on Mac, but YMMV!

At some point it would also be worth looking into WebSerial support to enable plotting directly from the browser. Right now this package is only aimed at Node.js though...

Draw control

The main draw() function provided by this package is async and supports custom implementations to pause, resume or cancel the processing of further drawing commands. By the default AxiDrawControl is used as default implementation.

If a control is provided, it will be checked prior to processing each individual command. Drawing will be paused if the control state is in paused state and the control will be rechecked every N milliseconds for updates (configurable). In paused state, the pen will be automatically lifted (if it wasn't already) and when resuming it will be sent down again (if it was originally down). Draw commands are only sent to the machine if no control is provided at all or if the control is in the "continue" state.

Metrics

The draw() function also records several metrics, useful for further analysis (or to identify optimizations) of the plotting process. These metrics include:

  • total duration
  • total distance traveled
  • draw distance (i.e. only whilst pen is down)
  • number of pen up/down commands (i.e. to consider servo lifespan)
  • total number of commands

Status

ALPHA - bleeding edge / work-in-progress

Search or submit any issues for this package

Installation

yarn add @thi.ng/axidraw

For Node.js REPL:

const axidraw = await import("@thi.ng/axidraw");

Package sizes (brotli'd, pre-treeshake): ESM: 2.15 KB

Dependencies

API

Generated API docs

Example usage

Basics

import { AxiDraw, polyline } from "@thi.ng/axidraw";

(async () => {

// instantiate w/ default options (see docs for info)
const axi = new AxiDraw();

// connect to 1st serial port matching given pre-string or regexp
// (the port used here is the default arg)
await axi.connect("/dev/tty.usbmodem");
// true

// vertices defining a polyline of a 100x100 mm square (top left at 20,20)
const verts = [[20, 20], [120, 20], [120, 120], [20, 120], [20, 20]];

// convert to drawing commands (w/ custom speed, 25%)
// see docs for config options
const path = polyline(verts, { speed: 0.25 })
// [
//   ["m", [20, 20]],
//   ["d"],
//   ["m", [120, 20], 0.25],
//   ["m", [120, 120], 0.25],
//   ["m", [20, 120], 0.25],
//   ["m", [20, 20], 0.25],
//   ["u"]
// ]

// draw/send seq of commands
// by default the given commands will be wrapped with a start/end
// command sequence, configurable via options given to AxiDraw ctor)...
await axi.draw(path);

})();

geom-axidraw example

Result shown here: https://mastodon.thi.ng/@toxi/109473655772673067

import { AxiDraw } from "@thi.ng/axidraw";
import { asCubic, group, pathFromCubics, star } from "@thi.ng/geom";
import { asAxiDraw } from "@thi.ng/geom-axidraw";
import { map, range } from "@thi.ng/transducers";

(async () => {
    // create group of bezier-interpolated star polygons,
    // with each path using a slightly different configuration
    const geo = group({ translate: [100, 100] }, [
        ...map(
            (t) =>
                pathFromCubics(
                    asCubic(star(90, 6, [t, 1]), {
                        breakPoints: true,
                        scale: 0.66,
                    })
                ),
            range(0.3, 1.01, 0.05)
        ),
    ]);

    // connect to plotter
    const axi = new AxiDraw();
    await axi.connect();
    // convert geometry to drawing commands & send to plotter
    await axi.draw(asAxiDraw(geo, { samples: 40 }));
})();

Other selected toots/tweets:

Authors

If this project contributes to an academic publication, please cite it as:

@misc{thing-axidraw,
  title = "@thi.ng/axidraw",
  author = "Karsten Schmidt",
  note = "https://thi.ng/axidraw",
  year = 2022
}

License

© 2022 - 2023 Karsten Schmidt // Apache License 2.0