Skip to content

G12.1, G13.1: select the kinematics type from G-code - #4414

Open
grandixximo wants to merge 9 commits into
LinuxCNC:masterfrom
grandixximo:g121-kins
Open

G12.1, G13.1: select the kinematics type from G-code#4414
grandixximo wants to merge 9 commits into
LinuxCNC:masterfrom
grandixximo:g121-kins

Conversation

@grandixximo

Copy link
Copy Markdown
Contributor

Switchable kinematics is selected today by writing motion.switchkins-type from HAL, in practice M68 E- Q- against an analog output netted in the INI. The interpreter never sees it, so a program is read, its limits checked and its path looked ahead in whatever kinematics the interpreter last knew about. This adds G12.1 P- and G13.1 so the selection goes through the interpreter and motion together.

Part of #4374, which is where the rest of the multiaxis work is described. Nothing here depends on the other pieces.

What it does

  • G12.1 P- selects a kinematics type, G13.1 cancels to type 0. Both queue a synchronisation point.
  • #<_kins_type> is read back from motion on every synch, so it stays right across an abort or a switch made behind the interpreter's back.
  • New motion.kins-type status pin reports the type actually in force.
  • Selecting from HAL is deprecated. motion.switchkins-type still works and warns once per session.
  • A type the module does not provide is refused and now says so, leaving the type, the pin and #<_kins_type> on the kinematics still running. Motion published the requested type before asking the module, so a refused type was reported as though it were running, and the refusal reached the operator as nothing but a line in the realtime log.
  • Every switchkins sim config moves to G12.1, so none of them trips the deprecation warning. The nets from motion.analog-out-03 go with them, and the trsrn vismach guis and the halshow watch lists follow motion.kins-type.

Why these numbers

Out-of-tree patches have used G12.1 and G13.1 for kinematics switching for years, so configurations in the wild already speak them.

They also keep LinuxCNC parallel with other controllers, where G12.1 and G13.1 turn polar coordinate interpolation on and off. That is itself a change of kinematics, and if LinuxCNC ever gets it, switchkins is where it belongs rather than as a mechanism of its own. G12 and G13 are circular pocket milling on those controllers, so leaving the plain codes free keeps room to port that later.

Renames

adjustKinsVar0 was the kinematics type and kinsType was a char toggling between 'r' and 's'. Neither name described what it held. The traj-prefixed status fields moved into EMC_TRAJ_STAT where they belong.

No other pin, G-code or INI name changes.

Testing

runtests on interp, kinematics, remap and motion: 108 run, 108 successful, 0 failed.

Every switchkins sim config driven headless through its own M428, M429 and M430, correct type each time and no deprecation warning: millturn, scara, bridgemill, hexapod, melfa, puma, xyzac-trt, xyzbc-trt, xyzab-tdr, xyzacb-trsrn and xyzbca-trsrn, the last two including the TWP wrappers. Those remaps check #<_kins_type> against what they asked for and stop the program if it disagrees, so they are a round trip test as well as a migration test.

Also checked by hand: a type the module does not provide, which leaves the kinematics, the pin and #<_kins_type> where they were and reports the refusal; a switch made from HAL behind the interpreter's back, which the interpreter picks up on the next synch, with one warning per session; and abort of a program that had switched mid-run, after which motion and the interpreter still agree.

G12.1 P- selects one of the kinematics offered by a switchable
kinematics module and G13.1 cancels back to kinematics 0.  Both are
queue synchronisation points, so no motion is ever planned in one
kinematics and executed in another.

Until now the only way to switch from a program was to write
motion.switchkins-type through an analog output and force a sync by
hand, typically M68 E3 Q1 followed by M66 E0 L0, wrapped in a
subroutine or a remapped M-code.  That also costs the #5399 variable
on every switch, because M66 writes it.

G13.1 cancels to kinematics 0 rather than restoring whatever was
selected before, which is how every other cancel in the language
behaves and keeps a block's meaning independent of the path taken
through the program.  To put back a caller's selection, read
#<_kins_type>:

    #<saved> = #<_kins_type>
    G12.1 P2
    ( ... )
    G12.1 P#<saved>

