Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

emcmot.h File Reference

#include "posemath.h"
#include "emcpos.h"
#include "cubic.h"
#include "pid.h"
#include "emcmotcfg.h"
#include "emcmotlog.h"
#include "tp.h"
#include "tc.h"
#include "mmxavg.h"

Include dependency graph for emcmot.h:

Include dependency graph

This graph shows which files directly or indirectly include this file:

Included by dependency graph

Go to the source code of this file.

Data Structures

struct  _EMC_TELEOP_DATA
struct  EMCMOT_COMMAND
struct  EMCMOT_COMP
struct  EMCMOT_CONFIG
struct  EMCMOT_DEBUG
struct  EMCMOT_ERROR
struct  EMCMOT_STATUS
struct  EMCMOT_STRUCT

Defines

#define ENABLE_PROBING
#define EMCMOT_TERM_COND_STOP   1
#define EMCMOT_TERM_COND_BLEND   2
#define EMCMOT_MOTION_ENABLE_BIT   0x0001
#define EMCMOT_MOTION_INPOS_BIT   0x0002
#define EMCMOT_MOTION_COORD_BIT   0x0004
#define EMCMOT_MOTION_ERROR_BIT   0x0008
#define EMCMOT_MOTION_TELEOP_BIT   0x0010
#define EMCMOT_AXIS_ENABLE_BIT   0x0001
#define EMCMOT_AXIS_ACTIVE_BIT   0x0002
#define EMCMOT_AXIS_INPOS_BIT   0x0004
#define EMCMOT_AXIS_ERROR_BIT   0x0008
#define EMCMOT_AXIS_MAX_SOFT_LIMIT_BIT   0x0010
#define EMCMOT_AXIS_MIN_SOFT_LIMIT_BIT   0x0020
#define EMCMOT_AXIS_MAX_HARD_LIMIT_BIT   0x0040
#define EMCMOT_AXIS_MIN_HARD_LIMIT_BIT   0x0080
#define EMCMOT_AXIS_HOME_SWITCH_BIT   0x0100
#define EMCMOT_AXIS_HOMING_BIT   0x0200
#define EMCMOT_AXIS_HOMED_BIT   0x0400
#define EMCMOT_AXIS_FERROR_BIT   0x1000
#define EMCMOT_AXIS_FAULT_BIT   0x2000
#define EMCMOT_COMMAND_OK   0
#define EMCMOT_COMMAND_UNKNOWN_COMMAND   1
#define EMCMOT_COMMAND_INVALID_COMMAND   2
#define EMCMOT_COMMAND_INVALID_PARAMS   3
#define EMCMOT_COMMAND_BAD_EXEC   4
#define KINEMATICS_SERIAL   KINEMATICS_FORWARD_ONLY
#define KINEMATICS_PARALLEL   KINEMATICS_INVERSE_ONLY
#define KINEMATICS_CUSTOM   KINEMATICS_BOTH
#define FREE_AXIS_QUEUE_SIZE   4
#define EMCMOT_COMP_SIZE   256

Typedefs

typedef unsigned short EMCMOT_MOTION_FLAG
typedef unsigned short EMCMOT_AXIS_FLAG
typedef _EMC_TELEOP_DATA EMC_TELEOP_DATA
typedef unsigned long int KINEMATICS_FORWARD_FLAGS
typedef unsigned long int KINEMATICS_INVERSE_FLAGS

Enumerations

enum  {
  EMCMOT_SET_TRAJ_CYCLE_TIME = 1, EMCMOT_SET_SERVO_CYCLE_TIME, EMCMOT_SET_POSITION_LIMITS, EMCMOT_SET_OUTPUT_LIMITS,
  EMCMOT_SET_OUTPUT_SCALE, EMCMOT_SET_INPUT_SCALE, EMCMOT_SET_MIN_FERROR, EMCMOT_SET_MAX_FERROR,
  EMCMOT_JOG_CONT, EMCMOT_JOG_INCR, EMCMOT_JOG_ABS, EMCMOT_SET_LINE,
  EMCMOT_SET_CIRCLE, EMCMOT_SET_VEL, EMCMOT_SET_VEL_LIMIT, EMCMOT_SET_AXIS_VEL_LIMIT,
  EMCMOT_SET_ACC, EMCMOT_PAUSE, EMCMOT_RESUME, EMCMOT_STEP,
  EMCMOT_ABORT, EMCMOT_SCALE, EMCMOT_ENABLE, EMCMOT_DISABLE,
  EMCMOT_SET_PID, EMCMOT_ENABLE_AMPLIFIER, EMCMOT_DISABLE_AMPLIFIER, EMCMOT_OPEN_LOG,
  EMCMOT_START_LOG, EMCMOT_STOP_LOG, EMCMOT_CLOSE_LOG, EMCMOT_DAC_OUT,
  EMCMOT_HOME, EMCMOT_FREE, EMCMOT_COORD, EMCMOT_TELEOP,
  EMCMOT_ENABLE_WATCHDOG, EMCMOT_DISABLE_WATCHDOG, EMCMOT_SET_POLARITY, EMCMOT_ACTIVATE_AXIS,
  EMCMOT_DEACTIVATE_AXIS, EMCMOT_SET_TERM_COND, EMCMOT_SET_HOMING_VEL, EMCMOT_SET_NUM_AXES,
  EMCMOT_SET_WORLD_HOME, EMCMOT_SET_JOINT_HOME, EMCMOT_SET_HOME_OFFSET, EMCMOT_OVERRIDE_LIMITS,
  EMCMOT_SET_TELEOP_VECTOR, EMCMOT_SET_PROBE_INDEX, EMCMOT_SET_PROBE_POLARITY, EMCMOT_CLEAR_PROBE_FLAGS,
  EMCMOT_PROBE, EMCMOT_SET_DEBUG, EMCMOT_SET_AOUT, EMCMOT_SET_DOUT
}
enum  KINEMATICS_TYPE { KINEMATICS_IDENTITY = 1, KINEMATICS_FORWARD_ONLY, KINEMATICS_INVERSE_ONLY, KINEMATICS_BOTH }

Functions

