0% found this document useful (0 votes)
76 views46 pages

Go To Cgtech Help Library

The document discusses the evolution of post-processors used in CAM systems to convert machine-independent toolpaths into machine-specific G-code files. It describes how post-processors have progressed from individual programs for each machine to generalized programs that use parameter files to more powerful languages embedded in the parameter files themselves. The document focuses on the CGTech post-processor and its use of a language based on the BASIC syntax to describe the conversion process for different machines through subroutines.

Uploaded by

cretu_zzzz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
76 views46 pages

Go To Cgtech Help Library

The document discusses the evolution of post-processors used in CAM systems to convert machine-independent toolpaths into machine-specific G-code files. It describes how post-processors have progressed from individual programs for each machine to generalized programs that use parameter files to more powerful languages embedded in the parameter files themselves. The document focuses on the CGTech post-processor and its use of a language based on the BASIC syntax to describe the conversion process for different machines through subroutines.

Uploaded by

cretu_zzzz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 46

Go to CGTech Help Library

CGTech Post-Processor Help


Introduction to the CGTech Post-Processor

A CAM system generates toolpaths that are largely independent of the machines that will
be used to manufacture a design. The syntax, or language, of these toolpaths is typically a
variant of APT CL. The machine controllers require files with a different syntax, often
referred to as machine code or G-Code. The purpose of an NC post-processor is to
convert the machine independent toolpaths to G-Code files.
An early strategy for creating post-processors was to have a tailored program for each
machine/control combination needed. Such a program required no input from the user
other than the machine independent toolpath files. But development of these post-
processors was time consuming and maintenance of a full suite of them quickly became a
nightmare in large organizations.
The next step in the evolution of post-processors was the "generalized post". With this
approach a single program would access a file of parameters for a given machine/control
combination, then process machine independent toolpaths according to the values and
settings of the parameters. As machines became more complex and controllers
correspondingly more capable, the parameter files grew rapidly from a few flags and
limit values to a very complex set of inter-related choices. Effectively the parameter files
were required to express some logic handling abilities.
So the next required evolutionary step became clear. The machine/control parameter files
were enhanced with the syntax of their own language, so that they could express the
complex logic required for modern machines and controls. The post-processor program
became simpler as the language got more powerful, so that now the principal role of the
post-processor is to interpret the language.
Unfortunately post-processor technology has not matured to the point that there is just
one language for describing how to convert machine independent toolpaths to G-Code.
Each post-processor vendor requires a different syntax and language. The language of the
CGTech Post-Processor borrows heavily from the syntax of BASIC (Beginner's All-
purpose Symbolic Instruction Code).
Why BASIC? The CAD/CAM world doesn't need another new language, so why not
BASIC? There is an inherent danger in borrowing the syntax of an established general-
purpose language for a specific task. Users who are familiar with the language can be
irritated by minor departures from the "standard". On the other hand, the fact that there
are users who don't have to learn the language from scratch, is a big plus. We have
attempted to minimize departures from BASIC syntax as much as possible. Where there
are extensions, we have borrowed from Visual-Basic's syntax.
The post-processor reads a machine independent toolpath, usually in some flavor of APT
CL, and processes one statement at a time. A statement can span several lines of the input
file. For each statement it invokes a "Sub" or subroutine which is a section of a
nominated machine/control dependent language file. Which "Sub" gets called depends on
the statement's major word. If there is no "Sub" for a particular major word, nothing
happens and no error message is generated. More typically the "Sub" will format a G-
Code line or lines, for output to a machine dependent toolpath and a log.
If you are new to the CGTech Post-Processor, it is suggested that you browse the Post-
Processor Language topics in the order they are presented. If you are already familiar
with the language and only need to apply it to VERICUT's Inspection Programming
capabilities, you could jump directly to the Probe Cycle Programming topic.
Post-Processor Language

Post-Processor Language Files

The file that contains all of the post-processor language to define how machine
independent toolpaths are to be converted to G-Code files for a single machine/control
combination, is often incorrectly referred to as a "Post". It is the logic embedded in such a
file, together with the CGTech Post-Processor program that performs the processing task,
but we have no intention of fighting the nomenclature.
A "post" file must contain all the language needed for a machine/control combination. It
cannot make reference to other language files, even for subroutines that are common to
many machine/control combinations. Each subroutine needed must be present in the
single file that will be accessed by the CGTech post-processor. The default file extension
for a "post" file is ".VcPost".
A VcPost file is typically encoded with ASCII. The language does not require the use of
any non-ASCII characters, but if a user needs to generate comments in the output G-
Code, or in the post-processor's log, with accented vowels or Eastern languages, a VcPost
file can be encoded with UTF-8 or Unicode. Any suitable text editor can be used to create
and maintain VcPost files. A word-processor can be used if you take great care to avoid
saving the files with any formatting information. The text editor embedded in VERICUT
is viable.
It is strongly recommended that you follow good programming practice in terms of
indenting blocks of logic to make the code more legible. Recognizing that we haven't yet
explained any of the language's syntax, the following snippet may make it clear what is
meant by indenting.

Sub GOTO
If (G = 0) Then
If (Z < Z.Previous) Then
Out "<N><G><X><Y>"
Out "<N><G><Z>"
Else
Out "<N><G><Z>"
Out "<N><G><X><Y>"
End If
Else
Out "<N><G><X><Y><Z><F>"
End If
End Sub
Statements, Continuations and Comments
Statements

Elements of the post-processor language are organized in statements to create a VcPost.


Very often a statement and a line of the file are the same thing. Using a piece of the same
code snippet from the previous page to illustrate this, still without any explanation of the
contents of the statements, ...

If (Z < Z.Previous) Then


Out "<N><G><X><Y>"
Out "<N><G><Z>"
Else
Out "<N><G><Z>"
Out "<N><G><X><Y>"
End If