Nothing cancels the selection implicitly.  It survives program end and
abort so that the kinematics keeps matching the position readout, since
switching re-derives world position from the joints and would otherwise
move the readout while the machine stands still.

Motion takes the G-code request and the motion.switchkins-type pin on
their edges, so whichever asked most recently wins and a config can use
either or both.  Writing the pin from motion instead does not work: the
configs source it from an analog output that would put its own value
back on the next servo cycle.  motion.kins-type reports the selection
now in force.

Q was parsed and carried all the way to motion without anything ever
reading it, so it is gone.

EMC_ADJUST_KINS_OFFSET_DATA is registered in the NML format and name
tables and has the update() its declaration promised, without which the
message could not cross the channel.
The interpreter tracked the kinematics it had selected itself, which is
not always the one motion is running.  An abort clears the interpreter
list, so a G12.1 that was queued but not yet sent is dropped while the
interpreter keeps the type it converted.  A config that drives
motion.switchkins-type from HAL changes the kinematics without the
interpreter hearing about it at all.  Either way #<_kins_type> reports
something that is not running, and the save and restore idiom

  #<saved> = #<_kins_type>
  G12.1 P3
  ( ... )
  G12.1 P#<saved>

puts back the wrong kinematics.

Carry the kinematics motion is running up into status and read it back
in Interp::synch(), which already runs after an abort and after every
completed switch.  Task no longer writes the requested value into
status, so the field has a single writer and always reports what motion
is actually running.
handle_kinematicsSwitch() assigned the requested type, published it on
motion.kins-type, stored it in the status, and only then asked the
module to switch.  A module that refuses a type it does not provide
goes on running the one it has, so the readout named a kinematics that
was not in force, and G12.1 P#<_kins_type> put that wrong number back.

Ask first, record after.  A refused switch leaves the type, the pin and
#<_kins_type> on the kinematics still running, and still raises the
motion error.  The refusal reached the operator as nothing at all, only
a line in the realtime log, which was survivable while switching came
from HAL and is not once a G-code block can ask: say which type was
refused and which one is still running.  The failure message names the
type that was asked for rather than the HAL pin, which is not where the
request came from when it came from G-code.

G12.1 P7 on xyzab_tdr_kins, which provides two types, left
motion.kins-type reading 7 while kinstype.is-0 stayed true.  It reads 0.
Comment thread configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc
Comment thread configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc
Comment thread docs/src/man/man9/motion.9.adoc Outdated
Comment thread docs/src/motion/switchkins.adoc Outdated

@Sigma1912 Sigma1912 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to keep the 'M428','M429' and 'M430' remaps in all those configs that do not have a M128/M129 call to switch the limit values?

The M66 sync after M128, M129 calls are required so the interpreter rereads the changed limit values. Once limit switching in this manner is no longer required both the M128 / M129 and the following M66 can go.

motion.switchkins-type cannot be the general way to choose kinematics.
The interpreter never sees it, so a program is read, its limits
checked and its path looked ahead in whatever kinematics the
interpreter last knew about, which need not be the one that ends up
running it.  Nothing in the pin can fix that; the interpreter has to be
told, which is what G12.1 and G13.1 are for.

Motion says so once per session, the first time the pin is used to
change the type.  A configuration that never switches never sees it,
and the G-code route never triggers it.  The pin is in a grace period:
it keeps working for now, and is meant to go.

Both the man page and the switchkins chapter claimed G12.1 and G13.1
write this pin.  They do not, and cannot: the configs source it from an
analog output that would put its own value back on the next servo
cycle.  They ask motion directly.
The G12.1 plumbing arrived from the out-of-tree patch with names that
describe nothing.  `adjustKinsVar0` is the kinematics type, there is no
Var1, and nothing adjusts an offset.  `kinsType` is not a type at all:
it was a char toggling between 'r' and 's' so the servo cycle could
notice that a new request had arrived.  The field named like a type was
a flag and the field with the opaque name was the type.

