:lang: en
:toc:

[[cha:core-components]]
= Core Components(((Core components)))

// Custom lang highlight
// must come after the doc title, to work around a bug in asciidoc 8.6.6
:ini: {basebackend@docbook:'':ini}
:hal: {basebackend@docbook:'':hal}
:ngc: {basebackend@docbook:'':ngc}

See also the man pages 'motion(9)'.

[[sec:motion]]
== Motion (((Motion)))

These pins and parameters are created by the realtime 'motmod' module.

This module provides a HAL interface for LinuxCNC's motion planner.

Basically motmod takes in a list of waypoints and generates a nice
blended and constraint-limited stream of joint positions to be fed
to the motor drives.

Optionally the number of Digital I/O is set with 'num_dio'.
The number of Analog I/O is set with 'num_aio', default is 4 each.
The number of Spindles is set with 'num_spindles', default is 1.

Pin and parameter names starting with 'axis.__L__' and 'joint.__N__' are read and
updated by the motion-controller function.

Motion is loaded with the motmod command. A kins should be loaded before
motion.

[source,{hal}]
----
loadrt motmod base_period_nsec=['period'] servo_period_nsec=['period']
              traj_period_nsec=['period'] num_joints=['0-9']
              num_dio=['1-64'] num_aio=['1-16'] unlock_joints_mask=['0xNN']
              num_spindles=['1-8']
----

* 'base_period_nsec = 50000' - the 'Base' task period in nanoseconds.
  This is the fastest thread in the machine.

[NOTE]
On servo-based systems, there is generally no reason for
'base_period_nsec' to be smaller than 'servo_period_nsec'.
On machines with software step generation, the 'base_period_nsec'
determines the maximum number of steps per second. In the absence of
long step length and step space requirements, the absolute maximum step
rate is one step per 'base_period_nsec'. Thus, the 'base_period_nsec' shown
above gives an absolute maximum step rate of 20,000 steps per
second. 50,000 ns (50 us) is a fairly conservative value.
The smallest usable value is related to the Latency Test result, the
necessary step length, and the processor speed.
Choosing a 'base_period_nsec' that is too low can lead to the "Unexpected
real time delay" message, lockups, or spontaneous reboots.

* 'servo_period_nsec = 1000000' - This is the 'Servo' task period in
  nanoseconds. This value will be rounded to an integer multiple of
  'base_period_nsec'. This period is used even on systems based on
  stepper motors.
+
This is the rate at which new motor positions are computed, following
error is checked, PID output values are updated, and so on.
Most systems will not need to change this value. It is the update rate
of the low level motion planner.

* 'traj_period_nsec = 100000' - This is the 'Trajectory Planner'
  task period in nanoseconds. This value will be rounded to an integer
  multiple of 'servo_period_nsec'. Except for machines with unusual
  kinematics (e.g., hexapods) there is no reason to make this value larger
  than 'servo_period_nsec'.

=== Options

If the number of digital I/O needed is more than the default of 4 you can
add up to 64 digital I/O by using the num_dio option when loading 'motmod'.

If the number of analog I/O needed is more than the default of 4 you can add
up to 16 analog I/O by using the num_aio option when loading 'motmod'.

The unlock_joints_mask parameter is used to create pins for a joint used
as a locking indexer (typically a rotary).  The mask bits select the
joint(s).  The LSB of the mask selects joint 0.
Example:

[source,{hal}]
----
unlock_joints_mask=0x38 selects joints 3,4,5
----

[[sec:motion-pins]]
=== Pins(((motion (HAL pins))))

These pins, parameters, and functions are created by the realtime 'motmod'
module.

* 'motion.adaptive-feed' - (float, in) When adaptive feed is enabled with 'M52 P1' , the
  commanded velocity is multiplied by this value. This effect is
  multiplicative with the NML-level feed override value and
  'motion.feed-hold'. As of version 2.9 of LinuxCNC it is possible to
  use a negative adaptive feed value to run the G-code path in reverse.
* 'motion.analog-in-00' - (float, in) These pins (00, 01, 02, 03 or more if configured) are
  controlled by M66.
