#include "rtapi_math.h"
#include "posemath.h"
#include "pentakins.h"
#include "kinematics.h"
#include "hal.h"
struct haldata {
hal_float_t basex[NUM_STRUTS];
hal_float_t basey[NUM_STRUTS];
hal_float_t basez[NUM_STRUTS];
hal_float_t effectorr[NUM_STRUTS];
hal_float_t effectorz[NUM_STRUTS];
hal_u32_t *last_iter;
hal_u32_t *max_iter;
hal_u32_t *iter_limit;
hal_float_t *max_error;
hal_float_t *conv_criterion;
hal_float_t *tool_offset;
} *haldata;
static int MatInvert5(double J[][NUM_STRUTS], double InvJ[][NUM_STRUTS])
{
double JAug[NUM_STRUTS][10], m, temp;
int j, k, n;
for (j=0; j<=4; ++j){
for (k=0; k<=4; ++k){
JAug[j][k] = J[j][k];
}
for(k=5; k<=9; ++k){
if (k-5 == j){
JAug[j][k]=1;
}
else{
JAug[j][k]=0;
}
}
}
for (k=0; k<=3; ++k){
if ((JAug[k][k]< 0.01) && (JAug[k][k] > -0.01)){
for (j=k+1;j<=4; ++j){
if ((JAug[j][k]>0.01) || (JAug[j][k]<-0.01)){
for (n=0; n<=9;++n){
temp = JAug[k][n];
JAug[k][n] = JAug[j][n];
JAug[j][n] = temp;
}
break;
}
}
}
for (j=k+1; j<=4; ++j){
m = -JAug[j][k] / JAug[k][k];
for (n=0; n<=9; ++n){
JAug[j][n]=JAug[j][n] + m*JAug[k][n];
if ((JAug[j][n] < 0.000001) && (JAug[j][n] > -0.000001)){
JAug[j][n] = 0;
}
}
}
}
for (j=0; j<=4; ++j){
m=1/JAug[j][j];
for(k=0; k<=9; ++k){
JAug[j][k] = m * JAug[j][k];
}
}
for (k=4; k>=0; --k){
for(j=k-1; j>=0; --j){
m = -JAug[j][k]/JAug[k][k];
for (n=0; n<=9; ++n){
JAug[j][n] = JAug[j][n] + m * JAug[k][n];
}
}
}
for (j=0; j<=4; ++j){
for (k=0; k<=4; ++k){
InvJ[j][k] = JAug[j][k+5];
}
}
return 0;
}
static void MatMult5(double J[][5], const double x[], double Ans[])
{
int j, k;
for (j=0; j<=4; ++j){
Ans[j] = 0;
for (k=0; k<=4; ++k){
Ans[j] = J[j][k]*x[k]+Ans[j];
}
}
}
static double sqr(double x)
{
return (x)*(x);
}
static PmCartesian b[NUM_STRUTS];
static double za[NUM_STRUTS], ra[NUM_STRUTS];
int pentakins_read_hal_pins(void) {
int t;
for (t = 0; t < NUM_STRUTS; t++) {
b[t].x = haldata->basex[t];
b[t].y = haldata->basey[t];
b[t].z = haldata->basez[t] + *haldata->tool_offset;
ra[t] = haldata->effectorr[t];
za[t] = haldata->effectorz[t] + *haldata->tool_offset;
}
return 0;
}
int InvKins(const double * coord,
double * struts)
{
PmCartesian xyz, pmcoord, temp;
PmRotationMatrix RMatrix, InvRMatrix;
PmRpy rpy;
int i;
pmcoord.x = coord[0];
pmcoord.y = coord[1];
pmcoord.z = coord[2];
rpy.r = coord[3];
rpy.p = coord[4];
rpy.y = 0;
pmRpyMatConvert(&rpy, &RMatrix);
for (i = 0; i < NUM_STRUTS; i++) {
pmCartCartSub(&b[i], &pmcoord, &temp);
pmMatInv(&RMatrix, &InvRMatrix);
pmMatCartMult(&InvRMatrix, &temp, &xyz);
struts[i] = sqrt( sqr(xyz.z - za[i]) + sqr( sqrt(sqr(xyz.x) + sqr(xyz.y)) - ra[i]) );
}
return 0;
}
int kinematicsForward(const double * joints,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
double Jacobian[NUM_STRUTS][NUM_STRUTS];
double InverseJacobian[NUM_STRUTS][NUM_STRUTS];
double InvKinStrutLength[NUM_STRUTS], StrutLengthDiff[NUM_STRUTS];
double delta[NUM_STRUTS];
double jointdelta[NUM_STRUTS];
double coord[NUM_STRUTS];
double conv_err = 1.0;
int iterate = 1;
int i, j;
int iteration = 0;
pentakins_read_hal_pins();
if (joints[0] <= 0.0 ||
joints[1] <= 0.0 ||
joints[2] <= 0.0 ||
joints[3] <= 0.0 ||
joints[4] <= 0.0 ) {
return -1;
}
coord[0] = pos->tran.x;
coord[1] = pos->tran.y;
coord[2] = pos->tran.z;
coord[3] = pos->a * PM_PI / 180.0;
coord[4] = pos->b * PM_PI / 180.0;
while (iterate) {
if ((conv_err > +(*haldata->max_error)) ||
(conv_err < -(*haldata->max_error))) {
return -2;
};
iteration++;
if (iteration > *haldata->iter_limit) {
return -5;
}
InvKins(coord, InvKinStrutLength);
for (i = 0; i < NUM_STRUTS; i++) {
StrutLengthDiff[i] = InvKinStrutLength[i] - joints[i];
coord[i] += 1e-4;
InvKins(coord, jointdelta);
coord[i] -= 1e-4;
for (j = 0; j < NUM_STRUTS; j++) {
InverseJacobian[j][i] = (jointdelta[j] - InvKinStrutLength[j]) * 1e4;
}
}
MatInvert5(InverseJacobian, Jacobian);
MatMult5(Jacobian, StrutLengthDiff, delta);
coord[0] -= delta[0];
coord[1] -= delta[1];
coord[2] -= delta[2];
coord[3] -= delta[3];
coord[4] -= delta[4];
conv_err = 0.0;
for (i = 0; i < NUM_STRUTS; i++) {
conv_err += fabs(StrutLengthDiff[i]);
}
iterate = 0;
for (i = 0; i < NUM_STRUTS; i++) {
if (fabs(StrutLengthDiff[i]) > *haldata->conv_criterion) {
iterate = 1;
}
}
}
pos->tran.x = coord[0];
pos->tran.y = coord[1];
pos->tran.z = coord[2];
pos->a = coord[3] * 180.0 / PM_PI;
pos->b = coord[4] * 180.0 / PM_PI;
*haldata->last_iter = iteration;
if (iteration > *haldata->max_iter){
*haldata->max_iter = iteration;
}
return 0;
}
int kinematicsInverse(const EmcPose * pos,
double * joints,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
double coord[NUM_STRUTS];
pentakins_read_hal_pins();
coord[0] = pos->tran.x;
coord[1] = pos->tran.y;
coord[2] = pos->tran.z;
coord[3] = pos->a * PM_PI / 180.0;
coord[4] = pos->b * PM_PI / 180.0;
if (0 != InvKins(coord,joints)) {
return -1;
}
return 0;
}
KINEMATICS_TYPE kinematicsType()
{
return KINEMATICS_BOTH;
}
#include "rtapi.h"
#include "rtapi_app.h"
EXPORT_SYMBOL(kinematicsType);
EXPORT_SYMBOL(kinematicsForward);
EXPORT_SYMBOL(kinematicsInverse);
MODULE_LICENSE("GPL");
int comp_id;
int rtapi_app_main(void)
{
int res = 0, i;
comp_id = hal_init("pentakins");
if (comp_id < 0)
return comp_id;
haldata = hal_malloc(sizeof(struct haldata));
if (!haldata)
goto error;
for (i = 0; i < 6; i++) {
if ((res = hal_param_float_newf(HAL_RW, &(haldata->basex[i]), comp_id,
"pentakins.base.%d.x", i)) < 0)
goto error;
if ((res = hal_param_float_newf(HAL_RW, &haldata->basey[i], comp_id,
"pentakins.base.%d.y", i)) < 0)
goto error;
if ((res = hal_param_float_newf(HAL_RW, &haldata->basez[i], comp_id,
"pentakins.base.%d.z", i)) < 0)
goto error;
if ((res = hal_param_float_newf(HAL_RW, &haldata->effectorr[i], comp_id,
"pentakins.effector.%d.r", i)) < 0)
goto error;
if ((res = hal_param_float_newf(HAL_RW, &haldata->effectorz[i], comp_id,
"pentakins.effector.%d.z", i)) < 0)
goto error;
}
if ((res = hal_pin_u32_newf(HAL_OUT, &haldata->last_iter, comp_id,
"pentakins.last-iterations")) < 0)
goto error;
*haldata->last_iter = 0;
if ((res = hal_pin_u32_newf(HAL_OUT, &haldata->max_iter, comp_id,
"pentakins.max-iterations")) < 0)
goto error;
*haldata->max_iter = 0;
if ((res = hal_pin_float_newf(HAL_IO, &haldata->max_error, comp_id,
"pentakins.max-error")) < 0)
goto error;
*haldata->max_error = 100;
if ((res = hal_pin_float_newf(HAL_IO, &haldata->conv_criterion, comp_id,
"pentakins.convergence-criterion")) < 0)
goto error;
*haldata->conv_criterion = 1e-9;
if ((res = hal_pin_u32_newf(HAL_IO, &haldata->iter_limit, comp_id,
"pentakins.limit-iterations")) < 0)
goto error;
*haldata->iter_limit = 120;
if ((res = hal_pin_float_newf(HAL_IN, &haldata->tool_offset, comp_id,
"pentakins.tool-offset")) < 0)
goto error;
*haldata->tool_offset = 0.0;
haldata->basex[0] = DEFAULT_BASE_0_X;
haldata->basey[0] = DEFAULT_BASE_0_Y;
haldata->basez[0] = DEFAULT_BASE_0_Z;
haldata->basex[1] = DEFAULT_BASE_1_X;
haldata->basey[1] = DEFAULT_BASE_1_Y;
haldata->basez[1] = DEFAULT_BASE_1_Z;
haldata->basex[2] = DEFAULT_BASE_2_X;
haldata->basey[2] = DEFAULT_BASE_2_Y;
haldata->basez[2] = DEFAULT_BASE_2_Z;
haldata->basex[3] = DEFAULT_BASE_3_X;
haldata->basey[3] = DEFAULT_BASE_3_Y;
haldata->basez[3] = DEFAULT_BASE_3_Z;
haldata->basex[4] = DEFAULT_BASE_4_X;
haldata->basey[4] = DEFAULT_BASE_4_Y;
haldata->basez[4] = DEFAULT_BASE_4_Z;
haldata->effectorz[0] = DEFAULT_EFFECTOR_0_Z;
haldata->effectorz[1] = DEFAULT_EFFECTOR_1_Z;
haldata->effectorz[2] = DEFAULT_EFFECTOR_2_Z;
haldata->effectorz[3] = DEFAULT_EFFECTOR_3_Z;
haldata->effectorz[4] = DEFAULT_EFFECTOR_4_Z;
haldata->effectorr[0] = DEFAULT_EFFECTOR_0_R;
haldata->effectorr[1] = DEFAULT_EFFECTOR_1_R;
haldata->effectorr[2] = DEFAULT_EFFECTOR_2_R;
haldata->effectorr[3] = DEFAULT_EFFECTOR_3_R;
haldata->effectorr[4] = DEFAULT_EFFECTOR_4_R;
hal_ready(comp_id);
return 0;
error:
hal_exit(comp_id);
return res;
}
void rtapi_app_exit(void)
{
hal_exit(comp_id);
}