int init_module (void)
void cleanup_module (void)
int kinematicsForward (const double *joint, EmcPose *world, const KINEMATICS_FORWARD_FLAGS *fflags, KINEMATICS_INVERSE_FLAGS *iflags)
int kinematicsInverse (const EmcPose *world, double *joints, const KINEMATICS_INVERSE_FLAGS *iflags, KINEMATICS_FORWARD_FLAGS *fflags)
int kinematicsHome (EmcPose *world, double *joint, KINEMATICS_FORWARD_FLAGS *fflags, KINEMATICS_INVERSE_FLAGS *iflags)
KINEMATICS_TYPE kinematicsType (void)
int kinematicsSetParameters (double *p)
int jacobianInverse (const EmcPose *pos, const EmcPose *vel, const double *joints, double *jointvels)
int jacobianForward (const double *joints, const double *jointvels, const EmcPose *pos, EmcPose *vel)
int emcmotErrorInit (EMCMOT_ERROR *errlog)
int emcmotErrorPut (EMCMOT_ERROR *errlog, const char *error)
int emcmotErrorGet (EMCMOT_ERROR *errlog, char *error)


Define Documentation

#define EMCMOT_AXIS_ACTIVE_BIT   0x0002
 

Definition at line 287 of file emcmot.h.

#define EMCMOT_AXIS_ENABLE_BIT   0x0001
 

Definition at line 286 of file emcmot.h.

#define EMCMOT_AXIS_ERROR_BIT   0x0008
 

Definition at line 289 of file emcmot.h.

#define EMCMOT_AXIS_FAULT_BIT   0x2000
 

Definition at line 301 of file emcmot.h.

#define EMCMOT_AXIS_FERROR_BIT   0x1000
 

Definition at line 300 of file emcmot.h.

#define EMCMOT_AXIS_HOMED_BIT   0x0400
 

Definition at line 298 of file emcmot.h.

#define EMCMOT_AXIS_HOME_SWITCH_BIT   0x0100
 

Definition at line 296 of file emcmot.h.

#define EMCMOT_AXIS_HOMING_BIT   0x0200
 

Definition at line 297 of file emcmot.h.

#define EMCMOT_AXIS_INPOS_BIT   0x0004
 

Definition at line 288 of file emcmot.h.

#define EMCMOT_AXIS_MAX_HARD_LIMIT_BIT   0x0040
 

Definition at line 293 of file emcmot.h.

#define EMCMOT_AXIS_MAX_SOFT_LIMIT_BIT   0x0010
 

Definition at line 291 of file emcmot.h.

#define EMCMOT_AXIS_MIN_HARD_LIMIT_BIT   0x0080
 

Definition at line 294 of file emcmot.h.

#define EMCMOT_AXIS_MIN_SOFT_LIMIT_BIT   0x0020
 

Definition at line 292 of file emcmot.h.

#define EMCMOT_COMMAND_BAD_EXEC   4
 

Definition at line 322 of file emcmot.h.

#define EMCMOT_COMMAND_INVALID_COMMAND   2
 

Definition at line 320 of file emcmot.h.

#define EMCMOT_COMMAND_INVALID_PARAMS   3
 

Definition at line 321 of file emcmot.h.

#define EMCMOT_COMMAND_OK   0
 

Definition at line 318 of file emcmot.h.

#define EMCMOT_COMMAND_UNKNOWN_COMMAND   1
 

Definition at line 319 of file emcmot.h.

#define EMCMOT_COMP_SIZE   256
 

Definition at line 610 of file emcmot.h.

#define EMCMOT_MOTION_COORD_BIT   0x0004
 

Definition at line 248 of file emcmot.h.

#define EMCMOT_MOTION_ENABLE_BIT   0x0001
 

Definition at line 246 of file emcmot.h.

#define EMCMOT_MOTION_ERROR_BIT   0x0008
 

Definition at line 249 of file emcmot.h.

#define EMCMOT_MOTION_INPOS_BIT   0x0002
 

Definition at line 247 of file emcmot.h.

#define EMCMOT_MOTION_TELEOP_BIT   0x0010
 

Definition at line 250 of file emcmot.h.

#define EMCMOT_TERM_COND_BLEND   2
 

Definition at line 176 of file emcmot.h.

#define EMCMOT_TERM_COND_STOP   1
 

Definition at line 175 of file emcmot.h.

#define ENABLE_PROBING
 

Definition at line 83 of file emcmot.h.

#define FREE_AXIS_QUEUE_SIZE   4
 

Definition at line 517 of file emcmot.h.

#define KINEMATICS_CUSTOM   KINEMATICS_BOTH
 

Definition at line 358 of file emcmot.h.

#define KINEMATICS_PARALLEL   KINEMATICS_INVERSE_ONLY
 

Definition at line 357 of file emcmot.h.

#define KINEMATICS_SERIAL   KINEMATICS_FORWARD_ONLY
 

Definition at line 356 of file emcmot.h.


Typedef Documentation

typedef unsigned short EMCMOT_AXIS_FLAG
 

Definition at line 104 of file emcmot.h.

typedef unsigned short EMCMOT_MOTION_FLAG
 

Definition at line 101 of file emcmot.h.

typedef struct _EMC_TELEOP_DATA EMC_TELEOP_DATA
 

typedef unsigned long int KINEMATICS_FORWARD_FLAGS
 

Definition at line 668 of file emcmot.h.

typedef unsigned long int KINEMATICS_INVERSE_FLAGS
 

