Stepper Motor Release

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
pwatson22
 
Posts: 3
Joined: Thu Apr 10, 2014 12:55 pm

Stepper Motor Release

Post by pwatson22 »

I'm working with V1 of the Adafruit Motor Shield to control two bipolar stepper motors. I recently discovered the "release()" command to get the motors to release the holding torque. I am running a solar tracker that tracks the position of the sun, and would like the motors to shut off while the tracker is oriented within an acceptable error of the position of the sun. I tried implementing the release() command in my while loop, however, the release only seemed to occur momentarily. Is there a way to make the release hold until the next movement. My code is below. Thank you for any help.

Code: Select all

 
      float maxRTCerr = 2;        //degrees total error (sum of azi/ele error vectors)
      if (RTCerr > maxRTCerr){      
           stepper1.moveTo(ycommand);
           stepper2.moveTo(xcommand);
     
      else if(RTCerr <= maxRTCerr){
           motor1.release();
           motor2.release();
      }
       

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Stepper Motor Release

Post by adafruit_support_bill »

Please post the rest of your code. I need to see all the motor declarations and the structure of your loop.

pwatson22
 
Posts: 3
Joined: Thu Apr 10, 2014 12:55 pm

Re: Stepper Motor Release

Post by pwatson22 »

Code: Select all

/*Arduino source code for Helios Solar Tracker.
Written by Laughlin Barker BSME & BS Environmental Studies '12
& Adapted by Patrick Watson
*/
#include "SunPositionAlgo_LowAc.h"
#include <Flash.h>
#include <EEPROM.h>
#include <AccelStepper.h>
#include <AFMotor.h>
#include "Wire.h"
#include "RTC_Code.h"
#include <RTClib.h>

RTC_DS1307 RTC;      //initialize RTC



//========================================
//==============  CONSTANTS  =============
//========================================
float latitude = 37.3490;      //SCU
float longitude = -121.939568;
float timezone = -7;            //Timezone

//If you live in the northern hemisphere, put 0 here. If you live in the southern hemisphere put 1.
  int useNorthAsZero = 0;

float l1 = 16;        //in - L1 on mirror structure (back arm)
float l2 = 14.69;        //in - L2 on mirror structure

float pitch = 0.125;    //in - leadscrew pitch (3/8 - 12 screw)
float starts = 2;        //# start
float lead = pitch*starts;  //in - lead of screw (distance traveled in 1 rotation)
float cartwidth = 4.5;        //in - width of cart on actuator
float lx = 48;              //in - length of x actuator space
float ly = 36;              //in - length of y actuator space

float stepper_resolution = 200;    //resolution of stepper

float xlims[2], ylims[2];    //x and y max/min in form [xmin, xmax], [ymin, ymax]
float args[2] = {180, 0};
long stepsx,stepsy;

float pi = 3.14159265;

//Logical holders for stepper zeroing
boolean xcal = 0;    //0 == FALSE i.e. not zeroed
boolean ycal = 0;
//========================================
//========================================


//========================================
//=============  GLOBAL VARS  ============
//========================================
float azi = 0;
float ele = 0;          //open loop azi and ele
float x, y, z;             //open loop x and y
//=====================
//INTERVAL BETWEEN MACHINE POSITION UPDATES
//Lets the program know how often to update the position of the machine(s) (in seconds)
  unsigned long updateEvery = 20;//seconds

float SunsAltitude, SunsAzimuth, h, delta;
unsigned long updateTime = 0,  now = 0;

//================== MOTOR CONFIG STUFF ================
AF_Stepper motor1(200, 1); //X motor
AF_Stepper motor2(200, 2); //Y motor

void forwardstep1() {              
  motor1.onestep(FORWARD, DOUBLE);
}
void backwardstep1() {  
  motor1.onestep(BACKWARD, DOUBLE);
}

void forwardstep2() {  
  motor2.onestep(FORWARD, DOUBLE);    
}
void backwardstep2() {  
  motor2.onestep(BACKWARD, DOUBLE);
}
// Motor shield has two motor ports, now we'll wrap them in an AccelStepper object
//AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);

int xcalpin = 19;
int ycalpin = 18;

void setup()
{  
    //setup steppers
    stepper1.setMaxSpeed(300);    //steps/s
    stepper1.setAcceleration(500);
    stepper2.setMaxSpeed(300);
    stepper2.setAcceleration(500);
    
    //start serial
    Serial.begin(115200);
   
    //start 1-wire bus & RTC
    Wire.begin();
//    RTC.begin();
    

    
    //uncomment if RTC is significantly off, upload, comment out, and then re-reupload
//    RTC.adjust(DateTime(14,2,25,11,01,00));
}

char X_buffer[8];
float maxPOS = 32e3;
float setPointPOS, requestedPOS;
int j=1;

long previousMillis = 0;
long interval = 5000;

void loop() //begin main loop
{
  
  int month, year, day, dayOfWeek;
  float hour, minute, second;
  byte secondRTC, minuteRTC, hourRTC, dayOfWeekRTC, dayOfMonthRTC, monthRTC, yearRTC;
   
  RTC_Code::getDateDs1307(&secondRTC, &minuteRTC, &hourRTC, &dayOfWeekRTC, &dayOfMonthRTC, &monthRTC, &yearRTC); 
  
  //The variables below can be set to accept input from devices other than an RTC.
  dayOfWeek=dayOfWeekRTC;//NOT CURRENTLY USED
  year = yearRTC;//NOT CURRENTLY USED

  
  month = monthRTC;
  day = dayOfMonthRTC;
  hour = hourRTC;
  minute = minuteRTC;
  second = secondRTC; 

  
  now = millis();
  if ( (now + updateEvery*1000) < updateTime){updateTime=now+updateEvery;}
  //END 
  
//  DateTime now = RTC.now();
  //if X and Y not calibrated, run motors until limit switch hit; will run on every restart
//   Serial.println("Zeroing X Actuator");
   
   while (xcal == 0){
    stepper2.moveTo(-100000);
    stepper2.run();
    Serial.println("Calibrating X");
      
      if (digitalRead(xcalpin)==0){
        xzero();
      }
      
    }
   while (ycal == 0){
    stepper1.moveTo(-100000);
    stepper1.run();
    Serial.println("Calibrating Y");
      
      if (digitalRead(ycalpin)==0){
        yzero();
        Serial.println("Both actuators properly zeroed");
        Serial.print(stepper2.currentPosition());
        Serial.print(" , ");
        Serial.print(stepper1.currentPosition());
        

      }
      
    }
    




  //==========FOR X===========
if (Serial.available()){
      //make sure we have all the data
      delay(5);
      //serial data is waiting, lets extract     
      int  i=0;     
      while(i<8){
        X_buffer[i] = Serial.read();
        //Serial.println(X_buffer);
        i++;
      }
     
      //flush serial buffer of extra data>9999
      Serial.flush();
      //convert numeric string to int var
      requestedPOS = atof(X_buffer);
      //check for set point greater than maxPWR limit
      if( requestedPOS < maxPOS){
        //Buffer contains a safe value, copy out to setPointPWR
        setPointPOS = requestedPOS;
//        Serial.print("Requested set point:");
//        Serial.println(setPointPOS);
      }
      
      else{
        Serial.println("'The sun don't shine here!"); //errorcode 2012, you requested a pathalogical power level
        setPointPOS = 0; //
      }
      if (j>0){
        Serial.print("Accepted AZI position:");
        Serial.println(requestedPOS);
        azi = setPointPOS;
        //stepsx = setPointPOS;
      }
      else if (j<0){
        Serial.print("Accepted ELE position:");
        Serial.println(requestedPOS);
        ele = setPointPOS;
        //stepsy = setPointPOS;
      }
      j=-j;
    }
     

 
 stepper1.run();
 stepper2.run();
 

     unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time it went through this routine
    previousMillis = currentMillis;   
    
 //================================================================================
 //                PERIODIC CALCULATIONS (not nec. every loop iteration)
 //================================================================================
    
    //get AZI and ELE of sun based on RTC
//    float azi_s = azi_func(latitude,longitude);
//    float ele_s = ele_func(latitude,longitude);
    

      SunPositionAlgo_LowAc::CalculateSunsPositionLowAc(month, day, hour, minute, second, timezone, latitude, longitude, SunsAltitude, SunsAzimuth, delta, h);
      SunsAltitude = SunsAltitude + (1.02/tan((SunsAltitude + 10.3/(SunsAltitude + 5.11)) * pi/180.0))/60.0;//Refraction Compensation: Meeus Pg. 105

           Serial.print("Sun's Alt: ");
           Serial.println(SunsAltitude);
           Serial.print("Sun's Az: ");
           Serial.println(SunsAzimuth);

    
    //instantaneous AZI and ELE of tracker
    float azi_t = tracker_azi();
    float ele_t = tracker_ele();
    
    //tracker commanded position vars
    float azi_t_command;
    float ele_t_command;
    long xcommand;
    long ycommand;
    

    
       azi_t_command = SunsAzimuth;
       ele_t_command = 90+(SunsAltitude+5.2);
       xcommand = x_step_pos(azi_t_command, ele_t_command);
       ycommand = y_step_pos(azi_t_command, ele_t_command);
      
      if (stepper2.currentPosition() > 0){
        azi_t = (180-tracker_azi());
      }
        else {
          azi_t = -(180+tracker_azi());
        }

      //Define X and Y in terms of current position  
      x = stepper2.currentPosition();
      y = stepper1.currentPosition();
      
      // Calculate the length between mounts based on current position
        h = abs(pow(pow(abs(x),2) + pow(abs(y),2),0.5))/800;

     
     //Calculate Zenith and Elevation angles using law of cosines
     double phi = acos((pow(l2,2) + pow(h,2) - pow(l1,2))/(2 * h *l2))*180/pi;
     ele_t = 90-phi-5.2; 

      float RTCerr = pow( (pow( (SunsAzimuth - azi_t) , 2) + pow( ((SunsAltitude) - ele_t) , 2 ) ) , 0.5);
    
//    if angular error ir greater than maxRTCerr, move tracker to sun orientation
    
    float maxRTCerr = 2;        //degrees total error (sum of azi/ele error vectors)
     if (RTCerr > maxRTCerr){      
stepper1.moveTo(ycommand);
stepper2.moveTo(xcommand);
       
       Serial.println("=====================================");
       
       Serial.println("OPEN-LOOP POSITIONING...");
       
       Serial.println("=====================================");
     }
     
     // Closed loop routine; only do it RTC error is within allowable limits
     else if(RTCerr <= maxRTCerr){
       motor1.release();
       motor2.release();
       
//       float EWcorr = senseEW();
//       float NScorr = senseNS();
//       
//       if (EWcorr != 0 || NScorr != 0){
//         azi_t_command = azi_t + EWcorr;
//         ele_t_command = ele_t + NScorr;
//         
//         xcommand = x_step_pos(azi_t_command, ele_t_command);
//         ycommand = y_step_pos(azi_t_command, ele_t_command);
//       }
//       else{
//         
//       xcommand = x_step_pos(azi_t_command, ele_t_command);
//       ycommand = y_step_pos(azi_t_command, ele_t_command);
//       }
//       
//       stepper1.moveTo(ycommand);
//       stepper2.moveTo(xcommand);
//       
//       delay(5000);
       
       Serial.println("=====================================");
       
       Serial.println("CLOSED LOOP MISALIGNMENT...CORRECTING");
       Serial.print("Correcting ");
       Serial.print(EWcorr);
       Serial.println(" degrees West...");

       Serial.print("Correcting ");
       Serial.print(NScorr);
       Serial.println(" degrees North");
       
       Serial.println("=====================================");      
     }
       
 long xcurrent = stepper2.currentPosition();
 long ycurrent = stepper1.currentPosition();

 //================================================================================
 //                PERIODIC SERIAL OUTPUT
 //================================================================================
    
    Serial.println("Step pos: ");
    Serial.print(xcurrent);
    Serial.print(" , ");
    Serial.println(ycurrent);
    Serial.println(" ");
    

      Serial.println(" ");   
      Serial.print("Time: ");
      RTC_Code::printtime(hourRTC, minuteRTC, secondRTC, monthRTC, dayOfMonthRTC, yearRTC, dayOfWeekRTC);//Displays the RTC time
      delay(500);


    
    Serial.print("Sun Pos: ");
    Serial.print(SunsAzimuth);
    Serial.print(" , ");
    Serial.println(SunsAltitude);
    Serial.println(" ");
    
  

    Serial.print("Tracker Pos: ");
    Serial.print(azi_t);
    Serial.print(" , ");
    Serial.println(ele_t);
    
    Serial.print("RTCerr: ");
    Serial.print(RTCerr);
    
    Serial.println("========================");

  }
  
}


