RFC alternative: evaluate a kinematics module outside RT by binding to its live HAL pins - #4
Open
grandixximo wants to merge 1 commit into
Open
RFC alternative: evaluate a kinematics module outside RT by binding to its live HAL pins#4grandixximo wants to merge 1 commit into
grandixximo wants to merge 1 commit into
Conversation
Alternative to publishing a parameter snapshot in shared memory.
A kinematics module's haldata is a struct of pin handles, and a handle
is an opaque pointer to the value cell that hal_get_real() reads. So a
second, non-RT copy of the module can point its haldata at the cells the
running RT instance already owns, and then its forward and inverse work
unmodified, on live values, at any pose the caller asks for.
Per module that comes to:
- export nonrt_attach(), which binds the input pins by name, runs the
same coordinate parse setup runs, and returns the module's existing
forward and inverse pointers;
- split the coordinate parse out of setup so nonrt_attach() can call
it without creating pins.
Nothing else changes. The kinematics math is untouched, there is no
parameter struct to declare, no shared header that grows once per
module, no snapshot to refresh from inside the servo loop and no
sequence counter to get right. Out-of-tree modules can opt in without
anyone editing a header they do not own.
Bind input pins only. Output pins and scratch storage stay private to
the non-RT copy: the two copies run in different processes and must not
write to each other's state. 5axiskins has neither, so its non-RT
haldata is one static struct. trivkins needs no binding at all, only a
statement that joints are axes.
hal_get_pin_value_by_name() already existed and already did the right
thing; it was simply never EXPORT_SYMBOL'd, so RT modules could not link
it. That one line is the entire HAL change.
Verified against the struct-snapshot version of this work: for the same
pivot length, kinslimits reports identical caps to the digit. With
5axiskins.pivot-length set by setp and no motion thread running, this
version reads the value that was set and the snapshot version reads the
setup default, because a snapshot only refreshes when RT calls forward
or inverse.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC, not a merge request. This is an alternative to #3, which sets out the problem, the mathematics and the diagnostic. Read that one first. Both branches are standalone and complete: same loader, same Jacobian, same limit calculation, same
kinslimitstool. They differ only in what a kinematics module has to do to be usable outside RT. Merge one or the other, not both.The idea
A kinematics module's
haldatais a struct of pin handles, and a handle is an opaque pointer to the value cellhal_get_real()reads. So a non-RT copy of the module can point itshaldataat the cells the running RT instance already owns, and its own forward and inverse then work unmodified, on live values, at any pose asked of them.That is the whole obligation, plus splitting the coordinate parse out of setup so the hook can run it without creating pins. Rules 1 to 5 in the other PR are gone: no parameter union in a shared header, no struct to register, no snapshot to refresh from inside the servo loop, no sequence counter, and the kinematics math is untouched. Out-of-tree modules can opt in without anyone editing a header they do not own.
trivkins needs no binding at all, only a statement that joints are axes, so a caller can skip the module entirely.
Cost, side by side
Counting only the parts that differ, with the loader, the Jacobian, the limit calculation and the diagnostic excluded because they are identical in both branches:
The HAL side is the sharpest difference.
hal_get_pin_value_by_name()already exists, already returns exactly the right pointer, and was simply neverEXPORT_SYMBOLed, so RT modules cannot link it. That one line is the entire HAL change here, against 212 lines of new allocator and a shmem layout revision there.They agree
With the pivot at its default of 250,
kinslimitsreports the same caps from both branches, to the digit:The identity path matches too, at 62.5 for the 3-4-5 move in the other PR. 5axiskins still loads under motmod after the setup refactor.
They disagree in one instructive place
Set
5axiskins.pivot-lengthto 100 with no motion thread running, and this branch reports caps for a 100 mm pivot while the snapshot branch reports caps for 250:dX/dB is 1.7453, which is 100 * pi/180, so it is reading the live pin. A snapshot only refreshes when RT calls forward or inverse, and nothing was calling them. On a running machine
do_forward_kins()covers that every servo cycle, so this is not a bug in the snapshot approach; it is a dependency the binding approach does not have.What binding still requires, and what I checked
No module in tree caches derived state. I went through all of them: every one reads its parameters inside forward and inverse, or in a helper those functions call, such as
genhex_read_hal_pinsandpentakins_read_hal_pins. So the recompute hook I expected to need is needed nowhere in tree. An out-of-tree module that does cache would need one, and would know it.Output pins and scratch must stay private. The two copies live in different processes and must not write to each other's state.
genserfuncsis the case in tree: it writeslast_iterationsand keeps ahal_malloc'dgo_posescratch, so a bound copy has to keep those private rather than point them at the RT cells. 5axiskins has neither, which is why its non-RThaldatais a single static struct. This is the one thing binding asks of a module author that the snapshot does not, and it is a real judgement call per module.The cell moves if the pin is later linked to a signal. These parameters are set with
setpin every config I have seen, so binding once is probably fine, but it deserves a decision rather than my assumption.Consistency across parameters is given up. Three rot-point values read one at a time can straddle a change that a snapshot would deliver atomically. Since machine geometry changing mid-move is not physical, I do not think this is a real loss, but it is the honest argument for the snapshot.
My view
I think this is the better answer and I would rather ship it. I am putting both up because the judgement about what a kinematics module should be obliged to do is not mine alone to make.