... has seven statements. Many programming languages use a particular character to
denote the end of a statement, such as the semi-colon in C and Java. This is not the case
in BASIC, nor in our post-processor language. The end of a statement is the end of the
line, unless the rightmost pair of characters indicate a continuation.

Continuations
The continuation characters are a space followed by an underscore, " _". It is easy to
think of the underscore alone as being the continuation character, but an underscore can
be used at the end of a variable name, such as "Radius_". We are not recommending this
because it would make the code more difficult to read. But if a name like this appeared at
the end of a line, the post-processor would treat the next line as the first of another
statement. An underscore which is intended to signify a continuation of the current line's
statement should be separated from the rest of the characters by at least one space. For
example;

Radius = squareRoot((X.Current - X.Previous) ^ 2 _


+ (Y.Current - Y.Previous) ^ 2)

Trying to split a function name or variable name between two lines of a statement is a
bad idea. It makes the code hard to read, and won't work. We haven't covered the topic of
string constants yet, but they consist of any characters between double-quotation marks.
"Any" includes the underscore character, so a single string constant cannot span two lines
of a statement. It is necessary to split the string into two or more, and concatenate them as
follows;

Sentence = "The quick brown fox jumps" _


& " over the lazy dog."

Strictly it is not necessary to use continuation characters at all. There is no practical limit
on the length of a line of code. But it makes sense to restrict lines to the width that can be
displayed by your text editor without having to scroll horizontally.

Comments
A comment can be appended to any line of code, simply by adding a single-quotation
mark and any characters for the comment.

Radius = 0.5 * Diameter 'This is a comment

It is also possible for a line to contain nothing but a comment, and this may well be the
better style to adopt for legibility.

' This line is just a comment


Radius = 0.5 * Diameter

A line with the continuation characters can also end with a comment, but this really gets
ugly because it makes it more difficult to see the continuations.

Sentence = "The quick" _ 'This sentence


& " brown fox" _ 'contains all
& " jumps over" _ 'the letters of
& " the lazy dog." 'the alphabet

It would be much better to give the comment its own line.

' This sentence contains all the letters of the alphabet


Sentence = "The quick brown fox jumps over the lazy dog."

While you can append comments to continued lines, it is not possible, nor necessary, to
split extensive comments into continuation lines. Since a comment can contain any
characters, a space and underscore on the right end will not cause the next line to be
treated as a continuation. If you need a multi-line comment, just use several individual
comment lines.

' Check for RAPID and perform horizontal or vertical


' moves, or vice versa, to "square" the motion.

No other syntax to denote a comment is supported. In particular the "Rem" style that
appears in some flavors of BASIC cannot be used.
Variables

Variables

There are just three types of variable in the post-processor language; numeric values, text
strings and an object analogous to a control's register that has both numeric and text
properties. We will refer to these three variable types as simply numbers, strings and
registers. There is no boolean variable type.
Variable names can be any combination of letters of the alphabet, numerals and the
underscore character, but must begin with a letter. There is no practical limit to their
length, so you can make them very descriptive. Names are case insensitive, so "radius",
"Radius" and "RADIUS" are synonyms. This slack attitude also applies to reserved words
in the language such as "If", "Then" and "Else", and also to subroutine and function
names. There are two schools of thought when it comes to compound names. One uses
uppercase for the first letter of each word, such as "CircleRadius", while the other
separates the words with an underscore, such as "circle_radius". We suggest that you pick
a style and stick with it. Having both in the same VcPost would be an invitation to bugs,
since "CircleRadius" and "circle_radius" are not synonyms.
Unlike BASIC, the post-processor language has no declaration statements, such as
"Dim". There are no arrays. We will leave the topic of registers for a while, but if the
following statements are the first to be executed that refer to "Radius" and "Tool", then
their types will be number and string respectively.

Radius = 0.125
Tool = "Drill"

Once a variable has been defined, its type cannot be altered. So

Tool = 5

would generate an error if it followed the prior lines.


This may not mean much yet, but also unlike BASIC, all variables are global in scope. If
you define a variable in one segment of your VcPost file, it is accessible from all others,
without the need to pass it as an argument between subroutines.
Variable names must be unique across all variable types, so you cannot have a number
and a string both called "Turret". There are reserved variable names which you must
avoid using for anything but their intended purpose.
Numbers
A number variable retains a 64bit precision numeric value. 64bit precision is good for
about 15 significant decimal digits. There is no distinction between fixed point values,
sometimes called integers, and floating point values, sometimes called floats or doubles.
Numeric constants can use integer, decimal or scientific notation. Thus the following are
all valid; 2, +3, -4, 1.625, -3.75, 1.E6, 2.25e-3, -4.125E+3. Note that embedded spaces in
a numeric constant are a bad idea. Use of a thousands separator, as in "1,000,000" would
not produce the desired result.
If you want to format a number variable for output, it should instead be defined as a
register. There are numerous functions for performing mathematical operations on
number variables.

Strings
A string variable retains a sequence of characters. There is no practical limit on the
number of characters. A string constant is a sequence of characters enclosed by double-
quotation marks.

Sample = "This is a sample string constant."

If a string constant needs to contain a double-quotation mark, then two such marks should
be used. For example;

Exclaim = """Hey!"", he said, ""Get off!"""

There are many functions for manipulating string variables.

Mixing
Number and string variable types cannot be mixed in arithmetic, string concatenation or
logical expressions. Thus if "Radius1" and "Radius2" are defined by;

Radius1 = 3.5
Radius2 = "1.25"

then any of the following statements will generate an error;

Sum = Radius1 + Radius2


Range = Radius1 & " to " & Radius2
If (Radius1 > Radius2) Then
Registers

A register is analogous to a control or machine register. It contains current and previous


floating point numeric values. It also carries information on how its current value is to be
formatted in a G-code file and the post-processor log. The numeric values are limited to
lie in a range, either dictated by the number of digits in the formatting, or specified by
tighter constraints. A scale can be applied to the current value prior to formatting.
Syntactically a register is treated like an Object in Visual Basic. It has several properties
but no methods. Samples of the properties and syntax used to access them are;

