Thank you. Did try to make some code, all loks trivial, except i do not undrestood how does we keep our z axis/ ensure 0 of z axis at the middle. ie - if in config i set up z as viable from 0 till 1800, then i could manipulate D1 (console height) and D5 (effector length) as in code below to compensate for this. but i to not see how it would work for different setups or and shell i do the same for forward kinematic. Or better skip both, and just setup machine for -900 till 900 z travel and play coordinate transfer ? this line : z_transformed = z - D1 + D5 ; // should return as at 0 level of arms for -900
#include "rtapi.h"
#include "rtapi_math.h"
#include "rtapi_string.h"
#include "posemath.h"
#include "hal.h"
#include "kinematics.h"
#include "switchkins.h"
struct scara_data {
hal_float_t *d1, *d2, *d3, *d4, *d5, *d6;
} *haldata = 0;
#define D1 (*(haldata->d1))
#define D2 (*(haldata->d2))
#define D3 (*(haldata->d3)) // Now used as Z_parallelogram height
#define D4 (*(haldata->d4)) // Keep as fixed second arm length
#define D5 (*(haldata->d5))
#define D6 (*(haldata->d6))
static
int scaraKinematicsForward(const double * joint,
EmcPose * world,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
double a0, a1, a3;
double x, y, z, c;
a0 = joint[0] * ( PM_PI / 180 );
a1 = joint[1] * ( PM_PI / 180 );
a3 = joint[3] * ( PM_PI / 180 );
a1 = a1 + a0;
a3 = a3 + a1;
// Compute projected second arm length dynamically
double D4_projected = sqrt(D4 * D4 - joint[2] * joint[2]);
x = D2*cos(a0) + D4_projected*cos(a1) + D6*cos(a3);
y = D2*sin(a0) + D4_projected*sin(a1) + D6*sin(a3);
// Compute parallelogram-based Z
z = sqrt((D3 - joint[2]) * (D3 - joint[2]) + D4_projected * D4_projected);
c = a3;
*iflags = 0;
if (joint[1] < 90)
*iflags = 1;
world->tran.x = x;
world->tran.y = y;
world->tran.z = z;
world->c = c * 180 / PM_PI;
world->a = joint[4];
world->b = joint[5];
return (0);
}
static int scaraKinematicsInverse(const EmcPose * world,
double * joint,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
double a3;
double q0, q1;
double xt, yt, rsq, cc;
double x, y, z, c;
double D4_projected, z_transformed;
x = world->tran.x;
y = world->tran.y;
z = world->tran.z;
c = world->c;
a3 = c * ( PM_PI / 180 );
xt = x - D6*cos(a3);
yt = y - D6*sin(a3);
z_transformed = z - D1 + D5 ; // should return as at 0 level of arms for -900
rsq = xt*xt + yt*yt;
D4_projected = sqrt(D4 * D4 - z_transformed * z_transformed);
cc = (rsq - D2 * D2 - D4_projected * D4_projected) / (2 * D2 * D4_projected);
if(cc < -1) cc = -1;
if(cc > 1) cc = 1;
q1 = acos(cc);
if (*iflags)
q1 = -q1;
q0 = atan2(yt, xt);
xt = D2 + D4_projected*cos(q1);
yt = D4_projected*sin(q1);
q0 = q0 - atan2(yt, xt);
q0 = q0 * (180 / PM_PI);
q1 = q1 * (180 / PM_PI);
joint[0] = q0;
joint[1] = q1;
// Compute inverse for parallelogram Z
joint[2] = sqrt(z_transformed * z_transformed - D4_projected * D4_projected);
joint[3] = c - ( q0 + q1);
joint[4] = world->a;
joint[5] = world->b;
*fflags = 0;
return (0);
} //scaraKinematicsInverse()
#define DEFAULT_D1 1200
#define DEFAULT_D2 1200
#define DEFAULT_D3 600
#define DEFAULT_D4 1500
#define DEFAULT_D5 300
#define DEFAULT_D6 0
static int scaraKinematicsSetup(const int comp_id,
const char* coordinates,
kparms* kp)
{
int res=0;
haldata = hal_malloc(sizeof(*haldata));
if (!haldata) goto error;
res += hal_pin_float_newf(HAL_IN, &(haldata->d1), comp_id,"%s.D1",kp->halprefix);
res += hal_pin_float_newf(HAL_IN, &(haldata->d2), comp_id,"%s.D2",kp->halprefix);
res += hal_pin_float_newf(HAL_IN, &(haldata->d3), comp_id,"%s.D3",kp->halprefix);
res += hal_pin_float_newf(HAL_IN, &(haldata->d4), comp_id,"%s.D4",kp->halprefix);
res += hal_pin_float_newf(HAL_IN, &(haldata->d5), comp_id,"%s.D5",kp->halprefix);
res += hal_pin_float_newf(HAL_IN, &(haldata->d6), comp_id,"%s.D6",kp->halprefix);
if (res) { goto error; }
D1 = DEFAULT_D1;
D2 = DEFAULT_D2;
D3 = DEFAULT_D3;
D4 = DEFAULT_D4;
D5 = DEFAULT_D5;
D6 = DEFAULT_D6;
return 0;
error:
return -1;
} // scaraKinematicsSetup()
int switchkinsSetup(kparms* kp,
KS* kset0, KS* kset1, KS* kset2,
KF* kfwd0, KF* kfwd1, KF* kfwd2,
KI* kinv0, KI* kinv1, KI* kinv2
)
{
kp->kinsname = "scarakins"; // !!! must agree with filename
kp->halprefix = "scarakins"; // hal pin names
kp->required_coordinates = "xyzabc"; // ab are scaragui table tilts
kp->allow_duplicates = 0;
kp->max_joints = strlen(kp->required_coordinates);
rtapi_print("\n!!! switchkins-type 0 is %s\n",kp->kinsname);
*kset0 = scaraKinematicsSetup;
*kfwd0 = scaraKinematicsForward;
*kinv0 = scaraKinematicsInverse;
*kset1 = identityKinematicsSetup;
*kfwd1 = identityKinematicsForward;
*kinv1 = identityKinematicsInverse;
*kset2 = userkKinematicsSetup;
*kfwd2 = userkKinematicsForward;
*kinv2 = userkKinematicsInverse;
return 0;
} // switchkinsSetup()