Definition at line 679 of file emcmot.h.


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
EMCMOT_SET_TRAJ_CYCLE_TIME 
EMCMOT_SET_SERVO_CYCLE_TIME 
EMCMOT_SET_POSITION_LIMITS 
EMCMOT_SET_OUTPUT_LIMITS 
EMCMOT_SET_OUTPUT_SCALE 
EMCMOT_SET_INPUT_SCALE 
EMCMOT_SET_MIN_FERROR 
EMCMOT_SET_MAX_FERROR 
EMCMOT_JOG_CONT 
EMCMOT_JOG_INCR 
EMCMOT_JOG_ABS 
EMCMOT_SET_LINE 
EMCMOT_SET_CIRCLE 
EMCMOT_SET_VEL 
EMCMOT_SET_VEL_LIMIT 
EMCMOT_SET_AXIS_VEL_LIMIT 
EMCMOT_SET_ACC 
EMCMOT_PAUSE 
EMCMOT_RESUME 
EMCMOT_STEP 
EMCMOT_ABORT 
EMCMOT_SCALE 
EMCMOT_ENABLE 
EMCMOT_DISABLE 
EMCMOT_SET_PID 
EMCMOT_ENABLE_AMPLIFIER 
EMCMOT_DISABLE_AMPLIFIER 
EMCMOT_OPEN_LOG 
EMCMOT_START_LOG 
EMCMOT_STOP_LOG 
EMCMOT_CLOSE_LOG 
EMCMOT_DAC_OUT 
EMCMOT_HOME 
EMCMOT_FREE 
EMCMOT_COORD 
EMCMOT_TELEOP 
EMCMOT_ENABLE_WATCHDOG 
EMCMOT_DISABLE_WATCHDOG 
EMCMOT_SET_POLARITY 
EMCMOT_ACTIVATE_AXIS 
EMCMOT_DEACTIVATE_AXIS 
EMCMOT_SET_TERM_COND 
EMCMOT_SET_HOMING_VEL 
EMCMOT_SET_NUM_AXES 
EMCMOT_SET_WORLD_HOME 
EMCMOT_SET_JOINT_HOME 
EMCMOT_SET_HOME_OFFSET 
EMCMOT_OVERRIDE_LIMITS 
EMCMOT_SET_TELEOP_VECTOR 
EMCMOT_SET_PROBE_INDEX 
EMCMOT_SET_PROBE_POLARITY 
EMCMOT_CLEAR_PROBE_FLAGS 
EMCMOT_PROBE 
EMCMOT_SET_DEBUG 
EMCMOT_SET_AOUT 
EMCMOT_SET_DOUT 

Definition at line 107 of file emcmot.h.

00107      {
00108   EMCMOT_SET_TRAJ_CYCLE_TIME = 1, /* set the cycle time */
00109   EMCMOT_SET_SERVO_CYCLE_TIME,  /* set the interpolation rate */
00110   EMCMOT_SET_POSITION_LIMITS,   /* set the axis position +/- limits */
00111   EMCMOT_SET_OUTPUT_LIMITS,     /* set the axis output +/- limits */
00112   EMCMOT_SET_OUTPUT_SCALE,      /* scale factor for outputs */
00113   EMCMOT_SET_INPUT_SCALE,       /* scale factor for inputs */
00114   EMCMOT_SET_MIN_FERROR,        /* minimum following error, input units */
00115   EMCMOT_SET_MAX_FERROR,        /* maximum following error, input units */
00116   EMCMOT_JOG_CONT,              /* continuous jog */
00117   EMCMOT_JOG_INCR,              /* incremental jog */
00118   EMCMOT_JOG_ABS,               /* absolute jog */
00119   EMCMOT_SET_LINE,              /* queue up a linear move */
00120   EMCMOT_SET_CIRCLE,            /* queue up a circular move */
00121   EMCMOT_SET_VEL,               /* set the velocity for subsequent moves */
00122   EMCMOT_SET_VEL_LIMIT,         /* set the absolute max vel for all moves */
00123   EMCMOT_SET_AXIS_VEL_LIMIT,    /* set the absolute max vel for each axis */
00124   EMCMOT_SET_ACC,               /* set the acceleration for moves */
00125   EMCMOT_PAUSE,                 /* pause motion */
00126   EMCMOT_RESUME,                /* resume motion */
00127   EMCMOT_STEP,                  /* resume motion until id encountered */
00128   EMCMOT_ABORT,                 /* abort motion */
00129   EMCMOT_SCALE,                 /* scale the speed */
00130   EMCMOT_ENABLE,                /* enable servos for active axes */
00131   EMCMOT_DISABLE,               /* disable servos for active axes */
00132   EMCMOT_SET_PID,               /* set PID gains */
00133   EMCMOT_ENABLE_AMPLIFIER,      /* enable amp outputs and dac writes */
00134   EMCMOT_DISABLE_AMPLIFIER,     /* disable amp outputs and dac writes */
00135   EMCMOT_OPEN_LOG,              /* open a log */
00136   EMCMOT_START_LOG,             /* start logging */
00137   EMCMOT_STOP_LOG,              /* stop logging */
00138   EMCMOT_CLOSE_LOG,             /* close log */
00139   EMCMOT_DAC_OUT,               /* write directly to the dacs */
00140   EMCMOT_HOME,                  /* home an axis */
00141   EMCMOT_FREE,                  /* set mode to free (joint) motion */
00142   EMCMOT_COORD,                 /* set mode to coordinated motion */
00143   EMCMOT_TELEOP,                 /* set mode to teleop*/
00144   EMCMOT_ENABLE_WATCHDOG,       /* enable watchdog sound, parport */
00145   EMCMOT_DISABLE_WATCHDOG,      /* enable watchdog sound, parport */
00146   EMCMOT_SET_POLARITY,          /* set polarity for axis flags */
00147   EMCMOT_ACTIVATE_AXIS,         /* make axis active */
00148   EMCMOT_DEACTIVATE_AXIS,       /* make axis inactive */
00149   EMCMOT_SET_TERM_COND,         /* set termination condition (stop, blend) */
00150   EMCMOT_SET_HOMING_VEL,        /* set the axis homing speed */
00151   EMCMOT_SET_NUM_AXES,          /* set the number of axes */
00152   EMCMOT_SET_WORLD_HOME,        /* set pose for world home */
00153   EMCMOT_SET_JOINT_HOME,        /* set value for joint homes */
00154   EMCMOT_SET_HOME_OFFSET,       /* where to go after a home */
00155   EMCMOT_OVERRIDE_LIMITS,       /* temporarily ignore limits until jog done */
00156   EMCMOT_SET_TELEOP_VECTOR,     /* Move at a given velocity  but in 
00157                                    world cartesian coordinates, not in joint 
00158                                    space like EMCMOT_JOG_* */
00159 #ifdef ENABLE_PROBING
00160   EMCMOT_SET_PROBE_INDEX,       /* set which wire the probe signal is on. */
00161   EMCMOT_SET_PROBE_POLARITY,    /* probe tripped on 0 to 1 transition or on
00162                                    1 to 0 transition. */
00163   EMCMOT_CLEAR_PROBE_FLAGS,     /* clears probeTripped flag */
00164   EMCMOT_PROBE,                  /* go towards a position, stop if the probe
00165                                    is tripped, and record the position where
00166                                    the probe tripped */
00167   EMCMOT_SET_DEBUG,             /* sets the debug level */
00168   EMCMOT_SET_AOUT,              /* sets an analog motion point for next move */
00169   EMCMOT_SET_DOUT               /* sets a digital motion point for next move */
00170 #endif
00171 
00172 };