* 'motion.analog-out-00' - (float, out) These pins (00, 01, 02, 03 or more if configured) are
  controlled by M67 or M68.
* 'motion.coord-error' - (bit, out) TRUE when motion has encountered an error, such as
  exceeding a soft limit
* 'motion.coord-mode' - (bit, out) TRUE when motion is in 'coordinated mode', as opposed to
  'teleop mode'
* 'motion.current-vel' - (float, out) The current tool velocity in user units per second.
* 'motion.digital-in-00' - (bit, in) These pins (00, 01, 02, 03 or more if configured) are
  controlled by M62-65.
* 'motion.digital-out-00' - (bit, out) These pins (00, 01, 02, 03 or more if configured) are
  controlled by the 'M62-65'.
* 'motion.distance-to-go' - (float,out) The distance remaining in the current move.
* 'motion.enable' - (bit, in) If this bit is driven FALSE, motion stops, the machine is
  placed in the 'machine off' state, and a message is displayed for the
  operator. For normal motion, drive this bit TRUE.
* 'motion.feed-hold' - (bit, in) When Feed Stop Control is enabled with 'M53 P1', and this
  bit is TRUE, the feed rate is set to 0.
* 'motion.feed-inhibit' - (bit, in) When this bit is TRUE, the feed rate is set to 0.
  This will be delayed during spindle synch moves till the end of the move.
* 'motion.in-position' - (bit, out) TRUE if the machine is in position.
* 'motion.motion-enabled' - (bit, out) TRUE when in 'machine on' state.
* 'motion.motion-type' - (s32, out) These values are from src/emc/nml_intf/motion_types.h
  - 0: Idle (no motion)
  - 1: Traverse
  - 2: Linear feed
  - 3: Arc feed
  - 4: Tool change
  - 5: Probing
  - 6: Rotary axis indexing
* 'motion.on-soft-limit' - (bit, out) TRUE when the machine is on a soft limit.
* 'motion.probe-input' - (bit, in)
  'G38.n' uses the value on this pin to determine when the probe has made contact.
  TRUE for probe contact closed (touching), FALSE for probe contact open.
* 'motion.program-line' - (s32, out) The current program line while executing.
  Zero if not running or between lines while single stepping.
* 'motion.requested-vel' - (float, out)
  The current requested velocity in user units per second.
  This value is the F-word setting from the G-code file, possibly reduced to accommodate machine velocity and acceleration limits.
  The value on this pin does not reflect the feed override or any other adjustments.
* 'motion.teleop-mode' - (bit, out) TRUE when motion is in 'teleop mode', as opposed to 'coordinated mode'
* 'motion.tooloffset.x ... motion.tooloffset.w' - (float, out, one per axis) shows the tool offset in effect;
  it could come from the tool table ('G43' active), or it could come from the G-code ('G43.1' active)

* 'motion.on-soft-limit' -
  (bit, out) TRUE when the machine is on a soft limit.
* 'motion.probe-input' -
  (bit, in) 'G38.n'  uses the value on this pin to determine when the
  probe has made contact.
  TRUE for probe contact closed (touching),
  FALSE for probe contact open.
* 'motion.program-line' -
  (s32, out) The current program line while executing. Zero if not
  running or between lines while single stepping.
* 'motion.requested-vel' -
  (float, out) The current requested velocity in user units per
  second.  This value is the F-word setting from the G-code file,
  possibly reduced to accommodate machine velocity and acceleration
  limits. The value on this pin does not reflect the feed override or
  any other adjustments.

* 'motion.teleop-mode' -
  (bit, out) TRUE when motion is in 'teleop mode', as opposed to
  'coordinated mode'

* 'motion.tooloffset.x ... motion.tooloffset.w' -
  (float, out, one per axis) shows the tool offset in effect;
  it could come from the tool table ('G43' active), or it could
  come from the G-code ('G43.1' active)

=== Parameters

Many of these parameters serve as debugging aids, and are subject to
change or removal at any time.

