Zaber Launcher Tutorials
Zaber Motion Library
Sample Projects
Virtual DeviceDropdown icon
About3D Viewer
AccountDropdown icon
Sign InSign Up
Zaber Motion LibraryGetting Started
How-to Guides
Communication
Controlling multiple devicesFinding the right serial port nameImproving performance of X-USBDC (FTDI)Interaction with Zaber LauncherTCP/IP (network) communication
Library Features
Arbitrary unit conversionsError handlingEventsG-CodeNon-blocking (simultaneous) axis movementSaving and loading stateSending arbitrary commands
Device Features
Device I/OLockstepOscilloscopePosition Velocity Time (PVT)PVT Sequence GenerationSettingsStreamed movementTriggersWarning flags
Product-Specific APIs
MicroscopeProcess controllerVirtual devices
Advanced
Building a Standalone Application with MATLAB CompilerBuilding the C++ Library from Source CodeCustom transportsDevice databaseLoggingMATLAB Migration GuidePackaging Your Program with PyinstallerThread safety
API ReferenceSupportBinary Protocol (Legacy)
© 2026 Zaber Technologies Inc.

G-Code

Our G-Code API provides a way to use G-Codes to control Zaber devices. The library interprets the codes and outputs Zaber ASCII protocol stream commands. You can review the usage of Streams in this article and the stream commands in the protocol manual.

This article assumes a basic understanding of G-Code. For example, Linux CNC offers a great reference.

Basic Usage

Starting with basic G-Code translation is easy.

Python
MATLAB (legacy)
# from zaber_motion.gcode import Translator

stream = device.streams.get_stream(1)
stream.setup_live(1, 2)

translator = Translator.setup(stream)

translator.translate("G28")
translator.translate("G0 X100")
translator.translate("G0 Y100")
translator.translate("G0 X0 Y0")

translator.flush()
stream.disable()
% import zaber.motion.gcode.Translator;

stream = device.getStreams().getStream(1);
stream.setupLive(1, 2);

translator = Translator.setup(stream);

translator.translate("G28");
translator.translate("G0 X100");
translator.translate("G0 Y100");
translator.translate("G0 X0 Y0");

translator.flush();
stream.disable();

First, you need to set up a live stream over the designated axes. Then, set up an instance of the Translator class over the stream. Afterward, you can start translating G-Code by calling the translate method. The device may not start moving immediately after calling

translate

because the instructions are buffered in the library for optimization. Additionally, the movements are also queued in the device to allow for smooth motion. To ensure that the library sends all the movements, call the flush method. The method also waits for the device to finish all the queued movements. At the end, we should call the disabled method to release the axes from the stream.

The translate method also returns a the TranslateResult data class instance. The instance contains generated commands as well as warnings produced during translation. The warnings can be useful in determining ignored or unknown instructions.

Python
MATLAB (legacy)
result = translator.translate("G28 G999")
print(result)
# {'_commands': ['on a b line abs 0 0'],
# '_warnings': [{'_message': 'Unknown command G999.', '_from_block': 4, '_to_block': 8}]}
result = translator.translate("G28 G999");
fprintf('Command: %s\n', result.getCommands());
fprintf('Warning: %s\n', result.getWarnings());
% Command: set maxspeed 630000
% Command: line abs 0
% Warning: TranslateMessage { message: Unknown command G999., fromBlock: 4, toBlock: 8 }

Additionally the translation can throw the GCodeSyntaxException and the

GCodeExecutionException

exceptions containing details of what went wrong.

Configuration

The translator's setup method takes additional argument for configuring the translator.

Python
MATLAB (legacy)
translator = Translator.setup(stream, TranslatorConfig(
  axis_mappings=[
    AxisMapping('X', axis_index=1),
    AxisMapping('Y', axis_index=0)
  ],
  axis_transformations=[
    AxisTransformation("X", scaling=-1),
    AxisTransformation("Y", translation=Measurement(20, Units.LENGTH_MILLIMETRES)),
  ],
))
axisMappings = [AxisMapping("X", 1), AxisMapping("Y", 0)];
axisTransformationX = AxisTransformation("X", java.lang.Double(-1), []);
axisTransformationY = AxisTransformation("Y", java.lang.Double(1), Measurement(20, Units.LENGTH_MILLIMETRES));
axisTransformations = [axisTransformationX, axisTransformationY];
translatorConfig = TranslatorConfig(axisMappings, axisTransformations);
translator = Translator.setup(stream, translatorConfig);

