NAV

Introduction

The Bantam Tools NextDraw Python library is an application programming interface (API) for the Bantam Tools NextDraw™, designed to let you control the NextDraw from within your own Python scripts.

This Python module supports the NextDraw with two distinct control approaches:

To distinguish between these two control methods, we will refer to them as the Plot context and the Interactive context, for plotting SVG files or using XY motion control commands, respectively. Certain options and functions can only be used in one or the other context. Please see Quick start: Plotting SVG and Quick start: Interactive XY for more information.

If you wish to use the NextDraw from the command line interface or within shell scripts or other environments that make use of shell commands, please see the separate API documentation for the Bantam Tools NextDraw™ CLI.

The Bantam Tools NextDraw™

The Bantam Tools NextDraw™ drawing and handwriting machine is the proven and reliable compatible computer-controlled plotter that provides versatile solutions to artists, innovators and educators.

The Bantam Tools NextDraw™ is designed and manufactured by Bantam Tools in Peekskill, New York.

For general information about getting started with and operating the machine, please see our extensive PDF user guide, available here.

Please also see the central documentation site for the Bantam Tools NextDraw; many additional resources are listed there.

NextDraw owners may request technical and other product support by contacting us directly through our contact form, or discord chat.

Installation

One line install

If you already have Python installed (versions 3.9 - 3.13), use the following in a terminal: python -m pip install https://software-download.bantamtools.com/nd/api/nextdraw_api.zip

This procedure installs both the NextDraw Python library and the NextDraw CLI. The link is permanent and will be kept up to date. The current release version is 1.5.0.

If you use this method, you may also want to download the zip file conventionally, since the download includes example python scripts, an example configuration file, an example SVG file, and instructions for un-installing the software.

Alternate install

Download the API from this permanent link. The current release version is 1.5.0.

Please see Installation.txt included with the download for full installation instructions.

(Abbreviated instructions: Install Python 3. Unzip the archive, move into the directory, and use python -m pip install . to install the software.)

Upgrading

If you already have this software installed, we recommend the following method to upgrade: python -m pip install https://software-download.bantamtools.com/nd/api/nextdraw_api.zip --upgrade --upgrade-strategy eager

Quick start: Plotting SVG

Quick start: Plotting SVG

Quick start example; Typical usage:

from nextdraw import NextDraw   # Import the module
nd1 = NextDraw()                # Create class instance
nd1.plot_setup(FILE_NAME)       # Load file & configure plot context
            # Plotting options can be set, here after plot_setup().
nd1.plot_run()                  # Plot the file

Example 1: Plot a file named NextDraw_trivial.svg

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.plot_setup("NextDraw_trivial.svg")
nd1.plot_run()

Example 2: Plot two copies of an SVG document contained within a string called input_svg, with full reordering enabled, and collect the output SVG as a string:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup(input_svg)
nd1.options.reordering = 2
output_svg = nd1.plot_run(True)  

plot_run(True) will generate output SVG. output_svg is a string equivalent to the contents of an SVG file.

The examples shown here will load and plot a file, using default option values. Four lines of code are needed: to import the module, create a class instance, load a file and select the Plot context, and begin plotting.

In addition to plotting a file, the API includes the ability to set a wide range of configuration options, and a number of utility functions. The options available in the Plot context include those described below in the Options: General and Options: Plot sections. Options may be set at any point after plot_setup() and before plot_run(). For more about the functions available in the Plot context, see Functions: general and Functions: Plot.

An SVG input is required for most operations that are outside of the Interactive context. (Certain utility modes that do not perform any plotting do allow the file input to be omitted, even in Plot context.) This SVG input may be the name (or full path) of an SVG file or it may be a string that contains the contents of an SVG document.

By default, no output SVG is returned as part of the plotting process. However, in some situations it may be use useful to have the program generate and return output SVG. The SVG returned by plot_run(True) is a string containing the contents of an SVG file. Keeping that output SVG allows the capability to pause and subsequently resume a plot in progress, or to preview a plot. See further discussion under res_plot and rendering below.

Quick start: Interactive XY

Quick start: Interactive XY

Example: Draw a single line in Interactive context:

from nextdraw import NextDraw   # import module
nd1 = NextDraw()                # Initialize class
nd1.interactive()               # Enter interactive context
if not nd1.connect():           # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
                                # Absolute moves follow:
nd1.moveto(1, 1)                # Pen-up move to (1 inch, 1 inch)
nd1.lineto(2, 1)                # Pen-down move, to (2 inch, 1 inch)
nd1.moveto(0, 0)                # Pen-up move, back to origin.
nd1.disconnect()                # Close serial port to NextDraw

The Interactive context is a separate mode of operation that that accepts direct XY motion control commands. It does not use an SVG file as an input.

Interactive control requires a persistent session, and only works from within a Python script.

Once the Python module is imported, call the interactive() method to enter the Interactive context. To establish a USB connection to the NextDraw, use connect(), which returns True when successfully connected. You must also use disconnect() at the end of your session to terminate the USB session.

Options may be specified at any point after the interactive() call. The options will be applied when you call connect(). If you change one or more options after calling connect(), use the update() method to process the changes to the options before calling additional motion commands.

The options available in the Interactive context include those described below in the Options: General and Options: Interactive sections. The options described in Options: Plot do not apply in the Interactive context.

Example scripts

Example scripts

Run an example script called "plot_inline.py" by calling the following from the command line (terminal/command prompt):

python plot_inline.py

Note that example scripts are not installed system-wide. For Python to find the file (plot_inline.py), it is easiest to call this command from within the directory where that file is located.

The examples_py_nextdraw folder in the API download contains a number of example scripts that demonstrate various features of the NextDraw Python API.

The files include:

Setting options

Setting options

One or more options may be specified with the following syntax:

options.option_name = value

Example 1: Set the pen-up position to 70% height before plotting, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.pen_pos_up = 70      # set pen-up position
nd1.plot_run()

Example 2: Set the pen-up position to 70% height before plotting, making use of the Interactive context:

from nextdraw import NextDraw   # import module
nd1 = NextDraw()                # Initialize class
nd1.interactive()                # Enter interactive context
nd1.options.pen_pos_up = 70      # set pen-up position
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(1, 1)                 # Absolute pen-up move, to (1 inch, 1 inch)
nd1.lineto(0, 0)                 # Absolute pen-down move, back to origin.
nd1.disconnect()                 # Close serial port to NextDraw

Most plotting options can be set directly like variables within Python. The particular options and their values are detailed in the sections below. For options that you do not directly specify, the default value will be used.

Options should be set after initialization into either the Plot context or the Interactive context, with plot_setup or interactive() respectively.

The default value of most options are set within the nextdraw_conf.py configuration file, within the files installed by the API. These include the pen up and pen down heights, basic speed settings, and so forth.

(Beyond the options documented in this API, the configuration file includes some additional defaults that can be overridden, if necessary, with the supplementary params syntax.)

A few specific options (including pen heights and plotting speed) can also be set by encoding settings into the SVG file. The mechanism for doing this is called "NextDraw Layer Control", and it involves using special escape codes in the name of the layer(s) in the SVG file. Several additional commands such as timed delays and forced pauses can be controlled through this mechanism as well.

The order of preference for options and parameters is as follows:

1. Options and values values specified in the SVG file (as in, by layer names) overrule those specified either by your script or in nextdraw_conf.py.

2. Options and values specified by your script overrule those in nextdraw_conf.py.

As an aside, if you also use Inkscape for plotting SVG files, please note that option values and settings that you select from within the Inkscape GUI are NOT consulted and do not affect plotting from outside Inkscape.

Options (General)

The following is a list of "General" options: options that can be set in either the Plot or Interactive contexts. Each of these is described individually, after the list.

Option Description
handling Specify handling mode for motion.
speed_pendown Maximum XY speed when the pen is down (plotting).
speed_penup Maximum XY speed when the pen is up.
accel Relative acceleration/deceleration speed.
pen_pos_down Pen height when the pen is down (plotting).
pen_pos_up Pen height when the pen is up.
pen_rate_lower Speed of lowering the pen-lift motor.
pen_rate_raise Speed of raising the pen-lift motor.
model Select plotter model of NextDraw hardware.
penlift Pen lift servo configuration.
homing Enable automatic homing (where supported).
port Specify a USB port or NextDraw to use.
port_config Override how the USB ports are located.

handling

handling

Example 1: Plot a document, using the "Handwriting" Handling mode

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.handling = 2
nd1.plot_run()

Example 2: Enter interactive context and select the "Constant speed" Handling mode:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.handling = 4

Select Handling mode for motion

Syntax: options.handling = value

The handling option allows you to select one of four general "Handling modes": Technical drawing, Handwriting, Sketching, or Constant speed. These names are descriptive, but you may find that one or a different handing mode works best for you and your actual usage.

The choice of Handling mode controls the overall scales of precision, speed and acceleration. For example, “100%” speed in Sketching is faster than “100% speed” in Handwriting, and maximum acceleration in Handwriting is higher than Maximum acceleration in Sketching.

Allowed values: Integers from 1 to 4:

Technical drawing is the default Handling mode. It uses a moderate top speed, medium-high Maximum acceleration, and high precision. It is a good starting point for many applications, including handwriting-like work in cases where precision is more important than speed.

The Handwriting Handling mode has moderate top speed, very high maximum acceleration, fast pen-up speeds, and relatively low precision. For handwriting-like work where acceleration on tiny strokes and curves is much more important than the top speed that can be achieved, the Handwriting Handling mode can give a significant reduction in total plot time. It is also a great choice for stipple drawings and other artwork or applications that involve very short or curvy movements.

The Sketching Handling mode has a high top speed, moderate Maximum acceleration, fast pen-up speeds, and moderate precision. For artwork or other use consisting of long strokes, where the top speed is more important than acceleration on short strokes, the Sketching Handling mode can give a significant reduction in total plot time.

The Constant speed Handling mode disables acceleration and moves the pen at a constant speed when it is down. It has a relatively low top speed, “instantaneous” acceleration, and high (theoretical) precision. In practice, motion artifacts from taking sharp corners without slowing down can make it less precise than the Technical drawing Handling mode except at low speeds. The Constant speed Handling mode is most useful for specialized applications where moving at a constant speed is a priority. The constant speed motion applied by this mode applies only when the pen is down; Acceleration is used during pen-up travel.

Default: 1 (Technical drawing), set in nextdraw_conf.py or your specified config file.

speed_pendown

speed_pendown

Example 1: Set up to plot with a maximum pen-down speed of 20% selected, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.speed_pendown = 20
nd1.plot_run()

Example 2: Set up to plot with a maximum pen-down speed of 20% selected, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()       
nd1.interactive()             
nd1.options.speed_pendown = 20

Pen-down Movement Speed

Syntax: options.speed_pendown = value

Specify the speed limit for the XY carriage when the pen is down. That is, the maximum speed that the pen may move at while writing or drawing. This value is expressed as a percentage of maximum travel speed.

Pen-down movements use smooth acceleration unless the constant-speed handling mode is selected. Increasing this maximum speed tends to greatly affect behavior at corners and precision, but has a lesser impact on the average speed and total plotting time, especially on documents that consist of many small movements.

Allowed values: Integers from 1 to 100.

Default: 25, set in nextdraw_conf.py

speed_penup

speed_penup

Example 1: Set up to plot with a maximum pen-up speed of 50% selected, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.speed_penup = 50
nd1.plot_run()

Example 2: Set up to plot with a maximum pen-up speed of 50% selected, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.speed_penup = 50

Pen-up Movement Speed

Syntax: options.speed_penup = value

Specify the speed limit for the XY carriage when the pen is up. That is, the maximum speed that the pen may move at while moving between paths that will be plotted. This value is expressed as a percentage of maximum travel speed.

Pen-up movements use smooth acceleration whether or not the constant-speed handling mode option is selected. Increasing this maximum speed tends to have a minor effect on plot quality, but can have a significant affect on total plotting time, especially on documents that have many large pen-up movements.

Allowed values: Integers from 1 to 100.

Default: 75, set in nextdraw_conf.py

accel

accel

Example 1: Set up to plot with an acceleration value of 80% selected, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.accel = 80
nd1.plot_run()

Example 2: Set up to plot with an acceleration value of 80% selected, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.accel = 80

Acceleration Factor

Syntax: options.accel = value

Specify the relative acceleration/deceleration speed. This value is expressed as a percentage of maximum acceleration rate. The acceleration rate does not affect the top speed that can be achieved, but does influence how long it takes to get to different speeds.

Allowed values: Integers from 1 to 100.

Default: 75, set in nextdraw_conf.py

pen_pos_down

pen_pos_down

Example 1: Prepare to plot, with the pen-down height set to 20%, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.pen_pos_down = 20
nd1.plot_run()

Example 2: Prepare to plot, with the pen-down height set to 20%, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.pen_pos_down = 20

Pen-down Position

Syntax: options.pen_pos_down = value

Specify the height of the pen when the pen is lowered (plotting). This value is expressed as a percentage of the vertical travel.

Depending on the operation that you are executing, setting this value may not immediately move the pen height to this position; rather, it sets the height that will be used as the pen-down position value.

Allowed values: Integers from 0 to 100.

Default: 40, set in nextdraw_conf.py

pen_pos_up

pen_pos_up

Example 1: Prepare to plot, with the pen-up height set to 80%, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.pen_pos_up = 80
nd1.plot_run()

Example 2: Prepare to plot, with the pen-up height set to 80%, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.pen_pos_up = 80

Pen-up Position

Syntax: options.pen_pos_up = value

Specify the height of the pen when the pen is raised (not plotting). This value is expressed as a percentage of the vertical travel.

Depending on the operation that you are executing, setting this value may not immediately move the pen height to this position; rather, it sets the height that will be used as the pen-up position value.

Allowed values: Integers from 0 to 100.