* 'motion-command-handler.time' - (s32, RO)
* 'motion-command-handler.tmax' - (s32, RW)
* 'motion-controller.time' - (s32, RO)
* 'motion-controller.tmax' - (s32, RW)
* 'motion.debug-bit-0' - (bit, RO) This is used for debugging purposes.
* 'motion.debug-bit-1' - (bit, RO) This is used for debugging purposes.
* 'motion.debug-float-0' - (float, RO) This is used for debugging purposes.
* 'motion.debug-float-1' - (float, RO) This is used for debugging purposes.
* 'motion.debug-float-2' - (float, RO) This is used for debugging purposes.
* 'motion.debug-float-3' - (float, RO) This is used for debugging purposes.
* 'motion.debug-s32-0' - (s32, RO) This is used for debugging purposes.
* 'motion.debug-s32-1' - (s32, RO) This is used for debugging purposes.
* 'motion.servo.last-period' - (u32, RO) The number of CPU cycles between invocations of the servo
  thread. Typically, this number divided by the CPU speed gives the time
  in seconds, and can be used to determine whether the realtime motion
  controller is meeting its timing constraints
* 'motion.servo.last-period-ns' - (float, RO)

=== Functions

Generally, these functions are both added to the servo-thread in the
order shown.

* 'motion-command-handler' - Processes motion commands coming from user space
* 'motion-controller' - Runs the LinuxCNC motion controller

== Spindle

LinuxCNC can control upto eight spindles.
Motion will produce the following pins:
The __N__ (integer between 0 and 7) substitutes the spindle number.

[[sec:spindle-pins]]
=== Pins(((spindle (HAL pins))))

* 'spindle.__N__.at-speed' - (bit, in)
  Motion will pause until this pin is TRUE, under the following conditions:
** before the first feed move after each spindle start or speed change;
** before the start of every chain of spindle-synchronized moves;
** and if in CSS mode, at every rapid to feed transition.
   This input can be used to ensure that the spindle is up to speed before
   starting a cut, or that a lathe spindle in CSS mode has slowed down
   after a large to small facing pass before starting the next pass at
   the large diameter.
   Many VFDs have an 'at speed' output.
   Otherwise, it is easy to generate this signal with the 'HAL near'
   component, by comparing requested and actual spindle speeds.
* 'spindle.__N__.brake' - (bit, out) TRUE when the spindle brake should be applied.
* 'spindle.__N__.forward' - (bit, out) TRUE when the spindle should rotate forward.
* 'spindle.__N__.index-enable' - (bit, I/O) For correct operation of spindle synchronized moves, this
  pin must be hooked to the index-enable pin of the spindle encoder.
* 'spindle.__N__.inhibit' - (bit, in) When this bit is TRUE, the spindle speed is set to 0.
* 'spindle.__N__.on' - (bit, out) TRUE when spindle should rotate.
* 'spindle.__N__.reverse' - (bit, out) TRUE when the spindle should rotate backward
* 'spindle.__N__.revs' - (float, in) For correct operation of spindle synchronized moves, this
  signal must be hooked to the position pin of the spindle encoder. The
  spindle encoder position should be scaled such that spindle-revs
  increases by 1.0 for each rotation of the spindle in the clockwise ('M3') direction.
* 'spindle.__N__.speed-in' - (float, in) Feedback of actual spindle speed in rotations per second.
  This is used by feed-per-revolution motion ('G95').
  If your spindle encoder driver does not have a velocity output, you can generate
  a suitable one by sending the spindle position through a 'ddt' component.
  If you do not have a spindle encoder, you can loop back 'spindle.__N__.speed-out-rps'.
* 'spindle.__N__.speed-out' - (float, out) Commanded spindle speed in rotations per minute. Positive
  for spindle forward ('M3'), negative for spindle reverse ('M4').
* 'spindle.__N__.speed-out-abs' - (float, out) Commanded spindle speed in rotations per minute. This will
  always be a positive number.
* 'spindle.__N__.speed-out-rps' - (float, out) Commanded spindle speed in rotations per second. Positive
  for spindle forward ('M3'), negative for spindle reverse ('M4').
* 'spindle.__N__.speed-out-rps-abs' - (float, out) Commanded spindle speed in rotations per second. This will
  always be a positive number.
