Hi Robert,
Thanks for the feedback. I spent some time investigating the dlopen
approach more carefully, and unfortunately it's not as straightforward
as I initially hoped.
The kinematics modules do compile as .so files and export
kinematicsForward/kinematicsInverse as dynamic symbols. However, the
problem is how they access parameters.
Looking at 5axiskins.so for example:
$ nm -D rtlib/5axiskins.so | grep kinematics
00000000000060c0 T kinematicsForward
0000000000006380 T kinematicsInverse
$ nm -D rtlib/5axiskins.so | grep " U "
U hal_init
U hal_malloc
U hal_pin_float_newf
...
The module stores parameters via a static haldata struct containing
pointers to HAL shared memory:
struct haldata {
hal_float_t *pivot_length; // pointer to HAL shared memory
} *haldata;
// In kinematicsInverse:
PmCartesian r = s2r(*(haldata->pivot_length), ...);
If I dlopen the module in my userspace planner:
I'd need to call rtapi_app_main() which does hal_init() - but HAL is
already initialized by the RT motion module. This would either fail or
create a duplicate component.
Even if initialization succeeded, the haldata pointers would reference
different shared memory than what motion is using. My pivot_length might
not be the same pin.
The static joint mappings (JX, JY, etc.) are set during rtapi_app_main()
based on the coordinates parameter - they'd be uninitialized in a
dlopen'd copy.
haldata is a static local variable (BSS), not exported, so I can't even
manually set it up.
I could try to mock the HAL functions and intercept pin creation, but
that feels fragile and complex.
Given this, I think the cleanest options are:
A) Extract pure math into shared headers - Both RT modules and userspace
call the same functions, passing parameters explicitly. RT gets params
from HAL pins, userspace reads them via halcmd/procfs. Requires
modifying existing RT kinematics.
B) Maintain separate userspace implementation - What I have now.
Duplicates the math but keeps RT modules untouched.
C) Conditional compilation - Single source with #ifdef USERSPACE_KINS to
switch between HAL pointers and direct parameters. Less invasive than
(A) but adds preprocessor complexity.
I'm leaning toward (A) as the cleanest long-term solution, but it
touches more files. Would that kind of refactoring be acceptable
upstream, or would (B) be preferred to avoid changing the RT kinematics?
Regarding uspace-only: I agree that's the practical direction. My 9D
planner is already uspace-only since it needs C++ and runs in milltask.
I just wanted to avoid maintaining duplicate kinematics math if there
was a clean way to share it.
*Luca Toniolo*
On 1/27/2026 6:38 PM, Robert Schöftner wrote:
On Di, 2026-01-27 at 16:59 +0800, Luca Toniolo wrote:
// Load the existing kinematics module
void *handle = dlopen("trivkins.so", RTLD_NOW);
kinematicsInverse_t kins_inverse = dlsym(handle,
"kinematicsInverse");
// Call it directly
kins_inverse(&world, joints, ...);
Pros: Uses exact same binary
Cons: Only works in uspace builds, needs careful handling of HAL
context
Thoughts?
it should be trivially possible to build 2 versions of the same source,
one for the "realtime" part and one for userspace. otoh it doesn't look
like rtai is receiving much development, unfortunately, Paolo
Mantegazza, the main driving force behind it passed away a year ago.
so for me, uspace-only is the way to go (most modern hardware
interfaces like ethernet mesa cards or ethercat also currently need a
uspace build). but maybe somebody who knows what is happening in the
rtai world can chime in.
I have never seen a xenomai linuxcnc system, but afaik there the
realtime stuff also runs in a kind of "normal" userspace and has no
problems with c++.
_______________________________________________
Emc-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/emc-developers