X.Prefix = "X"
X.Format = "s3.3sm"
X.Minimum = -499.999
X.Maximum = 500
If (X.Scale < 0) Then
DeltaX = X.Current - X.Previous
Message = "Set vernier to " & X.Output

A new variable is defined as a register as soon as the variable name is encountered with a
trailing period. Many registers are predefined and have reserved names, such as X, Y and
Z for the first 3 machine axes.
To shorten code and perhaps make it more comprehensible, a register variable name can
appear without a trailing period. If it appears in an arithmetic expression, an unqualified
register name implies its .Current property, thus the following lines of code have the
same effect;

Diameter = 2.0 + Z
Diameter = 2.0 + Z.Current

If an unqualified register name appears where a string is expected, such as in


concatenation, its formatted .Output property is assumed. So the following lines of code
have the same effect;

Message = "Raise to " & Z & " now."


Message = "Raise to " & Z.Output & " now."

There is one function of note for use with registers;

Zap R
will reset the previous value of register R to an undefined state. This is useful for a modal
register when it is necessary to force output of the current value even when it may not
have changed, perhaps after a tool change.

Properties

Name Type Description Access


Current number Current value of the register. Read/Write
{+}{s}#{.|,}#{s}{m|i}
• optional "+" is for plus sign preceding
positive value.
• first optional "s" is to suppress leading
zeros.
• first "#" is maximum number of
leading digits.
• optional "." or "," is decimal point
character
Other characters are unusual but
permitted.
Format string • second "#" is maximum number of Read/Write
decimal places.
• second optional "s" is to suppress
trailing zeros.
• optional "m" is for a modal value,
which will only be output when it has
changed.
• optional "i" is for an incremental value,
which will always be output when it is
non-zero.
"m" and "i" are mutually exclusive.
Format characters are case insensitive.
Increment to be applied to Current value each
time the register is output.
Increment number Normally only non-zero for the sequence Read/Write
number register, N.
Restricted to be a fixed-point value.
Maximum value that register can attain.
If not defined explicitly, will be implied by the
Maximum number Read/Write
number of leading and trailing digits in the
Format.
Minimum value that register can attain.
If not defined explicitly, will be implied by the
Minimum number Read/Write
number of leading and trailing digits in the
Format.
Output string Formatted current value. Read Only
Prefix used in formatted output.
Prefix string Read/Write
For example, "X" for the X register.
Previous number Previous value of the register. Read/Write
Scale to be appled to value before formatting.
Scale number Can be used to adjust units or to reverse an Read/Write
axis.
Reserved Variable Names
Numbers

Name Description
ArcRadius Radius of current arc.
ClearRetract Default clearance plane retract distance.
GOHOME retract distance. Zero if GOHOME without axis minor
HomeRetract
words should use FROM point.
Cumulative value of NURBS knot at current point (CATIA style
NurbsKnot
NURBS only).
NurbsOrder Order of current NURBS.
NurbsWeight Weight for current NURBS control point.
PathX Current X coordinate transformed by toolpath matrix.
PathY Current Y coordinate transformed by toolpath matrix.
PathZ Current Z coordinate transformed by toolpath matrix.
PathI Current I coordinate transformed by toolpath matrix.
PathJ Current J coordinate transformed by toolpath matrix.
PathK Current K coordinate transformed by toolpath matrix.
PathCenterX Current X coordinate of arc center, transformed by toolpath matrix.
PathCenterY Current Y coordinate of arc center, transformed by toolpath matrix.
PathCenterZ Current Z coordinate of arc center, transformed by toolpath matrix.
PathCenterI Current I coordinate of arc axis, transformed by toolpath matrix.
PathCenterJ Current J coordinate of arc axis, transformed by toolpath matrix.
PathCenterK Current K coordinate of arc axis, transformed by toolpath matrix.
RawX Current raw X coordinate from APT source.
RawY Current raw Y coordinate from APT source.
RawZ Current raw Z coordinate from APT source.
RawI Current raw I coordinate from APT source.
RawJ Current raw J coordinate from APT source.
RawK Current raw K coordinate from APT source.
RawCenterX Current raw X coordinate of arc center, from APT source.
RawCenterY Current raw Y coordinate of arc center, from APT source.
RawCenterZ Current raw Z coordinate of arc center, from APT source.
RawCenterI Current raw I coordinate of arc axis, from APT source.
RawCenterJ Current raw J coordinate of arc axis, from APT source.
RawCenterK Current raw K coordinate of arc axis, from APT source.

Strings

Name Description
Current APT statement.
APTLine All of the statement's parameters are concatenated into a single line,
even if the source has continuation lines.
Next APT statement.
APTNext All of the statement's parameters are concatenated into a single line,
even if the source has continuation lines.
Current APT statement's comment.
If the statement has text following "$$" characters, this variable is that
text with any leading and trailing spaces trimmed. For a DISPLY,
Comment
HEADER, INSERT, PARTNO, PPRINT or REMARK statement, this
variable is the text following the major word and its delimiter, with
leading and trailing spaces trimmed.
Today's date.
Date In the localized "short" format, so for example in the USA, Christmas
day would be "12/25/04".
Current time of day.
Time In the localized "medium" format, so for example in the UK, tea-time
would be "16:00:00".
Unit Linear unit, "in" or "mm".
Registers

Name Description
A Machine A axis.
B Machine B axis.
C Machine C axis.
F Feed rate.
G G-code.
H Head number.
I Machine X of arc axis.
J Machine Y of arc axis.
K Machine Z of arc axis.
M M-code.
N Sequence number.
R Radius.
S Spindle speed.
T Tool number.
U Machine U axis.
V Machine V axis.
W Machine W axis.
X Machine X axis.
Y Machine Y axis.
Z Machine Z axis.
Language Keywords
(Cannot be used as variable names.)

And Exit Not To


