Tips for Arduno software for Rotary Table Controllers

Discussion in 'Software and Programming' started by rodw, Feb 8, 2015.

Help Support HMEM by donating:

  1. May 1, 2015 #201

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    252
    Likes Received:
    78
    Location:
    Medina, Ohio USA
    Hey Rod, having some issues with accell and decell. Am trying to figure out how you are handling this. Is it just a ratio between min and max hz ?

    I currently have my max set at 12500 and min at 7000.
    Should I lower the min to get longer accell and decell or do I need to add steps to the "ramp up" and "ramp down" definition ?

    Scott

    Edit: Just changed min to 4000 and it seems to be working much better.

    I will have a full report on this project in a few days. It came out reeeealllllly nice !
     
    Last edited: May 1, 2015
  2. May 2, 2015 #202

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Scott, sorry for being a bit slow. I have not got back to this project. My foray into steppers got me in and I've been designing a CNC plasma cutter...

    I found it needed a bit of trial and error. Setting the start speed too low did not seem to be a good idea. The ramp up worked but it was really slow getting going...

    Basically, it starts out by working out how many steps (call it X) it needs to do to get from 7000 to 12500 and changes the frequency every time it does a step. Once it gets to 12500 it stays at that speed until It gets X steps away from the finishing position and the slows the frequency down each pulse until it gets back to 7000 on the very last step of the movement.

    If the distance is short, and it can't get up to 12500 and back down again, maybe it only has enough room to get to 9000 and back to 7500 again, it will never reach the max speed of 12500.

    I did link to a pdf file from TI that explains this. Worst case set the start and end speed to be the same.
     
    Scott_M likes this.
  3. May 2, 2015 #203

    Scott_M

    Scott_M

    Scott_M

    Well-Known Member

    Joined:
    Apr 13, 2013
    Messages:
    252
    Likes Received:
    78
    Location:
    Medina, Ohio USA
    Thanks Rod

    It seems like if the spread between min and max is large it is an issue. I think I may lower Max just so I can lower Min some more.
    This is a 40:1 Dividing head so it turns plenty fast. It is a like new 50's vintage "Cincinnati" It is HUGE ! My buddy is putting an 8" 3 jaw on it.
    I will post a build log on it next week when I get down to my buddy's and get some video of it. Here is a pic of the top of the Arduino box.

    I can't thank you enough for all you did on this project !! My project has turned out really well because of it.

    Scott

    P1030677.jpg

    P1030673.jpg
     
    larry1 likes this.
  4. May 2, 2015 #204

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Scott, that looks great. Keep the pics coming.I'm really pleased to see someone run with my contoller hardware.

    From talking to a mate, even MACH3 requires some experimentation with ramp up and ramp down parameters. And yes, I found much the same thing with the settings. I would keep the start speed as high as I could for reliable starting without loosing steps.
     
  5. May 3, 2015 #205

    Cogsy

    Cogsy

    Cogsy

    Well-Known Member Staff Member Global Moderator

    Joined:
    Jul 30, 2012
    Messages:
    2,674
    Likes Received:
    768
    Gender:
    Male
    Location:
    Perth, Western Australia
    I was in on the design and build of a largish CNC plasma cutter a couple of years ago. The one piece of advice I can give is that you really need a good automatic torch height controller.

    You probably already knew but just in case you didn't...
     
    rodw likes this.
  6. May 3, 2015 #206

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Cogsy, thanks. I had worked that out. I have not given a thought to the electronics yet. Been trying to teach myself 3D design and have almost finished the gantry which will be laser cut and welded with locating tabs to position everything. All because this software project got me in and I happened to have a BOC 40 amp plasma cutter here! One good thing is that it has a Thermo Dynamics cutting torch.
     
  7. Nov 21, 2015 #207

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    Just a quick hello and a big thank you!

    I have just installed v10 without any major problem. The only annoyance I had were the keys on my DFRobot LCD shield (which looks like a SainSmart). My quick-fix was to replace the #define mapButton in LCD.cpp with a simple function. Certainly a tad slower than the array[] lookup, but so far I can't see any problem from that.

    A quick question (or suggestion) : Is it possible to change the speed while in continuous mode ?

    Again a big hooray to Rod and this project !

    My code for LCD.cpp (uncomment the #define mapButton and buttonMappings[])

    Code:
    // map the buttons
    int mapButton(int value)
    {
      /* values depend on the version of the lcd board */
      if (value > 1000) return LCD_BUTTON_NONE;
      if (value < 50)   return LCD_BUTTON_RIGHT;
      if (value < 195)  return LCD_BUTTON_UP;
      if (value < 380)  return LCD_BUTTON_DOWN;
      if (value < 555)  return LCD_BUTTON_LEFT;
      if (value < 790)  return LCD_BUTTON_SELECT;
      return LCD_BUTTON_NONE;  // when all others fail, return this...
    }
    
     
  8. Nov 23, 2015 #208

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Thanks for feedback from a happy customer. If you modify the goConTurn procedure, you may be able to add new case statements for the up and down arrows to change the frequency.

    If you have a look at
    goSetSpeed() you will see it incrementing/decrementing in 5% intervals and calculating a value with
    Code:
    int speedPct = (int)((((float)((float)globals.maxStepperHz - (float)globals.minStepperHz) / (float)(Operating_Hz - globals.minStepperHz)))*100.0);
    
    So maintain a similar variable and increment on up arrow and decrement on down arrow.

    and then setting the speed with a call to
    Code:
    setSpeed(speedPct);
    Note there is not much dynamic memory left.... if you get erratic results you have a memory overflow condition and you will need to reduce the size of static strings (ie. Menu entries)
     
  9. Nov 23, 2015 #209

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Actually, I've got that a bit wrong. Speed is determined by the variable Operating_Hz
    The first line quoted in my last post calculates the percentage of the range that Operating_Hz is currently set to. (between the Minimum and the maximum)
    So do this calculation on entry to the goConTurn() procedure to get the current percentage and increment/decrement by 5% with up and down buttons and then call setSpeed()
     
  10. Nov 23, 2015 #210

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    That's not difficult. This is excellent code and a just-right solution.

    Yes, that's what I thought to do.

    I have seen that space is getting really, really tight. But I have a couple of things in my head which will need much more than available, so I stripped out all the linear stuff, the devices, the safe to eeprom. My configuration is now done with a couple of #defines at the beginning. It's clearly not as flexible and configurable like yours.

    My intended changes include:
    - change speed within all different menus (not just continuous)
    - add rotary enoder for direct turning
    - add one of those IR remote controls
    - maybe show RPM while turning (calculated, not measured)

    I still remain true to all your core routines (apart from kicking out the globals variable) so we could still walk in parallel.

    <><><><><>

    Well, no. Operating_Hz currently isn't used anywhere. At least not in v10. I have written a long reply regarding this, but deleted it. Basically this is the central function, as far as I can tell:

    Code:
    void setSpeed(int spdPct)
    {
      globals.maxStepperHz =  (long)((float)( Operating_Hz - globals.minStepperHz) * (float)spdPct/100.0) + globals.minStepperHz;
      globals.timerDelay = HzToTimeDelay(globals.maxStepperHz);
      Timer1.setPeriod(globals.timerDelay);      // set a timer of length in microseconds
    }
    You are modifying and operating around globals.maxStepperHz. Operating_Hz is just set once in setup() and never touched again. Because you are ramping to and from globals.maxStepperHz, and because Operating_Hz holds the MAX_FREQUENCY, it still works. So all is good functionality-wise, but by accident, so to speak. ;)

    Again thanks for sharing.
    Happy days to you, Rod!
     
  11. Nov 23, 2015 #211

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    Another bug (?)

    Apart from the Operating_Hz variable which probably should be used here as well, it seems to me that start and target needs to flip, otherwise rampSteps gets negative, which presumably stops the stepper immediately instead of ramping down.

    I am still not very clear about this frequency thing; so maybe this is as intended and not a bug.

    Code:
    void rampDown(void)
    {
      startDelay =   HzToTimeDelay(globals.minStepperHz);          
      targetDelay =  HzToTimeDelay(globals.maxStepperHz); 
      rampSteps = ((startDelay-targetDelay) * globals.microSteps);  
      startRampDown = rampSteps - 3L;      // Steps to start ramping down - steps count down so we start at a high #
      endRampUp =  rampSteps -1L;                      // We don't want to Ramp Up as we are supposed to be moving
      sDelay = targetDelay;
      steps = rampSteps + 1L;              // Run enough steps to stop gracefully
    }
    
    Hope you don't mind that I throw all this at you. :D
     
  12. Nov 23, 2015 #212

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Coming back to me now. Maybe I started to change the code to use Operating_Hz but changed my mind (ie. got confused.)

    The rampDown() and rampUp() procedures need the max and min StepperHz values. They can be changed at will until they are changed in setup or the Arduino is rebooted (which reads the values from eeprom again).

    The most valuable contribution would be to recode the menu library so that it uses PROGMEM variables. This would allow the variables to live in the codespace and never get loaded into the 2k variable storage area on bootup. This (Simple?) change would solve ALL of your code space issues.
     
  13. Nov 23, 2015 #213

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    I ran heaps of tests with print functions in the main loop to monitor the ISR routine to trace what was going on while ramping up and down. It is not intuitive. In the dividing functions, I am confident there are no bugs...

    This bit could be buggy as what I am attempting to do is to calculate the number of steps required to ramp up and ramp down for the continuous turning procedure to avoid missed steps and loss of position. Read on and hopefully, this will become clearer.

    A Frequency of 1 Hz means 1 on and off cycle per second. This needs 2 cycles (1 for on and 1 for off) through the ISR routine (last procedure in the file) . Think of AC power which is 50Hz.. (50 complete cycles per second) So rather than stuff around with a short pulse every now and again which is how most Arduino stepper drivers work, while the stepper is operating, the pulse goes on and off for an equal time period. This is how the data for a stepper motor is presented (eg data sheets quote frequencies).

    So now we get to the ramp down and ramp up functions. Steppers generate max torque at lower speeds. Starting at a high speed/low torque might lead to missed steps (and I had a lot before I got it to run reliably). So the idea according to the Texas Instruments documentation I referenced is to start slow and ramp up by adding 1 extra step through each iteration of the ISR until it reaches the Max operating frequency. (lets just assume that takes 1000 pulses. So before we stop, we also want to ramp down as at high speed the lack of torque could cause the stepper to overrun and run for more steps than it should. So before the end point, we ramp down 1000 steps in exactly the reverse manner.

    So finally, what happens if say the total movement is less than the sum of the ramp up and ramp down interval? Simple really. If say the total steps to move required was 1000, we would never get to operating speed. We'd ramp up to 500 steps, never reach operating speed then ramp down 500 steps.

    The other thing that is happening in the ISR is that the number of steps from the home position is maintained at all times. Remember that you have no control over the ISR, it is just triggered by the CPU 16,000,000 per second... (16 Mhz). We must be short and sweet in an ISR as we don't have much time to do stuff!
     
    Last edited: Nov 23, 2015
  14. Nov 23, 2015 #214

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335

    I just re-read your comment above As I said, it is not intuitive. The starting delay is bigger than the target delay because at this level we are counting the number of timer pulses between steps. Slow speed (start) = long delay. Target (fast) speed = short delay. Does that make sense?
     
  15. Nov 23, 2015 #215

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    It is slowly creeping in. Thank you for your patience and the time to reply with all these explanaitions!
     
    rodw likes this.
  16. Nov 23, 2015 #216

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    In that case you could do : "%s/Operating_Hz/MAX_STEPPER_HZ/g" and fix the two syntax errors you will get at compile time. Saves a byte or two ;)
     
  17. Nov 29, 2015 #217

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    Ron, another (probably stupid) question:

    I see you are using Timer1.initialize() in setSpeed() and in timerIsr() instead of Timer1.setPeriod(). Any special reasons for that? Surprisingly, the Timer1 inline-code says initialize() stops the timer.

    I have added the speed change into continuous turning. I particularly like that I now can actually see and hear the speed, instead of trial-and-erroring it in percent-steps.

    The solution has three parts. It also needs two new variables.

    Code:
    volatile long smoothRamp = 0L; // Steps to move to next speed (in continous mode)
    volatile long smoothDir = 0L;  // speeding up or down in smoothRamp
    
    First: Add buttons to goConTurn() as you have suggested:

    Code:
          case LCD_BUTTON_UP:
            rampTo(globals.maxStepperHz + 100);
            break;
            
          case LCD_BUTTON_DOWN:
            rampTo(globals.maxStepperHz - 100);
            break;
    
    Second: Add a function to ramp to new speed.

    Code:
    void rampTo(long nextHz)
    {
      /* should have some precautions against going too slow or fast */
    
      if(nextHz > globals.maxStepperHz) {
        // get faster
        startDelay =   HzToTimeDelay(globals.maxStepperHz);
        targetDelay =  HzToTimeDelay(nextHz);
        smoothDir = -1;
      } else {
        // get slower (or stay the same)
        startDelay =  HzToTimeDelay(nextHz);  
        targetDelay =   HzToTimeDelay(globals.maxStepperHz);
        smoothDir = +1;
      }
    
      globals.maxStepperHz = nextHz;
      smoothRamp = (startDelay - targetDelay) ;
    }
    
    Third: Add some code to timerISR(), right before your ramping if()'s

    Code:
          if(smoothRamp > 0) {
            stepcount++; stepcount++;
            stepmod = ((long)stepcount % (long)MICRO_STEPS);
            if (stepmod == 0) {
              smoothRamp--;
              sDelay += smoothDir;
              Timer1.initialize(sDelay); // adjust timer 1
            }
          }
    

    Cheers !
     
    rodw likes this.
  18. Nov 29, 2015 #218

    rodw

    rodw

    rodw

    Well-Known Member

    Joined:
    Dec 3, 2012
    Messages:
    1,138
    Likes Received:
    335
    Torfilli,

    It is a great enhancement that you have coded. I did not think of it.

    I had no idea I was doing something with the timer that was no quite right. But it worked :)

    Glad you have worked out the ramping up and down. I would have to revisit the code but there may be a more efficient way to code the feature but after a couple of glasses of red wine with dinner , it presently eludes me. But if it works :)
     
  19. Nov 30, 2015 #219

    Donrecardo

    Donrecardo

    Donrecardo

    Active Member

    Joined:
    Apr 14, 2008
    Messages:
    39
    Likes Received:
    5
    Hi Torfilli

    I too use a copy of a sainsmart LCD and my left button doesnt operate as it should

    I had the same problem with Chuck Fellows code but easily found the line where
    I could change the ADC value that equated to "left"
    You post explains how to change LCD.cpp to do the same thing but I dont really
    understand how to do it ( its an age thing ). Is it possible you could upload a copy of your LCD.cpp so I can see exactly what and where you have changed it
    Apart from the left button Rods code is working fine for me

    Regards
    Don
     
    rodw likes this.
  20. Nov 30, 2015 #220

    Torfilli

    Torfilli

    Torfilli

    Member

    Joined:
    Nov 21, 2015
    Messages:
    9
    Likes Received:
    4
    Hi Don,

    No problem at all; here it is.

    I have commented the lines 323-327 in the original code (from the package that Rod has uploaded elsewhere here in the thread) and have added immediately afterwards my replacement-function to return a keycode from the ADC value. No magic involved.

    The values in the if() statements vary from version to version, from resistors to resistors, of the shield so my version may not be cut-n-paste compatible. Just plug in the values you already have, and you should be good to go! If not, yell! and we'll find a way.

    Enjoy life!

    Torfilli

    View attachment LCD.zip
     
    rodw likes this.

Draft saved Draft deleted

Share This Page