Default: 60, set in nextdraw_conf.py

pen_rate_lower

pen_rate_lower

Example 1: Set up to plot, with the pen set to lower very slowly to the paper (5% speed), making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.pen_rate_lower = 5
nd1.plot_run()

Example 2: Set up to plot, with the pen set to lower very slowly to the paper (5% speed), making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.pen_rate_lower = 5

Pen Lowering Rate

Syntax: options.pen_rate_lower = value

Specify the rate at which the pen is lowered from the pen-up position to the pen-down position. This value is expressed as a relative percentage.

Allowed values: Integers from 1 to 100.

Default: 50, set in nextdraw_conf.py

pen_rate_raise

pen_rate_raise

Example 1: Set up to plot, with the pen set to raise very quickly to the paper (90% speed), making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.pen_rate_raise = 90
nd1.plot_run()

Example 2: Set up to plot, with the pen set to raise very quickly to the paper (90% speed), making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.pen_rate_raise = 90

model

model

Example 1: Set plotting size limits for the Bantam Tools NextDraw 2234, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.model = 10
nd1.plot_run()

Example 2: Set plotting size limits for the Bantam Tools NextDraw 1117, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.model = 9
if not nd1.connect():
    quit()

Select plotter model

Syntax: options.model = value

Select which specific plotter model you are using. This is used to set the limits of travel and configure certain other model-specific parameters.

Travel limits are set by dead reckoning, under the assumption that a given session (plot or interactive session) was started with the carriage in the Home Corner, and that no loss of position control has occurred. Movements are clipped to occur within these limits. Travel limits are not checked when using "walk" commands.

Allowed values: Integers from 1 to 10:

Default: 8 (Bantam Tools NextDraw™ 8511), set in nextdraw_conf.py or your specified config file.

The model-specific parameters that are set by the model selection can be overridden in your configuration file (nextdraw_conf.py or a custom configuration file), or with the params syntax, by using the overrides dict.

penlift

penlift

Example 1: Plot a file, using default pen-lift configuration.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.penlift = 1
nd1.plot_run()

Example 2: Plot a file, using narrow-band brushless pen-lift servo motor.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.penlift = 3
nd1.plot_run()

Pen lift servo configuration

Syntax: options.penlift = value

Select the hardware configuration for the pen-lift servo mechanism. This option is generally not needed unless you are using an AxiDraw machine that has been upgraded with a brushless pen-lift servo motor.

The default value, 1, specifies to use the standard configuration for the plotter model that is selected. On an AxiDraw, that is a standard hobby micro servo (including coreless versions). On a Bantam Tools NextDraw, the standard pen-lift mechanism is a narrow-band brushless servo motor.

A value of 3 selects the use of a narrow-band brushless pen-lift servo motor, even if the default for the model is the standard motor. Select this option for an AxiDraw with a brushless upgrade.

Allowed values: Integers from 1 to 3:

Default: 1 (Default for NextDraw model), set in nextdraw_conf.py

homing

homing

Example 1: Disable automatic homing in the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.homing = False
nd1.plot_run()

Example 2: Disable automatic homing in the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.homing = False

Enable automatic homing (where supported)

Syntax: options.homing = value

Automatic homing is enabled by default when you have selected a Bantam Tools NextDraw™ with the model option. Set the value of homing to False to disable automatic homing, if you would prefer to use a manual homing process.

When automatic homing is disabled (or when using AxiDraw models, which do not support automatic homing), make sure to move the carriage fully to the Home corner before beginning a plot or interactive session. An extended discussion about homing is available in section "3.2 Automatic and Manual Homing" of the Bantam Tools NextDraw User Guide.

Allowed values: True, False.

Default: True; set in nextdraw_conf.py

port

port

Example 1: Specify to use the USB port enumerated as /dev/cu.usbmodem1441, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.port = "/dev/cu.usbmodem1441"
nd1.plot_run()

Example 2: Specify to use the USB port enumerated as /dev/cu.usbmodem1441, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.port = "/dev/cu.usbmodem1441"
if not nd1.connect():
    quit()

Example 3: Specify to use the NextDraw with USB Nickname "UV LED Array", making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.port = "UV LED Array"
nd1.plot_run()

Example 4: Specify to use the NextDraw with USB Nickname "UV LED Array", making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.port = "UV LED Array"
if not nd1.connect():
    quit()

Specify a USB port or named NextDraw to use

Syntax: options.port = value

By default, the NextDraw software works with the first available NextDraw located on USB. Alternately, you can use the port option to specify a particular machine. You can specify the machine using the USB port enumeration (e.g., COM6 on Windows or /dev/cu.usbmodem1441 on a Mac) or by using an assigned USB nickname.

If any port is specified, then the software will attempt to open the connection to that (and only that) NextDraw or USB port. It will return an error if the port or NextDraw cannot be found. This behavior may be overridden by use of the port_config option.

USB port enumerations are typically not permanent; they may change with events as simple as unplugging a device and plugging it back in.

For a more permanent designation, you can assign an "NextDraw USB Nickname" to a given machine as well. This USB nickname may be read and written using the utility commands. (See utility_cmd for additional information.)

Be aware that if multiple NextDraw units are connected to one computer, it may not be trivial to identify which physical machine is currently identified as which USB device. You may wish to try an identifying action, for example raising the pen, to indicate which machine is which.

Allowed values of the port option are strings, which specify either the USB port or NextDraw USB nickname to use.

Default: None, set in nextdraw_conf.py

port_config

port_config

Example 1: Plot only to an NextDraw with USB Nickname "UV LED Array"; Return an error if that unit is not found, explicitly using the default value (0) of port_config, within the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.port="UV LED Array"
nd1.options.port_config = 0
nd1.plot_run()

Example 2: Plot only to an NextDraw with USB Nickname "UV LED Array"; Return an error if that unit is not found, explicitly using the default value (0) of port_config, within the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.port="UV LED Array"
nd1.options.port_config = 0

Example 3: Plot to the first available NextDraw found on USB, making use of the Plot context:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.port_config = 1
nd1.plot_run()

Example 4: Plot to the first available NextDraw found on USB, making use of the Interactive context:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.port_config = 1

Override how the USB ports are located

Syntax: options.port_config = value

By default, the software handles assignments of USB ports as follows:

The port_config option can override this behavior. Allowed values of this option are integers 0 and 1:

If port_config is 0, then the software will follow the default behavior described above.

If port_config is 1, then the software will communicate only with the first NextDraw located, even if a value of port is specified.

Default: 0, set in nextdraw_conf.py

Options (Plot)

The following is a list of options that can be set in the Plot context, and which are not applicable in the Interactive context.

Each of these arguments will be described individually, after the list.

Option Description
mode Specify general mode of operation.
utility_cmd Specify which utility-mode command to use.
dist Distance input for certain utility commands.
layer Specify which layer(s) to plot in the layers mode.
copies Specify the number of copies to plot.
page_delay Specify delay between pages, for multiple copies.
auto_rotate Enable auto-rotate when plotting.
preview Perform offline simulation of plot only.
rendering Render motion when using preview.
reordering Optimize plot order before plotting.
random_start Randomize start positions of closed paths.
hiding Enable hidden-line removal
report_time Report time and distance after the plot.
digest Return plot digest instead of full SVG
webhook Enable webhook alerts.
webhook_url URL for webhook alerts.

mode

mode

Example 1: Plot all document layers that have a layer name beginning with the number 1:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "layers"
nd1.options.layer = 1
nd1.plot_run()

Example 2: Cycle the pen up or down, using "cycle" mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "cycle"
nd1.plot_run()

Example 3: Disable the XY stepper motors, using "utility" mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "disable_xy"
nd1.plot_run()

General mode of operation

Specify the general mode of operation, within in the Plot context. This is equivalent to selecting a function "tab" in the Inkscape-based GUI for Bantam Tools NextDraw software.

The following is a list of allowed values of the mode option. Each of these modes will be described in detail, after the list.

Value Description
plot Plot the file. [DEFAULT]
layers Plot a single layer (or set of layers), selected by layer option
cycle A setup mode: Lower and then raise the pen
align A setup mode: Raise pen, disable XY stepper motors
find_home A setup mode: Perform automatic homing sequence
utility Execute a utility command, specified by utility_cmd option
sysinfo Query EBB firmware version and report system information
version Report NextDraw software version number
res_plot Resume a plot in progress, using stored plot progress data

Default: 'plot', set in nextdraw_conf.py

plot

mode: plot

Example 1: Plot a file called file.svg, explicitly setting plot mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "plot" # Default; you can comment out this line.
nd1.plot_run()

Example 2: Plot a file called file.svg, using multiple modes including plot:

import time
from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")

nd1.options.mode = "utility"        # Select utility mode
nd1.options.utility_cmd = "toggle"  # Select toggle action
nd1.plot_run()              # Execute that toggle
time.sleep(1.000)           # Wait one second
nd1.plot_run()              # Toggle pen again
time.sleep(1.000)           # Wait one second
nd1.options.mode = "plot"   # Configure back into plot mode
nd1.plot_run()              # plot the file

Plot the SVG file

Syntax: options.mode = "plot"

The plot mode is for plotting an SVG file. This the default mode of operation, when in the Plot context, and in most cases does not need to be explicitly specified. One case where you may need to explicitly switch the mode to plot is if you should switch to another mode and then need to switch back.

layers

mode: layers

Example 1: Plot all document layers that have a layer name beginning with the number 1:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "layers"
nd1.options.layer = 1
nd1.plot_run()

Example 2: Render a preview of how a layer called "5-blue" (the only layer in file.svg that has a name starting with the number 5) will plot, including pen-up travel, and estimate how long that layer will take to plot. Save the output SVG into a variable called "output_svg":

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "layers"
nd1.options.layer = 5
nd1.options.preview = True
nd1.options.rendering = True
output_svg = nd1.plot_run(True)

Plot a single layer (or set of layers)

Syntax: options.mode = "layers"

Plot a single layer (or set of layers), selected by the layer option.

When using the default (plot) mode, the entire document will be plotted. That is to say all paths, on all visible layers of the SVG document, will be plotted. You can instead use layers mode to plot a single layer or group of layers, for example to plot only layers that should be plotted in one color of ink.

If you plot in layers mode, only visible layers that have layer names beginning with the selected number will plot. The selected number is given by the value of the layer option, and may be in the range of 0 - 1000.

For example, a layer named "5-red" will be plotted if the number 5 is selected, but layers named "guide lines", "55", or "2-black" will be skipped.

Layers mode is equivalent to plotting from the "Layers" tab of NextDraw Control within Inkscape.

Sublayers and other named groups are not considered to be layers for this or other software features that operate by layers; only "top-level" layers can be addressed in layers mode.

See the description of the "layer" option below for additional information. For more information about options available based on layer name, and how to create layers when generating SVG outside of Inkscape, please see the NextDraw Layer Control documentation.

cycle

mode: cycle

Example: Cycle the pen down and then up, using "cycle" mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "cycle"
nd1.plot_run()

Cycle the pen down and back up

Syntax: options.mode = "cycle"

This is a setup mode that can be used used to prepare the NextDraw for use. It will lower the pen, wait 0.5 seconds, and then raise the pen. Cycling before inserting your pen ensures that your pen holder starts in the pen-up position, with current pen-up and pen-down heights applied.

Cycle mode is equivalent to selecting the "Setup" tab of the Bantam Tools NextDraw Inkscape extension and choosing the "Cycle pen down then up" option within that tab.

An SVG file input to plot_setup() is allowed but not required for this mode to operate correctly.

If you wish to only lower or raise the pen, not cycle down and up, use the lower_pen/raise_pen utility commands instead.

align

mode: align

Example: Put the NextDraw into Align mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "align"
nd1.plot_run()

Raise pen and disable XY stepper motors

Syntax: options.mode = "align"

This is a setup mode that may be used used to prepare the NextDraw for use. It will raise the pen to the "pen up" position and turn off (disengage) the XY stepper motors. In this configuration, one can manually move the carriage to the home corner and insert a pen.

Note that the pen will only be raised if it was in the down state or indeterminate state. It will not be raised if it was already in the pen-up state.

This mode is equivalent to selecting the "Setup" tab of the Bantam Tools NextDraw extension for Inkscape and choosing the "Raise pen, turn off motors" option within that tab. Both raising the pen and turning off the XY motors are actions that can also be initiated in utility mode.

An SVG file input to plot_setup() is allowed but not required for this mode to operate correctly.

find_home

mode: find_home

Example: Perform the automatic homing sequence (only).

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "find_home"
nd1.plot_run()

Perform automatic homing sequence

Syntax: options.mode = "find_home"

The find_home mode is a setup mode that begins the automatic homing cycle to move the carriage to the Home position.

Automatic homing is enabled by default when you have selected a Bantam Tools NextDraw™ with the model option, and have not disabled it with the homing option.

It is not usually necessary to use the find_home mode as a part of everyday operations, since the machine will (automatically) perform the homing sequence when needed. This mode is provided in case you should happen to have a reason to perform the automatic homing sequence that is before or otherwise separated from the typical homing process.

This mode is equivalent to selecting the "Setup" tab of the Bantam Tools NextDraw extension (within Inkscape) and choosing the "Perform automatic homing" option within that tab.

An SVG file input to plot_setup() is allowed but not required for this mode to operate correctly.

utility

mode: utility
Examples for the different utility commands are given along the description
of each individual utility_cmd item.

Execute a "utility" command

Syntax: options.mode = "utility"

Execute one of several "utility" commands, specified with the utility_cmd argument.

See the description of utility_cmd for additional information about the available commands.

This mode is equivalent to selecting the "Utility" tab of the Bantam Tools NextDraw extension for Inkscape.

An SVG file input to plot_setup() is allowed but not required for commands in utility mode.

sysinfo

mode: sysinfo

Example: Request sysinfo:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "sysinfo"
nd1.plot_run()