Case For Or Until
Debug If Out Wend
Do Log Select While
Else Loop Step Xor
ElseIf mod Sub Zap
End Next Then zapFrom
Functions
There is no provision for user-written functions in the post-processor language. You can
however write subroutines which are not named to match APT major words, and use
them anywhere.

Math Functions

Signature Description
number = abs(number) Absolute value.
number = acos(number)
or Inverse cosine (result in degrees).
number = inverseCosine(number)
number = alogE(number)
or
number = antiLogarithm(number) Natural anti-logarithm.
or
number = exp(number)
number = alog10(number) Base 10 anti-logarithm.
number = asin(number)
or Inverse sine (result in degrees).
number = inverseSine(number)
number = atn(number)
or
number = atan(number) Inverse tangent (result in degrees).
or
number = inverseTangent(number)
Inverse tangent of first argument divided by
number = atan2(number, number)
second argument (result in degrees).
number = cos(number)
or Cosine (argument in degrees).
number = cosine(number)
number = fix(number)
or Integer part.
number = int(number)
number = logE(number)
Natural logarithm.
or
number = logarithm(number)
number = log10(number) Base 10 logarithm.
number = root(number)
or
number = sqr(number)
or Square root.
number = sqrt(number)
or
number = squareRoot(number)
number = round(number)
or Round to nearest integer.
number = nint(number,)
number = sgn(number)
or Sign (-1, 0, or +1).
number = sign(number)
number = sin(number)
or Sine (argument in degrees).
number = sine(number)
number = tan(number)
or Tangent (argument in degrees).
number = tangent(number)

String Manipulation
(all positions are base 1)

Signature Description
number = Asc(string)
or Returns ASCII code of first character in argument.
number = Ascii(string)
string = Chr(number)
Returns string containing just the character with the
or
specified ASCII code.
string = Char(number)
number = InStr(string,
string) Returns position of first occurrence of second argument in
or first argument. If there is no such occurrence, returns
number = inString(string, zero.
string)
string = LCase(string)
Produces lowercase version of argument.
or
string = lowercase(string)
Returns characters from left of first argument, the number
string = Left(string, number)
of them being specified by the second argument.
number = Len(string)
or Returns number of characters in first argument.
number = Length(string)
string = LTrim(string)
or Trims whitespace from left of argument.
string = leftTrim(string)
string = Mid(string, number,
number) Returns characters from middle of first argument, from
or position specified by second argument, the number of
string = Middle(string, them being defined by the third argument.
number, number)
string = Right(string, Returns characters from right of first argument, the
number) number of them being specified by the second argument.
string = RTrim(string)
or Trims whitespace from right of argument.
string = rightTrim(string)
string = Trim(string) Trims whitespace from left and right of argument.
string = UCase(string)
or Produces uppercase version of argument.
string = uppercase(string)

Register Related

Signature Description
Zap register Sets previous value of register to an undefined state.

Input Related

Signature Description
Gets the word at the specified parameter position in
the current APT line.
string = getWord(number) Parameters are numbered from 1 for the major
word.
If the requested parameter is numeric, its text is
returned.
Gets the numeric value at the specified parameter
position in the current APT line.
Parameters are numbered from 1 for the major
number = getValue(number)
word.
If the requested parameter is not numeric, zero is
returned.
Gets the n'th non-numeric parameter in the current
APT line.
string = getNthWord(number)
If there are not enough non-numeric parameters, an
empty string is returned.
Gets the n'th numeric parameter in the current APT
line.
number = getNthValue(number)
If there are not enough numeric parameters, a zero
is returned.
Gets the cumulative knot value at the specified
NURBS point.
number = getKnotValue(number)
Points are numbered from 1.
If there are not enough points, a zero is returned.
Sets a flag so that the next FROM or GOTO point
will become the new HOME position.
zapFrom
Typically used during a tool change or tool axis
adjustment.

Output Related

Signature Description
Displays a dialog box with the current state of all
Debug
numbers, strings and registers.
or
The string in the statement, if present, is used for the
Debug string
dialog title.
Log string Sends a string to the log.
Sends a string to both the output G-Code file and the
Out string
log.
Subroutines

As the post-processor reads each APT statement from the input toolpath, it attempts to
invoke a subroutine, or "Sub", from the VcPost file. The names of the subroutines are
simply the corresponding APT major words. So when the post-processor encounters a
RAPID statement, it will try to call the RAPID subroutine. The syntax of the start and
end of such a subroutine is;

Sub RAPID
....
....
End Sub

Note that a subroutine has no arguments. Because all variables are global in scope, there
is no need to pass them as arguments between subroutines. The code between the "Sub"
and "End Sub" statements will be executed each time a RAPID statement is read.
If at some point within a subroutine you wish to bypass the remaining code, you can use
an "Exit" statement.

Sub PPRINT
....
....
If (display = 0) Then
Exit Sub
End If
....
....
End Sub

It is not necessary to write a subroutine for every APT major word that the post-processor
may encounter. If there is no subroutine for a particular major word, the post-processor
does nothing, and does not generate an error message.
Do not be surprised to see code statements in a VcPost file that are not in any subroutine.
While such lines can appear anywhere in the file, it is good practice to put them up front.
They get executed by the post-processor before any statements are read from the input
toolpath. Typically they are used to establish the output format of registers and specify
initial values. For example;

X.Prefix = "X"
X.Format = "s3.4sm"
Y.Prefix = "Y"
Y.Format = "s3.4sm"
Machine = "Horizontal Lathe"
Author = "I. B. Nutz"

Before & After


Depending on a statement's major word, the post-processor may perform some activities
before invoking the appropriate subroutine, and it may perform more afterwards. Using a
GOTO statement as an example, the post-processor will first convert the statement's X, Y
and Z coordinates, and I, J and K if present, to machine axis positions, load these into the
reserved machine axis registers, X, Y, Z and others, then invoke the GOTO subroutine.
Finally it will set the current value of the G register to 1. Performing this last activity
after the subroutine call allows the G register to be tested within the subroutine to check
for RAPID motion. The following table details the before and after activities for each
major word, in alphabetic order. If a major word is not in this list, there are no associated
before or after activities, but a subroutine will still be invoked if one is supplied.