You can use the configuration to remap translator axes or transform the coordinates of an axis. For example, you can invert the axis by specifying scaling=-1 or offset it by 20 mm by specifying translation.

Coordinate Systems

The translator support 9 coordinate system: G54-G59 and G59.1-G59.3. You can set coordinate system offset by programming G10 L2 P? where P? is the coordinate system number (G54 is P1). You can also retrieve currently used coordinate system or an offset of axis in a given coordinate system. See the example below.

Python
MATLAB (legacy)
translator.translate("G10 L2 P3 X200 Y50") # set up offset for G56
translator.translate("G56") # select G56
print(translator.coordinate_system)
# prints G56
offset = translator.get_axis_coordinate_system_offset("G56", "X", Units.LENGTH_MILLIMETRES)
print(offset)
# prints 200
translator.translate("G10 L2 P3 X200 Y50"); % set up offset for G56
translator.translate("G56"); % select G56
fprintf('%s\n', translator.getCoordinateSystem()); % prints G56
offset = translator.getAxisCoordinateSystemOffset("G56", "X", Units.LENGTH_MILLIMETRES);
fprintf('%f\n', offset); % prints 200

Interaction with Other Hardware

It's often useful to interact with other hardware on top of Zaber devices. You can, for example, use M-code M3 to turn on a spindle of a milling machine with digital input on Zaber controller. The example below demonstrates exactly that.

Python
MATLAB (legacy)
with open("C:\\prototype.tap") as file:
  while True:
    line = file.readline()
    if not line:
      break # EOF
    else if line == "M3":
      translator.flush() # finish all queued movements
      stream.set_digital_output(1, DigitalOutputAction.ON) # turn on digital output
      time.sleep(30) # wait 30 seconds for the spindle to reach full speed
    else:
      translator.translate(line)
fileId = fopen('C:\\prototype.tap','r');

while true
  line = fgetl(fileId);

  if ~ischar(line)
    fclose(fileId)
    break
  elseif line == "M3"
    translator.flush(); % Finish all queued movements
    stream.setDigitalOutput(1, DigitalOutputAction.ON); % Turn on digital output
    pause(30); % Wait 30 seconds for the spindle to reach full speed
  else
    translator.translate(line);
  end
end

It is crucial to always call the flush method before interacting with other hardware. By calling the method, you ensure that the device has reached the final position in the submitted G-Code.

If you also perform some movement outside of G-Code, make sure to call the reset_position method afterwards. The method queries the device and updates translator's internal position to match the device. Alternatively, you can use the set_position method to update the position manually.

Using patterns like the one above, you can interact with any external hardware like PLC, laser, pumps, etc.

Stream Command Passthrough

We provide a special M-Code M700 that allows to pass stream commands directly to the underlying stream. The commands are provided in G-Code comments with parentheses.

Python
MATLAB (legacy)
result = translator.translate("M700 (wait io ai 1 >= 0.5) (wait 200)")
print(result)
# {'_commands': ['wait io ai 1 >= 0.5', 'wait 200'],
# '_warnings': []}
result = translator.translate("M700 (wait io ai 1 >= 0.5) (wait 200)");
fprintf('Command: %s\n', result.getCommands());
fprintf('Warning: %s\n', result.getWarnings());
% Command: wait io ai 1 >= 0.5
% Command: wait 200
% Warning:

The example above passes two commands to the stream. The first one waits for analog input 1 to get above 0.5 V. The second one then waits additional 200 ms.

Path Control Mode

