Stratasys Catalyst CMB file parser

A company I used to work for owned a Stratasys 3d printer. The program that sends print files to the printer is called CatalystEX, and while it imports industry standard STL files, it exports and saves in the (almost certainly proprietary) CMB file format. These files encode the tool path that the printer uses to build the parts, so modifying it makes it possible to modify the print.
Why might one wish to modify the print? Perhaps because Catalyst is very “user friendly” and not a “powerful editing tool” like “some other programs” namely Blender. So, I started writing a bit of Python code capable of importing a CMB into Blender for editing, and then exporting the modified CMB for printing.

I didn’t get very far, but was making decent progress. I left the company, and no longer have access to the printer, and therefore further work would be highly difficult to carry out.

This effort was made feasible (and very likely possible at all) due to the extensive previous work of Andreas Reichinger which went into picking apart the CMB file format, which (at the time of this writing) can be found here: https://azttm.wordpress.com/2012/09/22/inside-the-stratasys-dimension-catalyst-cmb-file-format/

As I mentioned, I didn’t get very far, but I did manage to discover that the ”27 bytes ?” field was actually 35 bytes long. Not sure what it contains, or if it’s per-printer or what. I also never got around to writing out modified part programs, so I don’t know if there’s a sum-check built in or anything.

Below is the full text of the reverse-engineering reference, just in case the link goes off-line:

File Format

As the extension of the generated files (.cmb.gz) suggests, the files are a gzipped version of the CMB file. After extracting, we get a binary CMB file whose format will be described in the reminder of this blog.

Field Naming

Many fields of the header can be seen in the CMB View info pane. The names below are according to the names there. L and R corresponds to the left or right number in case of two numbers given. Fields that exist for part material and support material are denoted Part or Supp. I assume that always Part values come first in the file, but this is not verified if values did not differ in the test files.

Values that appear constant in the test-files are given with their values (mostly in hex).

int: 4 byte little endian (large values did not appear, but probably they are unsigned ints)
float: 4 byte little endian IEEE 754 binary32 standard encoding

string
1 int N (number of following characters)
N byte (probably) ASCII encoded characters (no special characters occured -> probably ASCII, code page unknown)

Header:

4 byte 33 20 33 20 (ASCII “3 3 “) probably magic number
4 byte 0E 08 05 01 Maybe definition of machine type? 8.5 might be Version R in Info Pane?
1 float Slice height (0.01 in)
1 float Part Volume
1 float Supp Volume
1 string Part material (“P400”)
1 string Supp material (“P400_r”)
6 float Bounding box of needed build room (xMin, yMin, zMin, xMax, yMax, zMax)
//following 12 numbers: Limits in Info pane (CMB View)
1 float Part Area L
1 float Part Area R
1 float Supp Area L
1 float Supp Area R
1 float Part Width L
1 float Part Width R
1 float Supp Width L
1 float Supp Width R
1 float Part Aspect Ratio L
1 float Part Aspect Ratio R
1 float Supp Aspect Ratio L
1 float Supp Aspect Ratio R

1 int #Slices (Total Number of Slices)
1 int Address of Layer Table (absolute address in file, see below)
1 string Comment (“Written by CatalystEX!!!!!”)
1 int always 1 (probably number of pack lists?)

1 string Pack List Name
1 string Version (“7.1 (4147)”)
1 string ? (“dimension”)
1 string Part Tip Size (“T12”)
1 string Supp Tip Size (“T12”)
1 int Build Time (in seconds)

//Following could already be part of the remaining protocol but was always constant
27 bytes ? 10 02 00 00 00 11 00 00 00 04 00 00 00 12 00 00 00 08 00 00 00 11 01 00 00 00 11

//Outline of Area of pack (displayed in catalyst when placing pack)
1 int C (count of vertices of outline)

C times:
1 byte 12
1 float x coordinate of vertex
1 float y coordinate of vertex

Tool paths and other controls