* 'spindle.__N__.orient-angle' - (float,out) Desired spindle orientation for M19. Value of the
  M19 R word parameter plus the value of the [RS274NGC]ORIENT_OFFSET INI parameter.
* 'spindle.__N__.orient-mode' - (s32,out) Desired spindle rotation mode M19. Default 0.
* 'spindle.__N__.orient' - (out,bit)
  Indicates start of spindle orient cycle. Set by M19. Cleared by any of M3, M4, or M5.
  If spindle-orient-fault is not zero during spindle-orient
  true, the M19 command fails with an error message.
* 'spindle.__N__.is-oriented' - (in, bit) Acknowledge pin for spindle-orient. Completes orient cycle.
  If spindle-orient was true when spindle-is-oriented was asserted, the spindle-orient pin is cleared and the
  spindle-locked pin is asserted. Also, the spindle-brake pin is asserted.
* 'spindle.__N__.orient-fault' - (s32, in) Fault code input for orient cycle. Any value other
  than zero  will cause the orient cycle to abort.
* 'spindle.__N__.lock' - (bit, out) Spindle orient complete pin. Cleared by any of M3, M4, or M5.

.HAL pin usage for M19 orient spindle
Conceptually the spindle is in one of the following modes:

- rotation mode (the default)
- searching for desired orientation mode
- orientation complete mode.

When an M19 is executed, the spindle changes to 'searching for desired
orientation', and the `spindle.__N__.orient` HAL pin is asserted.
The desired target position is specified by the `spindle.__N__.orient-angle`
and `spindle.__N__.orient-fwd` pins and driven by the M19 R and P parameters.

The HAL support logic is expected to react to `spindle.__N__.orient` by
moving the spindle to the desired position. When this is complete, the
HAL logic is expected to acknowledge this by asserting the `spindle.__N__.is-oriented` pin.

Motion then acknowledges this by deasserting the `spindle.__N__.orient` pin
and asserts the `spindle.__N__.locked` pin to indicate 'orientation complete' mode.
It also raises the `spindle.__N__.brake` pin. The spindle now is in 'orientation complete' mode.

If, during `spindle.__N__.orient` being true, and `spindle.__N__.is-oriented` not
yet asserted the `spindle.__N__.orient-fault` pin has a value other than
zero, the M19 command is aborted, a message including the fault code
is displayed, and the motion queue is flushed.
The spindle reverts to rotation mode.

Also, any of the M3, M4 or M5 commands cancel
either 'searching for desired orientation' or 'orientation complete' mode.
This is indicated by deasserting both the `spindle-orient` and `spindle-locked` pins.

The `spindle-orient-mode` pin reflects the M19 P word and shall be
interpreted as follows:

- 0: rotate clockwise or counterclockwise for smallest angular movement
- 1: always rotate clockwise
- 2: always rotate counterclockwise

It can be used with the `orient` HAL component which provides a PID
command value based on spindle encoder position, `spindle-orient-angle`
and `spindle-orient-mode`.

== Axis and Joint Pins and Parameters

These pins and parameters are created by the realtime 'motmod'
module.  [In 'trivial kinematics' machines, there is a one-to-one
correspondence between joints and axes.]
They are read and updated by the 'motion-controller' function.

See the motion man page 'motion(9)' for details on the pins and parameters.

== iocontrol

iocontrol - accepts NML I/O commands, interacts with HAL in userspace.

The signals are turned on and off in userspace - if you have strict
timing requirements or simply need more i/o, consider using the realtime
synchronized i/o provided by <<sec:motion,motion>> instead.

=== Pins (((iocontrol (HAL pins))))

