Go Down

Topic: H-bridge, microstepping and only two PWM's (Read 879 times) previous topic - next topic

e-San

May 29, 2017, 07:08 pm Last Edit: May 29, 2017, 07:38 pm by e-San Reason: images added/edited
Hi and hello arduino gurus and all society ;)

Today i have a challenge!

Few days ago i've been wondering "am i able to controll 3-axis cnc through an arduino as LPT->H-bridge converter?".
The answer is "yes"! Mega example can be found here.
Ok, that was easy, as mega has multiple PWM.

Damn, again i went to deep into my problem.

What do i really need? I need to drive three (3) steppers through arduino with microsteps. I've found an library that seems to do that with four PWM's per stepper (called cpwStepper).
It mainly uses simple calculations on how much should it put on PWM's to get a microstep curve (drive attachment - lowest one [By Misan2010 - Own work, CC BY 3.0, https://commons.wikimedia.org/w/index.php?curid=9787501]).



After some tweaks (minor) it gives me (on Serial.print) good curve. (attachment input.svg).



But i need to use only two PWM, so i had an idea to "flow" non-pwm pin and use only one PWM for coil.

This gives me some tricky curve (output.png). Cool, huh?



Calculating A = coil1a - coil1b and B = coil2a - coil2b gives me (for both 4xPWM and 2xPWM) same values (mix.png).



But my stepper does not go like it should... It looks like it goes one step (4 micro as it should) forward and then backward - not sure if steps are simmilar...

So... my question is - is this elecrically possible?

Best regards!


sdturner

"But i need to use only two PWM"

What kind of stepper are you trying to drive? Are you shorting 2 output pins together?

e-San

Hello!

This topic is old but i'm still on it ;)

I'm attaching my libraries, but i'm not quite sure if it's more smooth at all. Can anyone help me to fire out why?

Testing scetch:
Code: [Select]
#include <microStepper4.h>
#include <microStepper8.h>
#include <Stepper.h>

// make sure to use analog pins for motors if you plan on using microstepping
const int x_coil1a = 6;   //non_pwm
const int x_coil1b = 9;   //pwm
const int x_coil2a = 10;  //non_pwm
const int x_coil2b = 11;  //pwm
const boolean invert_x_dir = false;

int i;

unsigned long t;

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, x_coil1a, x_coil1b, x_coil2a, x_coil2b);
microStepper4 microStepper4_x(x_coil1a, x_coil1b, x_coil2a, x_coil2b);
microStepper8 microStepper8_x(x_coil1a, x_coil1b, x_coil2a, x_coil2b);

const int delay_base = 9090/8;

void setup()
{
  Serial.begin(9600);
  myStepper.setSpeed(33.3*4);
}

void loop()
{
  t = millis();
  // go forward 200 steps
  //Serial.println("4x Microstepping forward");
  i = 0;
  while(i<200*2*10) {
    microStepper4_x.takestep(invert_x_dir);
    //microStepper4_x.takestep(invert_x_dir);
    delayMicroseconds(delay_base);
    i++;
  } 
 
  i = 0;
  while(i<200*4*10) {
    microStepper8_x.takestep(invert_x_dir);
    //microStepper4_x.takestep(invert_x_dir);
    delayMicroseconds(delay_base/2);
    i++;
  }
 
  Serial.println(millis() - t);

  //delay(1000);
 
  t = millis();

  myStepper.step(10*stepsPerRevolution);

  Serial.println(millis() - t);

  //delay(1000);
 
  /*delay(3000);
 
  // go backward 200 steps
  Serial.println("4x Microstepping backward");
  i = 0;
  while(i<200*4) {
    microStepper4_x.takestep(!invert_x_dir);
    delayMicroseconds(delay_base);
    i++;
  }
  delay(3000);*/

}


Best regards!

MorganS

We would have to have the same hardware to test on. What stepper and what H bridge?
"The problem is in the code you didn't post."

e-San

#4
Jan 09, 2019, 01:11 pm Last Edit: Jan 09, 2019, 01:12 pm by e-San
Ok, it is smoother.

Answering Your question: L298N (standard arduino module) and MOONS 17HD4416-03N.

After some research I've changed PWM frequency to the highest on 9 and 10'th pin with this: http://playground.arduino.cc/Code/PwmFrequency

It breaks stepper library, but I'm ok with that. Here's my current sketch:

Code: [Select]
#include <microStepper4.h>
#include <microStepper8.h>
#include <Stepper.h>

// make sure to use analog pins for motors if you plan on using microstepping
// nano: PWM: 3, 5, 6, 9, 10, and 11. Provide 8-bit PWM output with the analogWrite() function.
const int x_coil1a = 6;   //non_pwm
const int x_coil1b = 9;   //pwm
const int x_coil2a = 11;  //non_pwm
const int x_coil2b = 10;  //pwm
const boolean invert_x_dir = false;

int i;

unsigned long t;
unsigned long revTime;

const int stepsPerRevolution4 = 2*200;
const int stepsPerRevolution8 = 4*200;
const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, x_coil1a, x_coil1b, x_coil2a, x_coil2b);
microStepper4 microStepper4_x(x_coil1a, x_coil1b, x_coil2a, x_coil2b);
microStepper8 microStepper8_x(x_coil1a, x_coil1b, x_coil2a, x_coil2b);

const int delay_base = 2209;

void setup()
{
  Serial.begin(9600);
  //myStepper.setSpeed(10000);

  setPwmFrequency( 9, 1);
  setPwmFrequency(10, 1);
}

void loop()
{
  // ### microstepper4 ###
  /*Serial.println("microstepper4");
  t = millis();
  
  for(int i = 0; i < stepsPerRevolution4; i++) {
    microStepper4_x.takestep(invert_x_dir);
    delayMicroseconds(delay_base);
  }  

  revTime = millis() - t;
  printSpeeds(revTime);

  delay(1000);*/

  // ### microstepper8 ###
  Serial.println("microstepper8:");
  t = micros();
  
  for(int i = 0; i < stepsPerRevolution8; i++) {
    microStepper8_x.takestep(invert_x_dir);
    delayMicroseconds(delay_base);
  }  

  revTime = micros() - t;
  printSpeeds(revTime);

  //delay(1000);

  // ### standard ###
  /*Serial.println("stepper:");
  t = millis();
  
  for(int i = 0; i < stepsPerRevolution4; i++) {
    myStepper.step(invert_x_dir);
    delayMicroseconds(delay_base);
  }  

  revTime = millis() - t;
  printSpeeds(revTime);

  delay(1000);*/

}

void printSpeeds(unsigned long oneRevolutionTime){
  float rpm;
  Serial.print("   One revolution took: ");
  Serial.print(oneRevolutionTime);
  Serial.println(" ms.");

  rpm = 60000000/(float)oneRevolutionTime;
  Serial.print("   ");
  Serial.print(rpm,5);
  Serial.println(" rpm");
  
}

/**
 * Divides a given PWM pin frequency by a divisor.
 *
 * The resulting frequency is equal to the base frequency divided by
 * the given divisor:
 *   - Base frequencies:
 *      o The base frequency for pins 3, 9, 10, and 11 is 31250 Hz.
 *      o The base frequency for pins 5 and 6 is 62500 Hz.
 *   - Divisors:
 *      o The divisors available on pins 5, 6, 9 and 10 are: 1, 8, 64,
 *        256, and 1024.
 *      o The divisors available on pins 3 and 11 are: 1, 8, 32, 64,
 *        128, 256, and 1024.
 *
 * PWM frequencies are tied together in pairs of pins. If one in a
 * pair is changed, the other is also changed to match:
 *   - Pins 5 and 6 are paired on timer0
 *   - Pins 9 and 10 are paired on timer1
 *   - Pins 3 and 11 are paired on timer2
 *
 * Note that this function will have side effects on anything else
 * that uses timers:
 *   - Changes on pins 3, 5, 6, or 11 may cause the delay() and
 *     millis() functions to stop working. Other timing-related
 *     functions may also be affected.
 *   - Changes on pins 9 or 10 will cause the Servo library to function
 *     incorrectly.
 *
 * Thanks to macegr of the Arduino forums for his documentation of the
 * PWM frequency divisors. His post can be viewed at:
 *   http://forum.arduino.cc/index.php?topic=16612#msg121031
 */

void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x07; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}


Becose I can not use now stepper (lib) i can compare only 4 and 8 libs and it looks now that it is smoother.
If there's anyone who can check this also i would be happy.

I tried to put function setPwmFrequency into my library, and it works (Serial.print prints infos), but does NOT change frequency - how to do that? Also, I'm going to make library universal (one for 4, 8 and maybe 16). Is it possible to make it faster?

Go Up