The header is followed by the tool paths and other machine control codes.
These are given as a stream of commands, always starting with a control code, followed by its specific data.

Command:

1 byte Control Code
x byte Data, depending on Control Code

Control Codes:

All control codes that occured will be detailed below. Only the Data part is outlined there.

03 End of Program

no Data

This is the very last command. After this, the Layer Table starts directly in the observed files.

05 Minimums

1 float minimum X of this layer
1 float minimum Y of this layer
1 float minimum Z of this layer

Always issued as a first command of a layer. It is the minimum in each direction that occurs in this layer. X & Y displayed at “Current level data” in CMB View.

06 Maximums

1 float maximum X of this layer
1 float maximum Y of this layer
1 float maximum Z of this layer

Always issued after 05 Minimums. It is the maximum in each direction that occurs in this layer. X & Y displayed at “Current level data” in CMB View.

07 End of Layer

no Data

Always issued at the end of one layer. After this command, the layer counter is incremented. The Layer Table (see below) points to the byte following this command, i.e. where the next layer starts.

0B Tool Path Way-Point

These obviously move the printing tip to a new location. They can be observed with the step-by-step simulator of CMB View. Probably linear interpolation is used between the current and the given location. No printing velocities or material feed rates are given, so these must be stored inside the machine, probably depending on the current printing mode and maybe also on the width parameter.
There are 4 subtypes depending on the first byte:

Type 0:

1 byte 00
1 float X coordinate
1 float Y coordinate
1 float Z coordinate
4 byte 00 00 00 00 (don’t know its purpose, always zero.)

Probably denotes a fast move, without printing.

Type 1:

1 byte 01
1 float X coordinate
1 float Y coordinate

A horizontal printing move, linearly interpolated from previous position.

Type 2:

1 byte 02
1 float X coordinate
1 float Y coordinate
1 float Z coordinate

An arbitrary printing move, linearly interpolated from previous position. Only pure z moves occured.

Type 3:

1 byte 03
1 float X coordinate
1 float Y coordinate
1 float width

In the CMB View simulator, this is executed in two steps: first the width is set, then the position (X & Y).
The given width is typically 1/100 of what is displayed in the CMB View simulator, but not always. These Values that occured, depending on Mode (fist binary value, second the value in the simulator):

first layer 0.00039 -> 0.0299
support 0.00037 -> 0.037
interface 0.000181 -> 0.0181
support & sparse raster 0.000161 -> 0.0161
part surface & solid raster 0.000201 -> 0.0201

0D Mode Change

1 byte Mode
1 byte 00 (maybe reserved when number of modes exceed 256?)

This command is always issued in a layer before any path commands, width is always set to 0 and the tip is in a safe height. Probably all Part Groups and Support Groups in the CMB Viewing Options have their own code. The following Modes occured:

65 “Part Interior”. Part Material. These are walls inside the part, when using sparse filling. The Sparse Raster is attached to these walls.
66 “Part Surface”. Part Material. This is the outer wall, printed exactly.
67 “Sparse Raster”. Part Material. When using sparse filling, the pattern inside parts. Is rastered diagonally, directions alternating with each layer.
68 “Solid Raster”. Part Material. Dense part filling, rastered diagonally, directions alternating with each layer. Used in dense filling, but also at some regions with sparse filling.
6B “Part First Layer”. Part Material. The filing of the first printed layer that fuses with the base. Sparse diagonal raster, printed after the perimeter (6E).
6E “Part First Layer Perimeter”. Part Material. The outline of the first printed layer that fuses with the base.
C8 “Support”. Suport Material. Outlines and fillings.
CA “Interface”. Support Material. The top layer of support material, before Part Material is printed on it, or touching on the side. Dense raster.
CB “Sparse Bridge”. ?

This command at least sets the material. Probably other parameters are set as well inside the printer. Why would they make a difference if not? Only for the visualization?

Layer Table

Follows always directly the tool path section (after control code 03), but could probably start at a different location, since its address is given in the header.

