# How can I modify trivkins.c? (and also other kinematics files)

07 Aug 2024 05:03 - 07 Aug 2024 05:10 #307141 by winyk
Hello, I am a beginner trying to learn LinuxCNC. Please note that not only that I am totally new to LinuxCNC, but I am also totally new to working with CNC machine, G code, and the C programming language, so please forgive me if I ask stupid questions. Since I don't have any lathe or mill that I can experiment with (without messing things up), I am playing with LinuxCNC on a virtual machine (Debian inside VirtualBox). I have successfully managed to build LinuxCNC using run-in-place method as instructed in this guide linuxcnc.org/docs/master/html/code/building-linuxcnc.html .

Right now, I want to understand how .c kinematics files work in LinuxCNC. So, as a first step, I did a little experiment by modifying the inverse kinematics function in trivkins.c (located at src/emc/kinematics/) as shown.
```int kinematicsInverse(const EmcPose * pos,
double *joints,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
EmcPose P;
P.tran.x = - pos -> tran.x;
P.tran.y = pos -> tran.y;
P.tran.z = pos -> tran.z;
return identityKinematicsInverse(&P, joints, iflags, fflags);
// return identityKinematicsInverse(pos, joints, iflags, fflags);
}```

My understanding is that the inverse kinematics translates the position of the tool into joints variables, so by putting a negative sign in front of pos -> tran.x before passing that to identityKinematicsInverse function, I expect the machine to move in -x direction whenever I command the machine with G code to move in +x direction (like G0 X10).

After I have modified trivkins.c, I compiled the file and rebuild LinuxCNC by going into /src and use  ./autogen.sh, then ./configure, and then make.
However, as you can see in the photo attached   , when I open axis.ini config (which I believe it uses trivkins.c), the machine still do engraving in the +x direction. Nor did it go to X-10 when I command it with G X10.

I tried modifying trivkins.c in different ways, such as setting some directions to a constant, but I still experience the same result. So what did I do wrong here? Why I see no changes in AXIS after I modified the kinematics files. I am pretty sure the trivkins.c was compiled because when I deliberately put syntax error line in there, make threw an error
##### Attachments:
Last edit: 07 Aug 2024 05:10 by winyk.

07 Aug 2024 05:39 - 07 Aug 2024 06:04 #307142 by Aciera
There are easier ways to start playing around with kinematics. I would suggest to have a look at 'millturn', also have a look at the linked paper:

forum.linuxcnc.org/38-general-linuxcnc-q...atic-mechanis#306700

Just for completness, 'trivkins.c' uses functions in 'kins_util.c':

But again, unless you know your way around with C I would strongly recommend using the .comp method with 'halcompile --install  your_path/your_kinematic.comp' as in the 'millturn' example pointed out in the link above.
##### Attachments:
Last edit: 07 Aug 2024 06:04 by Aciera. Reason: Fix typo
The following user(s) said Thank You: winyk

08 Aug 2024 11:01 #307253 by winyk
Thank you very much for providing the resources. Those will surely be helpful when I have to implement switchable kinematics (but still a lot more to learn to get to that point).

As you suggested, I have tried modifying kinematics using the userkins.comp method. I modify the inverse kinematics part of that file as followed
```int kinematicsInverse(const EmcPose * pos,
double *j,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
is_ready = 1; // Inverse is not called until homed for KINEMATICS_BOTH

// Update the kinematic joints specified by the
// [KINS]JOINTS setting (3 required for this template).
// Maximum number of joints is defined in include file:
//         emcmotcfg:EMCMOT_MAX_JOINTS (typ 16)
// Some joints may be claimed as 'extrajoints' and
// do not participate in kinematics calculations --
j[0] = - pos->tran.x; // joint 0
j[1] = pos->tran.y; // joint 1
j[2] = pos->tran.z; // joint 2

//example hal pin update (homing reqd before kinematicsInverse)
*haldata->out = *haldata->in; //dereference
//read from param example: *haldata->out = haldata->param_rw;

return 0;
} // kinematicsInverse()```

