Shop OBEX P1 Docs P2 Docs Learn Events
Stepper Motors with Activity Board and H-Bridge - Page 2 — Parallax Forums

Stepper Motors with Activity Board and H-Bridge

2

Comments

  • The high pulse width is the duration that the step pin remains in active "high" state.
  • I found a flaw with my programming for high pulse width, so hold off on testing, for a little while
  • plau45

    Actually it should be okay....

    I had an error in some other code where high_pulse_width, was defined by a uint8_t type, but in the code I gave you, it was defined as type uint32_t , which should make it work

    DUH
  • Okay, awesome. Thanks.
  • Bruce,
    You can also use the Propeller counters to drive stepper motors, which will result in a much higher running speed, because they don't require 381 cycles for the waitcnt to register.
    When you say propeller counters, are you referring to the pause function which would be in 1/256th of a second or are you talking about something else entirely?
  • idbruceidbruce Posts: 6,197
    edited 2017-06-27 22:20
    Propeller "Counters" is a very in depth subject, and no it is not a pause function. There are three main sources for learning about the counters, which are:

    1. The Propeller Manual briefly discusses certain items pertaining to the counters. You can find this information by looking for "counter" in the index, located at the rear of the book: https://parallax.com/sites/default/files/downloads/P8X32A-Web-PropellerManual-v1.2.pdf

    2. Application Note AN001 P8X32A Counters is an in depth document pertaining to the Propeller counters: https://parallax.com/sites/default/files/downloads/AN001-P8X32ACounters-v2.0.pdf

    3. Propeller Education Kit Labs Version 1.2 is a wonderful source for information pertaining to the Propeller, and Chapter 7 of this document discusses counters and the use of counters, 60 pages worth of information on all things counter related. You better put your thinking cap on: https://parallax.com/sites/default/files/downloads/122-32305-PE-Kit-Labs-Fundamentals-Text-v1.2.pdf
  • Bruce,
    This is a very strange situation I am in. The code was not working for me although it built correctly. The motor would just buzz and vibrate and I even turned up the inertia variable and nothing would happen except for having a higher pitch. I tried up to 50000 and still the same thing. I was just putting in a print("Done") statement at the end of each loop to check if it's executing the loop and when I did it all started working correctly. When I tried to change it to print("D") it went back to just buzzing. I have no clue why of all the words "Done" was the one to get it to work or why this even made it work. I didn't know if you knew what was going on.
  • LOL... That's funny.... I was working on a piece of code today, without any motors attached, and it only worked when a print statement was included.

    I would try a couple of things.....

    1. Increase the high pulse width.... It is currently written as
    uint32_t high_pulse_width = CLKFREQ / 209500;  // 381
    

    Which equates to 381 as written, and it is the absolute bare minimum. You could simply hard code higher values such as 400 or 500, which would be written as
    uint32_t high_pulse_width = 500;
    

    2. Increase the low pulse width, which can also be hard coded....
    uint32_t overcome_inertia = 20000
    
    uint32_t overcome_inertia = 30000
    
    uint32_t overcome_inertia = 40000
    
    uint32_t overcome_inertia = 50000
    



  • plau45

    Try this code instead.... Let me know if this helps....
    #include "simpletools.h"
    
    int main()
    {
    	// Set the desired number of steps
    	uint32_t required_steps = 40000;
    
    	// Set the desired direction of rotation.
    	// This variable can only be set to a
    	// value of 0 or 1.  A value of 0 will
    	// turn the motor either clockwise or
    	// counter-clockwise, dependant upon how the
    	// motor coils are attached to the stepper
    	//driver, and a value of 1 will turn it in
    	//the opposite direction of 0.
    	uint8_t direction_of_rotation = 0;
    
    	// Establish the IO pin being used to communicate
    	// with the direction pin of the stepper driver.
    	uint8_t direction_pin = 14;
    
    	// Establish the IO pin being used to communicate
    	// with the step pin of the stepper driver.
    	uint8_t step_pin = 15;
    
    	// Depending upon inertia of the motor and/or
    	// the load attached to the motor, you should be
    	// able to vary the running speed of the motor
    	// by adjusting this variable.  If the duration
    	// is too short, the motor will either wine, vibrate,
    	// and not move, or it will miss steps during runtime,
    	// and if the duration is too long, it will take
    	// forever to get from point A to point B,  You will
    	// have to experiment with this variable, depending
    	// upon you motor, load, desired speed, etc...	
    	uint32_t overcome_inertia = 20000;
    
    	// This variable must result in a value equal to
    	// or higher than 381, otherwise the system clock
    	// will roll over and cause unwanted delays.
    	// Additionally, the stepper driver IC (being the
    	// DRV8825 in your spefic case) may require a longer
    	// high pulse width.  Check the IC manufacturers
    	// specifications for the required pulse width.
    	uint32_t high_pulse_width = 400;
    
    	uint32_t counter;
    
    	// Set the DIRA register of the direction_pin as an output.
    	DIRA |= 1 << direction_pin;
    
    	// Set the DIRA register of the step_pin as an output.
    	DIRA |= 1 << step_pin;
    
    	// Set the OUTA register of the direction_pin to match
    	//the desired direction of rotation.
    	if(direction_of_rotation == 0)
    	{
    		OUTA &= (~1 << direction_pin);
    	}
    	else
    	{
    		OUTA |= 1 << direction_pin;
    	}
    
    	// Copy CNT
    	counter = CNT;  
      
    	// Spin the motor
    	while(required_steps != 0)
    	{
    
    		// At this location, drive the step pin high
    		// for the required high pulse width
    		OUTA |= 1 << step_pin;
    		waitcnt(counter += high_pulse_width);
    
    		// At this location, drive the step pin low
    		// long enough to overcome the inertia of the
    		// motor or the load attached to the motor
    		OUTA &= (~1 << step_pin);
    		waitcnt(counter += overcome_inertia);
    
    		// Decrement running_steps
    		required_steps--;
    	}
    }
    
  • If you are still having trouble with the code, then perhaps it is my masks. I am no expert with masks.

    Instead you could use something like...

    set_direction(X_STEP_PIN, 1);
    set_output(X_STEP_PIN, 0);

    set_direction(X_DIR_PIN, 1);
    set_output(X_DIR_PIN, 0);

    But research these functions before using them. I don't want to be responsible for fried boards.
  • kwinnkwinn Posts: 8,697
    plau45 wrote: »
    Bruce,
    This is a very strange situation I am in. The code was not working for me although it built correctly. The motor would just buzz and vibrate and I even turned up the inertia variable and nothing would happen except for having a higher pitch. I tried up to 50000 and still the same thing. I was just putting in a print("Done") statement at the end of each loop to check if it's executing the loop and when I did it all started working correctly. When I tried to change it to print("D") it went back to just buzzing. I have no clue why of all the words "Done" was the one to get it to work or why this even made it work. I didn't know if you knew what was going on.

    Sounds like the step frequency is too high. Steppers will not start up at high step rates. The armature just vibrates back and forth between the two full step positions. Adding the print probably slowed the loop enough for the armature to complete the full step.
  • kwinnkwinn Posts: 8,697
    PS - Try putting a wait in the loop instead of the print.
  • A print("Done") should take about 42,000 cycles at 115.2 k-baud. So you might be able to increase the inertia variable by 42,000, which would make it 92,000. Try that without a print to see if it works.
  • Not that this relates to the print("done") problem, but there is another item to consider when altering the overcome_inertia variable. Stepper motors are much more capable of higher speeds when higher voltages are used.

    Pololu lists that driver as being capable of handling 8.2V to 45V.

    However, from the very start, you must overcome inertia first. Once you start to move, then you can gradually increase your speed. If you have 45V going to the drivers, as compared to 8.2V, then you can increase this speed rather rapidly.
  • idbruceidbruce Posts: 6,197
    edited 2017-06-29 05:23
    plau45

    Here is another stepper driver, based upon a Propeller "counter". Please note that it actually looks quite similar to the other driver, but it is different and faster. Notice that the high_pulse_width is now fairly lower than the other driver, but it meets the 1.9uS specification for the DRV8825 that you quoted earlier. Once again, you will have to adjust the overcome_inertia variable to suit your particular application.

    As mentioned with the other driver, the overcome_inertia can be altered during the looping process to achieve ramping of the motor.

    EDIT: IMHO... This is a much better driver than the one that uses two waitcnt functions.

    EDIT: This driver had a mask problem, as pointed out by Ariba in a later post, and it has now been corrected.
    #include "simpletools.h"
    
    int main()
    {   
    	// Set the desired number of steps
    	uint32_t required_steps = 40000;
    
    	// Set the desired direction of rotation.
    	// This variable can only be set to a
    	// value of 0 or 1.  A value of 0 will
    	// turn the motor either clockwise or
    	// counter-clockwise, dependant upon how the
    	// motor coils are attached to the stepper
    	//driver, and a value of 1 will turn it in
    	//the opposite direction of 0.
    	uint8_t direction_of_rotation = 0;
    
    	// Establish the IO pin being used to communicate
    	// with the direction pin of the stepper driver.
    	uint8_t direction_pin = 14;
    
    	// Establish the IO pin being used to communicate
    	// with the step pin of the stepper driver.
    	uint8_t step_pin = 15;
    
    	// Depending upon inertia of the motor and/or
    	// the load attached to the motor, you should be
    	// able to vary the running speed of the motor
    	// by adjusting this variable.  If the duration
    	// is too short, the motor will either wine, vibrate,
    	// and not move, or it will miss steps during runtime,
    	// and if the duration is too long, it will take
    	// forever to get from point A to point B,  You will
    	// have to experiment with this variable, depending
    	// upon your motor, load, desired speed, etc...	
    	uint32_t overcome_inertia = CLKFREQ / 5714;
    
    	// This variable must meet the required pulse width
    	// of the stepper driver IC being used.  Check the
    	// IC manufacturers specifications for the required pulse width.
    	uint32_t high_pulse_width = CLKFREQ / 500000;  // 160 // 2uS
    
    	// Set DIRA as an output.
    	DIRA |= 1 << direction_pin;
    
    	// Set up the CTRMODE of Counter A for NCO/PWM single-ended.
    	CTRA = (4 << 26) | step_pin;
    
    	// Set the value to be added to PHSA with every clock cycle.
    	FRQA = 1;
    
    	// Set DIRA as an output.
    	DIRA |= 1 << step_pin;
    
    	// Set the OUTA register to match the desired direction of rotation.
    	if(direction_of_rotation == 0)
    	{
    		OUTA &= ~(1 << direction_pin);
    	}
    	else
    	{
    		OUTA |= 1 << direction_pin;
    	}
    
    	// Spin the motor
    	while(required_steps != 0)
    	{
    		// At this location, drive the step pin high
    		// for the required high pulse width
    		PHSA = -high_pulse_width;
    
    		// Wait for a specified period of time before sending another
    		// high pulse to the step pin.
    		waitcnt(overcome_inertia + CNT);
    
    		// Decrement required_steps
    		required_steps--;
    	}
    	print("done");
    }
    
  • I have been messing with some code that has a variety of issues, but I just resolved one of them.

    Parallax documentation states that the value of the offset must always be at least 381, well.... I just discovered a situation where it must be 385.
  • Thanks guys! I will try your new code Bruce and see where that takes me.

    Dave and kwinn,
    Thanks for your inputs. I was suspecting that the print did something to the output and the speed at which it was executed but was just shocked it was "Done" that did it. And I didn't know what the time required to print Done was so I was just going to keep it instead of doing a wait. I'm sure if I needed to that I could experiment with it and find the right value.
  • Bruce,
    Your new code worked great. The overcome_inertia is set to 500 now and that turns the motor with now issue. I just don't have any load on it right now. Now I need to incorporate the buttons into it which should be pretty straight forward. I'll tell you how it goes.
  • Which new code? Is it the post that uses the Propeller "counter"?
  • The most recent code you uploaded. The one based on the Propeller Counter I believe.
  • plau45plau45 Posts: 109
    edited 2017-06-28 18:02
    Bruce,
    I have successfully gotten the program to work with 2 push buttons and a single stepper. I however have a slight problem of not being able to alter the direction of the stepper. I thought I had a solution but it did not work. Also it doesn't matter which button I press, they both make the stepper run in a single direction. As for my naming variables of xPos and xNeg, they are just names for now. They are not supposed to be any specific direction for now. That I will find out when I incorporate the steppers into my actual brace. Here is the code, maybe you can find something that I missed. It does run properly with no errors I just can't seem to get the directions set up right.
    #include "simpletools.h"
     
    int main()
    {   
    	uint32_t required_steps = 40000;
    
    	uint8_t direction_pin = 14;
    	uint8_t step_pin = 15;
    
    	uint32_t overcome_inertia = CLKFREQ / 500;
    	uint32_t high_pulse_width = CLKFREQ / 500000;  // 160 // 2uS
    
    	// Set DIRA as an output.
    	DIRA |= 1 << direction_pin;
    
    	// Set up the CTRMODE of Counter A for NCO/PWM single-ended.
    	CTRA = (4 << 26) | step_pin;
    
    	// Set the value to be added to PHSA with every clock cycle.
    	FRQA = 1;
    
    	// Set DIRA as an output.
    	DIRA |= 1 << step_pin;
     
      while(1)
      {
        while( check_xPos() == 1 )
        {
          rotate_left( direction_pin, step_pin, overcome_inertia, high_pulse_width );
        }
        while( check_xNeg() == 1 )
        {
          rotate_right( direction_pin, step_pin, overcome_inertia, high_pulse_width );
        }            
      }
    }
          
          
    //Button Check Functions
    int check_xPos()
    {
      int xPos = input(0);
      return xPos;
    }
    
    int check_xNeg()
    {
      int xNeg = input(1);
      return xNeg;
    }
    
     
     
    //Function that rotates motor left   
    void rotate_left( uint8_t direction_pin, uint8_t step_pin, uint32_t overcome_inertia, uint32_t high_pulse_width )
    {
    	OUTA &= (~1 << direction_pin);
    
    	// Spin the motor
    		// At this location, drive the step pin high
    		// for the required high pulse width
    		PHSA = -high_pulse_width;
    
    		// Wait for a specified period of time before sending another
    		// high pulse to the step pin.
    		waitcnt(overcome_inertia + CNT);
    }
    
    
    //Function that rotates the motor right
    void rotate_right( uint8_t direction_pin, uint8_t step_pin, uint32_t overcome_inertia, uint32_t high_pulse_width )
    {
    	OUTA |= 1 << direction_pin;
    
    	// Spin the motor
    		// At this location, drive the step pin high
    		// for the required high pulse width
    		PHSA = -high_pulse_width;
    
    		// Wait for a specified period of time before sending another
    		// high pulse to the step pin.
    		waitcnt(overcome_inertia + CNT);
    }
    
  • plau45plau45 Posts: 109
    edited 2017-06-28 18:09
    I decided to use them as their own functions simply because it is easier for me to use this way and I think it is easier to understand.
  • plau45

    To enter code, click the "C" in the editor window, which will post to CODE tags in the editor window, then simply paste your code in between the two CODE tags.

    It looks like it should work at first glance, but perhaps there is a problem with your buttons or logic.

    A quick check would be to use the code I posted without changes, without buttons, or input logic. Simply alter the "as is" code

    FROM
    uint8_t direction_of_rotation = 0;
    


    TO
    uint8_t direction_of_rotation = 1;
    

    This will at least let you know if the problem is before or after code alteration.
  • Okay, so I have tried as you suggested and it will only rotate counter clockwise. Never clockwise.
  • AribaAriba Posts: 2,690
    in rotate_left:
    OUTA &= (~1 << direction_pin);
    
    should be:
    OUTA &= ~(1 << direction_pin);
    
    BTW: the simpletools library has some nice functions to set and clear single pins:
      high(direction_pin);    //forward
    
      low(direction_pin);     //backward
    
      pulse_out(step_pin,5);  //5us high pulse
    
    you find the functions in the help menu of SimpleIDE

    Andy

  • Thanks a bunch Ariba!
  • plau45

    I did say....
    If you are still having trouble with the code, then perhaps it is my masks. I am no expert with masks.

    Thanks Ariba
  • Okay, so I got the functions that you told us about to work, it really wasn't hard it just needed to be typed out lol. However it still does not work with turning clockwise. Only counter clockwise. I checked my wiring and it checks out. Maybe its something with the board (either the activity board or the driver) or the pins on said board. I don't know to much about this again so I could be totally wrong.
  • Repost your code with the code tags I told you about. Let's see what it looks like now. Perhaps take a photo of the board with the driver, so that we can see and verify.

    Possibly try my code again, with the direction bit changed as suggested before, but this time make sure that you include the change that Ariba suggested.
  • Here is the code you gave me that I added the snippets that Ariba suggested.
    #include "simpletools.h"
    
    int main()
    {   
    	// Set the desired number of steps
    	uint32_t required_steps = 40000;
    
    	// Set the desired direction of rotation.
    	// This variable can only be set to a
    	// value of 0 or 1.  A value of 0 will
    	// turn the motor either clockwise or
    	// counter-clockwise, dependant upon how the
    	// motor coils are attached to the stepper
    	//driver, and a value of 1 will turn it in
    	//the opposite direction of 0.
    	uint8_t direction_of_rotation = 0;
    
    	// Establish the IO pin being used to communicate
    	// with the direction pin of the stepper driver.
    	uint8_t direction_pin = 14;
    
    	// Establish the IO pin being used to communicate
    	// with the step pin of the stepper driver.
    	uint8_t step_pin = 15;
    
    	// Depending upon inertia of the motor and/or
    	// the load attached to the motor, you should be
    	// able to vary the running speed of the motor
    	// by adjusting this variable.  If the duration
    	// is too short, the motor will either wine, vibrate,
    	// and not move, or it will miss steps during runtime,
    	// and if the duration is too long, it will take
    	// forever to get from point A to point B,  You will
    	// have to experiment with this variable, depending
    	// upon your motor, load, desired speed, etc...	
    	uint32_t overcome_inertia = CLKFREQ / 500;
    
    	// This variable must meet the required pulse width
    	// of the stepper driver IC being used.  Check the
    	// IC manufacturers specifications for the required pulse width.
    	uint32_t high_pulse_width = CLKFREQ / 500000;  // 160 // 2uS
    
    	// Set DIRA as an output.
    	DIRA |= 1 << direction_pin;
    
    	// Set up the CTRMODE of Counter A for NCO/PWM single-ended.
    	CTRA = (4 << 26) | step_pin;
    
    	// Set the value to be added to PHSA with every clock cycle.
    	FRQA = 1;
    
    	// Set DIRA as an output.
    	DIRA |= 1 << step_pin;
    
    	// Set the OUTA register to match the desired direction of rotation.
    	if(direction_of_rotation == 0)
    	{
    		//OUTA &= ~(1 << direction_pin);
        high(14);
    	}
    	else
    	{
    		//OUTA |= 1 << direction_pin;
        low(14);
    	}
    
    	// Spin the motor
    	while(required_steps != 0)
    	{
    		// At this location, drive the step pin high
    		// for the required high pulse width
    		//PHSA = -high_pulse_width;
        pulse_out(step_pin, 5);
    		// Wait for a specified period of time before sending another
    		// high pulse to the step pin.
    		waitcnt(overcome_inertia + CNT);
    
    		// Decrement required_steps
    		required_steps--;
    	}
    	print("done");
    }
    

    I'm not currently at my board but when I am I will take a picture of it and show you.
Sign In or Register to comment.