enum KINEMATICS_TYPE
 

Enumeration values:
KINEMATICS_IDENTITY 
KINEMATICS_FORWARD_ONLY 
KINEMATICS_INVERSE_ONLY 
KINEMATICS_BOTH 

Definition at line 348 of file emcmot.h.

00348              {
00349   KINEMATICS_IDENTITY = 1,      /* forward=inverse, both well-behaved */
00350   KINEMATICS_FORWARD_ONLY,      /* forward but no inverse */
00351   KINEMATICS_INVERSE_ONLY,      /* inverse but no forward */
00352   KINEMATICS_BOTH               /* forward and inverse both */
00353 } KINEMATICS_TYPE;


Function Documentation

void cleanup_module void   
 

Definition at line 2904 of file emcsegmot.c.

02905 {
02906   int axis;
02907 
02908   /* release traj planner space */
02909 #if !defined(rtlinux)
02910   free(sqMemPool);
02911 #endif
02912   sqTrashQueue(&queue);
02913 
02914   /* release axis planner spaces */
02915   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++)
02916     {
02917       tpDelete(&freeAxis[axis]);
02918     }
02919 
02920   /* disable amps */
02921   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++)
02922     {
02923       extAmpEnable(axis,
02924                    ! GET_AXIS_ENABLE_POLARITY(axis));
02925     }
02926 
02927   /* quit board */
02928   extAioQuit();
02929   extDioQuit();
02930   extMotQuit();
02931 
02932 #ifdef rtlinux
02933 
02934 #ifdef RT_FIFO
02935   rtf_destroy(EMCMOT_COMMAND_RTF);
02936   rtf_destroy(EMCMOT_STATUS_RTF);
02937   rtf_destroy(EMCMOT_ERROR_RTF);
02938 #endif
02939 
02940   /* delete control task */
02941   rt_task_delete(&emcmotTask);
02942 
02943   /* FIXME */
02944   diagnostics("exited emcmot\n");
02945 
02946 #ifdef STEPPER_MOTORS
02947 
02948   /* delete stepper motor task */
02949   rt_task_delete(&smTask);
02950 
02951 #endif
02952 
02953 #else
02954 
02955   /* detach from shmem */
02956   if (NULL != shmem)
02957     {
02958       rcs_shm_close(shmem);
02959       shmem = NULL;
02960     }
02961 
02962 #endif
02963 }

int emcmotErrorGet EMCMOT_ERROR   errlog,
char *    error
 

Definition at line 77 of file emcmotutil.c.

00078 {
00079   char *p1;
00080   const char *p2;
00081   int i;
00082   if (errlog == 0 ||
00083       errlog->num == 0) {
00084       /* empty */
00085       return -1;
00086   }
00087 
00088   errlog->head++;
00089 
00090   //  strncpy(error, errlog->error[errlog->start], EMCMOT_ERROR_LEN);  
00091   // replaced strncpy with manual copy
00092   p1=error;
00093   p2=errlog->error[errlog->start];
00094   i=0;
00095   while(*p2 && i < EMCMOT_ERROR_LEN)
00096     {
00097       *p1 = *p2;
00098       p1++;
00099       p2++;
00100       i++;
00101     }
00102   *p1=0;
00103 
00104 
00105   errlog->start = (errlog->start + 1) % EMCMOT_ERROR_NUM;
00106   errlog->num--;
00107 
00108   errlog->tail = errlog->head;
00109 
00110   return 0;
00111 }

int emcmotErrorInit EMCMOT_ERROR   errlog
 

Referenced by init_module().

int emcmotErrorPut EMCMOT_ERROR   errlog,
const char *    error
 

Definition at line 41 of file emcmotutil.c.

00042 {
00043   char *p1;
00044   const char *p2;
00045   int i;
00046 
00047   if (errlog == 0 ||
00048       errlog->num == EMCMOT_ERROR_NUM) {
00049     /* full */
00050     return -1;
00051   }
00052 
00053   errlog->head++;
00054 
00055   // strncpy(errlog->error[errlog->end], error, EMCMOT_ERROR_LEN);
00056   // replaced strncpy with manual copy
00057   p1=errlog->error[errlog->end];
00058   p2=error;
00059   i=0;
00060   while(*p2 && i < EMCMOT_ERROR_LEN)
00061     {
00062       *p1 = *p2;
00063       p1++;
00064       p2++;
00065       i++;
00066     }
00067   *p1=0;
00068 
00069   errlog->end = (errlog->end + 1) % EMCMOT_ERROR_NUM;
00070   errlog->num++;
00071 
00072   errlog->tail = errlog->head;
00073 
00074   return 0;
00075 }

int init_module void   
 

Definition at line 2570 of file emcsegmot.c.