Before Sub After


If the minor word "CLW" is present, reverses the
ARCMOV
axis of the current arc.
For a BEGIN NURBS statement, sets the NURBS
order and the F register's current value, adjusts the
tool axis, updates the toolpath coordinates,
converts to machine axis positions and sets the
BEGIN
machine axis registers' current values. Each
subsequent NURBS point, until an END NURBS
statement is reached, has no major word but is
treated as if it has the major word NURBSTO.
For a $$*CATIA0 statement, sets the G register's
CATIA0
current value to 0.
Sets the G register's current value to 0. CATMAT
Updates the arc variables, and sets the G register's CIRCLE, For a statement that
current value to 2 (CW) or 3 (CCW). For a ARCDAT, includes the arc end-
statement with just 4 numeric parameters (x, y, z, MOVARC, point (9 numeric
r), the arc axis and the G value cannot be trusted. ARC parameters), sets the
Direction should be deduced from the following or G register's current
GOTO point. SURFACE value to 1.
Updates the toolpath coordinates, and sets the
CNTRL
NURBS weight (defaulting to 1.0).
Sets the F register's current value to the first FEDRAT
numeric parameter.
Sets the G register's current value to 0, updates the
toolpath coordinates, converts to machine axis
FROM
positions, and sets the machine axis registers'
current values.
Adjusts the toolpath coordinates, converts to
Sets the G register's
machine axis positions, and sets the machine axis GODLTA
current value to 1.
registers' current values.
Adjusts the toolpath coordinates, converts to
machine axis positions, and sets the machine axis
GOHOME
registers' current values. If the statement has no
or
axis minor words, motion will be to the FROM
HOME
position unless the reserved variable, HomeRetract
is defined and non-zero.
GOTO,
Updates the toolpath coordinates, converts to
CONT Sets the G register's
machine axis positions, and sets the machine axis
or current value to 1.
registers' current values.
VECTOR
Builds a list of cumulative NURBS knot values
which can be accessed by the getKnotValue KNOT
function.
If the first minor word in the statement is "TOOL"
or "WIRE", sets the T register's current value to LOAD
the first numeric parameter.
LOADTL
Sets the T register's current value to the first
or
numeric parameter.
CHGTOOL
Sets the G register's current value to 0. MSYS
Sets the NURBS order (defaulting to 4) and sets
the weight to 1.0 for the current point, which is NURBS
assumed to be the first knot (with a value of 0.0).
Each NURBS point between a BEGIN NURBS
and END NURBS statement is treated as if it had
this major word. Sets the knot and weight values,
NURBSTO
updates the toolpath coordinates, converts to
machine axis positions and sets the machine axis
registers' current values.
For a PPRINT/METRIC or PPRINT/INCH
statement, sets the reserved string Unit to "mm" or PPRINT
"in".
For a PPRINT/TOOL AXIS or $$TOOL AXIS
statement, updates the toolpath coordinates,
PPRINT
converts to machine axis positions and sets the
machine axis registers' current values.
For a PPRINT/VERICUT-MATRIX statement,
PPRINT
sets the G register's current value to 0.
For a PPRINT/VERICUT-TOOLID statement,
sets the T register's current value to the first PPRINT
numeric parameter.
Sets the G register's current value to 0. RAPID
Sets the G register's current value to 0, updates the
toolpath coordinates, converts to machine axis
RETRCT
positions, and sets the machine axis registers'
current values.
Provided the first minor word in the statement is
not ORIENT, sets the S register's current value. If
SPINDL
the minor word is OFF, LOCK or NEUTRAL the
or
value will be 0. Otherwise it will be the first
SPNDL
numeric parameter, or if there isn't one, the prior
non-zero spindle speed.
Adjusts tool axis, updates the toolpath coordinates,
converts to machine axis positions and sets the TLAXIS
machine axis registers' current values.
TLON
Updates the arc variables, and sets the G register's Sets the G register's
or
current value to 2 (CW) or 3 (CCW). current value to 1.
GOFWD
Sets the reserved string Unit to "mm" or "in". UNIT
If the first minor word in the statement is "TOOL"
UNLOAD
or "WIRE", sets the T register's current value to 0.

Calls
It is not normally necessary for a subroutine named for a major word to invoke one
named for another major word. But you can do so. You can also write a subroutine which
is not associated with a major word, which will never be invoked directly by the post-
processor. To call such a subroutine, you simply place its name in a statement on its own.
There are no arguments because all variables are global in scope. For example you could
write a subroutine to calculate rotate the current X and Y machine axis locations through
an angle.
Sub RotateXY
ca = cos(Angle)
sa = sin(Angle)
XRotated = X * ca - Y * sa
YRotated = Y * ca + X * sa
End Sub

Then to use this subroutine you would need to set up the "Angle" variable, invoke the
Sub and access the results.

Angle = 5
RotateXY
NewX = XRotated
NewY = YRotated
Assignment and Operators
Assignment
Assignment of a value to a variable is achieved using the equal sign, "=". The variable's
name goes on the left of the equal sign, and an expression that generates the required
value goes on the right. This is true for numbers, strings and register properties.

Diameter = R.Current * 2
Message = "Load tool " & T.Current
F.Prefix = " F"

If the variable or register on the left of the equal sign does not already exist, it will be
created by the assignment statement. If it does exist, its value or the value of its property,
will be adjusted.

Arithmetic Operators
Order of precedence is from top to bottom.

Operator Description Example Result