Typical response (example on Mac):

This is Bantam Tools NextDraw™ version 1.1.
Your software is up to date.

Your NextDraw has firmware version 3.0.2.
Your firmware is up to date; no updates are available.

Additional system information:
3.10.6 (main, Aug 30 2022, 04:58:14) [Clang 13.1.6 (clang-1316.0.21.2.5)]
Voltage readout: 296 (~ 9.08 V).
Current setpoint: 483 (~ 0.89 A).

Report system information

Syntax: options.mode = "sysinfo"

Query firmware version and report additional system information. This mode is equivalent to selecting the "Version" tab of NextDraw Control within Inkscape.

The information items listed are:

An SVG file input to plot_setup() is allowed but not required for this mode to operate correctly.

version

mode: version

Example: Query software version:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "version"
nd1.plot_run()

Typical response:

3.8.0

Alternative: read the version_string variable or version instead:

from nextdraw import NextDraw 
nextdraw_version_string1 = nextdraw.__version__

nd1 = NextDraw()
nextdraw_version_string2 = nd1.version_string

print(nextdraw_version_string1)
print(nextdraw_version_string2)

Typical response:

3.8.0
3.8.0

NextDraw Software Version

Syntax: options.mode = "version"

Query and report NextDraw software version. This mode is not available in the GUI (Inkscape) based version of this software.

An SVG file input to plot_setup() is allowed but not required for this mode to operate correctly.

Rather than running plot_run() in version mode, it is generally easier and more useful to instead read the version_string variable or nextdraw.__version__ provided by the Python module, as shown in the example.

res_plot

modes: res_plot

Example: Plot a file until it is paused (by button press or by NextDraw Layer Control). Wait 5 seconds. Then, resume plotting:

import time
from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
output_svg = nd1.plot_run(True)
time.sleep(5)
nd1.plot_setup(output_svg)
nd1.options.mode = "res_plot"
nd1.plot_run()

Resume a paused plot

Syntax: options.mode = "res_plot"

It is possible to pause a plot underway, and save the progress of the plot such that the plot can be resumed later. The res_plot ("resume plot") mode allows you to continue working with a plot that has been paused with progress saved.

Background: When using the Bantam Tools NextDraw extension for Inkscape, the following workflow is used to pause and resume plots that are underway:

  1. The plot is paused by pressing the physical pause button on the NextDraw, or using Control+C on the keyboard, if keyboard pausing is enabled with keyboard_pause. (Plots can also be paused at predefined points with NextDraw Layer Control.)
  2. The plot pauses after finishing queued motion commands.
  3. The SVG file is updated, saving an index of progress through the file.
  4. The user may then use the Resume tab to resume the plot, using the stored plot progress data from the file as a reference.

The same basic procedure may be used through the Python API, if the updated SVG is collected by as the output of plot_run, for example as: output_svg = plot_run(True).

The res_plot mode can only be used if the file contains a stored record of the progress through the file. This record is generated automatically when a plot is paused, and included in the output SVG. You must use this output SVG as the input to the next plotting cycle, by using plot_setup.

The position that a plot will be resumed at can be read and set by the res_read and res_adj_in/res_adj_mm utility commands.

utility_cmd

Specify the utility command to execute

Syntax: options.utility_cmd = "command_name"

This option allows you to specify exactly which particular "utility" command will be executed if the mode is set to utility. This option is ignored if any mode other than utility is active.

Please note that while some of these commands do perform movements, these commands should not be considered "real time" control commands. They are intended as utility commands, for test, setup, and calibration. (If you need real-time movement commands, consider using the Interactive context instead.)

An SVG document input to plot_setup() is allowed but not required in utility mode. However, several of the commands (such as res_adj_in, strip_data, etc.) are not useful unless input or input and output SVG are specified. For utility commands such as raise_pen that do not interact with the SVG document, execution is typically faster without SVG input file.

The following is a list of allowed values of the utility_cmd option. Each of these commands will be described in detail, after the list.

Value Description
lower_pen Lower the pen
raise_pen Raise the pen
toggle Raise the pen if it is lowered, or vice versa
walk_x Walk carriage in X by a distance given in inches
walk_y Walk carriage in Y by a distance given in inches
walk_mmx Walk carriage in X by a distance given in mm
walk_mmy Walk carriage in Y by a distance given in mm
walk_home Walk carriage to origin
set_home Set current carriage position as origin
enable_xy Enable (energize) XY stepper motors
disable_xy Disable (de-energize) XY stepper motors
res_read Read position where a paused plot will resume
res_adj_in Adjust resume position of paused plot in inches
res_adj_mm Adjust resume position of paused plot in mm
strip_data Strip plotter and preview data from file
list_names Read USB "nickname" or port of all attached machines
read_name Read the USB "nickname" of the NextDraw [DEFAULT]
write_name Write the USB "nickname" of the NextDraw
bootload Enter EBB bootloader mode

Default: 'read_name', set in nextdraw_conf.py

lower_pen, raise_pen

utility_cmd: lower pen, raise pen

Example 1: Lower the pen:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "lower_pen"
nd1.plot_run()

Example 2: Raise the pen, very slowly (10% speed), to 70% height:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "raise_pen"
nd1.options.pen_rate_raise = 10
nd1.options.pen_pos_up = 70
nd1.plot_run()

Utility commands: Lower or raise the pen holder

Syntax: options.utility_cmd = "lower_pen"

Syntax: options.utility_cmd = "raise_pen"

The lower_pen and raise_pen utility commands will, respectively, lower or raise the pen holder. These are often useful for setup and verification.

toggle

utility_cmd: toggle

Example: Toggle pen from up to down, or down to up:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "toggle"
nd1.plot_run()          # Execute the command

Utility command: Toggle the pen between up and down positions

Syntax: options.utility_cmd = "toggle"

The toggle utility command will raise the pen if it is already lowered, and lower the pen if it is already raised.

The initial pen state may not be well defined after first powering on or resetting the machine, so you may prefer to use the cycle mode for initial setup and everyday usage.

If you wish to only lower or raise the pen — not toggle to the opposite state — use one of the lower_pen/raise_pen utility commands instead.

walk_x, walk_y

utility_cmd: walk_x, walk_y

Example 1: Move the carriage 1 inch in the y direction (one inch forward and away from Home):

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_y"
nd1.options.dist = 1.0
nd1.plot_run()

Example 2: Move the carriage 1.5 inches in the +x direction, and then back:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_x"
nd1.options.dist = 1.5
nd1.plot_run()
nd1.options.dist = -1.5
nd1.plot_run()

Example 3: Move the carriage in a square, 10.0 cm on a side, with different speeds for each segment of movement:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_x"
nd1.options.dist = 3.937
nd1.plot_run()
nd1.options.utility_cmd = "walk_y"
nd1.options.dist = 3.937
nd1.plot_run()
nd1.options.utility_cmd = "walk_x"
nd1.options.dist = -3.937
nd1.plot_run()
nd1.options.utility_cmd = "walk_y"
nd1.options.dist = -3.937
nd1.plot_run()

Utility commands: Walk the carriage in the X or Y direction, inch units

Syntax: options.utility_cmd = "walk_x"

Syntax: options.utility_cmd = "walk_y"

These two "walk" commands will move the NextDraw carriage by a distance in inches given by the value of the dist option, along one axis or the other.

The dist option has a default value of 1.0. This distance is given in inches, when using the walk_x or walk_y utility commands. If you would prefer to use millimeter units, see the walk_mmx, walk_mmy commands instead.

The walk_x and walk_y movements are relative to the current position (not absolute), and are NOT checked versus the current carriage position for sane range of motion. Use caution: They can easily run the NextDraw past its safe range of motion.

Walk movements are "out of band" movements; they can provide a means of offsetting the XY position of the NextDraw carriage before starting a plot or an interactive session. This creates a "Local Origin" that acts as the zero for the plot, and to which the carriage will return to at the end of the plot.

This ability to offset the origin may occasionally provide utility in plot setup, testing, and calibration routines.

After using "walk" movements, and before plotting, you may wish to return the NextDraw carriage to the Home corner. Alternately, you can use the walk_home utility command to move the carriage back to the Global Origin and "reset" the Local Origin to the same position as the Global Origin.

Please note that these "walk" commands are not meant as a substitute for full motion control. Use the Interactive context if you need a full range of direct XY motion commands.

walk_mmx, walk_mmy

utility_cmd: walk_mmx, walk_mmy

Example 1: Move the carriage 1 mm in the y direction (one millimeter forward and away from Home):

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_mmy"
nd1.options.dist = 1.0
nd1.plot_run()

Example 2: Move the carriage 2.0 inches (5.08 mm) in the +x direction, and then back:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_mmx"
nd1.options.dist = 50.8
nd1.plot_run()
nd1.options.dist = -50.8
nd1.plot_run()

Example 3: Move the carriage in a square, 10.0 cm on a side, with different speeds for each side of movement:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_mmx"
nd1.options.dist = 100
nd1.plot_run()
nd1.options.utility_cmd = "walk_mmy"
nd1.options.dist = 100
nd1.plot_run()
nd1.options.utility_cmd = "walk_mmx"
nd1.options.dist = -100
nd1.plot_run()
nd1.options.utility_cmd = "walk_mmy"
nd1.options.dist = -100
nd1.plot_run()

Utility commands: Walk the carriage in the X or Y direction, mm units

Syntax: options.utility_cmd = "walk_mmx"

Syntax: options.utility_cmd = "walk_mmy"

These two "walk" commands will move the NextDraw carriage by a distance in millimeters given by the value of the dist option, along one axis or the other.

The dist option has a default value of 1.0. This distance is given in millimeters, when using the walk_mmx or walk_mmy utility commands. If you would prefer to use inch units, see the walk_x, walk_y commands instead.

The walk_mmx and walk_mmy movements are relative to the current position (not absolute), and are NOT checked versus the current carriage position for sane range of motion. Use caution: They can easily run the NextDraw past its safe range of motion.

Walk movements are "out of band" movements; they can provide a means of offsetting the XY position of the NextDraw carriage before starting a plot or an interactive session. This creates a "Local Origin" that acts as the zero for the plot, and to which the carriage will return to at the end of the plot.

This ability to offset the origin may occasionally provide utility in plot setup, testing, and calibration routines.

After using "walk" movements, and before plotting, you may wish to return the NextDraw carriage to the Home corner. Alternately, you can use the walk_home utility command to move the carriage back to the Global Origin and "reset" the Local Origin to the same position as the Global Origin.

Please note that these "walk" commands are not meant as a substitute for full motion control. Use the Interactive context if you need a full range of direct XY motion commands.

walk_home

utility_cmd: walk_home

Example 1: Make 20 random moves each in X and Y, each in the range 0-2 mm, using walk_mmx and walk_mmy, and then return Home with walk_home, even though we're not directly keeping track of the position.

import random
from nextdraw import NextDraw
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"

for x in range(20):
    nd1.options.utility_cmd = "walk_mmx"
    nd1.options.dist = 2 * random.random()
    nd1.plot_run()
    nd1.options.utility_cmd = "walk_mmy"
    nd1.options.dist = 2 * random.random()
    nd1.plot_run()

nd1.options.utility_cmd = "walk_home"
nd1.plot_run()

Example 2: Walk the carriage Home (more precisely, to the position where the motors were first enabled), if it ended up in some other position when a plot was stopped.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_home"
nd1.plot_run()

Utility command: Walk the carriage back to its origin

Syntax: options.utility_cmd = "walk_home"

The walk_home utility command is a special "walk" type command that moves the carriage to the Global Origin.

The Global Origin is the position where the motors are first enabled (when using manual homing) or in the physical Home position of the machine (when using automatic homing). The Global Origin can then be set to a different location by using the set_home utility command.

Thus, the walk_home command normally returns the carriage to the Home position. But, if the motors were initially enabled in some different position (and automatic homing is not enabled), this command will instead return the machine to that other position. And, if set_home was used to locate the Global Origin elsewhere, then walk_home will return the carriage to that location.

This command can be used to reset the NextDraw carriage position — moving it back to Home — after one or more of the other "walk" commands. Using walk_home clears any offsets applied with the "walk" commands, and resets the temporary "Local Origin" that the "walk" commands can create back to be the same as the Global Origin.

A common use for walk_home is to return the NextDraw to the Home position, for example after pausing a plot that will not be resumed.

Note that changing the motor resolution (for example, by changing the handling mode) will generally count as "re-enabling" the motors with the new resolution, and may alter the position that walk_home will return to.

set_home

utility_cmd: set_home

Example: Use walk commands to offset the NextDraw by (20, 0) mm from the Home position, and then call set_home to mark that position as the Global Origin. Test it by moving further off by (20, 10), and then return to (20, 0) by using walk_home

import time
from nextdraw import NextDraw
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_mmx"
nd1.options.dist = 20 
nd1.plot_run()        # Move to (20,0)
nd1.options.utility_cmd = "set_home"
nd1.plot_run()        # Mark position as Origin
nd1.options.utility_cmd = "walk_mmx"
nd1.options.dist = 20 
nd1.plot_run()        # Move further in X
nd1.options.utility_cmd = "walk_mmy"
nd1.options.dist = 10 
nd1.plot_run()        # Move further in Y
nd1.options.utility_cmd = "walk_home"
nd1.plot_run()        # Walk to new Origin

Utility command: Set current position as Global Origin

Syntax: options.utility_cmd = "set_home"

The set_home utility command sets the current carriage position as the Global Origin, which is to say, it sets the current position as the position that the walk_home utility command returns to.

In detail, set_home performs the following actions:

Because the home position is reset whenever the motors are re-enabled, using set_home has no effect in practice when there is no power to the pair of stepper motors that controls the XY position of the NextDraw carriage.

enable_xy, disable_xy

utility_cmd: enable_xy, disable_xy

