Powers on a Pololu Stepper Motor driver board equipped with an Allegro a4983 IC. First it searches for the home switch, then it moves endlessly back and forth with linear speed ramp At motor currents above 1A the driver board seriously needs extra cooling attached to the driver IC, like a simple aluminium piece with heat transfer grease Thanks to Atmel AVR446 Application Note!

Dependencies:   mbed

main.cpp

Committer:
gyurma
Date:
2011-03-01
Revision:
0:761688adad1d

File content as of revision 0:761688adad1d:

/****************************************************/
/*                                                  */
/* Title:   Linear speed profile implementation for */
/*          Pololu Breakout board with A4983        */
/*          with an mbed evaluation board           */
/* Author:  Martin Gyurkó                           */
/* email:   nospam@gyurma.de                        */
/*                                                  */
/* $ID:$ */
/****************************************************/

#include "mbed.h"

//communication channel
Serial pc(USBTX, USBRX);

//LEDs port definition on mbed
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

//ports connected to pololu driver board = straightforward connection of one side of mbed
DigitalOut Dir(p5); //direction of movement
DigitalOut Step(p6); //make one step at rising edge
DigitalOut nSleep(p7); // be HIGH to make it work
DigitalOut nReset(p8); // be HIGH to make it work
DigitalOut MS3(p9); //microstep mode selectors
DigitalOut MS2(p10);
DigitalOut MS1(p11);
DigitalOut nEnable(p12);// be LOW to make it work

//Home sensor input
DigitalIn  EndSwitchIn(p20); //normally HIGH when nothing inside optopath


#define HIGH 1
#define LOW 0
#define ON 1
#define OFF 0
#define Clockwise LOW
#define CounterClockwise HIGH

//which mode of driver to be used. This is now 1/16 stepping.
#define Factor  16

//Maximum distance to travel
//my linear motion sled has 3.25 rounds * 200 imp/round  *16
#define SMax   ( 650  * Factor ) //for sled

//for simple motor tests we set a real big distance:
//#define SMax   ( 40000  * Factor )

//minimum speed
#define VMin 1

//maximum speed (runtime settable)
double   VMax   = ( 66.64  * Factor );

//homing speed
#define VHome  (   30  * Factor )

//maximum acceleration
#define AMax   (800  * Factor )

//trace buffer for debugging, take care of size of ram!
//float TimeTrace[SMax];

// Make a step and wait some LowtTime time long
void MakeSpeedStep(float v = 1000) {
    if (v >= VMin) { //avoid crash because of division
        myled4 = 0;
        Step = HIGH;

        wait(0.000001); // minimum Hightime is 1us, this is ca 5us

        myled4 = 1;
        Step = LOW;

        wait(1/v); // minimum Lowtime is 1us
    }
}

// Make a step and wait some dt time long
int MakeTimedStep(float dt = 1000) {
    int temptime;
    int dummy = 0;
    if ((dt >= 0.000000001) && (dt < 10)) { // avoid too long or no waiting
        myled4 = 0;
        Step = HIGH;

        wait(0.000001); // minimum Hightime is 1us, this is ca 3us

        myled4 = 1;
        Step = LOW;
        //timing more accurate with a dummy operation
        temptime = (int) (dt * 10000000.0f);
        for (;temptime > 0; temptime--)
            dummy += temptime;//asm (" nop ");

        //wait(dt); // minimum Lowtime is 1us
    }
    return dummy; //needed beacause if omitted, the optimizer removes the timing loop :(
}

