.

     

MPI Application Template
template.c
 

motGate2.c -- Load and trigger motion profiles using a control Gate.
/* motGate2.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.
 */

/*

:Load and trigger motion profiles using a control Gate.

This sample program demonstrates how to use the motion HOLD attribute and
 a control Gate, to pre-load a single axis motion, and to synchronize the
 start of two independent motion profiles.

Here are the steps:

 1) Move the X axis.
 2) Set a control Gate.
 3) Load a Y axis motion profile, using the HOLD attribute.
 4) Clear the control Gate, causing the Y axis motion to execute.
 5) Set a control Gate.
 6) Load X and Y axis motion profiles, using the HOLD attribute.
 7) Clear the control Gate, causing the X and Y axis motions to execute
    simultaneously.


The XMP-Series controller supports a motion HOLD attribute, which is useful
 for pre-loading 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.

The msgCHECK(...) macros used in the following sample code are intended
 to convey our strong belief that ALL error return codes should be checked.
 Actual application code should use specific error handling techniques (other
 than msgCHECKs) best suited to your internal error recovery methods.
 
*/

#include <stdlib.h>
#include <stdio.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTION_NUMBER1  (0)
#define MOTION_NUMBER2  (1)
#define AXIS_NUMBER1    (0)
#define AXIS_NUMBER2    (1)
#define GATE_NUMBER     (0)
#define TIMEOUT         (0) /* Wait forever */

#define GOAL_POSITION1  ( 10000.0)
#define GOAL_POSITION2  (     0.0)
#define VELOCITY        ( 10000.0)
#define ACCELERATION    (100000.0)
#define DECELERATION    (100000.0)
#define JERK_PERCENT    (   100.0)


/* Perform basic command line parsing. (-control -server -port -trace) */
void basicParsing(int                    argc,
                  char                  *argv[],
                  MPIControlType        *controlType,
                  MPIControlAddress     *controlAddress)
{
    long argIndex;

    /* Parse command line for Control type and address */
    argIndex = argControl(argc, argv, controlType, controlAddress);

    /* Check for unknown/invalid command line arguments */
    if (argIndex < argc) {
        fprintf(stderr,"usage: %s %s\n", argv[0], ArgUSAGE);
        exit(MPIMessageARG_INVALID);
    }
}


/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motionX,
                 MPIMotion          *motionY,
                 long               *motionNumber,
                 MPIAxis            *axisX,
                 MPIAxis            *axisY,
                 long               *axisNumber)
{
    long returnValue;

    /* Create control object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize motion controller */
    returnValue = mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Create X axis object using AXIS_X number on controller */
    *axisX =
        mpiAxisCreate(*control,
                      axisNumber[0]);       /* axis Number */
    msgCHECK(mpiAxisValidate(*axisX));

    /* Create Y axis object using AXIS_Y number on controller */
    *axisY =
        mpiAxisCreate(*control,
                      axisNumber[1]);       /* axis Number */
    msgCHECK(mpiAxisValidate(*axisY));

    /* Create Motion object for axisX */
    *motionX =
        mpiMotionCreate(*control,
                        motionNumber[0],    /* motion supervisor number */
                        *axisX);
    msgCHECK(mpiMotionValidate(*motionX));

    /* Create Motion object for axisY */
    *motionY =
        mpiMotionCreate(*control,
                        motionNumber[1],    /* motion supervisor number */
                        *axisY);
    msgCHECK(mpiMotionValidate(*motionY));
}


/* Delete MPI objects */
void programCleanup(MPIControl  *control,
                    MPIMotion   *motionX,
                    MPIMotion   *motionY,
                    MPIAxis     *axisX,
                    MPIAxis     *axisY)
{
    long returnValue;

    /* Delete motion supervisor Y */
    returnValue =
        mpiMotionDelete(*motionY);
    msgCHECK(returnValue);

    *motionY = MPIHandleVOID;

    /* Delete motion supervisor X */
    returnValue =
        mpiMotionDelete(*motionX);
    msgCHECK(returnValue);

    *motionX = MPIHandleVOID;

    /* Delete axis Y */
    returnValue =
        mpiAxisDelete(*axisY);
    msgCHECK(returnValue);

    *axisY = MPIHandleVOID;

    /* Delete axis X */
    returnValue =
        mpiAxisDelete(*axisX);
    msgCHECK(returnValue);

    *axisX = MPIHandleVOID;

    /* Delete control object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}


/*
  waitForMotionDone() polls motion to see if the axis is in an idle or error
  state every 10ms. When it gets an MPIStateIdle, MPIStateERROR, or
  MPIStateSTOPPING_ERROR then the waitForMotionDone() exits.
*/
void waitForMotionDone(MPIMotion motion)
{
    MPIStatus   status;
    long        motionDone;
    long        returnValue = 0;


    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 10ms and give up control to other threads */
                meiPlatformSleep(10);
                break;
            }
            case MPIStateIDLE:
            case MPIStateSTOPPED:
            case MPIStateERROR:
            case MPIStateSTOPPING_ERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
}