02571 {
02572   int axis;
02573   int t;
02574 #ifdef rtlinux
02575   RTIME now;
02576 #endif
02577   PID_STRUCT pid;
02578 
02579 #ifdef rtlinux
02580 
02581 #ifdef RT_FIFO
02582   rtf_create(EMCMOT_COMMAND_RTF, sizeof(EMCMOT_COMMAND) + 1);
02583   rtf_create(EMCMOT_STATUS_RTF, sizeof(EMCMOT_STATUS) + 1);
02584   rtf_create(EMCMOT_ERROR_RTF, EMCMOT_ERROR_NUM * EMCMOT_ERROR_LEN + 1);
02585   /* log is created, deleted dynamically */
02586 
02587   /* fifo puts and gets work on buffer structs, so point to these */
02588   emcmotCommand = &emcmotCommandBuffer;
02589   emcmotStatus = &emcmotStatusBuffer;
02590 
02591 #else  /* not RT_FIFO */
02592   /* set upper memory pointers */
02593   emcmotStruct = (EMCMOT_STRUCT *) SHMEM_BASE_ADDRESS;
02594 
02595 #endif /* else not RT_FIFO */
02596 
02597 #else  /* not rtlinux */
02598   /* get command shmem */
02599   shmem = rcs_shm_open(SHMEM_KEY, sizeof(EMCMOT_STRUCT), 1, 0666);
02600   if (NULL == shmem ||
02601       NULL == shmem->addr)
02602     {
02603       diagnostics("can't get shared memory\n");
02604       return -1;
02605     }
02606 
02607   memset(shmem->addr, 0, sizeof(EMCMOT_STRUCT));
02608   /* map shmem area into local address space */
02609   emcmotStruct = (EMCMOT_STRUCT *) shmem->addr;
02610 
02611 #endif /* else not rtlinux */
02612 
02613 #ifndef RT_FIFO
02614   /* we'll reference emcmotStruct directly */
02615   emcmotCommand = (EMCMOT_COMMAND *) &emcmotStruct->command;
02616   emcmotStatus = (EMCMOT_STATUS *) &emcmotStruct->status;
02617   emcmotError = (EMCMOT_ERROR *) &emcmotStruct->error;
02618   emcmotLog = (EMCMOT_LOG *) &emcmotStruct->log;
02619 
02620   /* zero shared memory */
02621   for (t = 0; t < sizeof(EMCMOT_STRUCT); t++)
02622     {
02623       ((char *) emcmotStruct)[t] = 0;
02624     }
02625 #endif /* not RT_FIFO */
02626 
02627   /* init locals */
02628   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++)
02629     {
02630       maxLimitSwitchCount[axis] = 0;
02631       minLimitSwitchCount[axis] = 0;
02632       /* STEPPER MOTORS */
02633       smStepsPerUnit[axis] = 1.0;
02634       smStepsAccum[axis] = 0;
02635       smClkPhase[axis] = 0;
02636       /* END STEPPER MOTORS */
02637     }
02638 
02639 #ifndef RT_FIFO
02640   /* init error struct */
02641   emcmotErrorInit(emcmotError);
02642 #endif /* not RT_FIFO */
02643 
02644   /* init command struct */
02645   emcmotCommand->head = 0;
02646   emcmotCommand->command = 0;
02647   emcmotCommand->commandNum = 0;
02648   emcmotCommand->tail = 0;
02649 
02650   /* init status struct */
02651 
02652   emcmotStatus->head = 0;
02653 
02654   emcmotStatus->motionFlag = 0;
02655   SET_MOTION_ERROR_FLAG(0);
02656   SET_MOTION_COORD_FLAG(0);
02657   emcmotStatus->split = 0;
02658   emcmotStatus->commandEcho = 0;
02659   emcmotStatus->commandNumEcho = 0;
02660   emcmotStatus->commandStatus = 0;
02661   emcmotStatus->heartbeat = 0;
02662   emcmotStatus->computeTime = 0.0;
02663   emcmotStatus->numAxes = EMCMOT_MAX_AXIS;
02664   emcmotStatus->trajCycleTime = TRAJ_CYCLE_TIME;
02665   emcmotStatus->servoCycleTime = SERVO_CYCLE_TIME;
02666   emcmotStatus->pos.tran.x = 0.0;
02667   emcmotStatus->pos.tran.y = 0.0;
02668   emcmotStatus->pos.tran.z = 0.0;
02669   emcmotStatus->actualPos.tran.x = 0.0;
02670   emcmotStatus->actualPos.tran.y = 0.0;
02671   emcmotStatus->actualPos.tran.z = 0.0;
02672   emcmotStatus->vel = VELOCITY;
02673   emcmotStatus->limitVel = VELOCITY;
02674   emcmotStatus->acc = ACCELERATION;
02675   emcmotStatus->qVscale = 1.0;
02676   emcmotStatus->id = 0;
02677   emcmotStatus->depth = 0;
02678   emcmotStatus->activeDepth = 0;
02679   emcmotStatus->paused = 0;
02680   SET_MOTION_INPOS_FLAG(1);
02681   emcmotStatus->logOpen = 0;
02682   emcmotStatus->logStarted = 0;
02683   emcmotStatus->logSize = 0;
02684   emcmotStatus->logSkip = 0;
02685   emcmotStatus->logPoints = 0;
02686   SET_MOTION_ENABLE_FLAG(0);
02687 
02688   oldPos = emcmotStatus->pos;
02689   oldVel.tran.x = 0.0;
02690   oldVel.tran.y = 0.0;
02691   oldVel.tran.z = 0.0;
02692 
02693   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++)
02694     {
02695       emcmotStatus->homingVel[axis] = VELOCITY;
02696       emcmotStatus->axisFlag[axis] = 0;
02697       emcmotStatus->maxLimit[axis] = MAX_LIMIT;
02698       emcmotStatus->minLimit[axis] = MIN_LIMIT;
02699       emcmotStatus->maxOutput[axis] = MAX_OUTPUT;
02700       emcmotStatus->minOutput[axis] = MIN_OUTPUT;
02701       emcmotStatus->maxFerror[axis] = MAX_FERROR;
02702       emcmotStatus->ferror[axis] = 0.0;
02703       emcmotStatus->outputScale[axis] = OUTPUT_SCALE;
02704       emcmotStatus->outputOffset[axis] = OUTPUT_OFFSET;
02705       emcmotStatus->inputScale[axis] = INPUT_SCALE;
02706       emcmotStatus->inputOffset[axis] = INPUT_OFFSET;
02707       emcmotStatus->axVscale[axis] = 1.0;
02708       SET_AXIS_ENABLE_FLAG(axis, 0);
02709       SET_AXIS_ACTIVE_FLAG(axis, 1); /* default is use it */
02710       SET_AXIS_NSL_FLAG(axis, 0);
02711       SET_AXIS_PSL_FLAG(axis, 0);
02712       SET_AXIS_NHL_FLAG(axis, 0);
02713       SET_AXIS_PHL_FLAG(axis, 0);
02714       SET_AXIS_INPOS_FLAG(axis, 1);
02715       SET_AXIS_HOMING_FLAG(axis, 0);
02716       SET_AXIS_HOMED_FLAG(axis, 0);
02717       SET_AXIS_FERROR_FLAG(axis, 0);
02718       SET_AXIS_FAULT_FLAG(axis, 0);
02719       SET_AXIS_ERROR_FLAG(axis, 0);
02720       emcmotStatus->axisPolarity[axis] = (EMCMOT_AXIS_FLAG) 0xFFFFFFFF;
02721       /* will read encoders directly, so don't set them here */
02722     }
02723 
02724   /* FIXME-- add emcmotError */
02725 
02726   /* init min-max-avg stats */
02727   mmxavgInit(&tMmxavg, tMmxavgSpace, MMXAVG_SIZE);
02728   mmxavgInit(&sMmxavg, sMmxavgSpace, MMXAVG_SIZE);
02729   mmxavgInit(&nMmxavg, nMmxavgSpace, MMXAVG_SIZE);
02730   emcmotStatus->tMin = 0.0;
02731   emcmotStatus->tMax = 0.0;
02732   emcmotStatus->tAvg = 0.0;
02733   emcmotStatus->sMin = 0.0;
02734   emcmotStatus->sMax = 0.0;
02735   emcmotStatus->sAvg = 0.0;
02736   emcmotStatus->nMin = 0.0;
02737   emcmotStatus->nMax = 0.0;
02738   emcmotStatus->nAvg = 0.0;
02739 
02740   /* init motion queue */
02741 #ifdef rtlinux
02742   if ( -1 == sqInitQueue(&queue,(SEGMENT *)(SHMEM_BASE_ADDRESS+sizeof(EMCMOT_STRUCT)), TC_QUEUE_SIZE))
02743 #else
02744   sqMemPool = (SEGMENT *)malloc(TC_QUEUE_SIZE*sizeof(SEGMENT));
02745   if ( sqMemPool == NULL )
02746     {
02747       diagnostics("Error in init_module(): cannot allocate memory for segmentqueue\n");
02748       return -1;
02749     }
02750   if ( -1 == sqInitQueue(&queue,sqMemPool, TC_QUEUE_SIZE))
02751 #endif
02752     {
02753       diagnostics("can't initialize motion queue\n");
02754       return -1;
02755     }
02756   sqSetCycleTime(&queue, emcmotStatus->trajCycleTime);
02757   sqSetPos(&queue, emcmotStatus->pos);
02758   sqSetVmax(&queue, emcmotStatus->vel);
02759           sqSetFeed(&queue, emcmotStatus->vel);
02760           /* FIX ME ^^^^ the feed and the absolute maximum velocity
02761              are set the same number */
02762 
02763   sqSetMaxAcc(&queue, emcmotStatus->acc);
02764   sqSetMaxFeedOverride(&queue, 1.0 );
02765 
02766   /* init the axis components */
02767   pid.p = P_GAIN;
02768   pid.i = I_GAIN;
02769   pid.d = D_GAIN;
02770   pid.ff0 = FF0_GAIN;
02771   pid.ff1 = FF1_GAIN;
02772   pid.ff2 = FF2_GAIN;
02773   pid.backlash = BACKLASH;
02774   pid.bias = BIAS;
02775   pid.maxError = MAX_ERROR;
02776 
02777   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++)
02778     {
02779       if (-1 == tpCreate(&freeAxis[axis], FREE_AXIS_QUEUE_SIZE, freeAxisTcSpace[axis]))
02780         {
02781           diagnostics("can't create axis queue %d\n", axis);
02782           return -1;
02783         }
02784       tpInit(&freeAxis[axis]);
02785       tpSetCycleTime(&freeAxis[axis], emcmotStatus->trajCycleTime);
02786       tpSetPos(&freeAxis[axis], emcmotStatus->pos);
02787       tpSetVmax(&freeAxis[axis], emcmotStatus->vel);
02788       tpSetAmax(&freeAxis[axis], emcmotStatus->acc);
02789       pidInit(&emcmotStatus->pid[axis]);
02790       pidSetGains(&emcmotStatus->pid[axis], pid);
02791       cubicInit(&cubic[axis]);
02792     }
02793 
02794   /* init the time and rate using functions to affect traj, the
02795      pids, and the cubics properly, since they're coupled */
02796   setTrajCycleTime(TRAJ_CYCLE_TIME);
02797   setServoCycleTime(SERVO_CYCLE_TIME);
02798 
02799   /* init board */
02800   if (-1 == extMotInit((const char *) 0))
02801     {
02802       diagnostics("can't initialize motion hardware\n");
02803       return -1;
02804     }
02805   if (-1 == extDioInit((const char *) 0))
02806     {
02807       diagnostics("can't initialize DIO hardware\n");
02808       return -1;
02809     }
02810   if (-1 == extAioInit((const char *) 0))
02811     {
02812       diagnostics("can't initialize AIO hardware\n");
02813       return -1;
02814     }
02815 
02816   extEncoderSetIndexModel(EXT_ENCODER_INDEX_MODEL_MANUAL);
02817   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++)
02818     {
02819       rawInput[axis] = 0.0;
02820       rawOutput[axis] = 0.0;
02821       trajPos[axis] = 0.0;
02822       jointPos[axis] = 0.0;
02823       oldJointPos[axis] = 0.0;
02824       oldInput[axis] = 0.0;
02825 
02826       waitingForLatch[axis] = 0;
02827       latchFlag[axis] = 0;
02828       saveLatch[axis] = 0.0;
02829 
02830       wasOnLimit[axis] = 0;
02831       emcmotStatus->input[axis] = 0.0;
02832       lastInput[axis] = 0.0;
02833       emcmotStatus->output[axis] = 0.0;
02834 
02835       extAmpEnable(axis,
02836                    ! GET_AXIS_ENABLE_POLARITY(axis));
02837     }
02838 
02839   emcmotStatus->tail = 0;
02840 
02841 #ifdef rtlinux
02842 
02843   /* get current time as base for starting tasks */
02844   now = rt_get_time();
02845 
02846   /* init control task */
02847   rt_task_init(&emcmotTask,     /* RT_TASK * */
02848                emcmotController, /* task code */
02849                0,               /* startup arg to task code */
02850                RT_TASK_STACK_SIZE, /* task stack size */
02851                RT_TASK_PRIORITY); /* priority */
02852 
02853   /* make sure we save FP context */
02854 
02855 #if defined(rtlinux_09J) || defined(rtlinux_1_0)
02856   rt_task_use_fp(&emcmotTask, 1);
02857 #else
02858   rt_use_fp(1);
02859 #endif
02860 
02861   /* schedule control task to run */
02862   rt_task_make_periodic(&emcmotTask,
02863                         now + SECS_TO_RTIME(0.010),
02864                         (RTIME) (RT_TICKS_PER_SEC *
02865                                  emcmotStatus->servoCycleTime));
02866 
02867 #ifdef STEPPER_MOTORS
02868 
02869   /* init stepper motor task */
02870   rt_task_init(&smTask, /* RT_TASK * */
02871                smController, /* task code */
02872                0,               /* startup arg to task code */
02873                SM_TASK_STACK_SIZE, /* task stack size */
02874                SM_TASK_PRIORITY); /* priority */
02875 
02876   /* make sure we save FP context */
02877 #if defined(rtlinux_09J) || defined(rtlinux_1_0)
02878   rt_task_use_fp(&smTask, 1);
02879 #endif
02880 
02881   /* schedule stepper task to run at twice servo (axis) rate */
02882   rt_task_make_periodic(&smTask,
02883                         now + SECS_TO_RTIME(0.010),
02884                         ((RTIME) (RT_TICKS_PER_SEC *
02885                                  emcmotStatus->servoCycleTime)) >> 1);
02886 
02887 #endif
02888 
02889   /* FIXME */
02890   diagnostics("inited emcmot\n");
02891 
02892 #endif /* rtlinux */
02893 
02894 #if defined (rtlinux) && defined (RT_FIFO)
02895   /* create user process handler on control channel */
02896   rtf_create_handler(EMCMOT_COMMAND_RTF, /* fifo number */
02897                      emcmotCommandHandler /* control message handler */
02898                      );
02899 
02900 #endif /* rtlinux and RT_FIFO */
02901   return 0;
02902 }

