Own kinematics module for misalignment compensation

More
03 Sep 2022 12:14 - 04 Sep 2022 13:13 #251099 by LAUSCH
Hi there,

I would like to create my own kinematics module in order to compensate misalignment of my three axis CNC.
@jsskangas mentioned in another thread about this topic to create a dedicated kinematics module.
My approach was to use the userkins.comp file located in /home/christian/linuxcnc/src/hal/components/ and modify it to my needs.
Afterwards build and install the component using halcompile:
     $ cd linuxcnc/src/hal/components
     $ [sudo] halcompile --install userkins.comp
Last but not least modifying the INI to use the new kinematics module by KINEMATICS = userkins.

Now I have the following issues and questions:

1.) I use absolute encoder servo drives which means I don't need to 'home' the axes and NO_FORCE_HOMING = 1 and   HOME_ABSOLUTE_ENCODER = 2
When I now jog my axes (without prior homing) the modifications of userkins work e.g. the X axis moves by 0.1 when Y axis moves by 10mm. However if I enter 'MDI' mode the X axis jumps immediately as it performs the command of the userkins function. As I have not homed the value of j[1] is not 0 and thus the commanded X-Axis position is changed by 0.01*y-axis position. So lets say my Y-Axis value equals 200 when switching to MDI mode or press home-all-axes then the X-axis jumps by 2mm.
When I switch to NO_FORCE_HOMING = 0 it is basically the same as when 'home all axes' is pressed it also jumps.
    pos->tran.x = j[0] + j[1]*0.01; // X coordinate
 
    j[0] = pos->tran.x + pos->tran.y*0.01; // joint 0

2,) I was expecting that the modifications/math performed in the userkins is not shown in the G54 coordinates displayed in linuxCNC. E.g. when I move the Y axis by 100mm the machine also moves the X axis by 1mm to compensate the machine misalignment but  I have expected that the G54 coordinate value for the X-Axis shown in the GUI remains unchanged. Of course the absolute value has to change due to the absolute encoders.
  • To answer my own question (and thus maybe be helpful for others that are new to this topic). In the DRO the actual position is given. However when moving the axis by G-Code in MDI it does exactly what it should. In the above example: If commanding G1 Y0 X0 F2000 and afterwards G1 Y100 X0 F2000 the machine will actually go to Y100 and X1.

3.) When compiling userkins.comp in the first place I received an error message:
userkins.comp:114:1: warning: data definition has no type or storage class userkins.comp:114:1: warning: type defaults to ‘int’ in declaration of ‘KINS_NOT_SWITCHABLE’ [-Wimplicit-int] In file included from userkins.c:2: After commenting the line ‘KINS_NOT_SWITCHABLE’ it works fine. Can anyone tell me what this line is good for and why I receive this error message?

4.) I have not fully understood the two different functions of userkins "kinematicsForward" and "kinematicsInverse". I have understood that kinematicsInverse is only called after the axes have been homed.

5.) Just in order to double check: I assume (hope) that for calculating the new position the absolute values are taken? My desired compensation for the axis is not of a first order type but third order e.g. ax³+bx²+cx+d and directly derived from the measured deviation/misalignment of the axis.
  • After making some trials, I can confirm that absolute values are used
Attachments:
Last edit: 04 Sep 2022 13:13 by LAUSCH.

Please Log in or Create an account to join the conversation.

More
03 Sep 2022 15:00 #251107 by dgarrett
> After commenting the line ‘KINS_NOT_SWITCHABLE’ it
> works fine. Can anyone tell me what this line is good
> for and why I receive this error message?

The supplied userkins.comp is different in the 2.8 branch
and the master branch. The master branch uses
KINS_NOT_SWITCHABLE:

>> 13.5.5. Motion
>>
>> The motion module supports kinematics modules that
>> define new functions kinematicsSwitchable() and
>> kinematicsSwitch() to switch their kinematics type. A
>> HAL pin, motion.switchkins-type, is provided for use of
>> such kinematics modules.
>>
>> Provided kinematics modules that implement kinematics
>> switching use the switchkins.o object to supply the
>> required rtapi_main() and related functions. Kinematics
>> modules that do not support kinematics switching use
>> the macro "KINS_NOT_SWITCHABLE" provided by
>> kinematics.h.

The userkins man page informs the need to use a
file appropriate for the branch in use:

>> $ man userkins
>> Note: The userkins.comp file can be downloaded from:
>> ⟨https://github.com/LinuxCNC/linuxcnc/raw/2.8/src/hal/components/userkins.comp⟩
>> where '2.8' is the branch name (use 'master' for
>> the master branch)

As always, if using a Run-in-place (RIP) build, you
must source scripts/rip-environment in any shell that
invokes a LinuxCNC program (like halcompile).

If you have both a deb install and a RIP build on the
same machine, extra caution is required.


Ref Master:
linuxcnc.org/docs/devel/html/getting-sta...dating-linuxcnc.html
github.com/LinuxCNC/linuxcnc/blob/master...s/userkins.comp#L114
github.com/LinuxCNC/linuxcnc/blob/master...ts/userkins.comp#L20

Ref 2.8:
github.com/LinuxCNC/linuxcnc/blob/2.8/sr...ts/userkins.comp#L20
The following user(s) said Thank You: tommylight, LAUSCH

Please Log in or Create an account to join the conversation.