So:

  adjustKinsVar0              -> switchkins_type, an int
  kinsType ('r'/'s' toggle)   -> switchkins_seq, a counter
  trajKinsType                -> switchkins_seq in EMC_TRAJ_STAT
  trajKinsTypeModified        -> switchkins_changed in EMC_TRAJ_STAT
  ADJUST_KINS_OFFSET(double)  -> SELECT_KINS_TYPE(int)
  EMC_ADJUST_KINS_OFFSET_DATA -> EMC_TRAJ_SELECT_KINS
  EMCMOT_ADJUST_KINS_OFFSET_DATA -> EMCMOT_SELECT_KINS_TYPE
  emcAdjustKinsOffset()       -> emcSelectKinsType()

switchkins_type rather than kinsType because EMC_TRAJ_STAT already has
kinematics_type, which is the identity/serial/parallel/custom kind and
a different thing entirely.  switchkins_type is what the HAL pin and
switchkins.c already call it.

The three status fields were prefixed traj but lived in EMC_MOTION_STAT.
They are trajectory status, so they move into EMC_TRAJ_STAT and lose the
prefix, which also means EMC_TRAJ_STAT::update() carries them.

A counter instead of a two-state toggle keeps the property the toggle
had, that asking for the type already in force is still seen as a
request, without pretending to be an enum.

No G-code, HAL pin or INI name changes.
The four sim configs whose kinematics components now use the switchkins
core chose their kinematics by writing motion.switchkins-type through an
analog output, the route motion has just deprecated.  Each of them would
have met the user with the deprecation warning the first time they
pressed a kinematics button.

The M428, M429 and M430 remaps, the TWP wrappers behind G53.1, G53.3,
G53.6 and G69, the abort handler and remap.py now use G12.1 and G13.1.
That drops the M66 sync either side of every switch, the test that the
HAL pin exists at all, and the #5399 clobber each M66 costs, since G12.1
and G13.1 synchronise interpreter and motion themselves.  The check that
the switch took reads #<_kins_type> instead of the pin.

millturn keeps the M66 at the end of M428 and M429.  That one is not
there for the switch: M128 and M129 change the axis limits from a Tcl
script, which reaches motion through inihal, so read-ahead has to stop
until the new limits have landed.

The vismach guis for the two trsrn configs were reading the value
requested through the analog output.  They now take motion.kins-type,
which is the kinematics actually in force.

Eight other sim config directories still select kinematics from HAL:
bridgemill, table-rotary-tilting, hexapod-sim, melfa-sim, puma, and the
three copies of scara.  They are untouched here, and still work.
The rest of the sim configs that shipped with switchkins chose their
kinematics by writing motion.switchkins-type through an analog output,
which motion now reports as deprecated: bridgemill, table-rotary-tilting,
hexapod-sim, melfa-sim, puma and the three copies of scara.

Same change as the comp sims got.  The M428, M429 and M430 remaps use
G12.1 and G13.1, which drops the M66 sync either side of every switch,
the test for the hal pin, and the #5399 clobber each M66 costs.  The
check that the switch took reads #<_kins_type>.  The [HAL] net from
motion.analog-out-03 goes with them, and the two halshow watch lists
follow motion.kins-type instead of the pin that used to drive it.

No sim config selects kinematics from HAL now.
The G-code chapter told the reader a config may select the kinematics
"from G-code, from that pin, or from both", and the switchkins chapter
said the same twice, in its introduction and again under G-code
commands.  All three predate motion reporting the pin as deprecated, and
they contradict it.

They now say the pin is deprecated and why, in the same words as the man
page.  The G-code chapter keeps the fact that the pin takes the same
numbering, which is what somebody migrating away from it needs to know.
The paragraph read as though the pin were an equal alternative that
happened to carry a caveat.  State the deprecation first, as a warning.
@grandixximo

Copy link
Copy Markdown
Contributor Author

No reason beyond keeping this PR to one subject. Where there are no limits to switch the remap is now a G12.1 and the guard that checks the switch took, so you are right that it is thin, but dropping it means moving that guard somewhere or losing it, and it is what the halui buttons and the docs point at.

I would rather do it once the limits move out of M128/M129, because that is the change that empties the millturn remaps too, and then all of them can be cleaned up the same way in one pass instead of two. It also keeps this diff to one thing: migrate the selection mechanism, change nothing else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants