motid2.c -- Point to Point motion with motion/axis event identification.
/* motId2.c */
/* Copyright(c) 1991-2006 by Motion Engineering, Inc. All rights reserved.
*
* This software contains proprietary and confidential information of
* Motion Engineering Inc., and its suppliers. Except as may be set forth
* in the license agreement under which this software is supplied, use,
* disclosure, or reproduction is prohibited without the prior express
* written consent of Motion Engineering, Inc.
*/
/*
:Point to Point motion with motion/axis event identification.
The MPI supports a motion attribute that allows an application to tag
a mpiMotionStart(...) or mpiMotionModify(...) with an identification
value.
This feature is useful in tracking the commanded motions to the done
events. It is also applicable when using the AUTO_START attribute
with mpiMotionModify(...).
For example:
Suppose mpiMotionStart(...) is called with the MPIMotionAttrID attribute,
and the params.attributes.id = 1 and later mpiMotionModify(...) is called
with params.attributes.id = 2.
Case 1: MPIMotionAttrAUTO_START is not used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageIDLE, there will be 1 DONE
event with info->data.motion.id = 1.
Case 2: MPIMotionAttrAUTO_START is used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageAUTO_START,
there will be 2 DONE events. The first will have info->data.motion.id = 1
and the second will have info->data.motion.id = 2.
The XMP-Series controller supports some user data to be copied during Events
and then later retrieved from the Host via the Notify object.
There are MPIXmpSignalUserData words of data for the motion, axis and motor
event sources. The default configuration for the first word is the XMP's
sampleCounter. The default for the second word is "actualPosition" for axis
event sources, and "encoderPosition" for motor event sources.
In this sample, the second word for motion and axis events is configured for "id".
Note: Keeping the first word configured for the "sampleCounter" is very
helpful in determining event sequences.
Here is the default configuration for the event data:
union {
long sampleCounter;
struct {
long sampleCounter;
} motion;
struct {
long sampleCounter;
long actualPosition;
} axis;
struct {
long sampleCounter;
long encoderPosition;
} motor;
long word[MPIXmpSignalUserData];
} data;
Warning! This is a sample program to assist in the integration of an
MEI motion controller with your application. It may not contain all
of the logic and safety features that your application requires.
*/
#include <stdlib.h>
#include <stdio.h>
#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"
#define MOTION_COUNT (2)
#define AXIS_COUNT (1)
/* Command line arguments and defaults */
long axisNumber[AXIS_COUNT] = { 0, };
long motionNumber = 0;
MPIMotionType motionType = MPIMotionTypeS_CURVE;
Arg argList[] = {
{ "-axis", ArgTypeLONG, &axisNumber[0], },
{ "-motion", ArgTypeLONG, &motionNumber, },
{ "-type", ArgTypeLONG, &motionType, },
{ NULL, ArgTypeINVALID, NULL, }
};
/* Motion Parameters */
double position[MOTION_COUNT][AXIS_COUNT] = {
{ 20000.0, },
{ 0.0, },
};
MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
{ /* velocity accel decel jerkPercent */
{ 10000.0, 1000000.0, 1000000.0, 0.0, },
},
{ /* velocity accel decel jerkPercent*/
{ 10000.0, 100000.0, 100000.0, 0.0, },
},
};
MPIMotionSCurve sCurve[MOTION_COUNT] = {
{ &trajectory[0][0], &position[0][0], },
{ &trajectory[1][0], &position[1][0], },
};
MPIMotionTrapezoidal trapezoidal[MOTION_COUNT] = {
{ &trajectory[0][0], &position[0][0], },
{ &trajectory[1][0], &position[1][0], },
};
MPIMotionVelocity velocity[MOTION_COUNT] = {
{ &trajectory[0][0], },
{ &trajectory[1][0], },
};
int
main(int argc,
char *argv[])
{
MPIControl control; /* motion controller handle */
MPIAxis axis; /* axis object */
MPIMotion motion; /* motion object */
MPINotify notify; /* event notification object */
MPIEventMgr eventMgr; /* event manager handle */
MPIEventMask eventMask;
MPIEventNotifyData motionData;
MPIXmpAxis *xmpAxis;
long returnValue; /* return value from library */
long index;
long moveId; /* identification tag */
long motionDone; /* flag when Done occurs */
Service service;
MPIControlType controlType;
MPIControlAddress controlAddress;
long argIndex;
/* Parse command line for Control type and address */
argIndex =
argControl(argc,
argv,
&controlType,
&controlAddress);
/* Parse command line for application-specific arguments */
while (argIndex < argc) {
long argIndexNew;
argIndexNew = argSet(argList, argIndex, argc, argv);
if (argIndexNew <= argIndex) {
argIndex = argIndexNew;
break;
}
else {
argIndex = argIndexNew;
}
}
/* Check for unknown/invalid command line arguments */
if ((argIndex < argc) ||
(axisNumber[0] > (MPIXmpMAX_Axes - AXIS_COUNT)) ||
(motionNumber >= MPIXmpMAX_MSs) ||
(motionType < MPIMotionTypeFIRST) ||
(motionType >= MPIMotionTypeLAST)) {
mpiPlatformConsole("usage: %s %s\n"
"\t\t[-axis # (0 .. %d)]\n"
"\t\t[-motion # (0 .. %d)]\n"
"\t\t[-type # (0 .. %d)]\n",
argv[0],
ArgUSAGE,
MPIXmpMAX_Axes - AXIS_COUNT,
MPIXmpMAX_MSs - 1,
MPIMotionTypeLAST - 1);
exit(MPIMessageARG_INVALID);
}
switch (motionType) {
case MPIMotionTypeS_CURVE:
case MPIMotionTypeTRAPEZOIDAL:
case MPIMotionTypeVELOCITY: {
break;
}
default: {
mpiPlatformConsole("%s: %d: motion type not available\n",
argv[0],
motionType);
exit(MPIMessageUNSUPPORTED);
break;
}
}
/* Create motion controller object */
control =
mpiControlCreate(controlType,
&controlAddress);
msgCHECK(mpiControlValidate(control));
/* Initialize motion controller */
returnValue = mpiControlInit(control);
msgCHECK(returnValue);
/* Create axis object for axisNumber */
axis =
mpiAxisCreate(control,
axisNumber[0]);
msgCHECK(mpiAxisValidate(axis));
/* Create motion object, appending the axis object */
motion =
mpiMotionCreate(control,
motionNumber,
axis);
msgCHECK(mpiMotionValidate(motion));
/* Get current user data configuration */
mpiEventMaskCLEAR(eventMask);
returnValue =
mpiMotionEventNotifyGet(motion,
&eventMask,
&motionData);
msgCHECK(returnValue);
/* Request notification of ALL events from motion */
mpiEventMaskALL(eventMask);
mpiEventMaskALL(eventMask);
/* Request ID data from motion event info[...] */
returnValue =
mpiAxisMemory(axis, /* use ID from first axis in motion object */
(void **)&xmpAxis);
msgCHECK(returnValue);
motionData.address[1] = (void *)(&xmpAxis->MoveID);
returnValue =
mpiMotionEventNotifySet(motion,
eventMask,
&motionData);
msgCHECK(returnValue);
/* Configure sampleCounter and ID to be returned from Axis event sources */
returnValue =
mpiAxisEventNotifySet(axis,
eventMask, /* use the same eventMask as motion */
&motionData); /* use the same data as motion */
msgCHECK(returnValue);
/* Create event notification object for motion */
notify =
mpiNotifyCreate(eventMask,
motion);
msgCHECK(mpiNotifyValidate(notify));
/* Create event manager object */
eventMgr = mpiEventMgrCreate(control);
msgCHECK(mpiEventMgrValidate(eventMgr));
/* Add notify to event manager's list */
returnValue =
mpiEventMgrNotifyAppend(eventMgr,
notify);
msgCHECK(returnValue);
/* Create service thread */
service =
serviceCreate(eventMgr,
-1, /* default (max) priority */
-1); /* -1 => enable interrupts */
mpiAssert(service != NULL);
printf("Press any key to stop ...\n");
/* Loop repeatedly */
index = 0;
moveId = 0;
motionDone = TRUE;
while (mpiPlatformKey(MPIWaitPOLL) <= 0) {
MPIEventStatus eventStatus;
MPIEventStatusInfo *info;
if (motionDone) {
MPIMotionParams motionParams; /* motion parameters */
/* fill in the MPIMotionParams structure */
switch (motionType) {
case MPIMotionTypeS_CURVE: {
motionParams.sCurve = sCurve[index];
break;
}
case MPIMotionTypeTRAPEZOIDAL: {
motionParams.trapezoidal = trapezoidal[index];
break;
}
case MPIMotionTypeVELOCITY: {
motionParams.velocity = velocity[index];
break;
}
default: {
mpiAssert(FALSE);
break;
}
}
motionParams.attributes.id = moveId; /* identification tag */
returnValue =
mpiMotionStart(motion,
(MPIMotionType)(motionType | MPIMotionAttrMaskID),
&motionParams);
msgCHECK(returnValue);
printf("\n\nMotion Start #%d...\n", moveId);
moveId++;
motionDone = FALSE;
}
/* Wait for motion event */
returnValue =
mpiNotifyEventWait(notify,
&eventStatus,
MPIWaitFOREVER);
msgCHECK(returnValue);
info = (MPIEventStatusInfo *)eventStatus.info;
switch (eventStatus.type) {
/* In Coarse Event from axis source */
case MPIEventTypeIN_POSITION_COARSE: {
printf(" InCoarse #%ld(%ld)",
info->data.word[1], /* user configurable data */
info->data.axis.sampleCounter);
break;
}
/* In Fine Event from axis source */
case MPIEventTypeIN_POSITION_FINE: {
printf(" InFine #%ld(%ld)",
info->data.word[1], /* user configurable data */
info->data.axis.sampleCounter);
break;
}
/* In Fine Event from axis source */
case MPIEventTypeAT_TARGET: {
printf(" AtTarget #%ld(%ld)",
info->data.word[1], /* user configurable data */
info->data.axis.sampleCounter);
break;
}
/* Motion Done Event from motion source */
case MPIEventTypeMOTION_DONE: {
printf(" Done #%ld(%ld)",
info->data.word[1], /* user configurable data */
info->data.motion.sampleCounter);
motionDone = TRUE;
if (++index >= MOTION_COUNT) {
index = 0;
}
break;
}
default: {
printf(" %d #%ld(%ld)",
eventStatus.type,
info->data.word[1],
info->data.word[0]);
break;
}
}
}
printf("\n");
returnValue = mpiMotionDelete(motion);
msgCHECK(returnValue);
returnValue = mpiAxisDelete(axis);
msgCHECK(returnValue);
returnValue = serviceDelete(service);
msgCHECK(returnValue);
returnValue = mpiEventMgrDelete(eventMgr);
msgCHECK(returnValue);
returnValue = mpiNotifyDelete(notify);
msgCHECK(returnValue);
returnValue = mpiControlDelete(control);
msgCHECK(returnValue);
return ((int)returnValue);
}
|