int jacobianForward const double *    joints,
const double *    jointvels,
const EmcPose   pos,
EmcPose   vel
 

Definition at line 270 of file genhexkins.c.

00274 {
00275   double InverseJacobian[NUM_STRUTS][NUM_STRUTS];
00276   double Jacobian[NUM_STRUTS][NUM_STRUTS];
00277   double velmatrix[6];
00278 
00279   if (0 != JInvMat(pos, InverseJacobian)) {
00280     return -1;
00281   }
00282   if (0 != MatInvert(InverseJacobian, Jacobian)) {
00283     return -1;
00284   }
00285 
00286   /* Multiply J[] by jointvels to get vels */
00287   MatMult(Jacobian, jointvels, velmatrix);
00288   vel->tran.x = velmatrix[0];
00289   vel->tran.y = velmatrix[1];
00290   vel->tran.z = velmatrix[2];
00291   vel->a = velmatrix[3];
00292   vel->b = velmatrix[4];
00293   vel->c = velmatrix[5];
00294 
00295   return 0;
00296 }

int jacobianInverse const EmcPose   pos,
const EmcPose   vel,
const double *    joints,
double *    jointvels
 

Definition at line 242 of file genhexkins.c.

00246 {
00247   double InverseJacobian[NUM_STRUTS][NUM_STRUTS];
00248   double velmatrix[6];
00249 
00250   if (0 != JInvMat(pos, InverseJacobian)) {
00251     return -1;
00252   }
00253 
00254   /* Multiply Jinv[] by vel[] to get jointvels */
00255   velmatrix[0] = vel->tran.x;   /* dx/dt */
00256   velmatrix[1] = vel->tran.y;   /* dy/dt */
00257   velmatrix[2] = vel->tran.z;   /* dz/dt */
00258   velmatrix[3] = vel->a;        /* droll/dt */
00259   velmatrix[4] = vel->b;        /* dpitch/dt */
00260   velmatrix[5] = vel->c;        /* dyaw/dt */
00261   MatMult(InverseJacobian, velmatrix, jointvels);
00262 
00263   return 0;
00264 }

