Skip to content

Multiaxis kinematics and limits - #4373

Closed
grandixximo wants to merge 6 commits into
LinuxCNC:masterfrom
grandixximo:switchkins-comps
Closed

Multiaxis kinematics and limits#4373
grandixximo wants to merge 6 commits into
LinuxCNC:masterfrom
grandixximo:switchkins-comps

Conversation

@grandixximo

@grandixximo grandixximo commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Draft. This is where the multiaxis kinematics work is going, open early so it can be argued with. The first three commits are #4372, review those there. As pieces are agreed I will split them into small PRs, rebase this, and carry on, so nothing stalls behind it.

Plan, in order:

  1. Switchkins: one implementation, used by .comp, .c, in tree and out of tree.
  2. Tool length, oriented and integrated: a real tool vector in the machine's orientation, agreed on by the interpreter, the kinematics and the limits, instead of a scalar Z offset that each kinematics model re-derives for itself and that X and Y never get at all.
  3. Forward and inverse kinematics earlier in the pipeline.
  4. Velocity, acceleration, jerk and position limits, for every TP and every UI.

G12.1 and G13.1 sit on top of 1.

In this branch now

  • separate the dispatch from rtapi_app_main(): switchkins.c keeps the kinematics interface and the type dispatch and gains switchkinsInit(); the new switchkins_main.c takes rtapi_app_main() and the module parameters. The eight existing modules link both and are unchanged.
  • let halcompile components use the switchkins core: millturn, xyzab_tdr_kins, xyzacb_trsrn and xyzbca_trsrn drop their private copy of the dispatch and call switchkinsInit() from EXTRA_SETUP(), which halcompile runs between hal_init() and hal_ready(). They could not link switchkins.o before, because switchkins.c supplied rtapi_app_main() and so does halcompile. The generated per-comp .mak now takes a <component>-extra-objs list, and switchkins.h is installed.
  • add an out-of-tree module template: switchkinscomp.comp, TOPDIR plus #include of switchkins.c and kins_util.c, the same pattern tpcomp and homecomp use. No ABI, since the sources compile into the module.

User visible

  • The four components gain the coordinates= module parameter, their identity type now coming from kins_util.c.
  • A bad motion.switchkins-type is rejected and leaves the running kinematics alone, instead of switching to a type that does not exist and clearing every kinstype.is-N pin.
  • millturn loses its in and out example pins, template scaffolding referenced by no config. fpin and fdemo stay.
  • All other pin names unchanged.

All four sim configs give identical positions to master through the same MDI sequence, in every kinematics type.

kinematicsSwitch() stored the requested type in switchkins_type and only
then ran the switch statement that validates it, so an out of range
request left the module pointing at a kinematics that does not exist.
The switch itself returned -1 and motion raised its error flag, but
switchkins_type kept the bad value, so every kinematicsForward() and
kinematicsInverse() call after that failed too and printed

  switchkins: Forward BAD switchkins_type </7>

once per servo cycle for as long as the machine stayed up.

Validate the request first and return without touching switchkins_type,
which leaves the running kinematics in place.  With the range checked up
front the default arm of the switch is unreachable, so it goes away.
switchkins.c dispatched on switchkins_type with a three way switch and
created a fixed kinstype.is-0/1/2, so a module could never provide more
than three kinematics.

Hold the setup, forward and inverse functions in arrays and dispatch by
index.  switchkinsSetup() still provides types 0,1,2 exactly as before,
so no kinematics module changes and out of tree modules keep compiling.
A module wanting more calls the new switchkinsRegister() from within
switchkinsSetup(), once per additional type.  The kinstype.is-N pins are
created in a loop, which leaves the names of the first three unchanged.
Registration was restricted to types 3 and up, which left types 0,1,2
arriving one way and the rest another.  Allow any type from 0, so
registration is the general mechanism and the switchkinsSetup()
arguments are a shorthand for the first three.

A type has to come from one route or the other.  Registering one that
switchkinsSetup() already filled in is refused, and a rejected
registration now fails the module load instead of only printing, since
no caller checks the return value.