/* Function demonstrating how gates can control motion */
void gateControlledMotion(MPIControl         control,
                          MPIMotion          motion1,
                          MPIMotion          motion2,
                          MPIMotionParams   *motionParams,
                          MPIMotionType      motionType,
                          long               gateNumber,
                          long               hold)
{
    long returnValue;


    /* If hold = TRUE, turn on the HOLD bit of MPIMotionType */
    if (hold==TRUE) {
        motionType = (MPIMotionType) (motionType | MEIMotionAttrMaskHOLD);
    }

    printf("Turning control gate ON.\r");

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

    printf("Turned control gate ON. \n");
    printf("Press any key to call mpiMotionStart(...) %s HOLD attribute.\r",
           (hold) ? "with" : "without");

    /* Wait for a key form the user */
    meiPlatformKey(MPIWaitFOREVER);

    /* Load motion profile */
    returnValue = mpiMotionStart(motion1,
                                 motionType,
                                 motionParams);
    msgCHECK(returnValue);

    /* If user specified a second motion object */
    if (motion2!=MPIHandleVOID) {

        /* Load motion profile */
        returnValue = mpiMotionStart(motion2,
                                     motionType,
                                     motionParams);
        msgCHECK(returnValue);
    }

    printf("Called mpiMotionStart(...) %s HOLD attribute.               \n",
           (hold) ? "with" : "without");

    printf("Press any key to turn control gate OFF\r");

    /* Wait for a key form the user */
    meiPlatformKey(MPIWaitFOREVER);

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

    printf("Turned control gate OFF.              \n");
}


int main(int    argc,
         char   *argv[])
{
    MPIControl          control;    /* motion controller handle */
    MPIAxis             axisX;      /* X axis                   */
    MPIAxis             axisY;      /* Y axis                   */
    MPIMotion           motionX;    /* motion object for axisX  */
    MPIMotion           motionY;    /* motion object for axisY  */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotionParams     motionParams;   /* motion parameters            */
    MPITrajectory       trajectory;     /* trajectory information       */
    MEIMotionAttributes attributes;     /* motion attributes            */
    MEIMotionAttrHold   hold;           /* hold attribute configuration */

    long    axisNumber[2]   = { AXIS_NUMBER1,   AXIS_NUMBER2,   };
    long    motionNumber[2] = { MOTION_NUMBER1, MOTION_NUMBER2, };
    long    gateNumber      = GATE_NUMBER;
    float   gateTimeout     = (float)TIMEOUT;
    double  position;


    /* Set up motion parameters */
    trajectory.velocity     = VELOCITY;         /* counts per sec       */
    trajectory.acceleration = ACCELERATION;     /* counts per sec * sec */
    trajectory.deceleration = DECELERATION;     /* counts per sec * sec */
    trajectory.jerkPercent  = JERK_PERCENT;

    motionParams.sCurve.trajectory  = &trajectory;
    motionParams.sCurve.position    = &position;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc, argv, &controlType, &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motionX,
                &motionY,
                motionNumber,
                &axisX,
                &axisY,
                axisNumber);

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

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


    /* Tell axis to go to GOAL_POSITION1 */
    position = GOAL_POSITION1;  /* counts */

    printf("\n*** X AXIS ***\n");

    /* Execute X-axis motion without HOLD attribute */
    gateControlledMotion(control,
                         motionX,
                         MPIHandleVOID,
                         &motionParams,
                         MPIMotionTypeS_CURVE,
                         gateNumber,
                         FALSE);

    printf("Wating for motion to complete...\n");

    /* Wait for motion to complete */
    waitForMotionDone(motionX);

    printf("\n*** Y AXIS ***\n");

    /* Execute Y-axis motion with HOLD attribute */
    gateControlledMotion(control,
                         motionY,
                         MPIHandleVOID,
                         &motionParams,
                         MPIMotionTypeS_CURVE,
                         gateNumber,
                         TRUE);

    printf("Wating for motion to complete...\n");

    /* Wait for motion to complete */
    waitForMotionDone(motionY);


    /* Tell axis to go to GOAL_POSITION2 */
    position = GOAL_POSITION2;  /* counts */

    printf("\n*** X & Y AXES ***\n");

    /* Execute X,Y-axes motion with HOLD attribute */
    gateControlledMotion(control,
                         motionX,
                         motionY,
                         &motionParams,
                         MPIMotionTypeS_CURVE,
                         gateNumber,
                         TRUE);

    /* Delete MPI objects */
    programCleanup(&control,
                   &motionX,
                   &motionY,
                   &axisX,
                   &axisY);

    return MPIMessageOK;
}


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