Exponentiation.
^ The first number is raised to the power of 2^3 8
the second.
Multiplication.
* 2*3 6
Multiplies two numbers
Division.
/ 7/2 3.5
Divides first number by second.
Integer Division.
Both numbers are rounded to the nearest
\ integer value, 7\2 3
the first is divided by the second,
and the result is truncated to its integer part.
Modulus.
mod The remainder after dividing the first 7 mod 3 1
number by the second.
Addition.
+ 2+2 4
Adds two numbers.
Subtraction.
- 5-3 2
Subtracts second number from first.

String Operators

Operator Description Example Result


Concatenation.
& "tool" & "path" toolpath
Second string is appended to first.

Logical Operators
Order of precedence is from top to bottom.

Operator Description Example


True if both expressions are the same.
= Can be used with numbers or strings but not a mix. X=Y
String comparisons are case insensitive.
True if the expressions are different.
<> Can be used with numbers or strings but not a mix. X<>Y
String comparisons are case insensitive.
True if the first number is smaller than the second,
< or if the first string collates before the second. X<Y
String comparisons are case insensitive.
True if the first number is greater than the second,
> or if the first string collates after the second. X>Y
String comparisons are case insensitive.
True if the first number is smaller than or equal to
the second,
<= or if the first string collates before or is equal to the X <= Y
second.
String comparisons are case insensitive.
True if the first number is greater than or equal to
the second,
>= X >= Y
or if the first string collates after or is equal to the
second.
String comparisons are case insensitive.
Not Changes true to false, or false to true. Not (Z > 0)
(X > 2) And (X
And True if both expressions are true.
<10)
Or True if either or both expressions are true. (X = 5) Or (X = 6)
Xor True if one expression is true but not both. (X = 5) Xor (Y = 5)

Note that the "Like", "Is", "Eqv" and "Imp" operators available in some flavors of
BASIC, are not supported by the post-processor language.
Branching

There are two types of logic branching available in the post-processor language, the "If ...
Then ... Else" technique, and the "Select ... Case method.

If ... Then ... Else


Using "[" and "]" to bracket optional elements, the syntax is;

If condition Then
statements
[ElseIf condition Then
statements]
[ElseIf condition Then
statements]
[Else
statements]
End If

Note that a statement never appears on the same line following "Then", in an "If" or
"ElseIf". This is possible in BASIC but we have chosen not to support it, to encourage
more easily maintainable code. An "If" branch can be as simple as;

If (Offset < 0) Then


Offset = -Offset
End If

The parentheses around the condition are not strictly necessary but help improve
legibility. Stepping up in complexity, an "If" can represent an either/or condition;

If (word = "Off") Then


M.Current = 11
Else
M.Current = 10
End If

Or it can cover any number of options;

If (word = "Off") Then


display = 0
ElseIf (word = "On" ) Then
display = 1
Else
Out "<N>(" & Comment & ")"
End If

Select ... Case


Using "[" and "]" to bracket optional elements, the syntax is;

Select Case expression


Case condition[,condition][,condition]
statements
[Case condition[,condition][,condition]
statements]
[Case condition[,condition][,condition]
statements]
[Case Else
statements]
End Select

The expression can be a number, string or register property. Each condition should
involve the same variable type, with numeric register properties treated as numbers, and
text register properties treated as strings. There is a wide choice of condition syntax as
defined in the following table, in which variable denotes an expression that evaluates to a
number or string.

Syntax Actioned if ...


variable expression and variable are equal.
< variable expression is less than variable.
> variable expression is greater than variable.
<= variable expression is less than or equal to variable.
>= variable expression is greater than or equal to variable.
variable To variable expression is within the inclusive range.

Note that the operator "Is", available in some flavors of BASIC, is not supported by the
post-processor language. Nor are compound conditions that would require use of the
logical operators "Not", "And", "Or" or "Xor". At most one block of statements will be
executed during a pass through the "Select" construct, regardless of the value of the
expression and the conditions. If the expression matches more than one of the conditions,
only the statements following the first such condition will be executed.
Following is an example of the use of "Select ... Case" which parallels the last example
for the "If ... Then ... Else" technique.

Select Case word


Case "Off"
display = 0
Case "On"
display = 1
Case Else
Out "<N>(" & Comment & ")"
End Select

And here is an example that uses a number variable and illustrates more of the possible
conditions.

Select Case ShankDiameter


Case < 0.25
Chuck = "A"
Case 0.25 To 1
Chuck = "B"
Case 1 To 2.5
Chuck = "C"
Case > 2.5
Chuck = "D"
End Select
Looping

There are three types of looping available in the post-processor language, "For ... Next",
"Do ... Loop" and "While ... Wend.

For ... Next


Using "[" and "]" to bracket optional elements, the syntax is;

For counter = start To end [Step step]


statements
[Exit For
statements]
[Exit For
statements]
Next [counter]

The counter must be a number, or a register if its current value is to be used. The
elements start, end and step, if present, must all be expressions that evaluate to a number.
The value of the count and components of any of the expressions, can be altered within
the loop, but this tends to make debugging much more difficult. If step is missing, a value
of -1 is assumed if start is greater than end, otherwise +1 is used.
For a positive or zero step, the contents of the loop are executed provided counter is less
than or equal to end, and the counter gets increased by step. For a negative step, the
contents of the loop are executed provided counter is greater than or equal to end, and the
counter gets decreased by step. It is possible for the content of the loop to never be
executed, as would be the case with the following example.

For Count = 1 To 5 Step -2


...
Next

Do ... Loop
Using "[" and "]" to bracket optional elements, and "|" to indicate a choice of keywords,
the syntax is;

Do [While|Until condition]
statements
[Exit Do
statements]
[Exit Do
statements]
Loop [While|Until condition]

It would be very unusual to have While or Until conditions at both ends of the same
loop. With a While in the Do statement, the content of the loop will be executed if the
condition is true. With an Until in the Do statement, a false condition is required for the
loop content to be processed. A While in the Loop statement needs a true condition for
control to return to the Do, and an Until would require a false condition.
You can write a "Do ... Loop" with no conditions at either end, but you had better have
an "Exit Do" somewhere within it, or you could wait a while for the post-processor to
finish.