void xzero(){
  Serial.println("Zeroing X actuator");
  long tmppos = disp2steps(lx/2) - (cartwidth/2) * stepper_resolution / lead;
  tmppos = -tmppos;
   //calculating position based on screw and stepper info
  stepper2.setCurrentPosition(tmppos);    //makes zero in the middle of the x actuator when cart is at end...sneaky!
  Serial.print("Current position: ");
  Serial.println(stepper2.currentPosition());
  stepsx = stepper2.currentPosition();
  xcal = 1;
}

void yzero(){
  Serial.println("Zeroing Y actuator");
   //calculating position based on screw and stepper info
  long tmppos = 3.3 * stepper_resolution / pitch;
  stepper1.setCurrentPosition(tmppos);    //makes zero in the middle of the y actuator when cart is at end...sneaky!
  Serial.print("Current position: ");
  Serial.println(stepper1.currentPosition());
  stepsy = stepper1.currentPosition();
  ycal = 1;
  
}

long disp2steps(float disp){      //actuator displacement to steps
  long steps = disp * stepper_resolution / lead;    //will truncate; OK since 1 step = 0.00125" for .25 lead screw
  return steps;
}

float steps2disp(long isteps){
  float steps = (long)isteps;
  float disp = steps/(stepper_resolution / pitch);
  return disp;
}


