Repository navigation
genserkins: use posemath, remove gomath - #4676
grandixximo wants to merge 4 commits into
Conversation
2506950 to
3fdd1a8
Compare
5a1e25b to
81d3bd4
Compare
|
@BsAtHome this is the consolidation from the #4673 discussion. One choice I am not sure of: tpmod exports the two posemath functions only so the test can reach them. posemath as a module of its own would be the cleaner shape, but every module that links it would then need it loaded first, so I left that out of this PR, should it be a follow up? |
This cleanup is the right strategy. Exporting from tpmod,... making posemath a component would be a hassle and suddenly require load order control. That could potentially affect many configs. What happens when an RT module links to an additional DSO? Your test program could, in principle, link with libposemath.so at link-time. There are no RT/non-RT differences in that DSO afaik. There is no use of either RTAPI or ULAPI defines in posemath. Or would the import of libposemath.so cause name collisions? I think that the load order normally resolves names for runtime linking. maybe worth a test? |
|
I tested it. Linking works, and it shows the realtime component is not needed at all. The checker built as a realtime component with
So it works, but which copy the test checks depends on load order. And on RTAI a kernel module cannot link a userspace The simpler answer is your first point: posemath has no RTAPI or ULAPI code ( So unless you see a reason to keep it in realtime, I'll fold that into this PR: the test becomes a userspace program again, linked with |
|
Well, I thought the only requirement for the extra exported functions was being able to run the test. Since this works, the real question is whether the actual code is identical between the version in RT compiled If they are different, then running the test in RT and in non-RT may give different results. That would actually be an "interesting" problem... This needs to be checked before we go either way. The RTAI problem,... how many tests currently fail on RTAI? It is only tested incidental when someone tries it. However, this does make an argument for just doing the two export symbol lines if the test is to be done in RT. If the test can be done in non-RT, without loss of expression, then we can ignore RTAI and it would be preferable to do the test in non-RT. |
81d3bd4 to
be5bfed
Compare
|
I checked it. The flags do differ: the realtime objects add
So a userspace test of these two functions loses nothing against the realtime build; a comment in |
| genser_matrix *ab) | ||
| { | ||
| genser_matrix out; | ||
| int row, col, i; |
There was a problem hiding this comment.
These are loop variables constrained to the loop. They should be declared in the for() statement. It prevents scope creep of these locals.
(same comment many other places too in your added code)
There was a problem hiding this comment.
Done. Every loop in the code I added (the matrix and LU helpers, compute_jfwd(), link_pose_build(), genser_kin_fwd()) declares its variable in the for(), and the other locals moved into the scope that uses them.
| /* backsubstitute a column with a 1 in it to get the inverse */ | ||
| matrix_init(&out, n, n); | ||
| for (col = 0; col < n; col++) { | ||
| memset(v, 0, sizeof(v)); |
There was a problem hiding this comment.
You could declare v in the loop and assign {} to zero it, like in:
for (int col = 0; col < n; col++) {
double v[GENSER_MAX_JOINTS] = {};
...
}
...Makes locals local and does not require the memset.
There was a problem hiding this comment.
Done: double v[GENSER_MAX_JOINTS] = {0.0}; inside the loop, no memset(). I used {0.0} since an empty {} is standard C only from C23.
| int row, i; | ||
|
|
||
| for (row = 0; row < a->rows; row++) { | ||
| out[row] = 0; |
There was a problem hiding this comment.
out[row] is a double. Then you should assign 0.0.
There was a problem hiding this comment.
Done, and the other double constants in the added code too.
| static int ludcmp(double a[GENSER_MAX_JOINTS][GENSER_MAX_JOINTS], int n, int *indx) | ||
| { | ||
| double scale[GENSER_MAX_JOINTS]; | ||
| double big, dum, sum, temp; |
There was a problem hiding this comment.
Same comment on locals. Better to be declared within the scope they are required.
There was a problem hiding this comment.
Done: big, sum, the swap value and the pivot reciprocal now live in the loops that use them.
| joints[0],joints[1],joints[2],joints[3],joints[4],joints[5]); | ||
| if (0 != retval) { | ||
| printf("inv kins error %d <%s>\n", retval,go_result_to_string(retval)); | ||
| printf("inv kins error %d\n", retval); |
There was a problem hiding this comment.
The error string got removed. What error are possible? Worth looking into to convert to text again? Or are these trivial errors?
There was a problem hiding this comment.
Two errors are left: GENSER_ERROR, the inverse did not converge, and GENSER_SINGULAR, a Jacobian with no inverse. A small result_string() in ugenserkins.c prints them as text again.
genserkins was the only user of gomath. The pose, quaternion and RPY work now goes through posemath, which has the same routines. What posemath has no counterpart for stays with genser as static functions in genserfuncs.c: the small matrices of the Jacobian and their LU inverse, the Denavit-Hartenberg link pose, and the quaternion to rotation vector conversion, since pmQuatRotConvert() zeroes a rotation under 1e-6 and the inverse iterates to 1e-7. pmPosePoseMult() writes the result's translation before it reads the first operand's, so products whose result is an operand go through a copy. The thresholds are gomath's double ones, 1e-7, so the results do not move: over a grid of 592 poses the forward agrees to 1e-12, and the inverse returns the same joints and the same result at every pose except those with the wrist exactly straight, where its Jacobian is singular and the iteration may settle on another of the equivalent wrist solutions. At a pitch of minus a quarter turn the RPY conversion now takes the branch posemath has for it; gomath tested plus a quarter turn twice (LinuxCNC#389). genser_kin_jac_inv() and genser_kin_jac_fwd() had no callers and go, with the declarations of functions genserkins.h named but nothing defined.
With genserkins on posemath nothing uses gomath. Its headers were never exported, so no module outside the tree could include them.
pmCartCartParallel() and pmCartCartAntiParallel() are vector helpers with nothing of the planner in them, so they go with the rest of the PmCartesian functions. The debug JSON output they wrote goes with the move, since posemath has no planner debug output.
tests/blendmath compiled blendmath.c into a userspace program with -DULAPI. Since blendmath.c exports pmCircleEffectiveMinRadius() (LinuxCNC#4643), EXPORT_SYMBOL is undefined there, which GCC 13 lets through as an implicit int and GCC 14 rejects. The two functions it checks are posemath's now, and posemath uses neither RTAPI nor ULAPI, so it becomes tests/posemath-parallel: a program linked with libposemath, with no blendmath.c to compile and nothing exported from a module for the test. The checks themselves are unchanged.
be5bfed to
bee44a7
Compare
gomath came in with genserkins in 2009, adapted from Fred Proctor's code, with a TODO in its header: "find the new functions, add them to posemath, convert the rest". genserkins was its only user. This does that conversion and removes gomath.
Fixes #389: genser now uses posemath's RPY conversion, which handles a pitch of minus a quarter turn. With the default geometry and the wrist at -90, gomath reported A -54.7, C -54.7 and the inverse came back with other joints; it now reports A -180, B -90, C 0 and the inverse returns the joints it was given. This supersedes the gomath part of #4623, where @Rimas2200 found and fixed the same branch. The ZYX half of that fix still applies to posemath's pmMatZyxConvert(), which nothing calls today; I left it to #4623.
Testing: I compared genserkins before and after over a grid of 592 joint sets plus the poles. The forward agrees to 1e-12, and the inverse returns the same joints and the same result everywhere except with the wrist exactly straight, where its Jacobian is singular and the iteration can settle on another of the equivalent wrist solutions. The full test suite passes apart from tests/tool-frame, which #4673 fixes.
@BsAtHome this is the consolidation from the #4673 discussion. One choice I am not sure of: tpmod exports the two posemath functions only so the test can reach them. posemath as a module of its own would be the cleaner shape, but every module that links it would then need it loaded first, so I left that out of this PR.