Again, my intention here is to reverse the machine's movement in x-direction by 'intercepting' X value in G code, change that to negative value of itself, and set the joint variables to be that value using inverse kinematics (please correct me if my understanding of inverse kinematics is wrong.)

I followed the instruction listed in the description of that file to get the kinematics installed and modify the KINS part in axis_mm.ini accordingly. When I run the engraving G code in axis_mm.ini, I observed in the top left corner of the graphic display that the x-coordinates was showing some negative numbers. However, the +x direction vector (the green one) in the graphic display is also pointing in that same direction.

So, why does this happen? Did I do something wrong? I am not sure whether I have successfully reversed the x-direction or not .

Also, I noticed that the code in userkins.comp is very similar to C code, so is userkins.comp also written in C?, or is it a different language?
##### Attachments:

08 Aug 2024 11:45 #307256 by Aciera
The component language is very similar to C but saves the user a lot of tedious typing work.

Generally you need to look at the Forward and Inverse kinematic as a pair where one is the inverse of the other. Hence changing one will also require changing the other.

As an example have a look at 'millturn.comp'. 'Case 1' reverts the direction of the y-axis / j[1] :
```static bool is_ready=0;
int kinematicsForward(const double *j,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
static bool gave_msg;
// define forward kinematic models using case structure for
// for switchable kinematics
switch (switchkins_type) {
case 0:
pos->tran.x = j[0];
pos->tran.y = j[1];
pos->tran.z = j[2];
pos->a      = j[3];
break;
case 1:
pos->tran.x = j[2];
pos->tran.y = -j[1];
pos->tran.z = j[0];
pos->a      = j[3];
break;
}
// unused coordinates:
pos->b = 0;
pos->c = 0;
pos->u = 0;
pos->v = 0;
pos->w = 0;

if (*haldata->in && !is_ready && !gave_msg) {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s the 'in' pin not echoed until Inverse called\n",
__FILE__);
gave_msg=1;
}
return 0;
} // kinematicsForward()

int kinematicsInverse(const EmcPose * pos,
double *j,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
is_ready = 1; // Inverse is not called until homed for KINEMATICS_BOTH

// Update the kinematic joints specified by the
// [KINS]JOINTS setting (4 required for this template).
// define forward kinematic models using case structure for
// for switchable kinematics
switch (switchkins_type) {
case 0:
j[0] = pos->tran.x;
j[1] = pos->tran.y;
j[2] = pos->tran.z;
j[3] = pos->a;
break;
case 1:
j[2] = pos->tran.x;
j[1] = -pos->tran.y;
j[0] = pos->tran.z;
j[3] = pos->a;
break;
}

//example hal pin update (homing reqd before kinematicsInverse)
*haldata->out = *haldata->in; //dereference
//read from param example: *haldata->out = haldata->param_rw;

return 0;
} // kinematicsInverse()```
The following user(s) said Thank You: winyk

09 Aug 2024 01:48 #307285 by winyk
I tried reversing x-direction in both forward kinematics and inverse kinematics as you have suggested, but the machine still move in the +x direction. Now, the x in graphic display also shown as positive