The count of provided types is taken from the highest one filled by
either route rather than assumed to be three, so a module can register
all of them.  A type left out below that is a gap, and the load time
message now names the type and which of the three functions is missing
instead of saying only "Missing setup function".
switchkins.c owned rtapi_app_main(), so a module could only use it by
having no main of its own.  That ruled out halcompile components, which
is why the switchable kinematics in hal/components each carry a private
copy of the dispatch, the kinstype pins and the switch statement.

Move rtapi_app_main(), rtapi_app_exit() and the coordinates= and sparm=
module parameters to switchkins_main.c, and give switchkins.c a single
entry point:

    int switchkinsInit(const int comp_id, kparms* kp, const char* coordinates);

It counts and validates the registered types, creates the pins and
starts on type 0.  The caller owns the hal component, doing hal_init()
before and hal_ready() after, so anything that already has a component
can use switchkins by calling this.

The types switchkinsSetup() supplies now reach the arrays through
switchkinsRegister() like any others, rather than being written
directly through its out parameters.  One registration path means the
checks apply to every type, so a module that both fills an argument and
registers the same type is refused rather than silently overwriting.

The eight existing modules gain switchkins_main.o in their -objs and
are otherwise untouched.
millturn, xyzab_tdr_kins, xyzacb_trsrn and xyzbca_trsrn each carried
their own copy of the switchkins dispatch: a private switchkins_type, a
kinematicsSwitch() with a hand-written case per type, and a setup
routine that had to hal_set_unready() the component again because it
ran from kinematicsType(), long after halcompile had called
hal_ready().  Four copies of the same thing, none of them sharing the
fixes made to switchkins.c.

They could not link switchkins.o before, because switchkins.c supplied
rtapi_app_main() and so does halcompile.  Now that the dispatch is
separate from the 'main' program, a component can link it and call
switchkinsInit() from EXTRA_SETUP(), which halcompile runs after
hal_init() and before hal_ready().

Two build changes make that possible:

 - the generated per-comp .mak takes a <component>-extra-objs list, so
   a .comp can name objects besides its own.
 - switchkins.h is copied to ../include and installed, so
   <switchkins.h> resolves from a generated component source.

Each of the four now registers its kinematics types and calls
switchkinsInit().  Their identity type comes from kins_util.c, which
gets them the coordinates= module parameter they never had, and a bad
motion.switchkins-type is now rejected and leaves the running
kinematics alone instead of stranding the module on a type that does
not exist.

Pin names are unchanged, except that millturn's in/out example pins are
gone: they were template scaffolding copied from userkins.comp, unused
by the sim config, and a kinematics-type setup routine is where
kinematics pins belong now.  millturn keeps its fpin pin and fdemo
function.

The xyzab-tdr, xyzacb-trsrn, xyzbca-trsrn and millturn sim configs give
the same positions through the same MDI sequence as before, to four
decimals, in every kinematics type.
Nothing stopped an out-of-tree kinematics module from using switchkins
except that there was no way to get at the implementation, so anyone
writing one reimplemented kinematicsSwitch() and the kinstype.is-N
pins, or did without switching entirely.

switchkinscomp.comp is the template for doing it properly.  It sets
TOPDIR to a source tree and includes switchkins.c and kins_util.c,
which is how tpcomp.comp and homecomp.comp already reach the
trajectory planning and homing sources.  The module then registers its
kinstypes and calls switchkinsInit() from EXTRA_SETUP(), the same
fifteen lines the in-tree components use.

That gets an out-of-tree module the kinematics switching, the
kinstype.is-N pins, the coordinates= identity mapping and the HAL and
G-code controls, all from the one implementation, and it costs no ABI:
the sources are compiled into the module, so it is built against one
tree and rebuilt when that tree changes.

Like tpcomp, the template is not built in tree because it has no
kinematics until TOPDIR is set, so it is filtered out of COMPS and its
manpage is named explicitly.

Renamed to user_switchkins, pointed at this tree and loaded as
[KINS]KINEMATICS, it homes, switches to its example kinstype and back,
and rejects a kinstype it does not have.
@grandixximo
grandixximo deleted the switchkins-comps branch August 12, 2026 02:48
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.

1 participant