* 'iocontrol.0.coolant-flood' - (bit, out) TRUE when flood coolant is requested.
* 'iocontrol.0.coolant-mist' - (bit, out) TRUE when mist coolant is requested.
* 'iocontrol.0.emc-enable-in' - (bit, in) Should be driven FALSE when an external E-Stop condition exists.
* 'iocontrol.0.lube' - (bit, out) TRUE when lube is commanded.
* 'iocontrol.0.lube_level' - (bit, in) Should be driven TRUE when lube level is high enough.
* 'iocontrol.0.tool-change' - (bit, out) TRUE when a tool change is requested.
* 'iocontrol.0.tool-changed' - (bit, in) Should be driven TRUE when a tool change is completed.
* 'iocontrol.0.tool-number' - (s32, out) The current tool number.
* 'iocontrol.0.tool-prep-number' - (s32, out) The number of the next tool, from the RS274NGC T-word.
* 'iocontrol.0.tool-prepare' - (bit, out) TRUE when a tool prepare is requested.
* 'iocontrol.0.tool-prepared' - (bit, in) Should be driven TRUE when a tool prepare is completed.
* 'iocontrol.0.user-enable-out' - (bit, out) FALSE when an internal E-Stop condition exists.
* 'iocontrol.0.user-request-enable' - (bit, out) TRUE when the user has requested that E-Stop be cleared.

== INI settings

A number of INI settings are made available as HAL input pins.

=== Pins (((INI settings (HAL pins))))

_N_ refers to a joint number, _L_ refers to an axis letter.

* 'ini.__N__.ferror' - (float, in) [JOINT_N]FERROR
* 'ini.__N__.min_ferror' - (float, in) [JOINT_N]MIN_FERROR
* 'ini.__N__.backlash' - (float, in) [JOINT_N]BACKLASH
* 'ini.__N__.min_limit' - (float, in) [JOINT_N]MIN_LIMIT
* 'ini.__N__.max_limit' - (float, in) [JOINT_N]MAX_LIMIT
* 'ini.__N__.max_velocity' - (float, in) [JOINT_N]MAX_VELOCITY
* 'ini.__N__.max_acceleration' - (float, in) [JOINT_N]MAX_ACCELERATION
* 'ini.__N__.home' - (float, in) [JOINT_N]HOME
* 'ini.__N__.home_offset' - (float, in) [JOINT_N]HOME_OFFSET
* 'ini.__N__.home_offset' - (s32, in) [JOINT_N]HOME_SEQUENCE
* 'ini.__L__.min_limit' - (float, in) [AXIS_L]MIN_LIMIT
* 'ini.__L__.max_limit' - (float, in) [AXIS_L]MAX_LIMIT
* 'ini.__L__.max_velocity' - (float, in) [AXIS_L]MAX_VELOCITY
* 'ini.__L__.max_acceleration' - (float, in) [AXIS_L]MAX_ACCELERATION

[NOTE]
The per-axis min_limit and max_limit pins are honored continuously after homing.
The per-axis ferror and min_ferror pins are honored when the machine is on and
not in position.
The per-axis max_velocity and max_acceleration pins are sampled when the
machine is on and the motion_state is free (homing or jogging) but are not
sampled when in a program is running (auto mode) or in MDI mode.  Consequently,
changing the pin values when a program is running will not have effect until
the program is stopped and the motion_state is again free.

* 'ini.traj_arc_blend_enable' - (bit, in) [TRAJ]ARC_BLEND_ENABLE
* 'ini.traj_arc_blend_fallback_enable' - (bit, in) [TRAJ]ARC_BLEND_FALLBACK_ENABLE
* 'ini.traj_arc_blend_gap_cycles' - (float, in) [TRAJ]ARC_BLEND_GAP_CYCLES
* 'ini.traj_arc_blend_optimization_depth' - (float, in) [TRAJ]ARC_BLEND_OPTIMIZATION_DEPTH
* 'ini.traj_arc_blend_ramp_freq' - (float, in) [TRAJ]ARC_BLEND_RAMP_FREQ

[NOTE]
The traj_arc_blend pins are sampled continuously but changing pin values
while a program is running may not have immediate effect due to queueing
of commands.

* 'ini.traj_default_acceleration' - (float, in) [TRAJ]DEFAULT_ACCELERATION
* 'ini.traj_default_velocity' - (float, in) [TRAJ]DEFAULT_VELOCITY
* 'ini.traj_max_acceleration' - (float, in) [TRAJ]MAX_ACCELERATION

// vim: set syntax=asciidoc:
