.

     

MPI Application Template
template.c
 

motid3.c -- Point to Point motion with ID, APPEND, and HOLD attributes.
/* motId3.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 ID, APPEND, and HOLD attributes.

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 MEIXmpSignalUserData 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[MEIXmpSignalUserData];
    } data;


The APPEND attribute is useful for buffering moves in the controller.
 When the APPEND attribute is used with mpiMotionStart(...), a new motion
 profile is added to the end of any previously loaded motion profiles in
 the controller.  The XMP-Series controller automatically buffers the APPENDed
 MotionStarts, executing each sequentially after the Motion Done criteria has
 been met for each profile.  Each MotionStart profile generates a Motion Done
 event to the Host.

When APPEND attribute is used with mpiMotionModify(...), the motion profile
 is added to the end of any previously loaded motion profiles in the
 controller.  The XMP-Series controller automatically buffers the APPENDed
 MotionModifies, executing each sequentially.  Only the very last
 MotionModify waits for the Motion Done criteria to be met before generating
 a Motion Done event to the host.

The XMP-Series controller supports a motion HOLD attribute, which is useful
 for preloading and triggering motion profiles.  One or more motion
 supervisors can be started from the same HOLD conditions.  When multiple
 motion supervisors are triggered by the same HOLD conditions, the individual
 motion profiles will start in the same DSP sample period.  The HOLD can be
 set/cleared with a host function call, an XMP-Series controller internal
 variable or a Motor I/O state change.

The MEIMotionAttrHold{...} structure is used to configure the HOLD conditions:

 typedef    struct MEIMotionAttrHold {
    MEIMotionAttrHoldType   type;
    MEIMotionAttrHoldSource source;

    float   timeout;
} MEIMotionAttrHold;


The HOLD "type" can be one of the following:

 MEIMotionHoldTypeGATE - host software controlled.
 MEIMotionHoldTypeINPUT - XMP controller internal variable.
 MEIMotionHoldTypeMOTOR - XMP controller motor I/O state change.


For each HOLD "type" the "source" union, MEIMotionAttrHoldSource{...},
 configures the HOLD conditions:

 MEIMotionHoldTypeGATE:

  long gate - number between 0 to 31.

  The motion is held until the "gate" is cleared.  The function
  meiControlGateSet(...) is used to set/clear a gate.  When the closed
  parameter is TRUE, the gate is set, and motion is held.  When the
  closed parameter is FALSE, the gate is cleared, and motion starts.

 MEIMotionHoldTypeINPUT

  long *input - address of XMP memory location.
  long mask - bit mask, bitwise ANDed with the input value.
  long pattern - HOLD is released when masked value matches pattern.

  The motion is held until the value of the internal XMP memory location
  (pointed to by *input) bitwise ANDed with the mask matches the pattern.

 MEIMotionHoldTypeMOTOR

  long number - motor "n", XMP's dedicated inputs (Motor[n].IO.DedicaedIN.IO)
  long mask - bit mask, bitwise ANDed with the dedicated inputs.
  long pattern - HOLD is released when masked inputs matches pattern.

  The motion is held until the value of the dedicated input word
  (Motor[n].IO.DedicaedIN.IO) bitwise ANDed with the mask matches the
  pattern.


The HOLD "timeout" will cause the motion to start after the specified period
 (in seconds) even if the hold criteria have not been met.  To disable the
 timeout feature, set the timeout value to zero.

The MPI expects an array of hold attributes specifying separate attributes
 form each axis of a motion supervisor. All axes holding with the same hold
 attributes (same gate, same input, mask, and pattern) will start motion in
 the same sample even if the moves are specified using different motion
 supervisors.


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;
long            gateNumber = 0;
float           gateTimeout = (float)0.0;


Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },
    {   "-gate",    ArgTypeLONG,    &gateNumber,    },
    {   "-timeout", ArgTypeFLOAT,   &gateTimeout,   },

    {   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;

    MEIEventNotifyData  motionData;
    MEIXmpAxis          *xmpAxis;

    MPIMotionParams     motionParams;   /* motion parameters */
    MEIMotionAttributes attributes;     /* motion attributes */
    MEIMotionAttrHold   hold;           /* hold attribute configuration */

    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] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST) ||
        (gateNumber < 0) ||
        (gateNumber >= MEIXmpMaxGates) ||
        (gateTimeout < 0.0)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n"
                           "\t\t[-gate # (0 .. %d)]\n"
                           "\t\t[-timeout # (0.0 ..)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1,
                            MEIXmpMaxGates - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%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);
    meiEventMaskALL(eventMask);

    /* Request ID data from motion event info[...] */
    returnValue  =
        mpiAxisMemory(axis,     /* use ID from first axis in motion object */
                      (void **)&xmpAxis);
    msgCHECK(returnValue);

    /* Configure the second user data word for the ID */
    motionData.address[1] = (void *)(&xmpAxis->MoveID);

    /* Configure sampleCounter and ID to be returned from Motion event sources */
    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 */
    meiAssert(service != NULL);

    /* Configure Motion Attributes */
    hold.type = MEIMotionAttrHoldTypeGATE;  /* software motion Gate control */
    hold.source.gate = gateNumber;
    hold.timeout = gateTimeout;

    attributes.hold = &hold;
    motionParams.external = &attributes;


    printf("Press any key to stop ...\n");

    /* Loop repeatedly */
    index       = 0;
    moveId      = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MEIEventStatusInfo  *info;

        if (motionDone) {

            /* Set a control gate to prevent motion profile from executing */
            returnValue =
                meiControlGateSet(control,
                                  gateNumber,
                                  TRUE);    /* set gate */
            msgCHECK(returnValue);

            for (index = 0; index < MOTION_COUNT; index++) {
                /* 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: {
                        meiAssert(FALSE);
                        break;
                    }
                }

                motionParams.attributes.id = moveId;    /* identification tag */

                returnValue =
                    mpiMotionStart(motion,
                                   (MPIMotionType)(motionType |
                                   MPIMotionAttrMaskID |
                                   MPIMotionAttrMaskAPPEND |
                                   MEIMotionAttrMaskHOLD),
                                   &motionParams);
                msgCHECK(returnValue);

                printf("\nMotion Start #%d...\n", moveId);

                moveId++;
            }

            /* Clear a control gate, executing the preloaded motion */
            returnValue =
                meiControlGateSet(control,
                                  gateNumber,
                                  FALSE);   /* clear the gate */
            msgCHECK(returnValue);

            index = 0;
            motionDone = FALSE;
        }

        /* Wait for motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        info = (MEIEventStatusInfo *)eventStatus.info;

        switch (eventStatus.type) {
            /* In Coarse Event from axis source */
            case MEIEventTypeIN_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 MEIEventTypeIN_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 MEIEventTypeAT_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)\n",
                       info->data.word[1],
                       info->data.motion.sampleCounter);

                if (++index >= MOTION_COUNT) {
                    index = 0;
                    motionDone = TRUE;
                }
                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);
}


 
      
       Legal Notice  |  Tech Email  |  Feedback
      
Copyright ©
2001-2009 Motion Engineering