scstep.c -- Single Axis Sinusoidal Commutation Sample Configuration Program

/* ScStep.C  */

/* Copyright(c) 1991-2002 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.
 */

/*

:Single Axis Sinusoidal Commutation Sample Configuration Program

  Axis 0 -  Uses Stepper type initialization with a small
            90 (elec.) degree move.  Axis stays in open-loop mode
            with amplifier enabled.

  Note -    #def provided to reverse encoder and DAC phasing.
            Program disables HW Limits, Amp Fault, Home and
            Error Limit.

  Configure the XMP:

            Axis 0  Filter 0   Motor 0


 Note that the commutation configuration parameters will be different
 for your application.  Take particular care in setting the open-loop
 continuous DAC OutputLevel as this must be a safe level for your specific
 drive and motor combination.  Please read the MEI Sinusoidal Commutation
 Documentation.

Warning!  This is a sample program to assist in the integration of the
 XMP 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"

#if defined(ARG_MAIN_RENAME)
#define main StepSCMain

argMainRENAME(main, StepSC)
#endif

#define AXIS_CNT    (1)

/* Command line arguments and defaults */
long    axisNumber      = 0;
long    motionNumber    = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* option to reverse encoder phasing */
#undef ReverseEncPhasing
/* Option to reverse DAC phasing */
#undef ReverseDACPhasing


int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis handles */
    MPIFilter   filter;     /* filter handles */
    MPIMotor    motor;      /* motor handles  */

    MPIControlConfig    controlConfig;  /* motion controller configuration */
    MPIAxisConfig       axisConfig;     /* axis configuration */
    MPIFilterGain       gain;
    MPIMotorConfig      motorConfig;
    MEIMotorConfig      motorConfigXmp;
    MEIFilterGainPID    *pid;
    MEIXmpCommutationBlock  *commutation;

    MPIMotion       motion; /* Coordinated motion object handles */

    MPIControlType          controlType;
    MPIControlAddress       controlAddress;

    long    returnValue;    /* return value from library */

    long    nEncCountPerCycle = 4096; /* number of encoder counts per motor revolution */
    float   OpenDAC_Level   = (float)3277.0;  /* Open Loop DAC Level where 32767. = 10V) */
    float   N_CYCLES    =       (float)3.0;     /* number of elec. cycles per motor rev. */

#if defined(ReverseDACPhasing)
    long    dacCount;
    long    dacNumber[MPIMotorDacCountMAX];
    long    number;
#endif

    float   inPositionLimit = (float)1.0e10;

    long    argIndex, i;

    /* 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   >= MEIXmpMAX_Axes + AXIS_CNT) ||
        (motionNumber >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_CNT,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create device driver motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /*
       Configure motion controller
       Set Sample Rate = 2 kHz
       Configure for commutation B phase DACs and ADCs
     */
    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    controlConfig.sampleRate = 2000;

    /*
        When supporting commutation,
        Cmd and Aux DACs must be enabled.
        Enabling the same number of Cmd and Aux DACs as there are motors.
     */
    controlConfig.cmdDacCount = controlConfig.motorCount;
    controlConfig.auxDacCount = controlConfig.motorCount;

    /* Configure required number of A/D */
    controlConfig.adcCount = 8;

    returnValue =
        mpiControlConfigSet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    /* Create axis, filter and motor controller objects */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    filter =
        mpiFilterCreate(control,
                      axisNumber);
    msgCHECK(mpiFilterValidate(filter));

    motor =
        mpiMotorCreate(control,
                      axisNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Disable the amplifier */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                            FALSE);
    msgCHECK(returnValue);

    /*   Configure axis  */
    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    /* Set inPositionLimit */
    axisConfig.inPosition.tolerance.positionFine = inPositionLimit;

    returnValue =
        mpiAxisConfigSet(axis,
                        &axisConfig,
                        NULL);
    msgCHECK(returnValue);

    /* Configure Motor */
    returnValue =
        mpiMotorConfigGet(motor,
                         &motorConfig,
                         &motorConfigXmp);
    msgCHECK(returnValue);

    /*
       Disable limit error, home, amp fault & H/W Limits
       Set encoder phase
     */

    /* Disable limit error */
    motorConfig.event[MPIEventTypeLIMIT_ERROR].action           = MPIActionNONE;
    motorConfig.event[MPIEventTypeLIMIT_ERROR].trigger.error    = (float)50000;

    /* Disable home event */
    motorConfig.event[MPIEventTypeHOME].action  = MPIActionNONE;

    /* Disable amp fault event */
    motorConfig.event[MPIEventTypeAMP_FAULT].action = MPIActionNONE;

    /* Disable neg. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_NEG].action  = MPIActionNONE;

    /* Disable pos. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_POS].action  = MPIActionNONE;

    /*
       Set encoder phase:

       0 - for normal
       1 - for reversed
     */