While ... Wend


The syntax is;

While condition
statements
Wend

There is no "Exit" statement for a "While ... Wend" so it is vital that condition is changed
within the loop, and that it becomes false at some point.
Post-Processor Output

There are two types of post-processor language statement that generate output to files,
"Log" and "Out". "Log" only writes to a log file of the post-processor's activities, but
"Out" directs output both to the log file and to the G-Code file. Input lines from the APT
source are also sent to the log file, but this does not require any language statements in
the VcPost. The syntax for the output statements is;

Log string_expression
Out string_expression

But in each case the string_expression can take advantage of some extra features of the
language. In its simplest form an expression could be a string constant;

Out "(Load Palette)"

or it could involve concatenation of constants, string variables and textual register


properties.

Log "Job " & jobName & ", Spindle Speed " & S.Output

Remember that a string expression cannot contain a number variable, because there is no
way to specify the format required. If you need to output a number, you should probably
be using a register instead. If necessary, you could use a register just for this purpose;

Temp.Format = "s4.2"
Temp.Current = toolDia
Log "Tool Diameter = " & Temp.Output & "mm"

A reference to a register variable that does not have a property qualifier will use the
.Current property if a number is expected, and the .Output property when a string
would make sense. Thus this last example could be simplified to;

Temp.Format = "s4.2"
Temp = toolDia
Log "Tool Diameter = " & Temp & "mm"

To explore this topic further, let's use a sample that will be much more common. The
GOTO subroutine for a 3-axis machine needs to output lines similar to the following;
N12 G01 X1.25 Y2.375 Z4.5 F200

Probably the G, X, Y, Z and F registers will be modal, so that their values will only be
output when they have changed. The N register will always change so it doesn't matter
whether we think of this as being modal or not. Let's assume that the .Prefix property for
each register except N includes a leading space. With the rules that we have introduced so
far, you could write a statement to generate the required G-Code lines as follows;

Out N.Output & G.Output & X.Output & Y.Output & Z.Output & F.Output

Or more concisely;

Out N & G & X & Y & Z & F

Here is another way, that may not initially seem to have any advantage over the prior
implementation.

Out "<N><G><X><Y><Z><F>"

The key here is that the register references are now embedded in a string constant, using
the "<" and ">" characters. So if the output line has some constant elements and some
register values, it can be specified without using concatenation. The last line of our earlier
example could be written;

Log "Tool Diameter = <Temp>mm"

It is sometimes necessary to force output of a modal register's value whether it has


changed or not. A good example would be the need to re-specify the feed rate after a tool
change, even though the feed rate for the new tool may be the same as the that for the
prior one. There are two ways to do this. The first involves artificially changing the
register's .Previous property so that it doesn't match the .Current value. The Zap
function is provided for this purpose and you could have;

Zap F

somewhere in one of the subroutines involved in a tool change. The other technique is a
variant of the "<register>" syntax. By placing an exclamation point in front of the
register name, "<!register>", you will force output of that register's value.
The .Increment property of the N register should always be set to a positive value, in the
segment of your VcPost that is outside all subroutines.
N.Increment = 1

Each time an "Out" statement includes the N register, its value will automatically be
incremented. If the balance of the output line is modal registers, and none of them have
changed, then no output is generated and the N register will not be changed. To illustrate
this, we will go back to our early sample GOTO subroutine.

Sub GOTO
If (G = 0) Then
If (Z < Z.Previous) Then
Out "<N><G><X><Y>"
Out "<N><G><Z>"
Else
Out "<N><G><Z>"
Out "<N><G><X><Y>"
End If
Else
Out "<N><G><X><Y><Z><F>"
End If
End Sub

With the following APT input;

RAPID
GOTO/1,2,6
RAPID
GOTO/1,2,2

The generated G-Code would be;

N21G00X1.Y2.
N22Z6.
N23Z2.

Note that there is only one output line corresponding to the second GOTO, when both X
and Y are unchanged.
Post-Processor Debugging

While developing a VcPost file for a machine/control combination, it can be helpful to


step through a test toolpath with the post-processor and watch the effect that each input
line has on the numbers, strings and registers. To see a dialog like the one below, you
need to insert a simple post-processor language statement into your code.

Debug title_string

The title_string is optional, and if present will be used in the title bar of the window.

You could have just one "Debug" statement outside all the subroutines in the VcPost.
Then the window would appear as soon you start processing the input toolpath. As you
step through the toolpath, you can refresh the content of the Debug window at any time,
just by clicking on its icon.
Alternatively you can place "Debug" statements in several places, with different titles,
and a window will be added to the display each time the post-processor reaches such a
statement. Putting a "Debug" statement inside a loop would not be a good idea. You can
close any of the Debug windows by clicking on its icon.
A icon within the register table indicates that a property has no defined value.
Probe Cycle Programming

Introduction
VERICUT can be used to generate G-Code files that drive an NC machine through the
steps required to inspect a workpiece with one or more probes. You will find this
capability in the menus at Analysis menu > Inspection. Once you have picked the
features that are to inspected, you can use the (Use probe for all features) icon to
specify that each of them will be probed. Then the (Program probe cycles) icon will
present the Inspection Programming window, and prompt you to select a post-processor
language file. By convention such a file should have the extension ".VcPost".
Probe cycle programming uses the post-processor language file to determine how to
format the output G-Code files. In addition, comments within the file are used to define
the names of the probe cycles available on the target machine, and the names of each
cycle's parameters. Both types of names get displayed in the programming dialog's table,
and the user is expected to pick a cycle which is appropriate for measuring each feature,
and to provide numeric values for at least some of its parameters. This document is
primarily concerned with defining the syntax of the comments.
There are eight keywords used in the probe cycle comments, each of which starts with the
character "#". The keywords are;

#Init #End #Rapid #Move #Approach #Retract #Cycle #Save