More
04 Sep 2022 08:14 - 04 Sep 2022 18:43 #251157 by LAUSCH
Thanks for the comprehensive explanation. I got most of my issues solved and questions answered. But one big problem still persists and I don't understand this behavior.
Whenever I press "home all axes" or when the machine is turned off and on again it immediately executes a move of the X-Axis by following the command of my kinematics:
    pos->tran.x = j[0] + j[1]*0.01; // X coordinate
    j[0] = pos->tran.x + pos->tran.y*0.01; // joint 0
It takes the current value of j[1] and adds it to the the X-position. Can this behavior be suppressed? Why is it doing this?

I have come up with an idea how to solve the issue but I am looking for help how this can be implemented in the userkins component:

I would like to implement a simple command like the following:
if (y-axis-in-position) {      
             pos->tran.x = j[0] ;
} else {      
             pos->tran.x = j[0] + j[1]*0.01;
 }

However I was not able to pass the signal joint.1.in-position to userkins component and implement it in the if statement.

In my hal file I implemented:
net motion-in-pos motion.in-position  # true in case all axes are in the desired position
In userkins file I implemented:
              
int kinematicsForward(const double *j,
                      EmcPose * pos,
                     const KINEMATICS_FORWARD_FLAGS * fflags,
                     KINEMATICS_INVERSE_FLAGS * iflags)
{     static bool gave_msg;    
// [KINS]JOINTS=3

hal_bit_t *motion_in_pos; // command to implement hal pin

If(motion_in_pos){
    pos->tran.x = j[0]; // X coordinate
} else {
   pos->tran.x = j[0] + j[1]*0.01;
}
   pos->tran.y = j[1]; // Y coordinate
   pos->tran.z = j[2]; // Z coordinate

It doesn't throw me an error but it still does not solve the problem... Any suggestions or help would be very much appreciated and honored appropriately ;-)
Last edit: 04 Sep 2022 18:43 by LAUSCH.

Please Log in or Create an account to join the conversation.

More
07 Sep 2022 18:25 #251428 by LAUSCH
Now a few things are much clearer although not yet solved:

Biggest issue is still, that after homing my axis the modified axis of my kinematics module "jumps" whenever the control is switched off an on again.
In the meantime I have realized that his has nothing to deal with my absolute encoder or other settings.
While checking terminal response I noted that follwing command shows up when pressing "home all axes"
hal status motion mode changed
This indicates that the mode of the machine changes to "teleop mode"  motion.teleop-mode = True
Looking this up in the description gives me the following description:

The TELEOP command places the machine in teleoperating mode. In teleop mode, movement of the machine is based on Cartesian coordinates using kinematics, rather than on individual joints as in free mode.... On a machine with trivial kinematics, there is little difference between teleop mode and free mode, and GUIs for those machines might never even issue this command

This makes sort of sense but also seems to be the root cause for my issue.
When changing the Kinematics Type in the kinematics.comp file from KINEMATICS_IDENTITY to KINEMATICS_BOTH and turning the machine on again, allows me to switch between world and joint coordinate systems which is basically the same as setting the Pin motion.teleop-mode TRUE and FALSE respectively.
When performing home-all-axes the machine jumps but if afterwards the machine is put in joint mode (motion.teleop-mode set to FALSE) and then switch the machine on and off again there is no issue with jumps. 

Now the problem solving part starts figuring out how I can be in "world mode" without having my axes jumping. I have seen some kinematic modules that do not work with "pos->tran.x" but "world->tran.x". Does anyone have experience with this?

I have also implemented the current version of my kinematics file if anyone wants to have a look.

 
Attachments:

Please Log in or Create an account to join the conversation.

More
07 Sep 2022 19:08 #251430 by Aciera

4.) I have not fully understood the two different functions of userkins "kinematicsForward" and "kinematicsInverse". I have understood that kinematicsInverse is only called after the axes have been homed.

"kinematicsForward" is used to calculate the cartesian position from known joint positions
"kinematicsInverse" is used to calculate the required joint positions to reach a given cartesian position

linuxcnc.org/docs/stable/html/motion/kinematics.html

So "kinematicsForward" and "kinematicsInverse" are mutually inverse functions. And  this usually means that the functions for kinematicsForward and kinematicsInverse are not identical. Looking at your code it seems to me that you are applying the same 3rd order polynomial for both the forward and the inverse kinematic which seems wrong. 
Basically you should be able to feed a random joint position set into your forward kinematics to derive the cartesian position then feed that into the inverse kinematics and you should get the same joint position set you started with.
The following user(s) said Thank You: LAUSCH

Please Log in or Create an account to join the conversation.

More
08 Sep 2022 19:29 #251518 by LAUSCH
Thank you @Aciera!
That helped to finally solve the issue. I have for sure not fully understood the kinematics module despite reading many documents.
The solution is as simple as changing the sign between kinematicFoward and kinematicInverse in my special case.
Of course this solution also works with polynoms of higher degree to compensate for more complex deformation of a joint and also for misalignments in two different directions.

kinematicForward
pos->tran.x = joint[0] -0.01*joint[1]

kinematicInverse
j[0] = pos->tran.x + 0.01*pos->tran.y

In my case I had a misalignment of the Z-Axis in the direction of X which looks as shown in the attached picture. 
By the user defined kinematics module it was possible to compensate for the misalignment with deviations less than 0.02mm along the entire 350mm of my Z-axis
Attachments:
The following user(s) said Thank You: Aciera

Please Log in or Create an account to join the conversation.

Time to create page: 0.122 seconds
Powered by Kunena Forum