#ifdef ReverseEncPhasing
    motorConfig.encoderPhase = 1;
#else
    motorConfig.encoderPhase = 0;
#endif

    /* Setup commutation  */
    commutation = &motorConfigXmp.Commutation;

    /* Motor Controller commutation parameters */
    commutation->Mode        = MEIXmpCommModeOPEN_LOOP;
    commutation->Length      = nEncCountPerCycle;
    commutation->Scale       = (float)MEIXmpCOMM_TABLE_SIZE * N_CYCLES /
                               (float)commutation->Length;
    commutation->PhaseDelta  = MEIXmpCOMM_120DEGREES;
    commutation->OutputLevel = (float)0.0;   /* level will be ramped after enable */
    commutation->Offset      = (long)0;

#if defined(ReverseDACPhasing)
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseINVERTED;
#else
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseNORMAL;
#endif

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /* Get current configuration */
    returnValue =
        mpiFilterGainGet(filter,
                        MEIFilterGainIndexDEFAULT,
                        &gain);
    msgCHECK(returnValue);

    pid = (MEIFilterGainPID *)&gain;

    /* Filter Controller control parameters */
    pid->gain.proportional          = (float)100.;
    pid->gain.integral              = (float)0.0;
    pid->gain.derivative            = (float)400.;
    pid->feedForward.velocity       = (float)0.0;
    pid->feedForward.acceleration   = (float)0.0;
    pid->feedForward.friction       = (float)0.0;
    pid->integrationMax.moving      = (float)0.0;
    pid->integrationMax.rest        = (float)0.0;
    pid->output.limit               = (float)32767.0;
    pid->output.offset              = (float)0.0;

    /* Set filter configuration  */
    returnValue =
        mpiFilterGainSet(filter,
                        MEIFilterGainIndexDEFAULT,
                        &gain);
    msgCHECK(returnValue);

    /*
       Create a Motion Object and append an Axis
       Note 1 - separate axis appends will be required for coordinated motion
       Note 2 - Axis Map does not take effect until motion is commanded
     */
    motion =
         mpiMotionCreate(control,
                         motionNumber,
                         axis);
    msgCHECK(mpiMotionValidate(motion));

    /*  Clear out any previous errors */
    returnValue =
            mpiMotionAction(motion,MPIActionRESET);
    msgCHECK(returnValue);

    /*  Immediately send Map to controller  */
    returnValue =
        mpiMotionAction(motion,
                        (MPIAction)MEIActionMAP);
    msgCHECK(returnValue);

    /*  Enable the amplifier */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                            TRUE);
    msgCHECK(returnValue);

    /*
        DAC output will be ramped and stage will be pulled to a magnetic pole.
        Next, delay for stage to settle.  Implement outbound move,delay, then
        proceed with inbound move and delay.
     */

    returnValue =
        mpiMotorConfigGet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);


    for(i= 1; i <= 100; i++){

        commutation->OutputLevel = (float)(i)*((OpenDAC_Level)/((float)100.0));

        /* Set configuration */
        returnValue =
            mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
        msgCHECK(returnValue);


        meiPlatformSleep(30);
    }

    meiPlatformSleep(1000);

    /* Motor outbound move */

    for(i= 1; i <= 100; i++){

        commutation->Offset      = (long)(i*2.56);

        /* Set configuration */
        returnValue =
            mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
        msgCHECK(returnValue);

        meiPlatformSleep(30);

    }

    meiPlatformSleep(1000);

    /* Motor return move */
    for(i= 1; i <= 100; i++){


        commutation->Offset      = (long)(256 - (i*2.56));

            /* Set configuration */
        returnValue =
            mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
        msgCHECK(returnValue);

        meiPlatformSleep(30);
    }

    meiPlatformSleep(1000);


    /* Delete Objects */
    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiFilterDelete(filter);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}