here are my kinematicsForward and kinematicsInverse functions.
```int kinematicsForward(const double *j,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
static bool gave_msg;
// [KINS]JOINTS=3
pos->tran.x = - j[0]; // X coordinate
pos->tran.y = j[1]; // Y coordinate
pos->tran.z = j[2]; // Z coordinate
// unused coordinates:
pos->a = 0;
pos->b = 0;
pos->c = 0;
pos->u = 0;
pos->v = 0;
pos->w = 0;

if (*haldata->in && !is_ready && !gave_msg) {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s The 'in' pin not echoed until Inverse called\n",
__FILE__);
gave_msg=1;
}
return 0;
} // kinematicsForward()

int kinematicsInverse(const EmcPose * pos,
double *j,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
is_ready = 1; // Inverse is not called until homed for KINEMATICS_BOTH

// Update the kinematic joints specified by the
// [KINS]JOINTS setting (3 required for this template).
// Maximum number of joints is defined in include file:
//         emcmotcfg:EMCMOT_MAX_JOINTS (typ 16)
// Some joints may be claimed as 'extrajoints' and
// do not participate in kinematics calculations --
j[0] = - pos->tran.x; // joint 0
j[1] = pos->tran.y; // joint 1
j[2] = pos->tran.z; // joint 2

//example hal pin update (homing reqd before kinematicsInverse)
*haldata->out = *haldata->in; //dereference
//read from param example: *haldata->out = haldata->param_rw;

return 0;
} // kinematicsInverse()```

I have already made sure that I reinstall the component with halcompile --install mykins.comp after editing the file.
##### Attachments:

09 Aug 2024 07:26 #307296 by Aciera
I'm sorry, I forgot to mention this, the preview does not reflect machine movement (ie joint position) when using custom kinematics all it shows is axes position in a fixed coordinate system. If you want to see the effects off your custom kinematic then you would need a machine visualization (vismach) for your config. For a simple config with a 3axis mill see 'configs/sim/axis/vismach/3axis-tutorial' you can then change KINEMATICS = trivkins' to your kinematics. You should then see the spindle move to the left when jogging X in the positive direction:

##### Attachments:
The following user(s) said Thank You: winyk

14 Aug 2024 10:03 #307706 by winyk
Thank you. Although I am not sure what is the difference between 'machine movement' and 'axes position' that you have mentioned, I presume that AXIS preview does not reflect the underlying kinematics of the machine, correct? I think the fact that AXIS preview works this way can cause a lot of confusion to newbies like me. If this is the case, then what do the red, green, blue directional vectors shown in the AXIS preview tell us? Is there any way to configure AXIS preview so that the directional vectors agree with the underlying kinematics?

Anyway, after experimenting with 3axis-tutorial.ini, I can now see the effect of reversing the X coordinate in vismach. It turns out that reversing the coordinate in inverse kinematics alone is enough to see this effect, no need to modify the forward kinematics part. I also try with Y and Z as well. Reversing Y works as expected. However, as I try to reverse Z, I encountered error messages telling me that linear move would exceed joint 2's positive limit (no matter I move to +z or -z), and I am not sure why.

```int kinematicsInverse(const EmcPose * pos,
double *j,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
is_ready = 1; // Inverse is not called until homed for KINEMATICS_BOTH

// Update the kinematic joints specified by the
// [KINS]JOINTS setting (3 required for this template).
// Maximum number of joints is defined in include file:
//         emcmotcfg:EMCMOT_MAX_JOINTS (typ 16)
// Some joints may be claimed as 'extrajoints' and
// do not participate in kinematics calculations --
j[0] = pos->tran.x; // joint 0
j[1] = pos->tran.y; // joint 1
j[2] = - pos->tran.z; // joint 2

//example hal pin update (homing reqd before kinematicsInverse)
*haldata->out = *haldata->in; //dereference
//read from param example: *haldata->out = haldata->param_rw;

return 0;
} // kinematicsInverse()```

##### Attachments:

14 Aug 2024 12:01 #307710 by Aciera
What you see in the preview is current WorkCoordinateSystem (ie 'axes' XYZ) and the Gcode path. The Gcode preview is NOT a machine simulation (ie it does not show the 'joint' movement). All it does is give the operator a preview of the GCode presuming trivial kinematics. A standard coordinate system is cartesian and right handed. If you mirror the direction of the y axis in your kinematic then your machine will work in a _left_ handed cartesian coordinate system.

On a machine with trivial kinematics there is not much difference between joint/axis movement because the machine is already setup so the tool moves in a cartesian system. On non-trivial machines a move in a single axis direction (eg X) might involve more than one joint (on a 6DOF robot it may involve all 6 rotary joints to move along a single linear axis)

