-
Notifications
You must be signed in to change notification settings - Fork 296
Marlin Compatibility
For 3D printing there are a large number of utilities that are written to speak to Marlin or various other mostly-compatible variants. Even though there are several things that don't translate between Marlin and g2core, we can make an effort to at least accept gcode sliced for Marlin, and to be able to conditionally speak the Marlin protocol.
This makes g2core advanced 3d printing capabilities, such as instant feedhold and 6th order acceleration management accessible to upstream tools that speak Marlin. It also gives the authors of those various utilities (assuming that they are still being maintained) a migration path to native g2core support should they wish to do so.
Marlin compatibility support is viewed as a transition option to ease migration, and may be declared "done" once it's achieved broad enough support.
The Marlin compatibility mode is to solve two closely related problems:
- User-interfaces that are designed to control a Marlin-compatible machine use a different protocol than that of g2core. We'll call this "the Marlin protocol" as opposed to the "g2core protocol."
- Marlin has a large amount of M-codes that are not used by g2core (or are interpreted differently), and a handful of G-codes are interpreted differently. We'll call this the "Marlin flavor of gcode" as opposed to the "g2core flavor of gcode." Supported G/M-codes are listed later on this page. When possible, we will still support g2core extensions (such as
M100
,M100.1
, andM101
) when interpreting Marlin-flavor gcode.
These are treated as different problems, and are solved independently. This allows a UI that speaks the g2core-protocol to send a file sliced for a Marlin-based machine, without losing the advanced capabilities of g2core such as feed-hold. This also allows UIs that speak the Marlin protocol to talk to g2core. It's assumed that a UI designed to talk to Marlin will be sending Marlin-flavor gcode.
The Marlin compatibility mode is not a full 100% work-alike for Marlin, although some additional commands may be added over time. You have to use the g2core protocol for these:
- Configuration of the machine and various parameters
- Setup of motors, heaters, etc.
- Tuning PID, limit switch polarity, etc.
- Anything not natively supported by Marlin
There are a few concepts that convert more-or-less between g2core and Marlin, so they will be listed in this table.
g2core | Marlin | Notes |
---|---|---|
{"r":...,"f":[...]} |
ok |
In response to every sent gcode, g2core will return a response JSON, and Marlin will return ok . <br> (Marlin has an "advanced ok " option as well.) |
{"he1st":210} |
M104 S210 T1 |
Set temperature of extruder 1 to 210 . |
{"he1st":n} |
M105 |
Request the set temperature of extruder 1 (g2core) or current extruder and bed (Marlin). |
Nxxx (gcode) |
Nxxx (gcode) * (checksum) |
Marlin supports a checksum, and has special requirements on line numbers, where g2core accepts arbitrary line numbers and doesn't support a non-standard checksum. |
{"out4":0.5} |
M106 S128 |
Set output on the fan (or generic PWM output 4 for g2core) to 50%. |
The Marlin communications protocol is fairly simple, but also somewhat lossy. It's expected that requests (such as M105
) can be ignored and time out on the host side.
There's also no clear indication as to what's "part of the tape" gcode and what's a polling request such as M105
.
In some circumstances, such as during a M109
or M190
, progress updates will be printed without polling roughly every second. Other than that and the case of M155
, all status updates must be polled for.
See Replies from the RepRap machine to the host computer for some documentation.
When any line is sent, an ok
is returned as soon as it is optionally verified and parsed.
ok
may be followed by temperature codes in the form T:93.2 B:22.9
(generally in response to M105
) or position codes in the form X:9.2 Y:125.4 Z:3.7 E:1902.5 ...
(generally in response to M114
). See implementation for M114
in Marlin and Ultimaker2Marlin, as they differ in output after the E:
. (Q: Which extruder is E? Is E: in volumetric units for Ultimaker2Marlin?)
If the line started with Nxxx
and contains *nnn
(before any comment, which begins with ;
), then the xxx
and nnn
are verified as the next sequential line number and checksum, respectively.
The checksum is the XOR of all characters up to but not including the ;
(Cura discards everything from ;
on), then the checksum is appended to the line (before any ;
) with the sprintf style string "*%d"
. See the Cura code for an example:
checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))
self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
The line numbers (Nxxx
) must be sequential, or Marlin will assume one was missed.
If verification fails, it'll respond with a Resend: nnn
where nnn
is the last seen line number + 1. The host is then expected to send that line again.
There is the problem of knowing when to speak the Marlin protocol without removing the ability to speak the g2core protocol. It's assumed that we cannot modify a Marlin-speaking UI.
In order to do this, we have to detect when the device want to speak Marlin. There are two possible methods:
Marlin-based machines are generally running on an Arduino Mega, when will automatically reset upon connection due to the RTS pin is wired to the reset pin. In this case, the Mega boots into the STK500v2-speaking bootloader.
Of the two Marlin-speaking tools checked, Cura and OctoPrint, both try to talk to the stk500v2 bootloader immediately after opening a connection. (Note: The commands' values are not listed in the STK500v2 doc, but can be found here.) In both cases, if this communication is successful, then the connection is left open and the bootloader is told to exit into the main firmware.
If we see this communication, we have to handle it, but then we can put the connection into Marlin-protocol mode until the connection is closed.
Cura starts with a CMD_ENTER_PROGMODE_ISP
while OctoPrint starts with a CMD_SIGN_ON
(but ignores the value of the response, as long as it parses and has a valid checksum).
Cura:
if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:
raise ispBase.IspError("Failed to enter programming mode")
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
if self.sendMessage([0xEE])[1] == 0x00:
self._has_checksum = True
else:
self._has_checksum = False
# then, later, to leave ISP mode
if self.sendMessage([0x11]) != [0x11, 0x00]:
raise ispBase.IspError("Failed to leave programming mode")
OctoPrint:
self.sendMessage([1])
if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:
self.close()
raise ispBase.IspError("Failed to enter programming mode")
# then, later, to leave ISP mode
if self.sendMessage([0x11]) != [0x11, 0x00]:
raise ispBase.IspError("Failed to leave programming mode")
After the CMD_LEAVE_PROGMODE_ISP
(0x11
) then the handling of stk500v2 comands is no longer necessary (or desired).
In order to handle when an actual programmer attempts to connect, we need to also handle anything we don't know with a STATUS_CMD_FAILED
(0xC0
) reply.
We can ignore checksums on receive, but on transmit we should compute it correctly. It's a simple XOR of every byte of the message, including the header.
Messages either direction are of the following format:
- 1-byte:
0x1B
- 1-byte sequence number, which starts at 1 and overflows to 0
- 2-byte big-endian message-payload length (does not include the header):
msg_length
- 1-byte:
0x0E
-
msg_length
-bytes of the payload data - 1-byte checksum, which is the XOR of each byte of the message (including the header)
The M105
command is used to poll for temperature. Cura sends this and analyzes the returned value to determine if it's speaking to a Marlin-based machine. This should never be seen in a gcode "tape", but it is sent from the UI interleaved with gcode from the tape.
The M114
command is another command that should only be sent from the UI and never from the tape, and might be used to poll if a machine is Marlin-based or not.
The M115
command is used to return the machine's capabilities, and is another that should only be from a Marlin-speaking UI.
There is a small possibility of these commands showing up in the tape, but by the point we start seeing tape commands, we should already have seen some indication that it's a Marlin-protocol speaker or a g2core-protocol speaker.
Note that Marlin has several branches, and there are various "flavors" of gcode that work in various Marlins. This is partially controlled by compile-time options, but some variants may require using a completely different Marlin fork. (Needed: clear documentation of UltiGCode and Volumetric RepRap gcode.)
Gcode on Marlin must be all uppercase. g2core accepts both upper- and lower-case mixed.
On Marlin, motion of the extruder is a mixture of E
and T
words, where on g2core A
, B
, and C
are currently used. (This is planned to change to using spindle-based controls.)
On g2core, G0
does not accept an F
word and G1
requires one (but it is 'sticky,' so it only be included once, and from then on when it needs changed). In Marlin, G0 is the same as G1.
On Marlin, the T
word is effective immediately, and there is no M6
. 🙈
On Marlin, numbers after words are optional. For example, this is valid (where on g2core it's not): G28 X Y Z
👊
Generally, comments are handled the same way in Marlin and g2core.
In Ultimaker2Marlin there is some header gcode comments in the form ;FLAVOR:UltiGCode
, etc. Here's an example:
;FLAVOR:UltiGCode
;TIME:45010
;MATERIAL:40112
;MATERIAL2:0
;NOZZLE_DIAMETER:0.4
;Generated with Cura_SteamEngine 2.3.1-g2core-0.9
;LAYER_COUNT:240
;LAYER:0
M107
G10
G0 X60.763 Y31.538 Z0.27
;TYPE:SKIRT
Even when exporting "RepRap" flavor gcode, Cura prints some of these:
;FLAVOR:RepRap
;TIME:16333
;Generated with Cura_SteamEngine 2.3.1-g2core-0.9
...
;LAYER_COUNT:120
;LAYER:0
Note that, at least Cura will strip out all comments before sending, so they're not generally useful, and certainly not to be relied on.
When codes marked with 🐤 (for "canary") are seen, the protocol will be switched to Marlin-compatible.
When codes marked with ⚡ are seen, then the gcode-flavor will be switch to Marlin-flavor.
Note that the protocol and gcode-flavor are switched independently.
-
Exxx
- "extruder axis" ⚡- On Marlin, extruder moves are indicated with a fake-axis
E
. - These are currently mapped to
A
forT0
(which is first mapped toT1
, sinceT0
means "current tool" internally), andB
forT1
(which is internally mapped toT2
).
- On Marlin, extruder moves are indicated with a fake-axis
-
G0
- On Marlin,
G0
is the same asG1
.
- On Marlin,
-
G28
- homing- In Marlin,
G28
(no decimal) is homing, and the values are possibly provided without numbers, and the number (if provided) are ignored:G28 X Y Z
- If no axes are provided, then it will home all axes.
- As a side-effect, it clears the auto bed-levelling rotation, and sets the "active toolhead" to
T0
. - Will home Z first if Z homes up, then X, then Y. Otherwise it'll home X, then Y, then Z.
- In Marlin,
-
G29
- bed tramming- Not suppored in Ultimaker2Marlin
- There are two types of
G29
- "mesh bed leveling" and "auto bed leveling." Each takes different parameters. Here we'll discuss "auto bed leveling" withAUTO_BED_LEVELING_3POINT
compiled in only. - This will probe three points (internally stored and compiled-in as
ABL_PROBE_PT_[123]_[XYZ]
), then activate bed tramming ("leveling"). - The three points are stored in the firmware, and
G29
starts a "canned cycle" much like homing.
-
G10
,G11
- retract and unretract (prime) filament- Retracts or primes filament according to settings of
M207
.
- Retracts or primes filament according to settings of
-
M82
,M83
- set extruder to absolute/relative mode ⚡-
M82
sets theE
to be absolute, whileM83
makes it relative. - Not implemented in Ultimaker2Marlin, since E is volumetric and always effectively absolute and in volume.
-
-
M18
,M84
- Stop idle hold-
M84
Will, with no arguments, disable all motors. (M18
is accepted as an alias asM84
.) -
(Prerelease Marlin) With
X
,Y
,Z
, orE
it will disable just that motor. This is not supported at the moment.) -
M84
is internally queued as if it wereM100 ({"md":0})
- With
Sxxx
it acts the same asM85
-
-
M85
- Set inactivity shutdown timer-
M85
Will, with no arguments, disable all motors. -
M85 Sxxx
is internally queued as if it wereM100 ({"mt":xxx})
-
-
M104
,M109
,M140
,M190
- temperature control ⚡- On Marlin, you set the extruder temperature (and return immediately) with a
M104 Snnn Tnnn
-
Snnn
indicates the temperature in celsius -
Tnnn
(optional) indicates the tool, with the first being0
- If you wish to wait until the extruder is at temperature, change
M104
toM109
.- Cancel the wait with
M108
(with no further words). - With
Sxxx
it will only wait for heating. Change theSxxx
toRxxx
to wait for cooling or heating. - Both
M104
andM109
(with eitherS
orR
) will set the target temperature. - During heat-up, the temperature of the extruder and heat-bed will be automatically printed every second.
- Cancel the wait with
-
- On Marlin, the bed temperature is set with
M140 Snnn
, and it does NOT wait for the bed to heat up.-
Snnn
indicates the temperature in celsius - Wait for the heat bed with
M190 Sxxx
(for heating only) orM190 Rxxx
(for both heating and cooling)- Like
M109
,M190
will also set the target and print the temperature of the extruder and bed every second until while it's waiting.
- Like
-
- On Marlin, you set the extruder temperature (and return immediately) with a
-
M108
- temperature wait cancel 🐤-
M104
andM190
are cancelled withM108
. - Partially implemented - Marlin support is sketchy as well
-
-
M105
- temperature polling 🐤- Response is in the format:
ok T:18.2 /0.0 B:16.6 /0.0 @:0 B@:0
-
T:nnn
contains the temperature of the "current" extruder (in celsius). -
/nnn
contains the set temperature of the given extruder (in celsius). -
B:nnn
contains the bed temperature (in celsius). -
/nnn
after that is the set temperature of the bed (in celsius). -
@:nnn
is the power output level (0-PID_MAX, which appears to generally be 255). -
B@:nnn
is the bed power output level (0-MAX_BED_POWER, which appears to generally be 255).
-
- For Ultimaker Marlin, this differs from the response format of
M109
andM190
ofT:101.9 E:0 W:1
-
T:nnn
is the same -
E:nnn
is the extruder number -
W:nnn
is the seconds of wait time left (and may be?
) for the temperature to be considered "stable".
-
- For stock Marlin, the output format of
M109
andM190
is the same asM105
, except it adds theW:nnn
wait time. - Cura parses looking for
/T: *([0-9.]*)/
and/B: *([0-9.]*)/
only, and the rest appears to be ignored.
- Response is in the format:
-
M106
,M107
- set fans speed/turn fan off ⚡-
M106
turns the fan indicated withPx
to the speed indicated withSnnn
, or 255 by default.-
Snnn
has values fornnn
of integers between 0 - 255, and is silently clipped to those values.
-
-
M017
turns off the fan indicated inPx
.
-
-
M117
- display on LCD- This is similar to the
MSG
mechanism in g2core, except it's intended for driving an LCD display. - Current implementation simply ignores the line.
- This is similar to the
-
M110
- reset line number 🐤- A line of the form
NxxxM110*nnn
will set the current line number toNxxx
, and so the next line number expected will bexxx + 1
. - Note that Marlin requires lines with numbers to start with the
N
and end with the*nnn
withnnn
being the checksum. Any comment will follow the checksum and a;
. - Current implementation does NOT check for consecutive line numbers
- A line of the form
-
M114
- get current position 🐤- Since there are no status reports in Marlin-protocol, the position must be polled for.
M114
is the command used to poll for current position. - See discussion above about Response (R) analog for details
- Since there are no status reports in Marlin-protocol, the position must be polled for.
-
M115
- report firmware version and capabilities 🐤- Results in a string generated like:
"FIRMWARE_NAME:Marlin " DETAILED_BUILD_VERSION " SOURCE_CODE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
- This would show as:
"FIRMWARE_NAME:Marlin ${BRANCH}-${VERSION} SOURCE_CODE_URL:https://github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:Ultimaker EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000\n"
- Results in a string generated like:
-
M20
- List SD card- Response format for no items:
Begin file list
End file list
ok
-
M21
- Initialize SD card- Ignore and respond with an
ok
- Ignore and respond with an
-
M22
- Release SD card- Ignore and respond with an
ok
- Ignore and respond with an
-
M23
- Select SD file- Example:
M23 blah.gcode
- Respond with:
open failed, File: blah.gcode. ok
- (It appears that Marlin will actually say
ok
to that!)
- Example:
-
M111
- set debug level-
M111
is called by Repetier during connection, first withS6
and then withS7
. - Marlin doesn't officially support M111 other than in RC versions.
-
Getting Started Pages
- Home
- What is g2core?
- Who uses g2core?
- Jerk-Controlled Motion
- Getting Started with g2core
- Connecting to g2core
- Configuring g2core
- Flashing g2core
- Troubleshooting
Reference Pages
- Gcodes
- Mcodes
- Text Mode
- JSON Communications
- GPIO Digital IO
- Alarms & Exceptions
- Power Management
- Coordinate Systems
- Status Reports
- Status Codes
- G2 Communications
- Tool Offsets and Selection
- Probing
- Feedhold, Resume, Job Kill
- Marlin Compatibility
- 9 Axis UVW Operation
- gQuintic Specs
Discussion Topics
- Roadmap
- GPIO for 1.X Releases
- Toolheads
- Raster Streaming Prototol
- g2core REST Interface
- Gcode Parsing
- G2 3DP Dialect
- Consensus Gcode
- Digital DRO
- Overview of Motion Processing
Developer Pages
- Development & Contribution
- Branching and Release - DRAFT
- Getting Started with g2core Development
- Project Structure & Motate
- Compiling G2
- OSX w/Xcode
- OSX/Linux Command Line
- Windows10 w/AtmelStudio7
- Debugging G2 on OSX
- Board and Machine Profiles
- Arduino Due Pinout
- Arduino DUE External Interfaces
- Diagnostics
- Debugging w/Motate Pins
- Development Troubleshooting
- g2core Communications
- Git Procedures
- Windows 10 / VMware 8 Issues
- Dual Endpoint USB Internals
- G2core License
- VSCode Setup
- Compatibility Axioms
- Wiki History