Playing with Chuck's Rotary table code

Discussion in 'Software and Programming' started by Scott_M, Feb 12, 2015.

Help Support HMEM by donating:

  1. Feb 12, 2015 #1

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    251
    Likes Received:
    76
    Location:
    Medina, Ohio USA
    I wanted to see how Chuck's code worked with a micro-stepping driver so I rigged this test up using an old stepper and driver from my Tormach mill. This is a "Tordrive 2000" 10 microstep driver and a 640 oz. in. Nema 34 stepper motor. The motor is spec'd at 24-70 volts and 5.5 amps, I am kind of surprised how well it ran at 19 volts. The power supply I am using is a Laptop charger rated at 19.5volts and 6.2 amps.
    I modified Chuck's code a little bit to remove the second device. I also set the default delay to 0, with the micro-stepping driver it was running painfully slow with the delay set at 5. And just for fun I changed the "set num of divisions" to use 2 lines of the display.
    I know there was some concern that this code was using "floating point" math, I wanted to see where the limits would be.
    It looks like it will work for a 40:1 rotary table. But not for a 90:1.
    This test was with 80000 steps
    200 steps per turn for stepper x 10 microsteps x 40 turn table = 80000.

    Short video.
    www.sdmfabricating.com/upload_page/ArduinoRotaryTest.MOD
    I tried a different file format maybe you Mac guys can see it now ?

    Scott
     
    TorontoBuilder likes this.
  2. Feb 13, 2015 #2

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    I think with some modified code the Arduino can drive a 90:1 table. Well I hope it can. In previous tests, the Arduino could happily drive the microstepper (2000 steps) at the same speed as an ordinary driver (200 steps). I've played briefly tonight and have it running on a Freetronics LCD.

    You need to use Timer Interrupts. You can safely replace all of the ints and floats with longs so that alone will speed things up. eg. like this:

    Code:
    long del = 5L;                            // default delay value
    long divs = 0L;                           // Holds the number of divisions
    long pos = 0L;                            // Holds the current dividing head position (0 (zero) based)
    long lastpos = 0L;			// Last absolute stepper position
    long nextstep = 0L;                       // used for calculation of next stepper position
    long intsteps =0L;
    long laststep = 0L;
    long nsteps = 0L;                         // Count of steps to advance stepper
    long steps = 0L;
    long stepsDiv = 0L;			// Steps per Division
    long numSteps = 1000L;                // Number of steps per spindle revolution
    
    Note the use of the L modifier to tell C it is a long value.
    Then get rid of the ABS and ROUNDs on the float values where used in the formulas. By using longs, the results will always be a whole number. Like This

    Code:
      laststep = stepsDiv * lastpos;
      nextstep = stepsDiv * pos;
      nsteps = nextstep - laststep;
    

    And here is the setup for a timer interrupt stepper driver. If you set the vairable steps to some value, the ISR will drive the stepper that many steps in the background. Note I've left out the loop().

    If you look carefully, for each call to the interrupt the stepper pin changes state each call (eg high or low) until steps gets to zero. So steps may actually need to be 2 x what you need the stepper to step.

    Code:
    #define stepPin 4
    #define dirPin 5
    #define CLOCKWISE     HIGH
    #define ANTICLOCKWISE LOW
    int dir = CLOCKWISE;  // Clockwise
    int state = LOW;
    int steps = 8000;
    
    void setup() 
    {
      pinMode(stepPin, OUTPUT);
      pinMode(dirPin, OUTPUT);
    
      digitalWrite(dirPin, HIGH);
      digitalWrite(stepPin, state);
      
      Timer1.initialize(40); // set a timer of length in microseconds (or 0.1 sec - or 10Hz
      Timer1.attachInterrupt( timerIsr ); // attach the service routine here
    }
     
    
    void timerIsr()
    {
        // Toggle LED
      if(steps){
          state = state ^ 1;
          digitalWrite( stepPin, state );
          steps--;
      }
    }
    This line controls how fast the stepper is pulsed
    Code:
    Timer1.initialize(40); // set a timer of length in microseconds (or 0.1 sec - or 10Hz
    
    I'll try and insert this code over the weekend
     
    darkoford likes this.
  3. Feb 13, 2015 #3

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    251
    Likes Received:
    76
    Location:
    Medina, Ohio USA
    Hi Rod

    Thanks for your effort on this. I wish I had the programming skill to tackle something like this. I am still having trouble with syntax. It seems I always have the {} braces in the wrong place or I'm missing one.
    I'm playing with "if" and "else" now......I'll get there eventually.

    Thanks again

    Scott
     
  4. Feb 13, 2015 #4

    kvom

    kvom

    kvom

    Administrator Staff Member Administrator Global Moderator

    Joined:
    Jun 4, 2008
    Messages:
    3,143
    Likes Received:
    588
    In my programming days I used emacs as my editor. It had some nice features for coding:

    1) Cursor on a { or } highlighted the match

    2) Auto indents using tab key aligned { and } for the proper syntax.

    Also would find matching ( and ) the same way.

    I suppose more modern editors can do the same things, but once you learned emacs it was a very efficient editor in terms of keystrokes and facility.
     
  5. Feb 13, 2015 #5

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    251
    Likes Received:
    76
    Location:
    Medina, Ohio USA
    Thanks Kvom

    The Arduino editor also highlights the matching Brace, BUT..... you need to know what that means :( last night I struggled with getting some code to compile and it kept giving me an error " expected } at end of input" There was one, it showed the matching brace at the beginning of the loop. It took me a while to realize that I needed 2 at the end
    }
    }

    one for the last input and one to close the loop. I am plodding along.


    Scott
     
  6. Feb 13, 2015 #6

    chucketn

    chucketn

    chucketn

    Senior Citizen

    Joined:
    Dec 17, 2009
    Messages:
    1,300
    Likes Received:
    154
    Occupation:
    Fully retired
    Location:
    Near Jonesborough, TN
    For what it's worth, I have a 90:1 Rotary Table, and have Chuck F's sketch running a TB6560 driver with a stepper. I changed the RT divisions in his sketch to match my RT(90*200=18,000). I haven't finished machining the adaptor for the stepper to the RT yet, but it drives the stepper o.k.

    Chuck
     
  7. Feb 13, 2015 #7

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Scott, always be consistent with formatting and indenting as you can see it much more easilly. Just get in the habit of putting them in always And use the same convention. I like to put the opening brace at the end of the line but more often today you see it on a line on its own. Use the match brace feature of the editor. When there is only one line of code, they are optional As the compiler can work out what it is doing. One tip is to insert the braces before you fill in the code in between. Sometimes the error will be at the end of the file and the missing brace is much further up the page.
     
  8. Feb 13, 2015 #8

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    251
    Likes Received:
    76
    Location:
    Medina, Ohio USA
    Hi Chuck
    Yes it will work with full steps. Just keep in mind that accuracy will go down as diameter goes up.
    Pi * dia = circumference. Circumference / steps will give you linear accuracy per step.
    so on a 4" diameter that will give you about 7 tenths per step. For model work that is probably fine.

    The buddy I am looking into this for has a biga$$ RT with an 8" chuck. He want to do 12" diameter. That comes out to .002" per step. Which he is not thrilled about so I am trying to get it to work with microstepping.

    Scott
     
  9. Feb 13, 2015 #9

    chucketn

    chucketn

    chucketn

    Senior Citizen

    Joined:
    Dec 17, 2009
    Messages:
    1,300
    Likes Received:
    154
    Occupation:
    Fully retired
    Location:
    Near Jonesborough, TN
    The TB6560 will allow micro stepping. I'm waiting until the shop thaws a bit, and I get the adapter finished. Then I'll hook it all up and test with and without micro-stepping. I also have a couple of other driver shields and 2 screw shields to play with.

    Chuck
     
  10. Feb 13, 2015 #10

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Scott it will be easy. Start by making the changes in my first two code blocks.Also if your stepper driver has 10x more steps, then you need to make the delay 10 x shorter.

    Its probably worth explaining what interrupts are. There are two types. One that gets actioned when something happens. eg. a value is received on a port and the other is a timer interrupt hooked to the CPU clock. The arduino has several timer interrupts (I am using Timer1 interrupt as there is a library for it).

    So the Arduino has a 16 MhZ clock. So that means 16,000,000 times a second the timer fires and the CPU goes off and does its own internal processing that we don't have to know about as programmers. It all happens in the background.

    So with a timer interrupt, we are simply telling the CPU to chain to and run our code every now and again when it is going about its housekeeping. The code has to be short and sweet otherwise there won't be enough time to get it done and crazy things will happen. All we have to do is to decrement a global counter and send a signal to the stepper port. Harder to read but the code has to be highly efficient.

    After playing with a Gecko microdrive stepper board (2000 steps per rev), I settled on a timer that fired every 40 microseconds Thats 25,000 times a second. Each time it fires, the stepper signal will change from ON to OFF or vice versa. That means we will get 12,500 steps per second as only the ON's count. So Lets do the maths
    12500/2000 steps = 6.25 rev per second
    6.25 x 60 = 375 stepper RPM
    375 / 90 = 4.16 table RPM

    And this is roughly what I observed with a tacho

    If I went any faster (which the Arduino is easily capable of), I found that the Stepper stated to miss steps or just vibrate and make awful noises.

    Hope this helps, I will post up my code once I get it going. I've been trying to be good and not play with the Arduino during the workng week...
     
  11. Feb 13, 2015 #11

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Lets descibe what is gong on in here

    Code:
    void timerIsr()
    {
        // Toggle LED
      if(steps){
          state = state ^ 1;
          digitalWrite( stepPin, state );
          steps--;
      }
    
    So this code only fires if there is a value in the global variable steps. eg an efficient way of saying
    Code:
    if( steps <> 0)
    The next line changes the value in the global variable state using bitwise operator OR. An OR operation is only TRUE if the 2 values compared are not the same.
    Code:
    1 OR 1 = FALSE (0)
    0 OR 1 = TRUE (1)
    So this
    Code:
    state = state ^ 1;
    is a very efficient way of saying
    Code:
    if(state == 1){
       state = 0;
    }
    else{
       state=1;
    } 
    
    Finally
    Code:
     steps--;
    is a very efficient way of saying
    Code:
    steps = steps -1 ;
    Hope that all helps understand some code.
     
  12. Feb 14, 2015 #12

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Well I made some progress and incorporated the Interrupt code into Chucks code. I think it is time to hook up a stepper again.
    I added some debugging code that printed values to the serial port while the stepper port was being driven. In the time it took to print
    Code:
    isrSteps = 3694
    to the serial port, the ISR running in the background had sent 234 steps to the stepper port!

    I will share this eventually!
     
  13. Feb 14, 2015 #13

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    251
    Likes Received:
    76
    Location:
    Medina, Ohio USA
    Rod , thanks that is very helpful !

    And I will study your last post and play with it tomorrow.
    It really makes it a lot easier when you are trying to apply something that you want to do rather than some meaningless exercises in a tutorial that you may never use.

    I really appreciate your input !

    Thanks again

    Scott
     
    rodw likes this.
  14. Feb 14, 2015 #14

    kf2qd

    kf2qd

    kf2qd

    Well-Known Member

    Joined:
    Apr 1, 2008
    Messages:
    477
    Likes Received:
    36
    I have programmed in Pascal & C, Pascal used Begin and end statements, C usu { & }

    Many times in C the start a function like this -
    void function() {

    and end it like this -
    }

    The braces don't line up.
    I find it easier to read if I write it this way -
    void function()
    {

    and end it like this.
    }

    the braces line up.

    Always use the same indent amount and line up the braces.

    I would write this function -
    Code:
    void timerIsr()
    {
        // Toggle LED
      if(steps){
          state = state ^ 1;
          digitalWrite( stepPin, state );
          steps--;
      }
    }
    
    Code:
    void timerIsr()
    {
        // Toggle LED
      if(steps)
      {
          state = state ^ 1;
          digitalWrite( stepPin, state );
          steps--;
      }
    }
    
     
    Last edited: Feb 14, 2015
  15. Feb 14, 2015 #15

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Well, I pulled out the stepper and fired it up. It is now working with the interrupt code but I am not getting the results I expected as the distance travelled is changing depending on the time delay for the ISR. At first, I thought it might be becasue I was driving the stepper too fast. I'll do a bit more research on the stepper diver. I assumed it would trigger on a change of state from LOW to HIGH, maybe I need to only turn the signal on for a short time period instead of for 50% of the step pulse. It does help to clean up and simplify the code I thought.
     
  16. Feb 14, 2015 #16

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Attached is a simple working sketch to drive a stepper motor with interrupts.

    Just set these variables to suit your situation.

    Code:
    #define stepPin 1
    #define dirPin 2
    #define STEPS_PER_REV 2000
    This sketch will turn the stepper one full revolution in one direction, wait half a second and then turn it half a revolution in the opposite direction, then repeat ad infinitum.

    Sorry, I should have used a #define for the timer delay here. You may need to change this value.
    Code:
    Timer1.initialize(40); // set a timer of length in microseconds 
    
    Have a look at your stepper motor specs and see what frequency in Herz it has maximum torque and what is the maximum frequency it can handle. Remember if you are using a microdrive (like my Gecko) you can drive it 10x faster.

    My stepper has max torque at 400 Hz and fades right away out at about 1,000 Hz so that is the ideal range to drive it at. The value of 40 I've used is 12,500 Hz (1250 Hz at the stepper itself with my microdrive) and I can't drive it any faster (35 skips steps) so 50 might be a more conservative value to use as that will give you 10,000 Hz.(1000 Hz at the stepper with a microdrive)

    But the identical code plays up in Chucks sketch so I'm still not in the clear.

    View attachment ISRBlinkGecko.zip
     
  17. Feb 14, 2015 #17

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    251
    Likes Received:
    76
    Location:
    Medina, Ohio USA
    Hi Rod

    I can't compile your sketch. I get


    ISRBlinkGecko.ino: In function 'void setup()':
    ISRBlinkGecko:23: error: 'Timer1' was not declared in this scope

    Is the <TimerOne.h> library in the standard IDE ?

    Or..maybe I just havn't had enough coffee yet :)

    Scott
     
  18. Feb 14, 2015 #18

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,132
    Likes Received:
    334
    Scott, Sorry, I must have got the code from here. So long ago!
    http://playground.arduino.cc/Code/Timer1

    Yesterday I wrote from scratch a complete dividing sketch with the same functionality as Chuck's which is using the Timer1 example above. Very Exciting.

    If you are using a Freetronics LCD display and keyboard, This is the menu and form input library I'm using (but I've extended it by adding 2 more input field types). It will save a lot of time.
    https://github.com/rweather/arduinolibs

    I want to add a few more features like continuous turning, backlash compensation, jogging, set and return to a home position and speed control.
     

Share This Page