The translator supports continuous path mode (G64) where it rounds corners of line segments to maintain speed. The current implementation has certain limitations. Firstly, the corners are only rounded up to a specified path deviation from a corner (in contrast to milling machines' ability to maintain constant milling speed). You can specify the deviation with P parameter; otherwise, the default value of 0.1 mm applies. Secondly, the translator only looks ahead at two consequent linear movements and always reaches each segment at worst case as a tangent.

G64 is a default path control mode.

In addition to G64 the translator also supports exact path mode G61 and exact stop mode G61.1. Use these modes to enforce the exact travel of the specified path. You may also use G9 exact stop instruction to enforce stopping after a single block.

Feed Rate

The translator supports the feed rate (F) parameter for movements. The feed rate is specified in millimetres per minute. For example:

G1 X100 F1000 (move by 100 mm at 1000 mm/min)

Note that the first non-rapid movement must have the feed rate specified. Otherwise, the translator will throw an exception.

Additionally, you can use the set_feed_rate_override method to change the feed rate during translation. For example, the following code slows down all the non-rapid movements by half of the original feed rate.

Python
MATLAB (legacy)
translator.set_feed_rate_override(0.5)
translator.setFeedRateOverride(0.5);

The inverse time feed rate mode (G93) and units per revolution feed rate mode (G95) are not supported.

Offline Translation

In addition to streaming G-Code directly to the device, we also provide a way to translate instructions without sending the commands. You can, for example, use this for simulation purposes or processing of the generated commands.

Python
MATLAB (legacy)
# from zaber_motion.gcode import OfflineTranslator

translator = OfflineTranslator.setup(DeviceDefinition(device_id=30331, axes=[
  AxisDefinition(peripheral_id=70245, microstep_resolution=64),
  AxisDefinition(peripheral_id=70245, microstep_resolution=64),
  AxisDefinition(peripheral_id=70245, microstep_resolution=64),
], max_speed=Measurement(100, Units.VELOCITY_MILLIMETRES_PER_SECOND)))

result = translator.translate("G28")
print(result)
# {'_commands': ['on a b c line abs 0 0 0'], '_warnings': [] }
% import zaber.motion.gcode.OfflineTranslator;
% import zaber.motion.gcode.AxisDefinition;
% import zaber.motion.gcode.DeviceDefinition;

axisDefinition = AxisDefinition(70245, java.lang.Integer(64));
axisDefinitions = [axisDefinition, axisDefinition, axisDefinition];
translator = OfflineTranslator.setup(DeviceDefinition(30331, axisDefinitions, Measurement(100, Units.VELOCITY_MILLIMETRES_PER_SECOND)));

result = translator.translate("G28");
fprintf('Command: %s\n', result.getCommands());
fprintf('Warning: %s\n', result.getWarnings());
% Command: set maxspeed 23302
% Command: line abs 0 0 0
% Warning:

In order to create an offline translator, you have to specify information about the device ( TranslatorConfig ). You can find this information by accessing device settings in Zaber Launcher.

The interface of the OfflineTranslator class is nearly identical the one of the Translator class with notable exception of translate and flush methods being synchronous.

Supported Codes

The translator supports a wide range of semi-standard G-Codes and M-Codes.

  • G0 - traverse line
  • G1 - line
  • G2, G3 - arc, without support for parameters R and P
  • G4 - dwell (P in seconds)
  • G10 - set coordinate system (L2 only)
  • G17, G18, G19 - plane selection
  • G21 - millimeter system selection
  • G28, G28.1 - return to home, set home to the current position
  • G30, G30.1 - return to secondary home, set secondary home to the current position
  • G53 - machine coordinate system
  • G54-G59, G59.1-G59.3 - coordinate system selection
  • G61, G61.1, G64 - path control mode
  • G90, G91 - absolute/relative mode (G91 is default)
  • G90.1, G91.1 - absolute/relative arc distance mode (G91.1 is default)
  • G92, G92.1 - temporary work offset (not recommended)
  • M2, M30 - program stop and end
  • M64, M65 - set digital output
  • M66 - wait on input (E not supported; L0,L1,L2 not supported; Q not supported; use M700 when possible)
  • M68 - set analog output

If you require support of some additional codes for your application, please let us know.

Non-supported Codes

There are some codes that we explicitly don't support at this moment.

  • G20 - inch system selection
  • G40, G41, G42 - tool radius compensation
  • G43, G44, G49 - tool length compensation
  • G93 - inverse time feed rate mode
  • G95 - units per revolution feed rate mode

Custom Codes

Here you find all non-standard codes specific to our implementation.

  • M700 - stream command passthrough