Example 1: Enable the XY stepper motors:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "enable_xy"
nd1.plot_run()

Example 2: Disable the XY stepper motors:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "disable_xy"
nd1.plot_run()

Utility commands: Enable or Disable the XY motors

Syntax: options.utility_cmd = "enable_xy"

Syntax: options.utility_cmd = "disable_xy"

These two commands turn on or turn off, respectively, power to the pair of stepper motors that controls the XY position of the NextDraw carriage.

Stepper motor power is off by default at power up. It is often useful to turn off power to the XY motors so that the carriage can be manually moved to the home corner, prior to plotting.

res_read

utility_cmd: res_read

Example: Read pause position from file.svg. Also populate variable "resume_position" with that distance.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "utility"
nd1.options.utility_cmd = "res_read"
nd1.plot_run()
resume_position = nd1.res_dist
print(f"resume_position : {resume_position:.3f} mm")

Typical response, with a file paused at 200 mm of pen-down travel:

Plot was paused after 200.000 mm (7.874 inches) of pen-down travel.
resume_position : 200.000 mm

Typical responses, for a file that finished plotting normally:

No in-progress plot data found in file.
To set up the plot to be resumed at a given point, add an offset.
resume_position : 0.000 mm

Typical response, with a file that has had its resume position adjusted:

Plot was originally paused after 200.000 mm (7.874 inches) of
pen-down travel. The resume position was then adjusted to
225.400 mm (8.874 inches).
resume_position : 225.400 mm

Utility command: Read position where a paused plot will resume

Syntax: options.utility_cmd = "res_read"

When a plot is paused, the progress through the file is saved in the SVG document so that the plot may be resumed later with res_plot mode. The res_read utility command reads the SVG and reports that progress as human-readable text.

Plot progress is measured as the total path length of pen-down movement from the beginning of the plot to where it was paused. One may adjust that distance, so it is more proper to say that it measures the pen-down distance from the beginning of the plot to the point where the NextDraw would resume plotting with res_plot mode.

The "beginning of the plot" refers to the first vertex of the first plottable object in the SVG document. (Exactly what that object is depends on which optimizations are applied and, for example, whether the plot was started in Layers mode.)

The "beginning of the plot" still refers to the first plottable object, even when a plot is resumed with res_plot mode; it is not the position from which the plot was resumed. For example, if a plot were paused after plotting paths with a total arc length of 250 mm, and then resumed and paused again after drawing another 100 mm, res_plot would report a value of 350 mm.

In addition to printing the resume position, running this utility command with plot_run() also creates a Python variable, res_dist that contains the resume position in millimeters.

The resume position can be adjusted with the res_adj_in and res_adj_mm commands. See the res_plot mode description for further discussion of pause-and-resume methods when using this API.

res_adj_in, res_adj_mm

utility_cmd: res_adj_in, res_adj_mm

Example 1: Adjust resume position from file.svg, such that when resumed it would start 20 mm before its pause position. Also populate variable "resume_position" with that new distance.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "utility"
nd1.options.utility_cmd = "res_adj_mm"
nd1.options.dist = -20
output_svg = nd1.plot_run(True)  
resume_position = nd1.res_dist
print(f"New resume_position : {resume_position:.3f} mm")

Typical response, with a file paused at 200 mm of pen-down travel:

Plot was paused after 200.000 mm of pen-down travel.
After adding a new offset of -20.000 mm, the resume position
    is now set at 180.000 mm.
New resume_position : 180.000 mm

Example 2: Configure a document to begin printing (when used with res_plot mode) after 12.5 inches of pen-down distance.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "utility"
nd1.options.utility_cmd = "res_adj_in"
nd1.options.dist = 12.5
output_svg = nd1.plot_run(True)  
resume_position = nd1.res_dist
print(f"New resume_position : {resume_position:.3f} mm")

Typical response, with a file that was not initially paused:

This document was configured to start plotting at the beginning
of the file. After adding a new offset of 12.500 inches, the
resume position is now set at 12.500 inches.
New resume_position : 317.500 mm

Utility commands: Adjust resume position of paused plot

Syntax: options.utility_cmd = "res_adj_in"

Syntax: options.utility_cmd = "res_adj_mm"

These two commands adjust the position where a paused plot will resume, by a distance given by the value of the dist option and units selected by choosing either res_adj_in or res_adj_mm. See the res_read command description for how to read the existing resume position and for an extended discussion of what that position means.

The dist option has a default value of 1.0 and can be positive or negative. Its value, in units of inches when using res_adj_in, and in millimeters when using res_adj_mm, is added to the the current resume position to produce the new position.

If the new resume position is less than or equal to zero, it will reset to zero (the beginning of the plot), where res_plot mode cannot "resume" the plot. The resume position can also be set to a distance longer than the total pen-down length of the plot. In that case, res_plot mode can be run, but nothing will print (since the resume point is after the end of the plot).

If an SVG document does not have any in-progress plot saved, it is possible to use res_adj_in or res_adj_mm to add an offset from zero, and then start a plot at that position using res_plot. This provides a means of starting a plot partway through, even if it did not begin as a paused plot.

As with res_read, running the res_adj_in or res_adj_mm utility command with plot_run() creates a Python variable, res_dist that contains the new resume position in millimeters.

strip_data

utility_cmd: strip_data

Example: Strip NextDraw data from file.svg and save the resulting SVG as a string in a variable named output_svg:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "utility"
nd1.options.utility_cmd = "strip_data"
output_svg = nd1.plot_run(True)  

Utility command: Strip plotter and preview data from SVG file

Syntax: options.utility_cmd = "strip_data"

When you collect the output SVG returned by plot_run, the NextDraw software stores certain configuration data within that SVG. This data includes the setup data necessary for resuming a file that was paused or otherwise stopped while printing, as well as any rendered previews.

While this data does not typically cause any issues, the strip_data utility command can strip that data from the file, should that need arise.

In detail, strip_data removes:

In practice this command no effect unless an output file is specified.

list_names

utility_cmd: list_names

Example. List connected NextDraw units:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "list_names"
nd1.plot_run()
nextdraw_list = nd1.name_list

Typical response (with two connected NextDraw units, on Mac):

East
/dev/cu.usbmodem1441

Typical response (with two connected NextDraw units, on Windows):

East
COM4

Utility command: List connected NextDraw units

Syntax: options.utility_cmd = "list_names"

List connected NextDraw units, by USB "nickname" or by their USB port enumeration. NextDraw or AxiDraw machines may have a USB "nickname" assigned to them.

This list of connected units does not indicate whether or not an NextDraw is presently busy with another task; it simply lists each unit that is detected by your computer's USB interface.

In addition to printing the list of names, running this utility command with plot_run() also creates a Python list variable, name_list that contains the names.

See documentation for read_name and write_name below for more about NextDraw naming.

read_name

utility_cmd: read_name

Example: Read the USB Nickname from a single connected NextDraw:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "read_name"
nd1.plot_run() 

Typical response:

NextDraw nickname: NextDraw 16

Utility command: Read NextDraw USB Nickname

Syntax: options.utility_cmd = "read_name"

The read_name option is for reading an assigned USB "nickname." A nickname may be assigned to a given NextDraw or AxiDraw machine. Nicknames are not required, but may be helpful when operating more than one NextDraw: You can specify the given machine by name. (See the port option for additional information.)

When reading the name, it may be helpful to disconnect all NextDraw units other than that one, so that you can be sure of which NextDraw you are communicating with. Alternately, you can use an identifying action (say, toggling the pen) to identify which unit you are communicating with, or specify a port option.

write_name

utility_cmd: write_name

Example 1: Write a USB Nickname ("NextDraw 17") to a single connected NextDraw:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "write_nameNextDraw 17"
nd1.plot_run() 

Typical response:

Nickname written. Rebooting EBB.

Example 2: Clear the USB Nickname from the NextDraw nicknamed "NextDraw 17":

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.port = "NextDraw 17"
nd1.options.mode = "utility"
nd1.options.utility_cmd = "write_name"
nd1.plot_run() 

Utility command: Write NextDraw USB Nickname

Syntax: options.utility_cmd = "write_name[NICKNAME]"

The write_name command is for assigning a USB "nickname". A nickname may be assigned to a given NextDraw or AxiDraw machine. Nicknames are not required, but may be helpful when operating more than one NextDraw: You can specify the given machine by name. (See the port option for additional information.)

When writing the name, it may be helpful to disconnect all NextDraw units other than that one, so that you can be sure of which NextDraw you are communicating with. Alternately, you can use an identifying action (say, toggling the pen) to identify which unit you are communicating with, or specify a port option.

When using write_name, the name itself is specified by concatenating the name with the write_name option. For example as write_nameNorth to assign the nickname "North". The name may be up to 16 characters long. Using a nickname of at least 3 characters is recommended. Writing an empty string (with nothing following write_name) will clear the nickname. In cases where the name has a space, use quotation marks to enclose the combined command, as in "write_nameNextDraw 17".

Assigned Nicknames are semi-permanent; they will persist when power is cycled, but can be overwritten by this command, (or other utilities that assign a nickname), and will be erased (reset to default) if you should run a firmware update at some point in the future.

Since the nickname is stored in a certain flash memory cell that can only be written a limited number of times, avoid applications that involve automated, repeated changes to the nickname tag.

bootload

utility_cmd: bootload

Example: Put the NextDraw into bootloader mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "bootload"
nd1.plot_run()

Utility command: Enter EBB Bootloader Mode

Syntax: options.utility_cmd = "bootload"

This command will put the NextDraw's EBB control board into bootloader mode. This is a special mode that is sometimes used as part of the process of updating the EBB firmware. This command is not used in any part of normal NextDraw operation.

Bootloader mode may be identified by a particular rhythmic blinking of LEDs on the control board. If you should accidentally enter bootloader mode, disconnect the NextDraw from both USB and power and then connect them again.

dist

dist

Example 1: Move the carriage 1.5 inches in the +x direction:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "utility"
nd1.options.utility_cmd = "walk_x"
nd1.options.dist = 1.5
nd1.plot_run()

Example 2: Adjust resume position from file.svg, such that when resumed it would start 20 mm before its pause position.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "utility"
nd1.options.utility_cmd = "res_adj_mm"
nd1.options.dist = -20
output_svg = nd1.plot_run(True)

Distance for Walk and Adjust Resume Position utility commands

Syntax: options.dist = value

The dist option provides the amount of distance for utility mode commands, when the command specified by utility_cmd requires a distance input. The value of dist is a floating point number that may be positive or negative. Its default value is 1.0.

The units of the distance given by dist are selected by choosing a specific utility command. The distance is in millimeters for utility commands walk_mmx or walk_mmy and for the res_adj_mm command to adjust resume position. The distance is in inches for utility commands walk_x or walk_y and for the res_adj_in command to adjust resume position.

Values of dist should be chosen with care, since no limit checking is performed. This is especially true with the "walk" commands, which are relative to the current position (not absolute), and are NOT checked for safe range of motion. These are fully manual commands, and can easily run the NextDraw past its safe range of motion.

Allowed values: Floating point numbers (not limit checked).

Default: 1.0, set in nextdraw_conf.py

layer

layer

Example: Plot only layers with layer name beginning with "3":

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.mode = "layers"
nd1.options.layer = 3
nd1.plot_run()

Select layer(s) to plot when in layers mode

Syntax: options.layer = value

Specify a number which indicates which layer (or layers) will be plotted when plotting in layers mode.

Normally, when plot mode is selected, we plot paths from all layers. You can also choose to plot a single layer or group of layers, for example to plot only a single color of ink.

Plotting in layers mode, with a given layer specified by this option will plot only layers whose names begin with the selected number. While only a single integer value may be given for layer, that value may match with multiple layer names, so that any number of layers may be selected for plotting.

For example, suppose that your file has layers with the following names:

Then, if a layer value of 5 is given in layers mode, the two layers named "5-red" and "5 Outlines" will be plotted, while the layers named "guide lines", "55", and "2 black" will be skipped.

Allowed values: Integers from 1 to 1000.

Default: 1, given by default_Layer in nextdraw_conf.py

copies

copies

Example 1: Plot a file two times, using default options:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.copies = 2
nd1.plot_run()

Example 2: Plot a file continuously (until pause button pressed):

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.copies = 0
nd1.plot_run()

Example 3: Plot a file 25 times, with a 5 s delay between each plot:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.copies = 25
nd1.options.page_delay = 5
nd1.plot_run()

Number of copies to plot

Syntax: options.copies = value

If copies has a value other than 0, then a plot that is started in plot mode or layers mode will be plotted that number of times. This option has no effect in modes other than plot or layers.

An optional delay may be chosen between subsequent plots (e.g., for changing paper) with the page_delay option.

A value of 0 copies is a special value that will begin plotting a continuous sequence of copies, without a scheduled end. The sequence will continue until the physical pause button is pressed, unless the file itself specifies a pause through NextDraw Layer Control.

A set of plots in progress can be canceled at any time by pressing the physical pause button on the NextDraw. If a plot is active when the button is pressed, it will stop at that location in the usual way (saving progress in the output file, if an output file is specified). If the pause button is pressed while at home waiting between copies, then it simply exits without plotting any additional copies and without an error message.

Allowed values: Integers from 0 to 9999.

Default: 1, set in nextdraw_conf.py

page_delay

page_delay

Example 1: Plot a file 2 times, with a 5 s delay between plots

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.copies = 2
nd1.options.page_delay = 5
nd1.plot_run()

Example 2: Plot continuously, with a 30 s delay between each plot:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.copies = 0
nd1.options.page_delay = 30
nd1.plot_run()

Delay between copies

Syntax: options.page_delay = value

When plotting multiple copies, specify the delay in seconds between subsequent plots.

This value is used to specify the time interval that the NextDraw dwells at the home position between subsequent layer or document plots, when plotting multiple copies. See the description of copies for more information.