#slices times (value in header):
1 int Absolute file address at which layer i starts (Always the byte following the “end of layer” control code 07)

End of File:

2 byte A6 00 (constant?)
6 byte maybe checksum?
4 byte 00 00 00 00 (end of file?)

Typical Control Sequences

Here are some general observations of how the printing files are typically composed. If you plan to write your own file, better observe the inherent printing rules more closely. Be aware, that using the printer with custom print files may void your guarantee, if not worse. I do strongly discurage such practice!

Always, first the outlines are printed, then the fillings. Fillings are always 45° diagonally, alternating directions with each layer.
Each job starts with a Part material layer “Part First Layer Perimeter” filled with a semi-dense “Part First Layer”. This fuses well with the base material and is probably performed to have a stable bond with the base.
After this, the support material base is printed. The first 3 layers are slightly smaller than the first layer, but the fillings match exactly. Following 3 layers are more densely filled in the other direction, and finally one dense Interface layer is printed, without outlines.
After this, the first Part Material layer starts, containing support material as needed.
Support and Part material may alternate its printing order with each layer in order to reduce necessary material change.

Each layer starts with 05 Minimums, 06 Maximums followed by one or more print sequences.
A typical print sequence
1) starts with a 0D Mode Selection,
2) a 0B 00 Move (sometimes 0B 01, if no material change occurs and we are already at the safe height) to the start positiontypically (e.g. not for the first layer) in a safety height (0.026 inches higher),
3) a 0B 02 Move down to printing height at the same XY position (not issued when the previous command was already on the printing height),
4) a 0B 03 setting of the width (possibly starting material) with already the second XY position,
5) and a sequence of 0B 01 Moves for the remaining path.

Printing ends with
6) a 0B 03 setting width to 0, still issuing the last point of the shape. I think I observed, that this last point is often moved into the inside of a part, maybe to put the possible plastic fin of stopped extrusion somewhere, where it is not perceptible.
7) a 0B 02 move to a save height (at same XY position)

After this, it either goes with a 0B 01 move to the next position and starts again from 3), a Mode change occurs and it starts from 1), or an end of layer occurs (07), either starting the next layer, or the printing ends (03).

About Ziggy

I strive to be awesome for God. Support my efforts at: http://sub.tryop.com
This entry was posted in Other and tagged . Bookmark the permalink.

6 Responses to Stratasys Catalyst CMB file parser

  1. CaptMcAllister says:

    I have a personal Stratasys Dimension SST, and I’d be willing to lend a hand in determining the file format if you’re interested

  2. Ziggy says:

    Thanks! It would probably be ideal if you did the reverse-engineering yourself. We build the best tools who use them most. Do you have a particular need for reverse-engineering the format?

  3. Matt says:

    Is there a way to figure out what the print temperature is for the Dimension SST? We have one at my college, and I would like to see if I can print ASA rather than ABS, but I would need to adjust the nozzle temp. I have no experience with machines that don’t use gcode. In gcode I would use M104 S(temp) how does this differ?

  4. Ziggy says:

    I don’t actually know if the temperature set-point is in the print file, or in the printer settings, or even in the firmware. From my experience with Stratasys, I would wager it’s not easy to change, because they don’t want people mucking with the settings and producing bad prints. My advice would be to re-route the existing heater and thermocouple to a dummy block and then build your own temperature controls to run the tip heater. At that point, though, you’ve completely voided the warranty.
    You’d also need to do something about the filament cartridge interlocks, as each cassette has an onboard chip that keeps track of how much filament is left, so you couldn’t just re-use an existing empty case with new filament.

  5. Matt says:

    Not sure if youre still into this, but if you could write a script that extracts CMB info from the CMB file such as the Pack List, i can test it. I want to have an excel file that pulls all that info since we need to input it onto an excel form.

  6. Ziggy says:

    Sadly, I no longer have access to a Stratasys printer.

Leave a Reply

Your email address will not be published. Required fields are marked *