int kinematicsForward const double *    joint,
EmcPose   world,
const KINEMATICS_FORWARD_FLAGS   fflags,
KINEMATICS_INVERSE_FLAGS   iflags
 

Definition at line 304 of file genhexkins.c.

00308 {
00309   PmCartesian aw;
00310   PmCartesian InvKinStrutVect,InvKinStrutVectUnit;
00311   PmCartesian q_trans, RMatrix_a, RMatrix_a_cross_Strut;
00312 
00313   double Jacobian[NUM_STRUTS][NUM_STRUTS];
00314   double InverseJacobian[NUM_STRUTS][NUM_STRUTS];
00315   double InvKinStrutLength, StrutLengthDiff[NUM_STRUTS];
00316   double delta[NUM_STRUTS];
00317   double conv_err = 1.0;
00318 
00319   PmRotationMatrix RMatrix;
00320   PmRpy q_RPY;
00321 
00322   int iterate = 1;
00323   int i;
00324   int iteration = 0;
00325   int retval = 0;
00326 
00327 #define HIGH_CONV_CRITERION   (1e-12)
00328 #define MEDIUM_CONV_CRITERION (1e-5)
00329 #define LOW_CONV_CRITERION    (1e-3)
00330 #define MEDIUM_CONV_ITERATIONS  50
00331 #define LOW_CONV_ITERATIONS    100
00332 #define FAIL_CONV_ITERATIONS   150
00333 #define LARGE_CONV_ERROR 10000
00334   double conv_criterion = HIGH_CONV_CRITERION;
00335 
00336   /* abort on obvious problems, like joints <= 0 */
00337   /* FIXME-- should check against triangle inequality, so that joints
00338      are never too short to span shared base and platform sides */
00339   if (joints[0] <= 0.0 ||
00340       joints[1] <= 0.0 ||
00341       joints[2] <= 0.0 ||
00342       joints[3] <= 0.0 ||
00343       joints[4] <= 0.0 ||
00344       joints[5] <= 0.0) {
00345     return -1;
00346   }
00347 
00348   /* assign a,b,c to roll, pitch, yaw angles */
00349   q_RPY.r = pos->a * PM_PI / 180.0;
00350   q_RPY.p = pos->b * PM_PI / 180.0;
00351   q_RPY.y = pos->c * PM_PI / 180.0;
00352 
00353   /* Assign translation values in pos to q_trans */
00354   q_trans.x = pos->tran.x;
00355   q_trans.y = pos->tran.y;
00356   q_trans.z = pos->tran.z;
00357 
00358   /* Enter Newton-Raphson iterative method   */
00359   while (iterate) {
00360     /* check for large error and return error flag if no convergence */
00361     if ((conv_err > +LARGE_CONV_ERROR) || 
00362         (conv_err < -LARGE_CONV_ERROR)) {
00363       /* we can't converge */
00364       return -2;
00365     };
00366 
00367     iteration++;
00368 
00369 #if 0
00370     /* if forward kinematics are having a difficult time converging
00371        ease the restrictions on the convergence criterion */
00372     if (iteration == MEDIUM_CONV_ITERATIONS) {
00373       conv_criterion = MEDIUM_CONV_CRITERION;
00374       retval = -3;              /* this means if we eventually converge,
00375                                  the result is sloppy */
00376     }
00377 
00378     if (iteration == LOW_CONV_ITERATIONS) {
00379       conv_criterion = LOW_CONV_CRITERION;
00380       retval = -4;              /* this means if we eventually converge,
00381                                  the result is even sloppier */
00382     }
00383 #endif
00384 
00385     /* check iteration to see if the kinematics can reach the
00386        convergence criterion and return error flag if it can't */
00387     if (iteration > FAIL_CONV_ITERATIONS) {
00388       /* we can't converge */
00389       return -5;
00390     }
00391 
00392     /* Convert q_RPY to Rotation Matrix */
00393     pmRpyMatConvert(q_RPY, &RMatrix);
00394 
00395     /* compute StrutLengthDiff[] by running inverse kins on Cartesian
00396      estimate to get joint estimate, subtract joints to get joint deltas,
00397      and compute inv J while we're at it */
00398     for (i = 0; i < NUM_STRUTS; i++) {
00399       pmMatCartMult(RMatrix, a[i], &RMatrix_a);
00400       pmCartCartAdd(q_trans, RMatrix_a, &aw);
00401       pmCartCartSub(aw,b[i], &InvKinStrutVect);
00402       if (0 != pmCartUnit(InvKinStrutVect, &InvKinStrutVectUnit)) {
00403         return -1;
00404       }
00405       pmCartMag(InvKinStrutVect, &InvKinStrutLength);
00406       StrutLengthDiff[i] = InvKinStrutLength - joints[i];
00407 
00408       /* Determine RMatrix_a_cross_strut */
00409       pmCartCartCross(RMatrix_a, InvKinStrutVectUnit, &RMatrix_a_cross_Strut);
00410 
00411       /* Build Inverse Jacobian Matrix */
00412       InverseJacobian[i][0] = InvKinStrutVectUnit.x;
00413       InverseJacobian[i][1] = InvKinStrutVectUnit.y;
00414       InverseJacobian[i][2] = InvKinStrutVectUnit.z;
00415       InverseJacobian[i][3] = RMatrix_a_cross_Strut.x;
00416       InverseJacobian[i][4] = RMatrix_a_cross_Strut.y;
00417       InverseJacobian[i][5] = RMatrix_a_cross_Strut.z;
00418     }
00419 
00420     /* invert Inverse Jacobian */
00421     MatInvert(InverseJacobian, Jacobian);
00422 
00423     /* multiply Jacobian by LegLengthDiff */
00424     MatMult(Jacobian, StrutLengthDiff, delta);
00425 
00426     /* subtract delta from last iterations pos values */
00427     q_trans.x -= delta[0];
00428     q_trans.y -= delta[1];
00429     q_trans.z -= delta[2];
00430     q_RPY.r   -= delta[3];
00431     q_RPY.p   -= delta[4];
00432     q_RPY.y   -= delta[5];
00433 
00434     /* determine value of conv_error (used to determine if no convergence) */
00435     conv_err = 0.0;
00436     for (i = 0; i < NUM_STRUTS; i++) {
00437       conv_err += fabs(StrutLengthDiff[i]);
00438     }
00439 
00440     /* enter loop to determine if a strut needs another iteration */
00441     iterate = 0;                        /*assume iteration is done */
00442     for (i = 0; i < NUM_STRUTS; i++) {
00443       if (fabs(StrutLengthDiff[i]) > conv_criterion) {
00444         iterate = 1;
00445       }
00446     }
00447   } /* exit Newton-Raphson Iterative loop */
00448 
00449   /* assign r,p,w to a,b,c */
00450   pos->a = q_RPY.r * 180.0 / PM_PI;  
00451   pos->b = q_RPY.p * 180.0 / PM_PI;  
00452   pos->c = q_RPY.y * 180.0 / PM_PI;
00453   
00454   /* assign q_trans to pos */
00455   pos->tran.x = q_trans.x;
00456   pos->tran.y = q_trans.y;
00457   pos->tran.z = q_trans.z;
00458 
00459   return retval;
00460 }

