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 linuxcnc script starts one milltask -channel N, one iocontrol.N, one halui.N (if [HAL]HALUI is set) and the [CHANNEL_n]DISPLAY of every channel >= 1. motmod is loaded with num_channels=[EMCMOT]NUM_CHANNELS.

[EMC]NML_FILE

A multi-channel machine needs the NML configuration with the per-channel buffers. configs/common/linuxcnc_mc.nml defines emcCommand/emcStatus/emcError for channel 0 (unchanged names and keys, so single-channel clients keep working) and emcCommand_N, emcStatus_N, emcError_N for 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 its COORDINATES.

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 no JOINTS) 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 with GET / GETD.

JOINTS

The joints of the channel in COORDINATES order. The assignment is fixed in the INI; GET/GETD/RELEASE move ownership at run time. Channel 0 without [CHANNEL_0]JOINTS takes the joints its [TRAJ]COORDINATES name.

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_CODE for 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_PROGRAM for channel 0.

MDI_COMMAND

The MDI command of halui.N.

DISPLAY

A GUI started for this channel (axis, gmoccapy, …​ started with -channel N). mchmi shows 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

motion.N.in-position

bit out

planner of the channel is done

motion.N.program-line, motion.N.motion-type

s32 out

running line / motion type of the channel

motion.N.current-vel, motion.N.requested-vel, motion.N.distance-to-go

float out

path values of the channel

motion.N.adaptive-feed, motion.N.feed-hold, motion.N.feed-inhibit

in

feed inputs of the channel (stock semantics)

motion.N.tp-reverse

bit out

the channel runs its program backwards

motion.N.wait-mark-active, motion.N.wait-mark-id

bit / s32 out

the channel holds at a wait mark (number)

motion.N.wait-mark-set

u32 out

marks 0..31 this channel has set (bit per mark)

motion.N.wait-mark-abort-partners

bit in

an abort of this channel aborts the channels waiting on it (default 1)

motion.N.enabled

bit out

the joints of the channel are powered (machine on and the channel switched on)

motion.N.trafo-type, motion.N.tcs

s32 / bit out

transformation in force (0 off, 1 TRAORI, 2 TRANSMIT, 3 TRACYL), jog in the tool coordinate system

motion.N.synact-h-number, -value, -count

s32 / float / s32 out

H function of a synchronized action (the count strobes); channel 0: motion.synact-h-*

axis.N.L.jog-enable, jog-scale, jog-counts, jog-vel-mode, jog-accel-fraction, kb-jog-active, wheel-jog-active

wheel jog of pose slot L of the channel (stock axis.L.* semantics)

halui.N.*

every halui.* pin for channel N (halui.N.machine.on, halui.N.mode.mdi, halui.N.feed-override.counts, …​)

iocontrol.N.*

the I/O of channel N’s task (estop loop, tool prepare/change)

joint.J.amp-enable-out

bit out

follows machine enabled and the owner channel enabled; a joint no channel owns follows the machine

joint.J.feed-enable, axis.L.feed-enable

bit in (default 1)

the PLC feed enable of a joint / an axis, see Feed enable of joints and axes (PLC interlock)

plccam.<name>.in, .min, .max, .hyst, .invert, .out, .inside

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).