Allowed values: Non-negative numbers.

Default: 15; set in nextdraw_conf.py

auto_rotate

auto_rotate

Example 1: Plot a file, with auto_rotate disabled:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.auto_rotate = False
nd1.plot_run()

Enable auto-rotate

Syntax: options.auto_rotate = value

Disable auto-rotate; preserve plot orientation.

By default "auto rotate" is enabled: If the SVG file being plotted has a page size that is taller than it is wide, then it will print in landscape mode rather than portrait mode.

Auto-rotate may be disabled by setting the auto_rotate option to False. If auto_rotate is disabled, plot orientation will be preserved, which may result in clipping of the artwork to the available plot area.

Allowed values: True, False.

Default: True; set in nextdraw_conf.py

preview

preview

Example 1: Do not plot a file, but report how long it will take to plot.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.preview = True
nd1.options.report_time = True
nd1.plot_run()

Example 2: Preview a file, generating a rendered preview of all motion, making use of the rendering option to generate output SVG as "output_svg" that could be saved as an SVG file

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.preview = True
nd1.options.rendering = True
output_svg = nd1.plot_run(True)

Plot Preview

Syntax: options.preview = value

Plot Preview is an offline simulation mode where the serial port is not used, and the NextDraw does not move. This can be useful for one or more of the following reasons:

Since it is an offline simulation, it can be used even without an NextDraw present.

Note that the Plot Preview can be used in combination with other modes. If enabled, no serial communication will be attempted, so certain operations (e.g., raise pen) will neither function nor produce an error.

If Plot Preview is enabled, then it can also produce graphical output if both an appropriate value of the rendering option is chosen and an output file is generated. Rendered previews can be removed from an SVG file with the strip_data utility command.

Allowed values: True, False.

Default: False, set in nextdraw_conf.py

rendering

rendering

Example 1: Preview a file, generating a rendered preview of motion. Note that the preview and rendering options both default to True, and thus we do not need to set them explicitly.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
output_svg = nd1.plot_run(True)

Example 2: Preview a file, without generating a rendered preview:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.preview = False
nd1.options.rendering = False
output_svg = nd1.plot_run(True)

Enable preview rendering

Syntax: options.rendering = value

When plotting with Plot Preview --preview (-v) enabled and with an output file (--output_file or -o) specified, the default behavior is that a rendered preview of the plot, showing pen-up and pen-down motion, will be added to the output SVG file. That can be disabled with the rendering option.

This option is only applicable to the three modes which parse and plot the SVG document: plot (default), layers, and res_plot. Further, it only has an effect when Plot Preview is enabled.

When a preview is rendered, that preview is added to the output SVG document, in a special "documentation" layer that will not be plotted. (For more information about documentation layers, please see the NextDraw Layer Control documentation.)

The preview layer has sub-layers for showing the pen-up and/or pen-down movement of the carriage, depending which are generated. The rendering style option selects which of these (if any) are rendered.

Rendered previews can be removed from an SVG file with the strip_data utility command.

Allowed values: True, False.

Default: True, set in nextdraw_conf.py

reordering

reordering

Example 1: Plot an SVG file (file.svg), reordering for speed including allowing path reversal prior to plotting.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.reordering = 2
nd1.plot_run()

Example 2: Preview how an SVG file (file.svg) will plot with basic optimization, reordering elements for speed but preserving their directions. SVG objects in the output SVG will be preserved in their original order.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.preview = True
nd1.options.rendering = True
nd1.options.reordering = 1
output_svg = nd1.plot_run(True)

Specify level of plot optimization

Syntax: options.reordering = value

When so selected with the reordering option, a plot optimization tool is used to re-order elements in the input SVG prior to plotting or rendering a preview. By changing the order and (optionally) direction of paths, the plot duration can be lowered by reducing the amount of pen-up travel required during the plot.

The reordering option is only applicable in the Plot context, and only when in the modes that parse and plot the SVG document: plot (default), layers, and res_plot.

Normal order of plotting

Normally and by default, each path within a SVG document is plotted (with one exception) in the same order and in the same direction as it appears in the document. This order is generally the order in which the objects were created. In a graphical vector editor like Inkscape, newer objects are drawn on top of older ones; a "lower" object is one that appears earlier in the document.

The exception is that if one path ends very close to where another begins (and if those paths are not separated by layers), then those two paths are normally joined together, skipping an unnecessary pen lift. The maximum gap that can be joined is given by the min_gap parameter in the nextdraw_conf.py configuration file.

The default option, which generally respects the original document order, is often preferable, for example in handwriting-like applications, where you may wish the writing to be in the same order that a person would write the words, e.g. right-to-left, top-to-bottom on the page.

How reordering works

When you plot an SVG document, the following operations occur:

  1. A temporary copy of the SVG document is made.
  2. Graphical elements like circles and rectangles are rendered into paths.
  3. The document is separated by layers.
  4. Within each layer:
    • All groups, sub-layers, and compound paths are broken apart.
    • Paths are joined together if one starts where another ends.
    • The paths are re-ordered for speed.
  5. The document is plotted (or the preview is rendered).
  6. The document is reverted to the temporary copy.
  7. If rendering a preview, the preview paths are added to the document.

Path sorting uses a "greedy" algorithm, a suboptimal but relatively fast approach. Depending on the nature of the SVG document, it can reduce the pen-up travel distance by 50-90% and reduce the plotting time by 30-50%. Potential time savings should be weighed against the execution time of the sort, which may be considerable for documents with a great number of separate objects. In most cases reordering adds only a few seconds before plotting starts and results in a significant overall time savings.

If path reversal is allowed, then:

If path reversal is not allowed, then every path will be plotted in the same direction as it occurs in the document, even if that results in a slower plot.

You may find it helpful to run plots with preview, rendering, and/or report_time enabled. With those tools, you can visualize the effect that optimization has with different values of reordering and estimate the plot duration on documents that have and have not been sorted.

Re-ordering is by layer

The optimization tool is layer-aware: All objects will be left on their original layers. That makes it safe to use on multicolor plots where colors are separated by layers.

An SVG document without layers can still be optimized. The document root, the set of elements that are not in layers, is re-ordered as though it is a single layer.

If the SVG contains elements in document root that are separated by layers, each set of elements that is not separated by layers is treated as a virtual layer for the purposes of reordering.

Changes to the document are not saved

The changes to the order of elements in the SVG document are ephemeral and only made to the temporary copy. If you save an output SVG, the objects in that output SVG will retain their original order.

For example, if your SVG document has deeply nested groups, you can plot it with the reordering of 2, but if you save the output SVG, it will retain your original grouping.

Values of the reordering option

Allowed values: Integers 0 to 4:

The reordering values of 0 and 4 are identical except that the "strict" value of 4 also disables path joining. Path joining may be disabled separately via the min_gap parameter.

Default: 0 (Plot in original order, connecting adjoining paths to reduce unnecessary pen lifts), given by reordering in nextdraw_conf.py

random_start

random_start

Example: Plot a file, randomizing the start position of closed shapes within that file:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.random_start = True
nd1.plot_run()

Randomize start positions of closed paths

Syntax: options.random_start = True

Randomize start locations of closed paths.

By default, this option is disabled, and the NextDraw will draw closed paths in the direction that they are given in the file (or possibly, the reverse of that, depending on the reordering option).

A pen may form a visible mark at the location where it is lowered or raised. In artwork where the same closed shape is repeated many times, that can cause a seam-like visual artifact if many of those marks line up at matching points on the repeated shapes.

With the random_start option, the start position of closed paths — paths where the start points and end points are coincident — will be randomized, which can help to hide that specific type of visual artifact.

This feature may be enabled by setting random_start equal to True.

Allowed values: True, False.

Default: False, set in nextdraw_conf.py

hiding

hiding

Example: Plot a file, using hidden-line removal:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.hiding = True
nd1.plot_run()

Enable hidden-line removal

Syntax: options.hiding = True

By default, this option is disabled, and the NextDraw will draw all paths (or objects that can be directly represented as paths) in the SVG document. All fill and stroke (outline) properties of individual objects are ignored. Phrased differently, All paths are normally plotted as though there is a stroke along the path and no fill.

When the hiding option is enabled, the NextDraw software will instead plot paths (or not) based (1) on their fill and stroke properties and (2) whether or not they are occluded behind other objects. An object that does not have a stroke property (e.g., no outline in Inkscape) will not plot, nor will one hidden behind a solid fill. Typically, when working with documents that include filled regions, this means that the NextDraw output will visually resemble the original SVG artwork more closely. In cases of ambiguity, consider running Plot Preview (preview) with rendering enabled in order to understand how the document is processed.

There are two important drawbacks to bear in mind. First, the hiding option requires additional processing time before plotting, especially in instances with large numbers of objects to process. Second, hidden-line removal does not preserve the orientation of individual SVG strokes. We generally recommend using the reordering option, with "full" reordering ( options.reordering = 2) to orient the output paths for efficient plotting.

In cases where the processing time becomes large, or when processing repeatedly might be needed (as in, when a document might be paused and resumed during the plotting process), it may be convenient to instead process the document once, separately, using the digest option.

This feature may be enabled by setting hiding equal to True.

Allowed values: True, False.

Default: False, set in nextdraw_conf.py

report_time

report_time

Example 1: Plot a file and report time elapsed:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.report_time = True
nd1.plot_run()

Example 2: Preview a file and read out variables giving time and distance:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.report_time = True
nd1.options.preview = True
nd1.plot_run()
time_elapsed = nd1.time_elapsed
time_estimate = nd1.time_estimate 
dist_pen_down = nd1.distance_pendown
dist_pen_total = nd1.distance_total
pen_lifts = nd1.pen_lifts

Report time and distance

Syntax: options.report_time = value

Report time and distance plotted after each plot finishes.

By default, this option is disabled. Enabling it will print a report of time and distance travelled after each plot finishes. Using this feature in combination with Plot Preview (preview) can provide you with a time estimate of each plot, without requiring the use of the NextDraw.

Note also that this option is only applicable to the three modes which parse and plot the SVG document: plot (default), layers, and res_plot.

When resuming a plot with res_plot mode, please be aware that the distances reported will reflect the pen-down distance since the beginning of the document, rather than since the plot resumed. (Distances are calculated this way, using the total pen-down distance through the document, to ensure that a plot can be paused and resumed, even if started in res_plot mode.)

Whether or not report_time is enabled, calling plot_run() in an applicable mode will also populate five numeric Python variables that can be accessed from within a script:

Variable Meaning
time_elapsed Elapsed time (s)
time_estimate Estimated time (s)
distance_pendown Distance traveled with the pen down, m
distance_total Distance traveled, total, m.
pen_lifts Number of pen lifts

Both time variables are in units of seconds. The execution time of the plot_run() command is given by time_elapsed. This may be only a fraction of a second when running small documents with Plot Preview enabled, or lengthy when plotting documents. The estimated duration of the plot when working with Plot Preview enabled is given by time_estimate. When plotting a document (with Plot Preview not enabled), the value of time_estimate is equal to time_elapsed.

Both distance variables are in units of meters. The total distance traveled by the NextDraw Carriage is given by distance_total, including pen-up and pen-down travel. The distance of pen-down travel alone is given by distance_pendown.

The pen_lifts value reports the number of times that the pen was lifted during the plot.

The report_time option may be enabled by setting report_time equal to True.

Allowed values: True, False.

Default: False, set in nextdraw_conf.py

digest

digest

Example 1: Plot a file, returning the "Plob" plot digest instead of the full SVG:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.digest = 1
output_plob = nd1.plot_run(True)

Example 2: Do not plot the document. Instead, generate the "Plob" plot digest only:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.digest = 2
output_plob = nd1.plot_run(True)

Plot digest output option

Syntax: options.digest = value

When a digest value greater than 0 is chosen, plot_run(True) will not return the (lightly modified) input SVG, but instead a "plot digest object", or Plob. A Plob is a restricted-format subset of SVG that the NextDraw software "digests" the file into before plotting.

In detail, the Plob is a new file generated from the input SVG after:

Generating the Plob is destructive; any SVG shapes such as rectangles or original paths that were present in the original SVG document will not be present in the Plob output. Keep a copy of your original SVG document.

A Plob file may be used as the input to the NextDraw software, just like any other SVG input. Plotting a Plob prepared for the same NextDraw model allows the NextDraw software to skip all of the steps above and immediately begin plotting the document. Note however, that once generated, the Plob file cannot be modified at all, or it will no longer be recognized as a valid Plob file. (Two exceptions: Pause/resume data and plot preview updates are permitted modifications.)

If a plot underway is paused while the digest option is enabled, the output Plob will include plot progress data for resuming the plot, just as a regular SVG would. Partial plots -- those paused while plotting or that resume plotting in the middle of the document -- still contain the entire Plob including the parts that are not printed in those situations.

The digest option may be helpful in a variety of situations, including but not limited to:

If a digest value of 1 is chosen, plot_run(True) will return an output Plob instead of the full SVG, but no other changes occur. Plots and plot previews will proceed normally.

A digest value of 2 overrides most software functions, to only generate the Plob and perform no other function. (Internally, it sets preview to True and disables running previews and time estimates.) Using this option minimizes the total time for Plob generation, as there is no need to wait for a plot or preview to finish.

Allowed values: Integers from 0 to 2:

Default: 0 (Disabled), set in nextdraw_conf.py

webhook

webhook

Example: Plot a file and generate a webhook notification, to a specific URL when the plot finishes.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.webhook = True
nd1.options.webhook_url = "https://url.to.post.to/"
nd1.plot_run()

Enable webhook alerts

Syntax: options.webhook = value

If the webhook option is enabled and an URL is provided via the webhook_url option, then the software will post to that URL when a plot completes.

This feature can be used in combination with various services including ntfy and other well known ones like IFTTT and Zapier, to provide various forms of notifications such as email alerts, mobile alerts, or integration with other hardware or software.