int kinematicsHome EmcPose   world,
double *    joint,
KINEMATICS_FORWARD_FLAGS   fflags,
KINEMATICS_INVERSE_FLAGS   iflags
 

Definition at line 500 of file genhexkins.c.

00504 {
00505   *fflags = 0;
00506   *iflags = 0;
00507 
00508   return kinematicsInverse(world, joint, iflags, fflags);
00509 }

int kinematicsInverse const EmcPose   pos,
double *    joints,
const KINEMATICS_INVERSE_FLAGS   iflags,
KINEMATICS_FORWARD_FLAGS   fflags
 

Definition at line 464 of file genhexkins.c.

00468 {
00469   PmCartesian aw, temp;
00470   PmRotationMatrix RMatrix;
00471   PmRpy rpy;
00472   int i;
00473 
00474   /* define Rotation Matrix */
00475   rpy.r = pos->a * PM_PI / 180.0;
00476   rpy.p = pos->b * PM_PI / 180.0;
00477   rpy.y = pos->c * PM_PI / 180.0;
00478   pmRpyMatConvert(rpy, &RMatrix);
00479 
00480   /* enter for loop to calculate joints (strut lengths) */
00481   for (i = 0; i < NUM_STRUTS; i++) {
00482     /* convert location of platform strut end from platform
00483        to world coordinates */
00484     pmMatCartMult(RMatrix, a[i], &temp);
00485     pmCartCartAdd(pos->tran, temp, &aw);
00486 
00487     /* define strut lengths */
00488     pmCartCartSub(aw, b[i], &temp);
00489     pmCartMag(temp, &joints[i]);
00490   }
00491 
00492   return 0;
00493 }

int kinematicsSetParameters double *    p
 

KINEMATICS_TYPE kinematicsType void   
 

Definition at line 511 of file genhexkins.c.

Referenced by init_module().

00512 {
00513 #if 1
00514   return KINEMATICS_BOTH;
00515 #else
00516   return KINEMATICS_INVERSE_ONLY;
00517 #endif
00518 }


Generated on Sun Dec 2 15:27:55 2001 for EMC by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001