/** * \file frne.c * \author Peter Corke * \brief MEX file body * * * FRNE MEX file version of RNE.M * * TAU = FRNE(ROBOT, Q, QD, QDD) * TAU = FRNE(ROBOT, [Q QD QDD]) * * where Q, QD and QDD are row vectors of the manipulator state; pos, * vel, and accel. * * Returns the joint torque required to achieve the specified joint * position, velocity and acceleration state. Gravity is taken * from the robot object. * * TAU = RNE(ROBOT, Q, QD, QDD, GRAV) * TAU = RNE(ROBOT, [Q QD QDD], GRAV) * * GRAV overrides the gravity vector in the robot object. * * An external force/moment acting on the end of the manipulator may * also be specified by a 6-element vector [Fx Fy Fz Mx My Mz]. * * TAU = RNE(ROBOT, Q, QD, QDD, GRAV, FEXT) * TAU = RNE(ROBOT, [Q QD QDD], GRAV, FEXT) * */ /* * Copyright (C) 1999-2008, by Peter I. Corke * * This file is part of The Robotics Toolbox for Matlab (RTB). * * RTB is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RTB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Leser General Public License * along with RTB. If not, see . * */ #include "mex.h" #include #include "frne.h" /* #define DEBUG */ /* Input Arguments */ #define ROBOT_IN prhs[0] #define A1_IN prhs[1] #define A2_IN prhs[2] #define A3_IN prhs[3] #define A4_IN prhs[4] #define A5_IN prhs[5] /* Output Arguments */ #define TAU_OUT plhs[0] /* Some useful things */ #define NUMROWS(x) mxGetM(x) #define NUMCOLS(x) mxGetN(x) #define NUMELS(x) (mxGetN(x)*mxGetM(x)) #define POINTER(x) mxGetPr(x) /* forward defines */ static void rot_mat (Link *l, double th, double d, DHType type); static int mstruct_getfield_number(mxArray *m, char *field); static int mstruct_getint(mxArray *m, int i, char *field); static double mstruct_getreal(mxArray *m, int i, char *field); static double * mstruct_getrealvect(mxArray *m, int i, char *field); void error(char *s, ...); /* default values for gravity and external load */ /** * MEX function entry point. */ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { double *q, *qd, *qdd; double *tau; unsigned int m,n; int j, njoints, p, nq; double *fext = NULL; double *grav = NULL; Robot robot; mxArray *link0; mxArray *mx_robot; mxArray *mx_links; static int first_time = 0; /* fprintf(stderr, "Fast RNE: (c) Peter Corke 2002-2011\n"); */ if ( !mxIsClass(ROBOT_IN, "SerialLink") ) mexErrMsgTxt("frne: first argument is not a robot structure\n"); mx_robot = (mxArray *)ROBOT_IN; njoints = mstruct_getint(mx_robot, 0, "n"); /*********************************************************************** * Handle the different calling formats. * Setup pointers to q, qd and qdd inputs ***********************************************************************/ switch (nrhs) { case 2: /* * TAU = RNE(ROBOT, [Q QD QDD]) */ if (NUMCOLS(A1_IN) != 3 * njoints) mexErrMsgTxt("frne: too few cols in [Q QD QDD]"); q = POINTER(A1_IN); nq = NUMROWS(A1_IN); qd = &q[njoints*nq]; qdd = &q[2*njoints*nq]; break; case 3: /* * TAU = RNE(ROBOT, [Q QD QDD], GRAV) */ if (NUMCOLS(A1_IN) != (3 * njoints)) mexErrMsgTxt("frne: too few cols in [Q QD QDD]"); q = POINTER(A1_IN); nq = NUMROWS(A1_IN); qd = &q[njoints*nq]; qdd = &q[2*njoints*nq]; if (NUMELS(A2_IN) != 3) mexErrMsgTxt("frne: gravity vector expected"); grav = POINTER(A2_IN); break; case 4: /* * TAU = RNE(ROBOT, Q, QD, QDD) * TAU = RNE(ROBOT, [Q QD QDD], GRAV, FEXT) */ if (NUMCOLS(A1_IN) == (3 * njoints)) { q = POINTER(A1_IN); nq = NUMROWS(A1_IN); qd = &q[njoints*nq]; qdd = &q[2*njoints*nq]; if (NUMELS(A2_IN) != 3) mexErrMsgTxt("frne: gravity vector expected"); grav = POINTER(A2_IN); if (NUMELS(A3_IN) != 6) mexErrMsgTxt("frne: Fext vector expected"); fext = POINTER(A3_IN); } else { int nqd = NUMROWS(A2_IN), nqdd = NUMROWS(A3_IN); nq = NUMROWS(A1_IN); if ((nq != nqd) || (nqd != nqdd)) mexErrMsgTxt("frne: Q QD QDD must be same length"); if ( (NUMCOLS(A1_IN) != njoints) || (NUMCOLS(A2_IN) != njoints) || (NUMCOLS(A3_IN) != njoints) ) mexErrMsgTxt("frne: Q must have Naxis columns"); q = POINTER(A1_IN); qd = POINTER(A2_IN); qdd = POINTER(A3_IN); } break; case 5: { /* * TAU = RNE(ROBOT, Q, QD, QDD, GRAV) */ int nqd = NUMROWS(A2_IN), nqdd = NUMROWS(A3_IN); nq = NUMROWS(A1_IN); if ((nq != nqd) || (nqd != nqdd)) mexErrMsgTxt("frne: Q QD QDD must be same length"); if ( (NUMCOLS(A1_IN) != njoints) || (NUMCOLS(A2_IN) != njoints) || (NUMCOLS(A3_IN) != njoints) ) mexErrMsgTxt("frne: Q must have Naxis columns"); q = POINTER(A1_IN); qd = POINTER(A2_IN); qdd = POINTER(A3_IN); if (NUMELS(A4_IN) != 3) mexErrMsgTxt("frne: gravity vector expected"); grav = POINTER(A4_IN); break; } case 6: { /* * TAU = RNE(ROBOT, Q, QD, QDD, GRAV, FEXT) */ int nqd = NUMROWS(A2_IN), nqdd = NUMROWS(A3_IN); nq = NUMROWS(A1_IN); if ((nq != nqd) || (nqd != nqdd)) mexErrMsgTxt("frne: Q QD QDD must be same length"); if ( (NUMCOLS(A1_IN) != njoints) || (NUMCOLS(A2_IN) != njoints) || (NUMCOLS(A3_IN) != njoints) ) mexErrMsgTxt("frne: Q must have Naxis columns"); q = POINTER(A1_IN); qd = POINTER(A2_IN); qdd = POINTER(A3_IN); if (NUMELS(A4_IN) != 3) mexErrMsgTxt("frne: gravity vector expected"); grav = POINTER(A4_IN); if (NUMELS(A5_IN) != 6) mexErrMsgTxt("frne: Fext vector expected"); fext = POINTER(A5_IN); break; } default: mexErrMsgTxt("frne: wrong number of arguments."); } /* * fill out the robot structure */ robot.njoints = njoints; if (grav) robot.gravity = (Vect *)grav; else robot.gravity = (Vect *)mxGetPr( mxGetProperty(mx_robot, (mwIndex)0, "gravity") ); robot.dhtype = mstruct_getint(mx_robot, 0, "mdh"); /* build link structure */ robot.links = (Link *)mxCalloc((mwSize) njoints, (mwSize) sizeof(Link)); /*********************************************************************** * Now we have to get pointers to data spread all across a cell-array * of Matlab structures. * * Matlab structure elements can be found by name (slow) or by number (fast). * We assume that since the link structures are all created by the same * constructor, the index number for each element will be the same for all * links. However we make no assumption about the numbers themselves. ***********************************************************************/ /* get pointer to the first link structure */ link0 = mxGetProperty(mx_robot, (mwIndex) 0, "links"); if (link0 == NULL) mexErrMsgTxt("couldnt find element link in robot object"); /* * Elements of the link structure are: * * alpha: * A: * theta: * D: * offset: * sigma: * mdh: * m: * r: * I: * Jm: * G: * B: * Tc: */ if (first_time == 0) { mexPrintf("Fast RNE: (c) Peter Corke 2002-2012\n"); first_time = 1; } /* * copy data from the Link objects into the local links structure * to save function calls later */ for (j=0; jalpha = mxGetScalar( mxGetProperty(links, (mwIndex) j, "alpha") ); l->A = mxGetScalar( mxGetProperty(links, (mwIndex) j, "a") ); l->theta = mxGetScalar( mxGetProperty(links, (mwIndex) j, "theta") ); l->D = mxGetScalar( mxGetProperty(links, (mwIndex) j, "d") ); l->sigma = mxGetScalar( mxGetProperty(links, (mwIndex) j, "sigma") ); l->offset = mxGetScalar( mxGetProperty(links, (mwIndex) j, "offset") ); l->m = mxGetScalar( mxGetProperty(links, (mwIndex) j, "m") ); l->rbar = (Vect *)mxGetPr( mxGetProperty(links, (mwIndex) j, "r") ); l->I = mxGetPr( mxGetProperty(links, (mwIndex) j, "I") ); l->Jm = mxGetScalar( mxGetProperty(links, (mwIndex) j, "Jm") ); l->G = mxGetScalar( mxGetProperty(links, (mwIndex) j, "G") ); l->B = mxGetScalar( mxGetProperty(links, (mwIndex) j, "B") ); l->Tc = mxGetPr( mxGetProperty(links, (mwIndex) j, "Tc") ); } /* Create a matrix for the return argument */ TAU_OUT = mxCreateDoubleMatrix((mwSize) nq, (mwSize) njoints, mxREAL); tau = mxGetPr(TAU_OUT); #define MEL(x,R,C) (x[(R)+(C)*nq]) /* for each point in the input trajectory */ for (p=0; psigma) { case REVOLUTE: rot_mat(l, MEL(q,p,j)+l->offset, l->D, robot.dhtype); break; case PRISMATIC: rot_mat(l, l->theta, MEL(q,p,j)+l->offset, robot.dhtype); break; } #ifdef DEBUG rot_print("R", &l->R); vect_print("p*", &l->r); #endif } newton_euler(&robot, &tau[p], &qd[p], &qdd[p], fext, nq); } mxFree(robot.links); } /* * Written by; * * Peter I. Corke * CSIRO Division of Manufacturing Technology * Preston, Melbourne. Australia. 3072. * * pic@mlb.dmt.csiro.au * * Permission to use and distribute is granted, provided that this message * is retained, and due credit given when the results are incorporated in * publised work. * */ /** * Return the link rotation matrix and translation vector. * * @param l Link object for which R and p* are required. * @param th Joint angle, overrides value in link object * @param d Link extension, overrides value in link object * @param type Kinematic convention. */ static void rot_mat ( Link *l, double th, double d, DHType type ) { double st, ct, sa, ca; #ifdef sun sincos(th, &st, &ct); sincos(l->alpha, &sa, &ca); #else st = sin(th); ct = cos(th); sa = sin(l->alpha); ca = cos(l->alpha); #endif switch (type) { case STANDARD: l->R.n.x = ct; l->R.o.x = -ca*st; l->R.a.x = sa*st; l->R.n.y = st; l->R.o.y = ca*ct; l->R.a.y = -sa*ct; l->R.n.z = 0.0; l->R.o.z = sa; l->R.a.z = ca; l->r.x = l->A; l->r.y = d * sa; l->r.z = d * ca; break; case MODIFIED: l->R.n.x = ct; l->R.o.x = -st; l->R.a.x = 0.0; l->R.n.y = st*ca; l->R.o.y = ca*ct; l->R.a.y = -sa; l->R.n.z = st*sa; l->R.o.z = ct*sa; l->R.a.z = ca; l->r.x = l->A; l->r.y = -d * sa; l->r.z = d * ca; break; } } /************************************************************************* * Matlab structure access methods, get the field from joint i *************************************************************************/ static mxArray * mstruct_get_element(mxArray *m, int j, char *field) { mxArray *e; if ((e = mxGetProperty(m, (mwIndex)j, field)) != NULL) return e; else { error("No such field as %s", field); } } static int mstruct_getfield_number(mxArray *m, char *field) { int f; if ((f = mxGetFieldNumber(m, field)) < 0) error("no element %s in link structure"); return f; } static int mstruct_getint(mxArray *m, int i, char *field) { mxArray *e; e = mstruct_get_element(m, i, field); return (int) mxGetScalar(e); } static double mstruct_getreal(mxArray *m, int i, char *field) { mxArray *e; e = mstruct_get_element(m, i, field); return mxGetScalar(e); } static double * mstruct_getrealvect(mxArray *m, int i, char *field) { mxArray *e; e = mstruct_get_element(m, i, field); return mxGetPr(e); } #include /** * Error message handler. Takes printf() style format string and variable * arguments and sends resultant string to Matlab via \t mexErrMsgTxt(). * * @param s Error message string, \t printf() style. */ void error(char *s, ...) { char b[BUFSIZ]; va_list ap; va_start(ap, s); vsprintf(b, s, ap); mexErrMsgTxt(b); }