This chapter lists everything a configuration needs for more than one channel. All keys are additions; a configuration without them is a stock LinuxCNC configuration.
Switching channels on
[EMC]
NML_FILE = linuxcnc_mc.nml ; the NML buffers of all channels
[EMCMOT]
EMCMOT = motmod
NUM_CHANNELS = 3 ; default 1 = stock LinuxCNC
[KINS]
KINEMATICS = trivkins coordinates=XZCXZWCXYZB
JOINTS = 11
[EMCMOT]NUM_CHANNELS-
Number of channels (1..4). The
linuxcncscript starts onemilltask -channel N, oneiocontrol.N, onehalui.N(if[HAL]HALUIis set) and the[CHANNEL_n]DISPLAYof every channel >= 1.motmodis loaded withnum_channels=[EMCMOT]NUM_CHANNELS. [EMC]NML_FILE-
A multi-channel machine needs the NML configuration with the per-channel buffers.
configs/common/linuxcnc_mc.nmldefinesemcCommand/emcStatus/emcErrorfor channel 0 (unchanged names and keys, so single-channel clients keep working) andemcCommand_N,emcStatus_N,emcError_Nfor N = 1..3. [KINS]KINEMATICS-
Identity kinematics (
trivkins) with one letter per joint in channel order. Every channel maps its pose to its joints one-to-one ([CHANNEL_n]JOINTS); a channel’s letter list is itsCOORDINATES.
The [CHANNEL_n] section
One section per channel, [CHANNEL_0] is optional (channel 0 takes
[TRAJ], [RS274NGC], [EMCIO] and [DISPLAY] as usual and reads only
the keys it needs from [CHANNEL_0]).
[CHANNEL_1]
NAME = REVOLVER 2
COORDINATES = X Z W C
JOINTS = 3 4 5 6
MASTER_SPINDLE = 1
PARAMETER_FILE = turret2.var
TOOL_TABLE = turret2.tbl
TOOL_DB = turret2.tools
DB_PROGRAM = mctooldb
RS274NGC_STARTUP_CODE = G18 G21 G40 G49 G54 G80 G90 G94
STARTUP_PROGRAM = hochlauf_kanal2.ngc
MDI_COMMAND = G0 X2=120 Z2=290
DISPLAY = axis
POSTGUI_HALFILE = channel1_postgui.hal
WAIT_MARK_TIMEOUT = 30
TOOL_SENSOR_X = -120.5
NAME-
Shown in the GUI headers.
COORDINATES-
The axis letters of the channel (its pose slots), in the order of
JOINTS. An empty value (COORDINATES =with nothing after it, and noJOINTS) makes a channel without axes of its own: an auxiliary channel that runs M-codes, dwells, wait marks, channel statements and HAL handshakes, e.g. a tool changer built of hydraulic actuators (the FP4 example, FP4). It is always in position, needs no homing of its own and may still fetch axes withGET/GETD. JOINTS-
The joints of the channel in
COORDINATESorder. The assignment is fixed in the INI;GET/GETD/RELEASEmove ownership at run time. Channel 0 without[CHANNEL_0]JOINTStakes the joints its[TRAJ]COORDINATESname. MASTER_SPINDLE-
Spindle of the channel for CSS and feed per revolution (
SETMS(n)changes it from the program). PARAMETER_FILE-
Must differ per channel (each interpreter writes its own).
TOOL_TABLE,TOOL_DB,DB_PROGRAM-
Tool table or tool management of the channel’s carrier, see Tool management per channel. Without them the
[EMCIO]values are used. RS274NGC_STARTUP_CODE-
Overrides
[RS274NGC]RS274NGC_STARTUP_CODEfor this channel. STARTUP_PROGRAM-
A G-code file the channel’s task runs once at start, line by line, after the startup code (the Siemens power-on program). The place for static synchronized actions (
IDS=) that must be in force from the first moment. A relative name is looked up next to the INI file, then in[DISPLAY]PROGRAM_PREFIX. Errors are reported and skip the rest of the file; the task runs on. Also allowed as[RS274NGC]STARTUP_PROGRAMfor channel 0. MDI_COMMAND-
The MDI command of
halui.N. DISPLAY-
A GUI started for this channel (
axis,gmoccapy, … started with-channel N).mchmishows all channels in one window and is configured once in[DISPLAY]DISPLAY. POSTGUI_HALFILE,POSTGUI_HALCMD-
Run by the channel’s GUI once its pins exist.
WAIT_MARK_TIMEOUT-
Seconds a channel waits at a wait mark or an axis exchange before it aborts with an error (0 = forever).
TOOL_SENSOR_<axis>-
Position of the fixed tool measuring point for the JOG form Werkz. messen of
mchmi(one key per machine axis, e.g.TOOL_SENSOR_X = -120.5,TOOL_SENSOR_Z2 = 300). TRAORI_k_*,TRANSMIT_k_*,TRACYL_k_*-
Kinematic transformation data sets, see [cha:kinematic-transformations].
PYVCP,RESTART_ORDER,TOOL_STATIONS-
GUI details: a PYVCP panel for the channel’s AXIS, the order of the restart (run from line) preamble and the number of stations of the channel’s tool carrier for
mchmi.
Machine axis names
When an axis letter exists in more than one channel, the machine axes are
named with a counter in channel order: with channel 0 = X Z C, channel 1 =
X Z W C and channel 2 = X Y Z B the machine has X1 X2 X3, Z1 Z2 Z3,
C1 C2, W, Y, B. These names are shown by the GUIs, used in the
G-code axis words (X2=120, see [cha:multichannel-gcode]) and in all
statements that name an axis (GETD(C1), $AA_IM[Z3], POS[W]=…,
TRANSMIT_1_ROT = C1). A letter that exists once keeps its plain word
(W300, Y-18).
HAL pins per channel
Channel 0 keeps all stock pin names (motion., axis.L., halui.,
iocontrol.0.). Channel N >= 1 adds:
| Pin | Type | Meaning |
|---|---|---|
|
bit out |
planner of the channel is done |
|
s32 out |
running line / motion type of the channel |
|
float out |
path values of the channel |
|
in |
feed inputs of the channel (stock semantics) |
|
bit out |
the channel runs its program backwards |
|
bit / s32 out |
the channel holds at a wait mark (number) |
|
u32 out |
marks 0..31 this channel has set (bit per mark) |
|
bit in |
an abort of this channel aborts the channels waiting on it (default 1) |
|
bit out |
the joints of the channel are powered (machine on and the channel switched on) |
|
s32 / bit out |
transformation in force (0 off, 1 TRAORI, 2 TRANSMIT, 3 TRACYL), jog in the tool coordinate system |
|
s32 / float / s32 out |
H function of a synchronized action (the count strobes); channel 0: |
|
wheel jog of pose slot L of the channel (stock |
|
|
every |
|
|
the I/O of channel N’s task (estop loop, tool prepare/change) |
|
|
bit out |
follows machine enabled and the owner channel enabled; a joint no channel owns follows the machine |
|
bit in (default 1) |
the PLC feed enable of a joint / an axis, see Feed enable of joints and axes (PLC interlock) |
|
a PLC cam of the INI file, see PLC cams |
The wait marks of channel 0 are motion.wait-mark-active,
motion.wait-mark-id, motion.wait-mark-set,
motion.wait-mark-abort-partners.
Feed enable of joints and axes (PLC interlock)
Every joint has the input joint.J.feed-enable, every axis letter
axis.L.feed-enable, both TRUE by default (an unconnected pin changes
nothing). The PLC pulls a pin FALSE to lock the joint or axis against
operator errors, for example Y and Z while a tool change is running:
-
A jog of a locked joint (free mode) or axis (world mode, every channel) is refused with the message "feed disabled by the PLC"; a jog that is running when the pin drops stops with the jog deceleration.
-
A coordinated move (AUTO, MDI) of a channel that would move a locked joint or axis is held before it starts: the channel’s feed goes to 0, like
motion.N.feed-inhibit, with the message "the move is held" once. The planner looks at the current and the next segment, so a move of other axes continues and the hold takes effect at the segment that needs the locked one. When the PLC releases the pin, the move continues. -
Joints are checked through the kinematics of the channel (the end point of the segment is converted to joint positions), axes through the pose of the channel’s planner: a lock of joint 2 holds a move that changes joint 2 whatever the kinematics, a lock of axis Z holds a move that changes the programmed Z.
Homing is not affected by the feed enable. The DMU 60 sim interlocks
the head and the gripper arm with two PLC cams (next section): net
greifer-ruhe plccam.greifer-ruhe.out ⇒ joint.1.feed-enable
joint.2.feed-enable locks Y and Z while the arm is away from its rest,
and net z-wechselpos plccam.z-wechselpos.out ⇒ joint.6.feed-enable
motion.digital-in-02 locks the arm unless Z is at the tool change
position (approached with the tool length offset cancelled, G49
before M6). The changer program does not rely on the lock alone: it
reads the Z cam on the digital input and waits for it (WHILE $A_IN[2]
== 0) before every swing of the arm.
PLC cams
A cam is a range on an axis: its output is TRUE while the position lies inside, for enables such as "gripper open/close only in the working area" or the feed enable above. The cams are declared in the INI file, one section per cam numbered from 0 without a gap:
[PLCCAM_0] NAME = greifer-ruhe ; optional, default: the number JOINT = 6 ; the position joint.6.pos-fb ... AXIS = Z ; ... or axis.z.pos-cmd ... PIN = pos.out ; ... or any float pin or signal MIN = 89 ; the DMU 60: the gripper arm rests at W 90 MAX = 91 HYST = 0.5 ; optional hysteresis INVERT = 0 ; optional THREAD = servo-thread ; optional
The HAL file loads them, after the servo thread exists, with
loadusr -w plccam_ini
which loads the real-time component plccam with the names
plccam.<name>, adds them to the thread, sets the range and links the
position. The output plccam.<name>.out is TRUE while MIN ⇐ position
⇐ MAX; once inside, it stays TRUE until the position has left the range
by more than HYST (no chatter on the edge); INVERT = 1 turns it round;
.inside is the output without the inversion. The pins .min, .max,
.hyst and .invert can also be set from the PLC at run time. The
component is documented in plccam(9).
Machine on, off, estop
Channel 0’s machine on enables the machine as in LinuxCNC. The task of a
channel >= 1 switches only its own joints on and off: the joints of a
channel that is off are unpowered (joint.J.amp-enable-out low), follow
their feedback and refuse jogs and programs; its task reports ON only while
its joints are powered. When the machine goes off (channel 0 off, estop,
fault) every channel needs its own switch-on again. Homing a joint of a
switched-off channel is refused and home all needs every channel on.
The simplest way to run the machine is one key for everything: mchmi
exports mchmi.machine-on, mchmi.machine-off, mchmi.estop-activate,
mchmi.estop-reset (one pulse per key press) and mchmi.feed-override
(the feed pot in percent), and a netted pin carries its key alone. The
G200 configuration (index_g200_postgui.hal) nets them to the
halui.N.* pins of every channel:
net mchmi-machine-on mchmi.machine-on => halui.machine.on halui.1.machine.on halui.2.machine.on
net mchmi-machine-off mchmi.machine-off => halui.machine.off halui.1.machine.off halui.2.machine.off
setp halui.1.feed-override.count-enable 1
setp halui.1.feed-override.direct-value 1
setp halui.1.feed-override.scale 0.01
net mchmi-feed mchmi.feed-override => halui.feed-override.counts halui.1.feed-override.counts
Take a channel out of a net, or gate it with an input, when its area has to be switched off alone (tool change, robot loading); split the feed net when the hardware has separate pots.
Tool management per channel
Every channel has its own tool table or tool management. With
DB_PROGRAM = mctooldb ([EMCIO] or [CHANNEL_n]) the program
mctooldb(1) serves the tools of the channel’s carrier from the file
TOOL_DB (one tool per line, key=value pairs): tool number t with
sister tools st, station, geometry, and tool life monitoring by piece
count or time with set point, actual value, pre-warning and disabled.
An exhausted tool is replaced by its sister at the next tool change, the
program statements SETPIECE(n) and TOOLSET(id, key, value) and the
named parameters #<_tool[id]key> give the program access (see
[cha:multichannel-gcode]). mchmi edits the files in its WZ-Liste
area.
Magazines and buffer places
After the SINUMERIK tool management a tool sits on a place of a
magazine: real magazines are numbered 1 to 9997, the buffer
magazine 9998 holds the spindle, the grippers, loaders and transfer
places, the load magazine 9999 the load stations. The tool file
records the place as mag= (default 1) and station=; a tool taken
from a real magazine into the buffer (into a gripper, into the spindle)
keeps its owner place in home_mag= / home_station=, and that place
stays reserved for it until it is back in a real magazine. The
configuration is read by mctooldb and the interpreter from INI
sections whose CHANNEL names the channel owning the tool file (a
channel without a TOOL_DB of its own, e.g. a tool changer channel,
shares channel 0’s file and magazines):
[TOOLMAG_0] CHANNEL = 0 NUMBER = 1 ; magazine number NAME = Teller KIND = CHAIN ; CHAIN (also disc), TURRET, PLANE PLACES = 30 AXIS = A ; optional: the axis that positions the magazine AXIS_CHANNEL = 1 ; the channel that owns that axis (default CHANNEL) PITCH = -12 ; axis travel per place ZERO = 0 ; axis position with place 1 at the change point FIXED = 1 ; fixed place coding: a tool returns to its owner place only STRATEGY = owner ; free place search: owner (then first), first, nearest LOCKED = 29 30 ; locked places PLACETYPE_5 = 2 ; place type, matched against placetype= of a tool [TOOLBUFFER_0] CHANNEL = 0 PLACE_1 = SPINDLE 1 ; kind and index: SPINDLE, GRIPPER, LOADER, TRANSFER PLACE_2 = GRIPPER 1 PLACE_3 = GRIPPER 2 [TOOLLOAD_0] CHANNEL = 0 PLACE_1 = LOADPOINT 1 ; LOADPOINT (the tool leaves the places) or STATION (it stays)
Without these sections there is one magazine 1 with TOOL_STATIONS
places and the spindle as buffer place 1, and the tool change only sets
loaded= as before (turrets, plain changers). With a buffer configured
the tool change of T.. M6 books the places: the old spindle tool goes
back to its owner place (or a free one), the new tool onto the spindle
place - unless the change program booked the moves itself with MVTOOL
(see [cha:multichannel-gcode]). The program statements and the system
variables $TC_MPP6[m,p], $TC_MAP8[m], $A_MYMLN[id] … read and
write the places; mchmi shows them in the WZ-Liste.
Asynchronous subprograms (ASUP) and event programs
As on the SINUMERIK a channel can run programs outside the part
program: asynchronous subprograms on request and an event program
at defined events. Per channel in the INI ([CHANNEL_n], a channel 0
may use [RS274NGC]):
[CHANNEL_1]
ASUP_1 = wechsler.ngc ; up to ASUP_8
PROG_EVENT = wechsler.ngc ; the event program
PROG_EVENT_MASK = 12 ; bit 0 program start, bit 1 program end,
; bit 2 reset, bit 3 power-on
The file names are looked up next to the INI file, then in
[DISPLAY]PROGRAM_PREFIX. An ASUP is started by a rising edge on the
HAL pin iocontrol.N.asup-<k>, by linuxcnc.command(channel=N).asup(k)
or by the panel; iocontrol.N.asup-active and stat.asup show the
running program (1 to 8, 100 plus the event number for the event
program, 0 none). The request is served while the channel is idle: the
task remembers mode and open program, switches to AUTO, runs the file
from its first line and, when it ends (M2, M30) or is reset, opens
the previous program again and restores the mode. A request while a
program runs interrupts it as on the SINUMERIK: the motion stops, the
block the program was in is remembered, the ASUP runs; when the ASUP
executed REPOSA (also REPOSL, REPOSQ, REPOSH) the program goes
on at that block afterwards, read through to there like a run from that
line (modal state and offsets re-established, the first move goes from
where the ASUP ended straight to the block’s end; spindle and coolant
stay as the ASUP left them) - without REPOSA the program stays
aborted. A request with the machine off, with the axes not homed, while
an MDI command runs or while another ASUP runs is refused with an error
("ASUP k: the channel is not idle"); a HAL edge that arrives while
another ASUP or the event program runs is served after it (a tool
change request during the retract).
The event program runs the same way at the events of PROG_EVENT_MASK:
1 before a program started with Cycle Start (the program follows when
the event program is through), 2 after a program reached its end,
3 after the operator’s reset (not after the reset of an event program
itself) and 4 once after the first machine-on with the axes homed.
The interpreter reads the number as $P_PROG_EVENT (0 in ordinary
programs and ASUPs), so one file serves every event:
IF $P_PROG_EVENT == 3 OR $P_PROG_EVENT == 4
GOTOF FREIFAHREN ; after a reset or at power-on: a safe state
ENDIF
...
M17
FREIFAHREN:
...
M17
A tool changer channel uses this like a cyclic PLC program: its event
program retracts from an interrupted change at power-on and after a
reset and then serves the tool prepare / change requests of the
machining channel in an endless loop (LOOP … ENDLOOP polling
$A_IN[n]), so the channel always runs; a reset stops it and the reset
event starts it again, a request still pending is served right away
(the DMU 60 example, wechsler.ngc).
Python interface
linuxcnc.stat(channel=N), linuxcnc.command(channel=N) and
linuxcnc.error_channel(channel=N) address a channel (the keyword is
accepted by stock-compatible clients as well; without it channel 0).
command.asup(k) starts the asynchronous subprogram ASUP_k of the
channel, stat.asup names the running one (Asynchronous subprograms (ASUP) and event programs).
linuxcnc.nmlfile must point at the configuration’s [EMC]NML_FILE.
New status fields: pose_joint (joint in each pose slot, -1 = none),
master_spindle, enabled, synact, ac_marker, ac_param,
ac_timer, sa_r, ac_delt, sa_h_number/sa_h_value/sa_h_count,
aa_mm, ac_mea, trafo_type, trafo_num, trafo_d, tcs. New
commands: synact(op, id) (0 CANCEL, 1 LOCK, 2 UNLOCK, 3 RESET),
set_tcs(on), set_axis_limits(axis, lo, hi) (jog limits of the
channel’s slot, used by the collision guard).