Controlling stepper motors based on servo motor angles

Hi, I am working on solar panel tracker based on servo motor for moving the solar sensor, and two stepper motors to move two mirrors to reflect the sunlight perpendicular to the solar panel.

The stepper motors move based on how many angles the servo made to track the sunlight. And the equation is
Steps = 4.5*angles
actual move = previous steps - current steps
so the steppers should make number of steps saved in "actual move"

The problem is that the stepper moves clockwise as intended in the first time, then the next move when there is a change in servo angles, move counterclockwise. I really do not understand why it does that. :confused: :confused:

Here is the code:

#include <Servo.h>                   // include Servo library 
#include <AccelStepper.h>            // inlcude stepper library 


int UpMirror1 = 15;            //int = integer , float = 
int UpMirror2 = 16;
int DownMirror1 = 17;
int DownMirror2 = 18; 

int flag = 0;
int flag1 = 0; 
int x = 0;
int x1 = 0; 
int x2 = 0;

Servo servo_SolarTracker; //  servo to move the solar tracker 
int servo_angle = 0;   // start at 0 degree     
int servoLimitHigh = 180;
int servoLimitLow = 0;

AccelStepper stepper1(1, 2, 5);        //pin 2 for controling steps and 5 for direction of stepper 1
AccelStepper stepper2(1, 3, 6);        //pin 3 for controlling steps and 6 for direction of stepper 2



void setup()
{
  Serial.begin(9600);    //only for testing 

  pinMode(UpMirror1,OUTPUT);
  pinMode(UpMirror2,OUTPUT);
  pinMode(DownMirror1,OUTPUT);
  pinMode(DownMirror2,OUTPUT);
  
  servo_SolarTracker.attach(9);   //attach servo signal to pin 9 in Arduino 
  servo_SolarTracker.write(0);    // move servo to 0 degree at first 
  delay(3000);        // wait for 3 seconds 

  stepper1.setMaxSpeed(1000);   // set max speed of stepper1 motors
  stepper2.setMaxSpeed(1000);   // set max speed of stepper2 motors 
}

void loop() 
{
  int tol = 50;       //tolerance 
  
  int lt = analogRead(A0); // top left
  int rt = analogRead(A1); // top right
  int ld = analogRead(A2); // down left
  int rd = analogRead(A3); // down rigt

  Serial.print("Lift Top: ");
  Serial.println(lt);        //only for testing
  Serial.print("Right Top: "); 
  Serial.println(rt);
  Serial.print("Lift Down: ");
  Serial.println(ld);
  Serial.print("Right Down: ");
  Serial.println(rd);
 
  int avr_sunrise = (lt + ld) / 2; // average value sunrise
  int avr_sunset = (rt + rd) / 2; // average value sunset

  int diff = avr_sunrise - avr_sunset;// check the diffirence of left and rigt
  diff = abs (diff);

  Serial.print("Average sunrise: ");                         //only for testing
  Serial.println(avr_sunrise);
  Serial.print("Average sunset: ");
  Serial.println(avr_sunset);
  Serial.print("Difference: ");
  Serial.println(diff);

  while (diff > tol) // check if the diffirence is in the tolerance else change vertical angle
  {    
    if (avr_sunset > avr_sunrise){
    servo_angle = servo_angle+2;
     if (servo_angle >= servoLimitHigh) 
     { 
      servo_angle = servoLimitHigh;
     }}

    else if (avr_sunrise > avr_sunset){
    servo_angle = servo_angle-2;
    
     if (servo_angle <= servoLimitLow) 
     { 
      servo_angle = servoLimitLow;
     }}
  
  servo_SolarTracker.write(servo_angle);
  
     lt = analogRead(A0); // top left
     rt = analogRead(A1); // top right
     ld = analogRead(A2); // down left
     rd = analogRead(A3); // down rigt
     avr_sunrise = (lt + ld) / 2;
     avr_sunset = (rt + rd) / 2;
     diff = avr_sunrise - avr_sunset;// check the diffirence of left and rigt
     diff = abs (diff);
     flag =1;
     Serial.print("Lift Top: ");
     Serial.println(lt);        //only for testing
     Serial.print("Right Top: "); 
     Serial.println(rt);
     Serial.print("Lift Down: ");
     Serial.println(ld);
     Serial.print("Right Down: ");
     Serial.println(rd);
     Serial.print("Average sunrise: ");                         //only for testing
     Serial.println(avr_sunrise);
     Serial.print("Average sunset: ");
     Serial.println(avr_sunset);
     Serial.print("Difference: ");
     Serial.println(diff);
     Serial.print("Servo angle: ");
     Serial.println(servo_angle);
     delay(1000);
      x = 4.5 * servo_angle;                    //x is steps relating to servo_angle
      x1 = x - x2;                              //x1 is the difference between the current and previous steps
}
   x2 = x;

   stepper1.moveTo(x1);                                // 1600 / 360 = 4.44 , x = 4.5*servo_angle 
   stepper1.setSpeed(50);
   stepper1.runSpeedToPosition();
   stepper2.moveTo(x1);                                // 1600 / 360 = 4.44 , x = 4.5*servo_angle 
   stepper2.setSpeed(50);
   stepper2.runSpeedToPosition();
   
   Serial.print("Stepper: ");
   Serial.println(x);
   Serial.print("Stepper difference: ");
   Serial.println(x1);
   }

The servo moves between 0 and 180 so the steppers move between 0 and 810. Why are you calculating a change in position and then using it as an absolute position? For example, when you start at 0 (stepper position 0) and move to 90 (stepper position 405) you subtract 0 from 405 and move the stepper to position 405. But then when you then move to 80 (stepper position 360) you subtract 405 from 360 and move to stepper position -45! You want 360, not -45.

You should just multiply servo_angle by 4.5 and use that as the argument to "stepper1.moveTo()". Something like this:

   delay(1000);
    
    x = 4.5 * servo_angle;                    //x is steps relating to servo_angle
  }


  stepper1.moveTo(x);                                // 1600 / 360 = 4.44 , x = 4.5*servo_angle
  stepper1.setSpeed(50);
  stepper1.runSpeedToPosition();
  
  stepper2.moveTo(x);                                // 1600 / 360 = 4.44 , x = 4.5*servo_angle
  stepper2.setSpeed(50);
  stepper2.runSpeedToPosition();


  Serial.print("Stepper position: ");
  Serial.println(x);

Thank for your reply, :slight_smile:

I have tried to understand the Accel Library of stepper motors, then I got that there are two functions, which are :
moveTo() for absolute movement
move() for relative movement.

so, you mean that when the program starts steppers can act like servo with a saved position every time when I use moveTo() as a control for movement?

Barahim:
so, you mean that when the program starts steppers can act like servo with a saved position every time when I use moveTo() as a control for movement?

Sort of, but the position gets lost whenever the sketch is restarted. Typically you would provide some position feedback, like a limit switch. When the sketch starts you would move the stepper toward the limit and, when the switch is reached, you know you are at the limit position. You tell the library the position and from there you can treat the stepper like a servo, assuming it isn't under enough load to cause steps to be lost.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.