int main() {
    char    OldEndSwitchIn = HIGH;
//   char inchar;
    int i;
    double dummy = 0.0f;
    int     counter = 0;
//init max time base
    double   t0 = sqrt(2.0/AMax)*0.676;

    double   newt;

// ********** caculations for acceleration and deceleration **********
    int     countLimSMax = VMax*VMax/(2*AMax); //if we can reach max speed we use this many steps
    int     countAccelLim = SMax/2; //if we can not reach max speed, we need to decelerate from half the stepdistance
    int     countLim = (countLimSMax<countAccelLim)?countLimSMax:countAccelLim; //which do we use?

//    double  tmp;

//set communication speed
    pc.baud(115200);
//test to see if comm is working
    printf("Hello!\n");

//  define filesystem
//    LocalFileSystem local("local");

    myled1 = 0;
    myled2 = 0;
    myled3 = 0;
    myled4 = 0;

// select which factor mode is to be set on the a4983
// compile time selection depending on Factor
#if (Factor==1)
    MS1 = LOW;
    MS2 = LOW;
    MS3 = LOW;  // 1/1
#elif (Factor==2)
    MS1 = HIGH;
    MS2 = LOW;
    MS3 = LOW;  // 1/2
#elif (Factor==4)
    MS1 = LOW;
    MS2 = HIGH;
    MS3 = LOW;  // 1/4
#elif (Factor==8)
    MS1 = HIGH;
    MS2 = HIGH;
    MS3 = LOW;  // 1/8
#elif (Factor==16)
    MS1 = HIGH;
    MS2 = HIGH;
    MS3 = HIGH; // 1/16
#endif

// ************ initialisation of power stage: ***********

    Dir = CounterClockwise;
    Step = LOW;
    nSleep = HIGH;
    nEnable = HIGH;
    nReset = LOW;
    myled1 = 1;
    myled2 = 0;
    myled3 = 0;
    myled4 = 0;

    wait(0.5);

    nReset = HIGH;
    myled1 = 0;
    myled2 = 1;
    myled3 = 0;
    myled4 = 0;

    wait(0.5);

    nEnable = LOW;
    myled1 = 1;
    myled2 = 1;
    myled3 = 0;
    myled4 = 0;

    wait(0.5);

    Step = HIGH;
    myled1 = 0;
    myled2 = 0;
    myled3 = 1;
    myled4 = 0;

    wait(0.5);

    Step = LOW;
    myled1 = 1;
    myled2 = 0;
    myled3 = 1;
    myled4 = 0;

    wait(0.5);

// test for setting up power stage
    /*  while( 1 )
      {
        //by using the endswitch we can make single steps forward and see how the micsosteps are behaving
        Step = EndSwitchIn;
      }
    */

// ************* Homing routine *************
// moves stepper in one direction until the endswitch triggers
    while ( 1 ) {
        if (( EndSwitchIn == LOW) && (OldEndSwitchIn == HIGH )) break;
        OldEndSwitchIn = EndSwitchIn;
        MakeSpeedStep(VHome*Factor);
    }

// wait for settling the sled
    wait(0.2);

// ************* Main endless loop ******************
// reads speed from a terminal and makes a movement with this maximum speed.
// acceleration and distance limits maximum reachable speed
    while ( 1 ) {
        // before every run we read how big VMax should be
        scanf("%lf",&VMax);
        // just an echo to see that serial connection is working
        printf("input was:%f\n\r", VMax);

        //normally i set a positive speed and so the movement is an oscillation
        //at negative values i want to let it go the same direction again and thus i have to set back Dir to original state
        if (VMax < 0.0f)
            Dir=!Dir; //let it go the

        // special case for driver testing and current setting purposes
        // for external current measurements make reset and set phases to 100% and 0%
        if (VMax == 1.0f) {
            nEnable = LOW;
            nReset = LOW;
            printf("reset low\n\r");
            wait(0.05);
            nReset = HIGH;
            printf("reset high\n\r");
            for (i = 0; i < (Factor/2); i++) //after so many steps the one of the phases has 100% and we can measure the max current
                MakeSpeedStep(VHome*Factor);
            printf("made %d steps\n\r", i);
        }
        // normal operation
        // no 0 speed allowed
        else if (VMax != 0.0f) {
            nEnable = LOW;
            VMax*=Factor;
            countLimSMax = VMax*VMax/(2*AMax);
            countLim = (countLimSMax<countAccelLim)?countLimSMax:countAccelLim; //depending on acceleration and max speed we decide which is to be used
            Dir=!Dir; //change direction to opposite
            counter = 1;
            newt = t0; //in the beginning there was a steptime of t0...
            printf("CountLimSMax: %d CountAccelLim: %d CountLim: %d \r\n", countLimSMax, countAccelLim, countLim);
            //make linear speed ramp movement
            //it is possible to stop it anytime during movement by hitting enter
            while ( (counter < SMax ) && !pc.readable() ) {
                //  TimeTrace[counter]=newt;
                // make the pulse and wait
                dummy = MakeTimedStep(newt);
                // at acceleration phase
                if (  counter <= countLim ) {
                    // use only one of these methods!
                    // newtonian approximation method
                    newt = newt - 2.0 * newt / (4.0*counter + 1.0);
                    // accurate method with double precision
                    // newt = t0*((sqrt((long double)(counter+1))-sqrt((long double)counter)));
                }
                // at constant speed phase
                else if ((countLim < counter) && (counter <= (SMax-countLim) )) {
                    //if (Dir == 1) newt = 1/VMax;
                    //to maintain execution time the processor is doing some really hard work ;)
                    dummy = dummy - 2.0 * newt / (4.0*counter + 1.0);
                }
                // at deceleration phase
                else {
                    // newtonian approximation method
                    newt = newt + 2.0 * newt / (4.0*(SMax-counter) + 1.0) ;
                    // accurate method with double precision
                    // newt = t0*(sqrt((long double)(SMax-counter+1))-sqrt((long double)(SMax-counter)));
                }
                //increase step counter
                counter++;
            }
            nEnable = HIGH; //when waiting shut down output to save power and avoid overheating
            printf("dummy = %f\n\r",dummy);//to ensure the compiler doesnt optimize the countings away...
        }

// ************ write trace to file ************
// File usage for tracing is buggy... fix it!
        /*
               FILE *fp = fopen("/local/out.txt", "w");  // Open "out.txt" on the local file system for writing
               tmp = 0.0f;

               for(int i=1; i<SMax; i++)
               {
                   tmp+=TimeTrace[i];
                   if (TimeTrace[i] != 0.0f)
                       fprintf(fp,"%8d %lf %lf %lf\r\n", i, TimeTrace[i]*1000, tmp, 1/TimeTrace[i]);
               }

        //        fprintf(fp,"Hi \r\n");
               fclose(fp);
        */
    }
}