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

Reply via email to