A subroutine or "Sub" within the post-processor language file can employ at most just
one of these keywords. It may have more than one comment line with the same keyword.
Such comment lines must be between the "Sub" and "End Sub" statements.
In addition to the keyword, any of the comment lines can also contain parameter names,
which should be separated by spaces. Each parameter name will be used as the name of a
register in the post-processor, so the name must conform to the rules for variable names.
They must start with a letter and can only contain letters, numerals and the underscore
character, "_". Note that there are language words that cannot be used as parameter
names. Parameters can be essential to the interpretation of a probe cycle, or optional. An
exclamation mark, "!", preceding a parameter's name in the comment line declares it as
mandatory. The syntax should become much clearer in the following examples.
#Init
There should only be one subroutine containing a comment line with the #Init keyword,
and it will be invoked once, before any other subroutines, when the post-processor is run.
For example, if the following is defined in the post-processor language file,

Sub Initialize()
' #Init Offset Clearance FeedRate
Out "<N> G17"
End Sub

then the first row in the inspection programming table will initially look like this.

Note that it is the name of the subroutine, "Initialize", that appears in the "Cycle" column
of the table. So you can alter the prompt in the table to match the user's language and
preferences. The parameter names that follow the #Init keyword on the comment line will
appear in the numbered columns, in the order they are listed. If you need more
parameters than can comfortably fit on one comment line, simply add more lines, each
with the #Init keyword. There is a maximum of 16 parameters per subroutine. As with the
subroutine name, the parameter names can be localized for language and user taste.
In this example the three parameters are optional, so none of their names are preceded by
an exclamation mark. Note too that none of the parameters are used in the subroutine. If
the user provides a value for one of them in the table, that value will be established as the
current value of the register of the same name, before the subroutine is invoked.

#End
There should only be one subroutine containing a comment line with the #End keyword,
and it will be invoked once, after all other subroutines. For example,

Sub Terminate()
' #End
End Sub
This subroutine has no parameters, and more unusually, no executable statements, but its
name will appear in the last row of the table.

#Rapid
One or more rows for rapid motion can be inserted in the programming table before the
approach to any feature that is to be measured. There should only be one subroutine
containing a comment line with the #Rapid keyword, and it will be invoked for each of
the corresponding rows in the table. This example will "square" the rapid motion. Note
that all three parameters are mandatory, so their names are preceded by exclamation
marks.

Sub Rapid()
' #Rapid !X !Y !Z
If (Z < Z.Previous) Then
Out "<N> G0<X><Y>"
Out "<N><Z>"
Else
Out "<N> G0<Z>"
Out "<N><X><Y>"
End If
End Sub

A corresponding row in the table will initially look like,

The background of table cells for mandatory parameters is pink. As the user replaces the
parameter names with numeric values, the pink will be removed. He or she should aim to
eliminate all the pink before running the post-processor.
#Move
Like rapid motions, one or more feedrate motions can be inserted in the programming
table before the approach to a feature that is to be measured. There should only be one
subroutine containing a comment line with the #Move keyword, and it will be invoked
for each of the corresponding rows in the table. This example has a mix of mandatory and
optional parameters.

Sub Move()
' #Move !X !Y !Z FeedRate
Out "<N> G1<X><Y><Z><FeedRate>"
End Sub

If the user leaves the word "FeedRate" in the last parameter's cell, the register with the
same name will not be altered from its prior state.

#Approach
There should only be one subroutine containing a comment line with the #Approach
keyword, and it will be invoked immediately before each of the cycle routines that
measure a feature. For example,

Sub Approach()
' #Approach !X !Y !Z Clearance FeedRate
Z = Z + Clearance
If (Z < Z.Previous) Then
Out "<N> G1<X><Y><FeedRate>"
Out "<N><Z>"
Else
Out "<N> G1<Z><FeedRate>"
Out "<N><X><Y>"
End If
Z = Z - Clearance
GoFeel
End Sub

If you find that there are several parameters that are common to almost all of your cycle
subroutines, you may wish to move them to the approach subroutine. Since this is always
called before the cycle, you can reduce the number of columns used in the table and
provide a more consistent user interface across different cycle types.

#Retract
There should only be one subroutine containing a comment line with the #Retract
keyword, and it will be invoked after each of the cycle routines that measure a feature.
For example,

Sub Retract()
' #Retract Clearance FeedRate
Z = Z + Clearance
Out "<N> G1<Z><FeedRate>"
End Sub

#Cycle
There should as many subroutines containing a comment line with the #Cycle keyword as
there are probe cycles available on the target machine. Typically each such subroutine
will have numerous parameters, and we suggest listing the mandatory ones before the
optional ones. In this example the parameter list is spread across two comment lines, both
beginning with the #Cycle keyword.

Sub WallThick()
' #Cycle !X !Y !Width !Depth !Angle
' #Cycle !Correction Offset MaxSafe
MVAR =4
CPA =X
CPO =Y
SETVAL = Width
ID = Depth
STA1 = Angle
Out "<N><MVAR><CPA><CPO><SETVAL><ID><STA1>"
Out "<N><Correction><Offset><MaxSafe>"
Out "<N> CYCLE979"
End Sub

The alphabetically sorted set of all cycle subroutines is offered in a drop-down list in the
fourth column of each feature row of the table.
Once a cycle type has been selected, the parameters of the corresponding subroutine will
be inserted into the table. Not all of them are included in this illustration.

#Save
Some suites of probe cycles have the ability to save the result of one measurement and
compare it with other measurements in a later cycle. For example, if you wanted to check
that the Z dimension of one surface matched that of another, you could save the result of
probing the first surface, then on the second one use a cycle that compared the new
probed Z with the stored value. If your target machine has this capability, you need a
single subroutine containing the #Save keyword. For example,

Sub Store()
' #Save
Out "<N> G65 P9834"
End Sub

The user will then be able to insert a "save" row prior to any retract.
As with any of the keyword identified subroutines, the #Save subroutine can have
parameters if needed.

You might also like