When enabled, webhook alerts are only generated when a plot finishes (or is paused) and all three of these conditions are met:

  1. When actually plotting to the NextDraw (not in preview mode),
  2. In a mode that plots a document: plot (default), layers, or res_plot, and
  3. An URL is provided via the webhook_url option.

The data posted to the URL is JSON formatted and contains the following key/value pairs:

Key Value
value1 Document name
value2 Elapsed time
value3 Port (if provided)

The "Port" value here is taken from the port option. If you are operating multiple named NextDraw machines, this value can be used to indicate which machine has completed a plot.

Allowed values: True, False.

Default: False, set in nextdraw_conf.py

webhook_url

webhook_url

Example: Plot a file and generate a webhook notification, to a specific URL when the plot finishes.

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
nd1.options.webhook = True
nd1.options.webhook_url = "https://url.to.post.to/"
nd1.plot_run()

URL for webhook alerts

Syntax: options.webhook_url = value

The URL to post data to, if the webhook option is enabled.

The webhook option has no effect unless a URL is also provided, via this option.

An extended discussion about webhooks, including instructions for setting up mobile/online notifications, is available in section "6.7 Notifications settings" of the Bantam Tools NextDraw User Guide.

Default: None, set in nextdraw_conf.py

Options (Interactive)

One option, units, applies only in the Interactive context, within a Python script.

units

units

Example: Move to different positions, given in inch and cm units:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():            # Open serial port to NextDraw
    quit()
nd1.moveto(1, 1)                 # Pen-up move to (1, 1) inch
nd1.options.units = 1            # set working units to cm.
nd1.update()                     # Process changes to options 
nd1.line(5.08, 5.08)             # Relative line of (2, 2) inches
nd1.moveto(0,0)                  # Pen-up move, back to origin.
nd1.disconnect()                 # Close serial port to NextDraw

Plot units

Syntax: options.units = value

Set the units for movement commands given in the Interactive context. If you change the units after calling connect(), use the update() method to process that change before calling additional motion commands.

The units option cannot presently be set in a configuration file.

Allowed values: Integers from 0 to 2:

Default: 0 (inches; not adjustable).

Additional parameters

Additional parameters

One or more parameters may be specified with the following syntax:

params.parameter_name = value

Example 1: Use the "skip_voltage_check" parameter to disable monitoring of the NextDraw's input power level. This example will suppress the warning about low voltage level if you run this snippet with input power disconnected from the machine.

from nextdraw import NextDraw 
nd1 = NextDraw()                  # create class instance "nd1"
nd1.plot_setup("file.svg")
nd1.params.skip_voltage_check = True     # Disable check of motor input power
nd1.plot_run()

Example 2: Read out boolean parameter for whether clipping to page is enabled.

Also enabling digital output pin B3 to be high (on) when the pen is down, using the special "use_b3_out" parameter.

from nextdraw import NextDraw       # import module
nd1 = NextDraw()              # Initialize class
nd1.interactive()                    # Enter interactive context
clipping = nd1.params.clip_to_page   # Read "clip_to_page" parameter value
nd1.params.use_b3_out = True         # enable digital output B3.
if not nd1.connect():             # Open serial port to NextDraw;
    quit()                          #   Exit, if no connection.
nd1.moveto(1, 1)                     # Pen-up move
nd1.lineto(0, 0)                     # Pen-down move back to origin
nd1.disconnect()                     # Close serial port to NextDraw

As a supplement to the many options detailed above, there are additional parameters available in the nextdraw_conf.py configuration file that are not normally adjusted in the course of typical applications.

For any parameter that has a default value defined in the nextdraw_conf.py configuration file and that does not have an option name defined above, you can set that parameter value in analogy with the params syntax examples given here. You can also read the value of any parameter, as though it were any other Python variable.

For your reference, an example configuration file can be in the API download at:
examples_config/nextdraw_conf_copy.py

Many of the default parameter values (such as travel limits) have carefully chosen values. In cases where you need to override parameters, proceed with caution, since the potential exists for behavior and/or damage of an unpredictable nature. You are welcome to contact technical support for situation-specific advice.

Python variables

Python variables

Example 1: Print the software version string

from nextdraw import NextDraw 
nd1 = NextDraw()                # create class instance "nd1"
print(f"NextDraw software version: {nd1.version_string}")

Certain accessible (public) variables are provided by the NextDraw() class, and can be read as needed by your script that uses the class. Different variables are populated and available under different circumstances.

Variable Meaning
version_string Software version string
connected True if connected.
fw_version_string Firmware version string
nickname Nickname of the connected machine, if any
time_elapsed Time elapsed in plot_run()
time_estimate Estimated total time of a plot
distance_pendown Real or estimated pen-down distance
distance_total Real or estimated distance moved
pen_lifts Real or estimated count of pen lifts
res_dist Resume position
name_list List of connected machines

version_string is a string containing the software version number. It is available as soon as the NextDraw() class instance is created (and thus, in either the Plot context or Interactive context).

connected is available in the Interactive context. It is True when there is an active connection to the machine and False otherwise.

fw_version_string and nickname are available in both the Plot context and Interactive context. In the Plot context, they are available after plot_run(), and in the Interactive context they are available after connect().

time_elapsed, time_estimate, distance_pendown, distance_total, and pen_lifts are populated by plot_run() in the Plot context. They are discussed in the report_time section.

res_dist is populated when using the res_read, res_adj_in, or res_adj_mm utility commands, which are available in the Plot context. See the description of res_read for more information.

And, name_list is populated when using the list_names utility command, which is available in the Plot context.

Error handling

Error handling

Example 1: Plot a file, raising RunTime error on failure to connect, pause button press, loss of connection, or keyboard interrupt

from nextdraw import NextDraw 
nd1 = NextDraw()              # create class instance "nd1"
nd1.plot_setup("file.svg")

nd1.keyboard_pause = True            # Enable keyboard interrupt to pause plot

nd1.errors.connect = True        # Raise error on failure to connect
nd1.errors.button = True         # Raise error on pause button press
nd1.errors.keyboard = True       # Raise error on keyboard interrupt
nd1.errors.disconnect = True     # Raise error on loss of connection
try:
    nd1.plot_run()
except RuntimeError:
    print(f"plot failed with error {nd1.errors.code}")

Example 2: Plot a file without raising extra runtime errors, but checking for an error code after plot_run returns:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
output_svg = nd1.plot_run(True)
if nd1.errors.code == 102:
    print("plot paused by button press.")

This API allows you to configure whether or not certain error conditions will raise a Python error. Some actions — such as calling an interactive movement function before connecting to the NextDraw — will always raise a RuntimeError. However, one may prefer to raise an error or not raise an error when (e.g.,) the pause button is pressed in the middle of a plot.

The following four variables are available, and can be set True to cause the API to raise a RuntimeError when the given condition is met. If you do set them, do so before plot_run() in the Plot context or connect() in the Interactive context.

Variable Raise error:
errors.connect On failure to connect (default: False)
errors.button When pause button is pressed (default: False)
errors.keyboard On keyboard interrupt (if enabled) (default: False)
errors.disconnect On loss of USB connection (default: False)
errors.power On loss of power (default: False)
errors.homing On homing failure (default: False)

It is important to note that raising one of these errors may halt execution of the current function, which can prevent functions including plot_run(True) from returning data and thus hindering the ability to resume a plot.

It may be preferable to allow the function to terminate normally, collecting and saving its return data, and then to query the variable errors.code which can indicate these same error conditions:

errors.code value Meaning
0 No error; operation nominal
101 Failed to connect
102 Stopped by pause button press
103 Stopped by keyboard interrupt (if enabled)
104 Lost USB connectivity
105 Lost power
106 Homing failed

Keyboard interrupts

While Python scripts can typically be stopped by a Control+C keyboard operation, resulting in a KeyboardInterrupt error, a more graceful interrupt can be enabled by setting the keyboard_pause variable to True. If keyboard_pause is set to True in your script, then a Control+C keyboard interrupt will stop a plot much in the same way that pressing the pause button will, potentially allowing the plot to be resumed later. Alternately, it can be caused to raise a RuntimeError if errors.keyboard is set also set to True.

This approach is particularly useful for working with multi-threaded python scripts, as one can simulate a keyboard interrupt, and in doing so, programmatically initiate a pause event that gracefully ends a plot.

keyboard_pause is False by default. If you wish to set it True, do so prior to plot_run() in the Plot context or connect() in the Interactive context.

Functions: General

One function, load_config(), is available within both the Plot and Interactive context.

load_config

load_config()

Example 1: Loading settings from a file, and use the Interactive context

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.load_config("nextdraw_conf_copy.py")
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(1, 1)                 # Move to (1, 1) inch
nd1.lineto(3.5, 1)               # Line to (3.5, 1) inch
nd1.moveto(0, 0)                 # Raise pen, return home
nd1.disconnect()                 # Close serial port

Example 2: Plot a file, using settings from a configuration file

from nextdraw import NextDraw   
nd1 = NextDraw()
nd1.plot_setup("NextDraw_trivial.svg")
nd1.load_config("nextdraw_conf_copy.py")
nd1.plot_run()

Load settings from NextDraw configuration file

Syntax: load_config(file name or path)

The load_config function reads an NextDraw configuration file and applies the settings within that file. The configuration file argument to the function ("file name or path") is required. It can be either the name of the configuration file or the path to the file. The function can be called in either the Plot or Interactive context; use plot_setup() or interactive() before calling load_config().

It is never necessary to use the load_config function. All options and parameters can be set directly within your Python script using the normal syntax to specify options along with the params syntax. However, load_config() does provide a method of separating settings out from the script, which can be helpful when working with multiple sets of options, or to ensure a uniform method for setting options when also working with the NextDraw CLI.

An example configuration file can be in the API download at: examples_config/nextdraw_conf_copy.py

You can duplicate, move, rename, and edit this file as needed, though you should keep the ".py" file extension. You may wish to use different configuration files to have quick settings ready for (for example) draft versus final plotting speeds, different size NextDraw models, different paper size limits, which particular NextDraw unit to plot to, or previewing without plotting. Configuration files do not need to be as complex as the example file; it is perfectly reasonable to use a configuration file that specifies even just a single option value.

Functions: Plot

This is the Python function reference for the functions available within the Plot context. These functions do not apply in the Interactive context.

Each function will be described individually, after the list.

Function Description
plot_setup() Parse SVG file and initialize Plot context.
plot_run() Perform the specified Plot context action.

plot_setup

plot_setup()

Example: Plot a file until it is paused (by button press or by NextDraw Layer Control). Wait 5 seconds. Then, resume plotting.

import time
from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
output_svg = nd1.plot_run(True)
time.sleep(5)
nd1.plot_setup(output_svg)
nd1.options.mode = "res_plot"
output_svg = nd1.plot_run(True)

Initialize Plot context and Parse SVG input

Syntax: plot_setup(svg_input=None)

The plot_setup function parses the input SVG and initializes the various configuration option variables. Calling this function configures the software into the Plot context. This function must be called before setting the values of any configuration option variables.

The SVG file argument to the function ("svg_input") is optional. If provided, it may be the name or path of an SVG file (which will be opened and parsed) or it may be a string that contains the contents of an SVG file. The example shown illustrates calling plot_setup with both an SVG file as input as well as a string containing the contents of an SVG file.

If it is called without a file name argument, as plot_setup() or plot_setup(None), then the Plot context will still be initialized but it will not have an SVG file available to plot. This approach can be helpful when using modes that do not plot the file ( cycle, align, utility, sysinfo, version) since no file need be provided. Execution of these utility modes may also be faster (particularly versus large SVG inputs), since the input file will not be parsed.

plot_run

plot_run()

Example 1: Cycle the pen down then up, using "cycle" mode:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup()
nd1.options.mode = "cycle"
nd1.plot_run()

Example 2: Plot file.svg and capture the output as output_svg:

from nextdraw import NextDraw 
nd1 = NextDraw()
nd1.plot_setup("file.svg")
output_svg = nd1.plot_run(True)

Perform the action that is configured within Plot context

Syntax: plot_run(output=False)

This function performs the action (plotting or otherwise) as set by the configuration variables that you have specified. Broadly speaking, this is the function that "runs the NextDraw software" when working in the Plot context.

By default, no output is returned by this function. If you would like to generate SVG output, call plot_run(True), for example as: output_svg = nd1.plot_run(True)

The output that is returned is a normally an output string consisting of the serialized contents of an SVG file. The output SVG contains the same SVG drawing that it accepted as input, but may also have plot progress saved in the file, or a rendered preview contained within it. You may choose to save this output SVG as an SVG file. (In addition to this full SVG output, the digest option also provides a way to return a limited "plot digest object" instead.)

If the Plot context was initialized without an input SVG file (using plot_setup() or plot_setup(None)), then the output returned will be an "empty" SVG placeholder file.

If the digest option is enabled, any SVG returned will be in the restricted "Plob" digest format. The digest option can also disable plots and previews entirely.

Functions: Interactive

This is the Python function reference for the functions available within the Interactive context. These functions do not apply in the Plot context.

Each function will be described individually, after the list.

Function Description
interactive() Initialize Interactive context.
connect() Open serial connection to NextDraw.
disconnect() Close serial connection to NextDraw.
update() Apply changes to options.
goto() Absolute move to (x,y) location.
moveto() Absolute pen-up move to (x,y) location.
lineto() Absolute pen-down move to (x,y) location.
go() Relative move of distance (Δx,Δy).
move() Relative pen-up move of (Δx,Δy).
line() Relative pen-down move of (Δx,Δy).
penup() Raise the pen.
pendown() Lower the pen.
draw_path() Draw a path defined by a coordinate list.
delay() Execute a hardware-timed delay.
block() Wait for all motion commands to complete.
current_pos() Query machine XY position.
turtle_pos() Query turtle XY position.
current_pen() Query if machine pen state is up.
turtle_pen() Query if turtle pen state is up.
usb_command() Low-level serial command.
usb_query() Low-level serial query.

