Saturday, 3 April 2010

Arduino - Fancy Stepper Timer

I got distracted into writing an Arduino 2-channel stepper motor controller program for telescope tracking. It's unrelated to cnc, but it's a small exercise in Arduino programming and might be useful for others...

Ladyada.net has a motor shield for Arduinos that can be used to drive stepper motors (and other things). It comes with a program to drive the stepper motors, but it is blocking while it takes the delay between steps for one stepper motor, so the other stepper motor can't run concurrently.

Busy with searching Virtual Easter Eggs, I was too lazy to put together a proper interrupt-driven solution, so my Fancy Timer class is a quick work-around. If there is enough interest, I can put together an ISR solution.

So, here it goes: The following Arduino program lets you use 2 stepper motors simultaneously with the ladyada.net motor shield.

Limitation: As it's not interrupt-driven, it uses the built-in Arduino timer function, which has a granularity of 1ms, so it will all work fine for reasonably slow motor speeds. I suggest 200 to 300 pulses per second will be fine.

// FancyTimer - Lets you track multiple timers
// or stepper motors in parallel
// Copyright (C) 2010 www.cncorbust.com
// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General
// Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at
// your option) any later version.
// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE.  See the GNU General Public
// License for more details.
// You should have received a copy of the GNU General Public
// License along with this program.  If not, see
// <http://www.gnu.org/licenses/>.
//
// General idea:
// Class FancyTimer takes care of determining when an action
// (step) needs to be taken.
// You 'constantly' poll the class instance in loop().
// The poll method returns 'true' whenever you need to take
// action.
// You can create multiple instances of this class to track
// multiple timers/stepper motors at different speeds
// You can change the speed of each timer/stepper motor
// at any time and independently.
//
// Caveat:
// This only works if the motors run slowly enough, eg,
// up to maybe 200 steps per second
// Don't 'pause' calling the poll method or you will get a
// quick sequence of steps to "catch up"
// The method fails when the in-built timer wraps around
// to zero (after 50 days).
//
// ===============================================
// ============= The fancy timer. ================
// ===============================================
class FancyTimer
{
  public:

   // "steps per hour" because it keeps it precise
  unsigned long stepsPerHour;

  // how many steps we should be taking by now
  // in multiples of 1/3600000
  unsigned long current;

  // last time we were called to check
  unsigned long lastMillis;
 
  FancyTimer()
  {
    stepsPerHour = 0;
    current = 0;
    lastMillis = 0;
  }
 
  void setSpeed(unsigned long stepsPerHour)
  {
    this->stepsPerHour = stepsPerHour;
  }
 
  long getSpeed()
  {
    return this->stepsPerHour;
  }
 
  // returns true if it is time to take action
  boolean checkTime()
  {
    unsigned long oldMillis = lastMillis;
    lastMillis = millis();
    current += (lastMillis-oldMillis) * stepsPerHour;
   
    if(current>=3600000L)
    {
      current -= 3600000L;
     return true;
    }
    return false;
  }
};

// ================================================
// Here begins YOUR program
// This is an example to drive 2 stepper motors with
// afmotor.h from ladyada.
// ================================================

#include <AFMotor.h>

AF_Stepper motor1(48, 1);
AF_Stepper motor2(48, 2);

FancyTimer fancy1;
FancyTimer fancy2;

int motor1Direction = FORWARD;
int motor2Direction = FORWARD;

void setup()
{
}

void loop()
{
  // check condition / user input
  // and set motor speed and direction for each motor.
  //
  // We don't do this for this example, and simply
  // set the speed and direction for both motors.
  // Motor 1: 20 steps per second
  fancy1.setSpeed(20*3600L);
  motor1Direction = BACKWARD;

  // 13.521 steps pers second, ie, 13.521 * 3600 = 48675.6
  fancy2.setSpeed(48676L);
  motor2Direction = FORWARD;

  // Now poll timer to check if we need to take action:
  if( fancy1.checkTime() )
  {
    motor1.onestep(motor1Direction,INTERLEAVE);
  }

  // Now poll timer 2. For this example, we also switch off
  // the motor if it's not moving
  if( fancy2.checkTime() )
  {
    motor2.onestep(motor2Direction,DOUBLE);
  }
  else if( fancy2.getSpeed() == 0L )
  {
    motor2.release();
  }  
}

9 comments:

ivlasic said...

Hallo Thomas,

i just get the same schield and want to drive two stepper motors to controll my telescope.
Could you help me with it.
I am worried because of blocking when using both motors.

Igor

Thomas said...

Hi Igor

I can try to help. Have you tried the Fancy Stepper Timer ? How far did you get with your setup ?

email: Thomas at cncorbust.com

Anonymous said...

Hi Thomas
I also would like to improve a telescope tracker ia alt-az mount. Can you help me??

Thomas said...

Anonymous: I'm happy to try.

Anonymous said...

Hi my idea is to permit to regulate indipendently the speed of the two motor by two pot so that you can track for some minutes a star. Once you find the right speed the telescope would track for more time... I will now try to have a google account so no more anonymus!!
Cordially
Marc

Thomas said...

Hi Marc,
With your Alt-Azimuth mount, do you intend to track for the purpose of taking photos, or just for visual observation? If photos, how long is your longest expected exposure (single image, not stacking)?
Are you able to calibrate the orientation of the telescope?

Thomas

Marc62 said...

Hi Thomas
excuse me for the delay but i was away for job..
No I would like to track only for visual. This will help me also to track clouds for time lapse photos.
Yes I'm able to calibrate telescope I also are able to make telescopes!!
Cordially
Marc

Thomas said...

Hi Marc
Well, if you can calibrate the orientation of the telescope, then (in theory) you could calculate the required movement to follow a star based on current time, location, and telescope view direction. It might be a bit of a stretch for an Arduino to do all that sine and cosine stuff, but if you are happy with a straight line movement, then it would have to calculate it only once.

Alternatively, maybe a simpler method would be to center a star (or other straight-line-moving-target), then wait for some time, then center the star again. The Arduino could calculate the required velocity to continue the straight line at the same speed.

Thomas

Marc62 said...

Hi Thomas
sure I was thinking about your second suggest cause I'm interested not oly to track stars. Now I will try write something that will permitt me to do this. I hope You will be here for some help....
Cordially
Marc