In your case if you reverse the Z axis then your machine joint[2] would need to move upwards and thus beyond it's positive limit hence you get an error
The following user(s) said Thank You: winyk

14 Aug 2024 14:59 #307717
Hello winyk. I've read your post, and there are few things i wanna mention.

I've developed custom kinematics module for my machine a while ago. Since you are starter, i suggest you to learn HAL layer of LinuxCNC first.
HAL layer is nothing but modules that run at background in while loop, with some sleep. Don't consider this layer as a software layer, it is actually a system that gives you ability to configure your modules, make them able to communicate with each other and allows you to collaborate across modules. In while loop, they checks some conditions, some values etc. and do the work. These modules are named as 'hal component'.

At the core of LinuxCNC, there is a motion hal component. You can check it in the documentation given below:

--> linuxcnc.org/docs/devel/html/man/man9/motion.9.html

This hal component is responsible for interpreting G-code commands and converting them into real-time control signals for machine's hardware. When you give "G90 G0 X10" command,
this is the component which gets 10 value near X and convert it to control signals for motor controller. This conversion uses your kinematics module. Your kinematics module is also a hal component, and the starter script loads it at the beginning. If you check your hal file, you are gonna see some lines like below:

...
...
...
...
...
loadrt motmod servo_period_nsec=<value_from_your_ini_file> num_joints=<value_from_your_ini_file> tp=tp kins=<value_from_your_ini_file>

If you know what ini file format is, these lines gonna look like below.

...
...
...
...
...
loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[TRAJ]AXES tp=tp kins=[KINEMATICS]KINEMATICS

Since you are giving the file name of your kinematics module in your .ini file like below:
[KINEMATICS]
KINEMATICS=mykins

The motmod hal component uses your kinematics component to make the calculations.

After you run "halcompile --install mykins.comp" command, the halcompile exe does these steps given below:

1. Convert .comp file to appropriate .c file
2. Compile generated .c file with system's compiler, generate a shared library (.so file)
3. Locate that .so file in /usr/lib/linuxcnc/rt-preempt/ directory.

Since you are new in C programming, you need to learn basic flow of compilation of a .c source file. You need to check what is .so file, how it can be used etc. to understand concept. The key thing you need to know is, you are generating a calculation module which exports some symbols with names as 'kinematicsInverse, kinematicsForward, .. etc.', you are locating it in the system's directory. After that, during the start of LinuxCNC, it loads motion hal component with that hal component. So the conversion and calculation of machine movement is being calculated by your code. There are so many things you need to know, but this is a basic flow.

If you wanna change the direction of your X axis, you need to change kinematicsInverse function only. The j variable is responsible for generating physical coordinates. You are getting commanded value from const EmcPose * pos variable, which is your commanded coordinate of machine, and forwarding it to physical value. This is the point that you give 10 and make it -10. So, don't change both of them to negative, change only 'kinematicsInverse' to negative. If you do this, hopefully you are gonna see your "G90 G0 X10" command is resulted as X=-10. If i am wrong, maybe i need to remember some things.

I developed some kinematics module to fix geometrical errors of my machine(squareness, straightness) a while ago. I was adding extra moves to X,Y,Z axises according to each other to neutralize the physical oscillation that one makes along any axis. There are different topics that you can use this kinematics module, but this is the core flow. If you have any other questions, i would be happy to discuss them.

Don't forget, if you are trying to change kinematics module, you need to change your ini file. Check the given link below:

--> linuxcnc.org/docs/html/config/ini-config.html#sub:ini:sec:kins

If you don't change your ini file, your hal component can't be loaded. I assume the reason that you didn't get the right result is giving negative value in both reverse and forward functions, but i can be wrong, so don't forget to check your ini and hal files.
The following user(s) said Thank You: rajsekhar, winyk