interactive

interactive()

Example: Draw a single line in Interactive context, using absolute moves:

from nextdraw import NextDraw   # import module
nd1 = NextDraw()                # Initialize class
nd1.interactive()                # Enter interactive context
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(1, 1)                 # Pen-up move to (1,1) inches
nd1.lineto(2, 1)                 # Pen-down move, to (2,1) inches
nd1.moveto(0, 0)                 # Pen-up move, back to origin
nd1.disconnect()                 # Close serial port to NextDraw

Initialize Interactive context

Syntax: interactive()

The interactive() function configures the software into the Interactive context. This function must be called before setting the the values of any configuration option variables within Interactive context.

connect

connect()

Example 1: Draw a single line in Interactive context using relative moves, with a pen-down speed of 20%:

from nextdraw import NextDraw  
nd1 = NextDraw()
nd1.interactive()
nd1.options.speed_pendown = 20
connected = nd1.connect()
if not connected:
    quit()
nd1.move(1, 1)
nd1.line(1, 1)
nd1.move(-2, -2)  # Pen-up move back to origin
nd1.disconnect()

Example 2: The same, but using the "connected" variable to check for a connection:

from nextdraw import NextDraw  
nd1 = NextDraw()
nd1.interactive()
nd1.options.speed_pendown = 20
nd1.connect()
if not nd1.connected:
    quit()
nd1.move(1, 1)
nd1.line(1, 1)
nd1.move(-2, -2)  # Pen-up move back to origin
nd1.disconnect()

Open serial connection to NextDraw

Syntax: connect()

The nature of an Interactive context session is that you directly specify not only every individual movement, but also when the session begins and ends. The connect() function a USB serial connection to the NextDraw. It also applies any option values that you have set after calling interactive(). The port must be closed with the disconnect() function at the end of your session.

Most functions in the interactive API, including all motion commands, will raise an error if they are called before connect() or when there is otherwise not an active connection to the NextDraw hardware. The connect() function returns either True or False, respectively, if it successfully connected or did not. A variable, connected, is also set to True upon a successful connection. Disconnecting via disconnect() as well as certain errors in USB communication will set connected to False. You can poll this variable to check if the connection appears to be active.

In addition to opening the USB connection, connect() is also used to process and apply any plot options that you wish to set. If you wish to change one or more options after calling connect(), use the update() method to process the changes to the options before calling additional motion commands.

In detail, connect() does the following:

Options that specify the USB port or its behavior (port or port_config) must be specified before (not after) opening the port with connect().

Since connect() performs automatic homing, when automatic homing is enabled, best practice is to set the model -- and if you wish to disable automatic homing to do so -- before calling connect().

disconnect

disconnect()

Example: Open and close an interactive connection to NextDraw:

from nextdraw import NextDraw  
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.disconnect()

Close serial connection to NextDraw

Syntax: disconnect()

The disconnect() function closes a serial connection to NextDraw that was opened with the connect() function. It also sets the connected variable to False.

update

update()

Example: Use update() to apply changes to options after connect():

from nextdraw import NextDraw  # import module
nd1 = NextDraw()               # Initialize class
nd1.interactive()              # Enter interactive context
if not nd1.connect():          # Open serial port to NextDraw;
    quit()                     #   Exit, if no connection.
nd1.moveto(1, 1)               # Pen-up move to (1, 1) inch
nd1.options.units = 1          # set working units to cm.
nd1.options.speed_pendown = 10 # set pen-down speed to 10%
nd1.update()                   # Process changes to options 
nd1.move(5.08, 5.08)           # Relative move: (5.08, 5.08) cm
nd1.moveto(0,0)                # Pen-up move, back to origin.
nd1.disconnect()               # Close serial port to NextDraw

Apply changes to options, within Interactive context

Syntax: update()

Plot options may be specified at any point after the interactive() call. Options given before connect() will be applied by connect().

If, however, you change one or more options after calling connect(), you must use the update() method to process and apply those changes before calling additional motion commands. Changing options and using motion commands before calling update() may lead to undefined behavior.

Note that options which select the USB port or a particular NextDraw (port or port_config) must be specified before opening the port with connect(); they cannot be adjusted once the port is already open, even by update().

goto

goto()

Example: Draw a square using goto() for absolute position moves, in combination with penup() and pendown() commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.speed_pendown = 50   # set pen-down speed to 50%
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.goto(1, 1)                   # Move to (1, 1) inch
nd1.pendown()                    # Lower pen
nd1.goto(3.5, 1)                 # Move to (3.5, 1) inch
nd1.goto(3.5, 3.5)               # Move to (3.5, 3.5) inch
nd1.goto(1, 3.5)                 # Move to (1, 3.5) inch
nd1.goto(1, 1)                   # Move to (1, 1) inch
nd1.penup()                      # Raise pen
nd1.goto(0, 0)                   # Move to Home (0, 0)
nd1.disconnect()                 # Close serial port

Absolute move to (x,y) location

Syntax: goto(final_x, final_y)

The goto(x,y) command is an absolute move command, that moves the carriage to the final XY position that you have specified. In combination with setting options and using penup() and pendown(), it is sufficient to provide essentially any type of movement that is required.

The arguments to goto() are floating point numbers that represent the movement destination position. The units are in inches, unless specified otherwise with the units option. In most cases both arguments should be non-negative, since all allowed positions are in the (positive,positive) quadrant with respect to the Home position.

The limits of travel are given by the hardware model, as specified with the model option. Limit checking assumes that the session has been started with the NextDraw carriage located at the Home position.

Relative movement commands can be used together with absolute movement commands as needed.

moveto

moveto()

Example: Draw a square using moveto() and lineto() absolute position movement commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.speed_pendown = 50   # set pen-down speed to 50%
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(1, 1)                 # Move to (1, 1) inch
nd1.lineto(3.5, 1)               # Move to (3.5, 1) inch
nd1.lineto(3.5, 3.5)
nd1.lineto(1, 3.5)
nd1.lineto(1, 1)
nd1.moveto(0, 0)                 # Raise pen, return home
nd1.disconnect()                 # Close serial port

Absolute pen-up move to (x,y) location

Syntax: moveto(final_x, final_y)

The moveto(x,y) command is an absolute move command, that performs a pen-up movement of the carriage to the final XY position that you have specified. In combination with setting options and using the lineto() function, it is sufficient to provide essentially any type of movement that is required.

The function works by raising the pen (if it is not already raised) and then performing a goto() movement to the given position.

The arguments to moveto() are floating point numbers that represent the movement destination position. The units are in inches, unless specified otherwise with the units option. In most cases both arguments should be non-negative, since all allowed positions are in the (positive,positive) quadrant with respect to the Home position.

The limits of travel are given by the hardware model, as specified with the model option. Limit checking assumes that the session has been started with the NextDraw carriage located at the Home position.

lineto

lineto()

Example: Draw a square using moveto() and lineto() absolute position movement commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(1, 1)                 # Move to (1, 1) inch
nd1.lineto(3.5, 1)               # Move to (3.5, 1) inch
nd1.lineto(3.5, 3.5)
nd1.lineto(1, 3.5)
nd1.lineto(1, 1)
nd1.moveto(0, 0)                  # Raise pen, return home
nd1.disconnect()                 # Close serial port

Absolute pen-down move to (x,y) location

Syntax: lineto(final_x, final_y)

The lineto(x,y) command is an absolute move command, that performs a pen-down movement of the carriage to the final XY position that you have specified. In combination with setting options and using the moveto() function, it is sufficient to provide essentially any type of movement that is required.

The function works by lowering the pen (if it is not already lowered) and then performing a goto() movement to the given position.

The arguments to lineto() are floating point numbers that represent the movement destination position. The units are in inches, unless specified otherwise with the units option. In most cases both arguments should be non-negative, since all allowed positions are in the (positive,positive) quadrant with respect to the Home position.

The limits of travel are given by the hardware model, as specified with the model option. Limit checking assumes that the session has been started with the NextDraw carriage located at the Home position.

go

go()

Example: Draw a square using go() for relative position moves, in combination with penup() and pendown() commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.speed_pendown = 50   # set pen-down speed to 50%
if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.go(1, 1)                     # Move to (1, 1) inch
nd1.pendown()                    # Lower pen
nd1.go(2.5, 0)                   # Ends up at (3.5, 1) inch
nd1.go(0, 2.5)                   # Ends up at (3.5, 3.5) inch
nd1.go(-2.5, 0)                  # Ends up at (1, 3.5) inch
nd1.go(0, -2.5)                  # Ends up at (1, 1) inch
nd1.penup()                      # Raise pen
nd1.go(-1, -1)                   # Move to Home position
nd1.disconnect()                 # Close serial port

Relative move by (x,y) with respect to current location

Syntax: go(delta_x, delta_y)

The go(x,y) command is a relative move command, that moves the carriage by the distances that you have specified. In combination with setting options and using penup() and pendown(), it is sufficient to provide essentially any type of movement that is required.

The arguments to go() are floating point numbers that represent the movement distances. The units are in inches, unless specified otherwise with the units option.

The limits of travel are given by the hardware model, as specified with the model option. Limit checking assumes that the session has been started with the NextDraw carriage located at the Home position.

Relative movement commands can be used together with absolute movement commands as needed.

move

move()

Example: Draw a square using move() and line() relative position movement commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():     # Open serial port to NextDraw;
    quit()                  #   Exit, if no connection.
nd1.move(1, 1)               # Move to (1, 1) inch
nd1.line(2.5, 0)             # Lower pen, move to (3.5, 1) inch
nd1.line(0, 2.5)             # Move to (3.5, 3.5) inch
nd1.line(-2.5, 0)            # Move to (1, 3.5) inch
nd1.line(0, -2.5)            # Move to (1, 1) inch
nd1.move(-1, -1)             # Raise pen, return home
nd1.disconnect()             # Close serial port

Relative pen-up move by (x,y) with respect to current location

Syntax: move(delta_x, delta_y)

The move(x,y) command is a relative move command, that performs a pen-up movement of the carriage by the distances that you have specified. In combination with setting options and using the line() function, it is sufficient to provide essentially any type of movement that is required.

The function works by raising the pen (if it is not already raised) and then performing a go() movement with the given distances

The arguments to move() are floating point numbers that represent the movement distances. The units are in inches, unless specified otherwise with the units option.

The limits of travel are given by the hardware model, as specified with the model option. Limit checking assumes that the session has been started with the NextDraw carriage located at the Home position.

line

line()

Example: Draw a square using move() and line() relative position movement commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():     # Open serial port to NextDraw;
    quit()                  #   Exit, if no connection.
nd1.move(1, 1)               # Move to (1, 1) inch
nd1.line(2.5, 0)             # Lower pen, move to (3.5, 1) inch
nd1.line(0, 2.5)             # Move to (3.5, 3.5) inch
nd1.line(-2.5, 0)            # Move to (1, 3.5) inch
nd1.line(0, -2.5)            # Move to (1, 1) inch
nd1.move(-1, -1)             # Raise pen, return home
nd1.disconnect()             # Close serial port

Relative pen-down move by (x,y) with respect to current location

Syntax: line(delta_x, delta_y)

The line(x,y) command is a relative move command, that performs a pen-up movement of the carriage by the distances that you have specified. In combination with setting options and using the move() function, it is sufficient to provide essentially any type of movement that is required.

The function works by raising the pen (if it is not already raised) and then performing a go() movement with the given distances

The arguments to line() are floating point numbers that represent the movement distances. The units are in inches, unless specified otherwise with the units option.

The limits of travel are given by the hardware model, as specified with the model option. Limit checking assumes that the session has been started with the NextDraw carriage located at the Home position.

penup

penup()

Example: Draw a line using go() and goto() for movement, in combination with penup() and pendown() commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.pen_pos_down = 20    # Set some options
nd1.options.pen_pos_up = 80
nd1.options.pen_rate_raise = 90
nd1.options.accel = 80

if not nd1.connect():         # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.goto(1, 1)                   # Move to (1, 1) inch
nd1.pendown()                    # Lower pen
nd1.go(2.5, 2.5)                 # Move by (2.5, 2.5) inch
nd1.penup()                      # Raise pen
nd1.goto(0, 0)                   # Move to Home position
nd1.disconnect()                 # Close serial port

Raise the pen

Syntax: penup()

The penup() command is a command to raise the pen while in Interactive context. It is particularly useful in combination with the go() and goto() commands, which cause movements but do not raise or lower the pen.

Note that, penup() will only raise the pen if it was in the down state or an indeterminate state. It will not be raised if it was already in the pen-up state.

pendown

pendown()

Example: Draw some lines using mixed movement commands, in combination with penup() and pendown() commands in the Interactive context.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():       # Open serial port to NextDraw;
    quit()                 #   Exit, if no connection.
nd1.moveto(1, 1)            # Pen-up move to (1, 1) inch
nd1.pendown()               # Lower pen
nd1.go(2.5, -1)             # Move by (2.5, -1) inch
nd1.penup()                 # Raise pen
nd1.go(0, 3)                # Move by (0, 3) inch
nd1.lineto(0, 0)            # Pen-down move to home corner
nd1.penup()                 # Raise pen
nd1.disconnect()            # Close serial port

Lower the pen

Syntax: pendown()

The pendown() command is a command to lower the pen while in Interactive context. It is particularly useful in combination with the go() and goto() commands, which cause movements but do not raise or lower the pen.

By default, whenever the "turtle" (theoretical) XY position is outside of the travel limits, (1) the physical XY position is clipped to remain within those limits, and (2) the pen is kept lifted. Accordingly, if pendown() is called while the pen is outside of travel limits, the turtle pen (theoretical pen) will be lowered, but the pen will not physically be lowered.