float tracker_azi(){
  float x = steps2disp(stepper2.currentPosition());
  float y = steps2disp(stepper1.currentPosition());
  float azi = azi_pos(x, y, l1, l2, args);
  return azi;
}

float tracker_ele(){
  float x = steps2disp(stepper2.currentPosition());
  float y = steps2disp(stepper1.currentPosition());
  float h = pow( (pow(x,2) + pow(y,2)) ,0.5);
  float ele = ele_pos(x, y, l1, l2, args);
  return ele;
}

long x_step_pos(float azi, float ele){
  float x = aziele2x(azi, ele, l1, l2, args);
  long x_steps = disp2steps(x);
  return x_steps;
}

long y_step_pos(float azi, float ele){
  float y = aziele2y(azi, ele, l1, l2, args);
  long y_steps = disp2steps(y);
  return y_steps;
}

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Stepper Motor Release

Post by adafruit_support_bill »

release() is a function of the Adafruit library. AccelStepper knows nothing about it. So when your loop comes around again and calls stepperXrun(), AccelStepper can turn them back on again.

pwatson22
 
Posts: 3
Joined: Thu Apr 10, 2014 12:55 pm

Re: Stepper Motor Release

Post by pwatson22 »

Thank you for the help. I see what you mean. I've tried changing my code to get rid of this problem, however, my changes result in the motors not moving at all or the motors only moving a single step at a time. Is there a way with the AF_stepper class to replace this stepper#.run command?

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Stepper Motor Release

Post by adafruit_support_bill »

It is possible. But you would need to calculate the step times yourself.

Another approach is to set a boolean "release" flag when you want to release the motors, then add a test for "release" in your step functions.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”