(So long as the turtle pen remains down, any turtle motion that brings the turtle into bounds will cause the pen to be lowered at the position where the turtle and physical pen enters the bounds.)

The theoretical and physical pen states can be read with the current_pen and turtle_pen functions.

Automatic pen lifts at the bounds of travel and the limitation against physically lowering the pen while motion is clipped may be disabled by setting auto_clip_lift = False in the config file or via params.

Note that pendown() will only lower the pen if it was in the up state or an indeterminate state. It will not be lowered if it was already in the pen-down state.

draw_path

draw_path()

Example 1: Draw a square using draw_path(), with explicitly given vertices:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():            # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(1, 1)                 # Pen-up move to (1, 1) inch
nd1.options.units = 1            # Switch to cm units
nd1.update()                     # Process changes to options
# Make a list of points to draw a square, 1 cm on a side:
points = [[2, 2], [3, 2], [3, 3], [2, 3], [2, 2]]
nd1.draw_path(points)            # Plot the path
nd1.moveto(0, 0)                 # Return Home
nd1.disconnect()                 # Close serial port

Example 2: Draw a sine wave, 100 mm wide, using draw_path():

import math
from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.units = 2        # Set mm units
if not nd1.connect():        # Open serial port to NextDraw;
    quit()                  #   Exit, if no connection.

# Make a list of points to draw a square, 1 cm on a side:
vertices = []
for vertex in range(1000):
    x_position = vertex/10
    y_position = 25 + 10 * math.sin(math.tau * vertex / 100)
    vertices.append([x_position, y_position])
nd1.draw_path(vertices)      # Plot the path
nd1.moveto(0, 0)             # Return Home
nd1.disconnect()             # Close serial port

Draw a path from a list of vertices

Syntax: draw_path(vertex_list)

The draw_path() command is a command to plot a continuous pen-down shape within the Interactive context. It allows one to compose a coordinate list within a python script and then have the NextDraw draw the resulting, potentially complex, path.

The argument vertex_list is a python list of (at least two) 2-element lists, where each 2-element list [x_position, y_position] represents an (x, y) coordinate pair. The units of the coordinates can be set with the units option.

When called, draw_path() executes the following actions:

If the input path exceeds the travel bounds, only the portion within travel bounds will be drawn. If the path leaves the travel bounds and re-enters, then multiple pen-down paths will be created from that, with automatic pen-up moves between them. If the initial vertex is outside of the travel bounds, the first pen-up move will be to the point where the path enters the travel bounds. And, if the last coordinate is out of bounds, the final turtle position will be that of the last vertex in the input path, and different from the current_pos.

Please note that the auto_clip_lift parameter that can disable automatic pen lits on individual XY motion commands is ignored by draw_path(). draw_path() always clips paths and raises the pen at the travel bounds.

The interactive_draw_path.py example script contains additional examples of using draw_path().

delay

delay()

Example: Draw two line segments, separated by a 2.5 second interval:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()

if not nd1.connect():            # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.goto(1, 1)                   # Move to (1, 1) inch
nd1.pendown()                    # Lower pen
nd1.go(1, 1)                     # Move by (1, 1) inch
nd1.delay(2500)                  # Wait 2.5 seconds
nd1.go(1, 1)                     # Move by (1, 1) inch
nd1.penup()                      # Raise pen
nd1.goto(0, 0)                   # Move to Home position
nd1.disconnect()                 # Close serial port

Execute a hardware-timed delay

Syntax: delay(time_ms)

The delay() command is a command to execute a hardware-timed delay while in Interactive context. It effectively calls for a movement command that lasts time_ms milliseconds, but where the total movement distance is zero.

The delay() command is different from (e.g.,) the sleep command in Python in that the time delay is queued with other motion control commands and executed by the NextDraw's EBB control board. It can be used to insert a delay between motion commands that would otherwise be adjoining.

block

block()

Example: Use block() to ensure that motion is complete before reading step position:

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():            # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.goto(1, 1)                   # Move to (1, 1) inch
nd1.pendown()                    # Lower pen
nd1.go(1, 1)                     # Move by (1, 1) inch
nd1.delay(2500)                  # Wait 2.5 seconds
nd1.block()                      # Wait until delay is complete
step_pos = nd1.usb_query("QS\r") # Query step position
print("Step pos: " + step_pos)
nd1.penup()                      # Raise pen
nd1.goto(0, 0)                   # Move to Home position
nd1.disconnect()                 # Close serial port

Wait for all motion commands to complete

Syntax: block()

The block command polls the NextDraw to determine if any motion commands are currently executing or queued to execute. If so, it checks again, every 50 ms, until all existing motion commands are completed, and then returns.

Standard Interactive context motion commands are typically made of relatively short motion segments that are automatically queued, and the block command isn't necessary or helpful in most common use cases. However, in certain circumstances, such as when using low-level usb commands or sequencing external equipment, block() may be helpful to ensure that no motion commands are executing at some point in the script.

current_pos

current_pos()

Example: Move to two different positions, reporting turtle and physical position after each move. The first position (2,1) is in bounds, so the turtle and physical position agree. The second position (2,-1) is out of bounds. The new turtle position is (2,-1), but physical motion is clipped at (2,0) to remain within the bounds of motion.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():            # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(2, 1)                 # Pen-up move to (2, 1) inch
xy = nd1.turtle_pos()            # Query turtle position
print(f"Turtle XY position: {xy[0]:f}, {xy[1]:f}")
xy = nd1.current_pos()           # Query current position
print(f"Physical XY position: {xy[0]:f}, {xy[1]:f}")

nd1.moveto(2,-1)                 # Pen-up move to (2,-1) inch
xy = nd1.turtle_pos()            # Query turtle position
print(f"Turtle XY position: {xy[0]:f}, {xy[1]:f}")
xy = nd1.current_pos()           # Query current position
print(f"Physical XY position: {xy[0]:f}, {xy[1]:f}")

nd1.disconnect()                 # Close serial port

Query the last-known machine position

Syntax: current_pos()

The current_pos() function queries and reports the last known XY machine position.

The function returns a 2-element tuple, giving the last-known (x,y) machine position. Position values are given in the currently active units, as set by the units option. If you do not explicitly set units, the function returns values in the default inch units.

Plotter travel is clipped to remain within the bounds of travel, and the physical machine position will not agree with the "turtle" position, if a movement outside of bounds is requested. See turtle_pos to query the current turtle position.

For the physical up or down state of the pen, use the current_pen function.

turtle_pos

turtle_pos()

Example: Move to two different positions, reporting turtle and physical position after each move. The first position (2,1) is in bounds, so the turtle and physical position agree. The second position (2,-1) is out of bounds. The new turtle position is (2,-1), but physical motion is clipped at (2,0) to remain within the bounds of motion.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():            # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(2, 1)                 # Pen-up move to (2, 1) inch
xy = nd1.turtle_pos()            # Query turtle position
print(f"Turtle XY position: {xy[0]:f}, {xy[1]:f}")
xy = nd1.current_pos()           # Query current position
print(f"Physical XY position: {xy[0]:f}, {xy[1]:f}")

nd1.moveto(2, -1)                # Pen-up move to (2, -1) inch
xy = nd1.turtle_pos()            # Query turtle position
print(f"Turtle XY position: {xy[0]:f}, {xy[1]:f}")
xy = nd1.current_pos()           # Query current position
print(f"Physical XY position: {xy[0]:f}, {xy[1]:f}")

nd1.disconnect()                 # Close serial port

Query the last-known turtle XY position

Syntax: turtle_pos()

The turtle_pos() function queries and reports the last known XY "turtle" position. The turtle is a theoretical device that represents the requested pen position. It is repositioned by the various Interactive mode motion commands but not constrained or clipped by any hardware travel limits.

The returned value is a 2-element tuple, giving the last-known (x,y) turtle position. Position values are given in the currently active units, as set by the units option. If you do not explicitly set units, the function returns values in the default inch units.

Plotter travel is clipped to remain within the bounds of travel, and the physical machine position will not agree with the "turtle" position, if a movement outside of bounds is requested. See current_pos to query the current machine position.

For the theoretical up or down state of the pen, use the turtle_pen function.

current_pen, turtle_pen

current_pen(), turtle_pen()

Example: Command four pen-down lines to be drawn, from (5, 5) to (5, 3), (5, 1), (5, 1), and (5, -3), reporting turtle and physical position and pen state after each move. The first two lines, to (5, 3) and (5, 1) are normal moves within travel limits. The third line is clipped at position (5, 0), and the physical pen pen is raised there. The fourth line is entirely out of bounds, and no movement is made. The turtle and physical positions (both XY and pen state) agree so long as the turtle is within bounds.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
nd1.options.units = 1                # Set units to cm
if not nd1.connect():                # Open serial port to NextDraw;
    quit()                          #   Exit, if no connection.

nd1.moveto(5, 5)                     # Pen-up absolute move to (5, 5) cm.

for _rep in range(0, 4):            # Repeat four times:
    nd1.line(0, -2)                  # Pen-down move by -2 cm in Y

    xy = nd1.turtle_pos()            # Query turtle position
    print(f"Turtle   XY position: {xy[0]:f}, {xy[1]:f}")
    xy = nd1.current_pos()           # Query machine position
    print(f"Physical XY position: {xy[0]:f}, {xy[1]:f}")

    pen_up = nd1.turtle_pen()        # Query turtle pen state
    print("Turtle   pen up: " + str(pen_up))
    pen_up = nd1.current_pen()       # Query machine pen state
    print("Physical pen up: " + str(pen_up))

nd1.moveto(0, 0)                     # return home
nd1.disconnect()                     # Close serial port to NextDraw

Query if physical pen state is up, Query if turtle pen state is up

Syntax: current_pen()

Syntax: turtle_pen()

The current_pen() function queries and reports the physical pen state, with True representing pen up and False representing pen down. The turtle_pen() function queries and reports the theoretical or "turtle" pen state, with True representing pen up and False representing pen down.

In addition to general use, these functions may be particularly helpful when motion exceeds the configured bounds of travel. Plotter travel is clipped to remain within the bounds of travel. If travel outside of those limits is commanded, then the physical machine position (including pen state) will differ from the theoretical, or "turtle" position. (See the description of turtle_pen for more about the turtle.)

By default, whenever the turtle is outside of the travel bounds (whenever the motion is clipped at its limits), the pen is physically raised and kept up, even if the turtle is still configured in the pen-down state.

Thus, it may be useful to query the actual pen state with current_pen(), as well as the theoretical pen state with turtle_pen().

The physical pen will remain in the pen up state until the turtle is brought back within bounds. If necessary, an automatic pen-up movement will be added to move the pen to the place where the turtle begins its next pen-down travel within bounds.

Automatic pen lifts at the bounds of travel may be overridden by setting auto_clip_lift = False in the config file or via params.

usb_command, usb_query

usb_command(), usb_query()

Example: Enter interactive context, move using moveto(). Query and print internal hardware step position, and return home using the firmware HM command.

from nextdraw import NextDraw
nd1 = NextDraw()
nd1.interactive()
if not nd1.connect():            # Open serial port to NextDraw;
    quit()                      #   Exit, if no connection.
nd1.moveto(2, 1)                 # Pen-up move to (2, 1) inch
step_pos = nd1.usb_query("QS") # Query step position
print("Step pos: " + step_pos)
nd1.usb_command("HM,3200")     # Return home at 3200 steps/s
nd1.disconnect()                 # Close serial port

Issue a low-level command or query over USB

Syntax: usb_command(command)

Syntax: usb_query(query)

The usb_command() function allows you to issue a direct command to the NextDraw's EBB driver board over USB while in Interactive context. The matching usb_query() function can be used for various types of queries.

While these two "raw USB" serial interface functions are powerful, they also present certain hazards. They essentially bypass all syntax and context checking, as well as the software counters, speed, position, and limit checks that otherwise ensure safe and reliable operation.

To be perfectly clear: We recommend against using usb_command and usb_query except in cases where you need access to features of the command set that are not otherwise accessible through this API. When using them, proceed with caution, since the potential exists for behavior and/or damage of an unpredictable nature. You are welcome to contact technical support for situation-specific advice.

The command or query argument is a string formatted in accordance with the EBB serial command set, documented here. Note that the NextDraw software uses the "future syntax mode", and not the "legacy syntax mode". Results returned by usb_query are stripped of leading and trailing whitespace using the python .strip() method.

Migrating from AxiDraw API

If you are updating from the AxiDraw CLI or Python API, please see our separate documentation on migrating from AxiDraw APIs.

API Changelog

Revision Notes: Summary of changes affecting API.

The changelog.txt file included with the download includes additional details.

v 1.5 (2025-07)

Bug fix and compatibility update.

Archived release here.

v 1.4 (2025-03)

Change to homing behavior: If any of the Walk Carriage commands (walk_x, walk_y, walk_mmx, walk_mmy, walk_home) are used when both (1) automatic homing is enabled and (2) the carriage has not already been homed, the automatic homing sequence will run before executing that command.

Updates to how manual homing, and XY offsets, can be used to offset the "local origin" when starting a plot, to better match the behavior specified in this documentation.

New set_home utility command added.

Remove support for python 3.8, add support for Python 3.13. Python versions 3.9 - 3.13 are currently supported. (Python 3.8 end of life was on 2024-10-07.)

Archived release here.

v 1.3 (2024-07)

NextDraw Layer Control now supports different optimization levels by layer.

Archived release 1.3.0 here.

Bug fix update 1.3.2 (October 2024)here

v 1.1 (2024-06)

Initial public release of this software. As of this release, Python versions 3.8 - 3.12 are currently supported.

Archived release here.

Copyright

Documentation Copyright 2025 Windell H. Oskay, Bantam Tools. All rights reserved.