diff --git a/examples/Microstepping/Microstepping.ino b/examples/Microstepping/Microstepping.ino new file mode 100644 index 0000000..8708aa3 --- /dev/null +++ b/examples/Microstepping/Microstepping.ino @@ -0,0 +1,70 @@ +/* +Stepper Motor Control - revolutions with microstepping + +This program drives a bipolar stepper motor in microstepping mode. +The motor is attached to digital pins D1-D4 of an ESP-8266. +D3, D4 are connected to the direction pins, D1 and D2 are connetec to the PWM/ENABLE pins of the L293D H bridge chip. + +The motor swings the same number of steps clockwise and back. + + +Created 17 Mar. 2017 +by Attila Kovács + +*/ + +#include "Stepper.h" + +#define DIR_MOTOR_A D3 +#define DIR_MOTOR_B D4 +#define PWM_MOTOR_A D1 +#define PWM_MOTOR_B D2 + +const int stepsPerRevolution = 48; // change this to fit the number of steps per revolution +const int microSteps = 8; // valid values are 2, 4, 8 +int revolutions = 2; // number of revoluations +int stepsToSwing = microSteps * stepsPerRevolution * revolutions; //number of steps to do +int motorRpm = 100; // motor speed + + +// stepper motor with 8 microstpesinitialized, pin D3, D4 are connected to the H bridge chip inputs, +// D1 (PWM_MOTOR_A) and D2 (PWM_MOTOR_B) are connected to the enable pin of the H bridge chip +Stepper myStepper(stepsPerRevolution, true, microSteps, DIR_MOTOR_A, DIR_MOTOR_B, PWM_MOTOR_A, PWM_MOTOR_B); + +// driving without microsteps +// DO NOT forget to adjust the number of steps to do, since there is no microstepping used. (microSteps = 1;) +//Stepper myStepper(stepsPerRevolution, D3, D4); + + +void setup() { + // Set the PWM/enable pins. + // Only needed in the case of full step drive. Not needed for microstep mode. + pinMode(PWM_MOTOR_A, OUTPUT); + pinMode(PWM_MOTOR_B, OUTPUT); + digitalWrite(PWM_MOTOR_A, HIGH); + digitalWrite(PWM_MOTOR_B, HIGH); + + // set the speed of the motor + myStepper.setSpeed(motorRpm); + // initialize the serial port: + Serial.begin(250000); +} + + +void loop() { + // Swing clockwise. + Serial.println("clockwise"); + myStepper.step(stepsToSwing); + myStepper.off(); + yield(); + delay(500); + yield(); + + Serial.println("counterclockwise"); + // Swing to the other direction. + myStepper.step(-stepsToSwing); + yield(); + myStepper.off(); + delay(500); + yield(); +} diff --git a/src/Stepper.cpp b/src/Stepper.cpp index 1f76295..785d7c4 100644 --- a/src/Stepper.cpp +++ b/src/Stepper.cpp @@ -1,5 +1,5 @@ /* - * Stepper.cpp - Stepper library for Wiring/Arduino - Version 1.1.0 + * Stepper.cpp - Stepper library for Wiring/Arduino - Version 1.2.0 * * Original library (0.1) by Tom Igoe. * Two-wire modifications (0.2) by Sebastian Gassner @@ -8,6 +8,7 @@ * High-speed stepping mod by Eugene Kozlenko * Timer rollover fix by Eugene Kozlenko * Five phase five wire (1.1.0) by Ryan Orendorff + * Microstepping on bipolar(1.2.0) by Attila Kovács * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -72,12 +73,36 @@ * * The circuits can be found at * - * http://www.arduino.cc/en/Tutorial/Stepper + * http://www.arduino.cc/en/Reference/Stepper */ #include "Arduino.h" #include "Stepper.h" + /* + * Setting the static members arrays to store the 1/2, 1/4, 1/8 microstepping sine, cosine tables + */ +int const Stepper::microstepping_1_2[4][2][2] = { + { { 0, 100 },{ 71, 71 } }, + { { 100, 0 },{ 71, -71 } }, + { { 0, -100 },{ -71, -71 } }, + { { -100, 0 },{ -71, 71 } } +}; + +int const Stepper::microstepping_1_4[4][4][2] = { + { { 0, 100 },{ 38, 92 },{ 71, 71 },{ 92, 38 } }, + { { 100, 0 },{ 92, -38 },{ 71, -71 },{ 38, -92 } }, + { { 0, -100 },{ -38, -92 },{ -71, -71 },{ -92, -38 } }, + { { -100, 0 },{ -92, 38 },{ -71, 71 },{ -38, 92 } } +}; + +int const Stepper::microstepping_1_8[4][8][2] = { + { { 0, 100 },{ 20, 98 },{ 38, 92 },{ 56, 83 },{ 71, 71 },{ 83, 56 },{ 92, 38 },{ 98, 20 }, }, + { { 100, 0 },{ 98, -20 },{ 92, -38 },{ 83, -56 },{ 71, -71 },{ 56, -83 },{ 38, -92 },{ 20, -98 } }, + { { -0, -100 },{ -20, -98 },{ -38, -92 },{ -56, -83 },{ -71, -71 },{ -83, -56 },{ -92, -38 },{ -98, -20 }, }, + { { -100, 0 },{ -98, 20 },{ -92, 38 },{ -83, 56 },{ -71, 71 },{ -56, 83 },{ -38, 92 },{ -20, 98 } } +}; + /* * two-wire constructor. * Sets which wires should control the motor. @@ -106,6 +131,48 @@ Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2) this->pin_count = 2; } +/* + * two-wire + PWM constructor + * Sets which wires should control the motor direction and PWM signals, + * number of steps per full rotation and the micro steps per step. + */ +Stepper::Stepper(int number_of_steps, bool micro_stepping, int number_of_micro_steps, + int motor_pin_1, int motor_pin_2, + int motor_pwm_pin_1, int motor_pwm_pin_2) +{ + this->step_number = 0; // which step the motor is on + this->direction = 0; // motor direction + this->last_step_time = 0; // time stamp in us of the last step taken + this->number_of_steps = number_of_steps; // total number of steps for this motor + + // Arduino pins for the motor control connection: + this->motor_pin_1 = motor_pin_1; + this->motor_pin_2 = motor_pin_2; + + // Pins for the PWM signals + this->motor_pwm_pin_1 = motor_pwm_pin_1; + this->motor_pwm_pin_2 = motor_pwm_pin_2; + + + // setup the pins on the microcontroller: + pinMode(this->motor_pin_1, OUTPUT); + pinMode(this->motor_pin_2, OUTPUT); + pinMode(this->motor_pwm_pin_1, OUTPUT); + pinMode(this->motor_pwm_pin_2, OUTPUT); + + // set microstepping mode + this->micro_stepping = micro_stepping; + this->number_of_micro_steps = number_of_micro_steps; + + // When there are only 2 pins, set the others to 0: + this->motor_pin_3 = 0; + this->motor_pin_4 = 0; + this->motor_pin_5 = 0; + + // pin_count is used by the stepMotor() method: + this->pin_count = 2; +} + /* * constructor for four-pin version @@ -138,6 +205,55 @@ Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, this->pin_count = 4; } + +/* +* four-wire + PWM constructor +* Sets which wires should control the motor direction and PWM signals, +* number of steps per full rotation and the micro steps per step. +*/ +Stepper::Stepper(int number_of_steps, bool micro_stepping, int number_of_micro_steps, + int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4, + int motor_pwm_pin_1, int motor_pwm_pin_2) +{ + this->step_number = 0; // which step the motor is on + this->direction = 0; // motor direction + this->last_step_time = 0; // time stamp in us of the last step taken + this->number_of_steps = number_of_steps; // total number of steps for this motor + + // Arduino pins for the motor control connection: + this->motor_pin_1 = motor_pin_1; + this->motor_pin_2 = motor_pin_2; + this->motor_pin_3 = motor_pin_3; + this->motor_pin_4 = motor_pin_4; + + // Pins for the PWM signals + this->motor_pwm_pin_1 = motor_pwm_pin_1; + this->motor_pwm_pin_2 = motor_pwm_pin_2; + + + // setup the pins on the microcontroller: + pinMode(this->motor_pin_1, OUTPUT); + pinMode(this->motor_pin_2, OUTPUT); + pinMode(this->motor_pin_3, OUTPUT); + pinMode(this->motor_pin_4, OUTPUT); + + pinMode(this->motor_pwm_pin_1, OUTPUT); + pinMode(this->motor_pwm_pin_2, OUTPUT); + + // set microstepping mode + this->micro_stepping = micro_stepping; + this->number_of_micro_steps = number_of_micro_steps; + + // When there are only 2 pins, set the others to 0: + this->motor_pin_3 = 0; + this->motor_pin_4 = 0; + this->motor_pin_5 = 0; + + // pin_count is used by the stepMotor() method: + this->pin_count = 2; +} + + /* * constructor for five phase motor with five wires * Sets which wires should control the motor. @@ -175,6 +291,13 @@ Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, void Stepper::setSpeed(long whatSpeed) { this->step_delay = 60L * 1000L * 1000L / this->number_of_steps / whatSpeed; + if (this->micro_stepping) { + this->micro_step_delay = step_delay / number_of_micro_steps; + // the PWM signal frqequency is proprtinal to the RPM + analogWriteFreq(whatSpeed * 100); + } + else + this->micro_step_delay = 0; } /* @@ -190,40 +313,156 @@ void Stepper::step(int steps_to_move) if (steps_to_move < 0) { this->direction = 0; } - // decrement the number of steps, moving one step each time: - while (steps_left > 0) + // if no microstepping is set + if (!this->micro_stepping) { - unsigned long now = micros(); - // move only if the appropriate delay has passed: - if (now - this->last_step_time >= this->step_delay) + // decrement the number of steps, moving one step each time: + while (steps_left > 0) { - // get the timeStamp of when you stepped: - this->last_step_time = now; - // increment or decrement the step number, - // depending on direction: - if (this->direction == 1) + unsigned long now = micros(); + // move only if the appropriate delay has passed: + if (now - this->last_step_time >= this->step_delay) { - this->step_number++; - if (this->step_number == this->number_of_steps) { - this->step_number = 0; + // get the timeStamp of when you stepped: + this->last_step_time = now; + // increment or decrement the step number, + // depending on direction: + if (this->direction == 1) + { + this->step_number++; + if (this->step_number == this->number_of_steps) { + this->step_number = 0; + } + } + else + { + if (this->step_number == 0) { + this->step_number = this->number_of_steps; + } + this->step_number--; } + // decrement the steps left: + steps_left--; + // step the motor to step number 0, 1, ..., {3 or 10} + if (this->pin_count == 5) + stepMotor(this->step_number % 10); + else + stepMotor(this->step_number % 4); } - else + } + } + + // if microstepping is used + else + { + // decrement the number of steps, moving one step each time: + while (steps_left > 0) + { + unsigned long now = micros(); + // move only if the appropriate delay has passed: + if (now - this->last_step_time >= this->micro_step_delay) { - if (this->step_number == 0) { - this->step_number = this->number_of_steps; + // get the timeStamp of when you stepped: + this->last_step_time = now; + + // increment or decrement the whole step number, + // depending on direction: + if (this->direction == 1) + { + this->micro_step_number++; + // if there is whole step + if (this->micro_step_number == this->number_of_micro_steps) { + this->step_number++; + if (this->step_number == this->number_of_steps) { + this->step_number = 0; + } + this->micro_step_number = 0; //there was a whole step, microstep is reset to 0 + } } - this->step_number--; + else + { + // if there is whole step + if (this->micro_step_number == 0) { + if (this->step_number == 0) { + this->step_number = this->number_of_steps; + } + this->step_number--; + this->micro_step_number = this->number_of_micro_steps; + } + this->micro_step_number--; + } + + // decrement the steps left: + + steps_left--; + + // step the motor to step number 0, 1, ..., {3 or 10} + if (this->pin_count == 2 || this->pin_count == 4) + microStepMotor(this->step_number % 4, this->micro_step_number); } - // decrement the steps left: - steps_left--; - // step the motor to step number 0, 1, ..., {3 or 10} - if (this->pin_count == 5) - stepMotor(this->step_number % 10); - else - stepMotor(this->step_number % 4); } - } + } +} + +/* +* Moves the motor forward or backwards in microsteps. +*/ +void Stepper::microStepMotor(int this_step, int this_micro_step) +{ + //yield() might be needed at slow RPM and/or many steps on an ESP8266 + //yield(); + int coil1value; + int coil2value; + + switch (this->number_of_micro_steps) { + case 2: + coil1value = microstepping_1_2[this_step][this_micro_step][0]; + coil2value = microstepping_1_2[this_step][this_micro_step][1]; + break; + case 4: + coil1value = microstepping_1_4[this_step][this_micro_step][0]; + coil2value = microstepping_1_4[this_step][this_micro_step][1]; + break; + case 8: + coil1value = microstepping_1_8[this_step][this_micro_step][0]; + coil2value = microstepping_1_8[this_step][this_micro_step][1]; + break; + } + + // set the correct PWM on the enable pin + analogWrite(motor_pwm_pin_1, (abs(coil1value) * PWMRANGE) / 100); + analogWrite(motor_pwm_pin_2, (abs(coil2value) * PWMRANGE) / 100); + + if (this->pin_count == 2) { + if (coil1value > 0) + digitalWrite(motor_pin_1, HIGH); + else + digitalWrite(motor_pin_1, LOW); + + if (coil2value > 0) + digitalWrite(motor_pin_2, HIGH); + else + digitalWrite(motor_pin_2, LOW); + } + else if (this->pin_count == 4) { + if (coil1value > 0) { + digitalWrite(motor_pin_1, HIGH); + digitalWrite(motor_pin_2, LOW); + } + else { + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, HIGH); + } + + if (coil2value > 0) { + digitalWrite(motor_pin_3, HIGH); + digitalWrite(motor_pin_4, LOW); + } + else { + digitalWrite(motor_pin_3, LOW); + digitalWrite(motor_pin_4, HIGH); + } + } } /* @@ -231,6 +470,8 @@ void Stepper::step(int steps_to_move) */ void Stepper::stepMotor(int thisStep) { + //yield() might be needed at slow RPM and/or many steps on an ESP8266 + //yield(); if (this->pin_count == 2) { switch (thisStep) { case 0: // 01 @@ -356,6 +597,37 @@ void Stepper::stepMotor(int thisStep) } } + +/* +off() turns of the motor by clearing motor pins to by clearing pwm/enable pins: +*/ +void Stepper::off(void) +{ + // if microstepping is used, the motor can be turned off by clearing the PWM pins (even in the case of 2 wire configuration) + if (this->micro_stepping) { + analogWrite(motor_pwm_pin_1, 0); + analogWrite(motor_pwm_pin_2, 0); + } + else if (this->pin_count == 2) { + //This is not possible with 2 wire configuration without using the PWM/enable pins. + //The two wire stepper (full step mode) should be initialized with the PWM pins, to be able to switch off the motor. + //Or using the microstepping mode, the PWM/enable pins are known. + } + else if (this->pin_count == 4) { + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, LOW); + digitalWrite(motor_pin_3, LOW); + digitalWrite(motor_pin_4, LOW); + } + else if (this->pin_count == 5) { + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, LOW); + digitalWrite(motor_pin_3, LOW); + digitalWrite(motor_pin_4, LOW); + digitalWrite(motor_pin_5, LOW); + } +} + /* version() returns the version of the library: */ diff --git a/src/Stepper.h b/src/Stepper.h index 2e68979..989c75a 100644 --- a/src/Stepper.h +++ b/src/Stepper.h @@ -1,5 +1,5 @@ /* - * Stepper.h - Stepper library for Wiring/Arduino - Version 1.1.0 + * Stepper.h - Stepper library for Wiring/Arduino - Version 1.2.0 * * Original library (0.1) by Tom Igoe. * Two-wire modifications (0.2) by Sebastian Gassner @@ -8,6 +8,7 @@ * High-speed stepping mod by Eugene Kozlenko * Timer rollover fix by Eugene Kozlenko * Five phase five wire (1.1.0) by Ryan Orendorff + * Microstepping on bipolar(1.2.0) by Attila Kovács * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -72,7 +73,7 @@ * * The circuits can be found at * - * http://www.arduino.cc/en/Tutorial/Stepper + * http://www.arduino.cc/en/Reference/Stepper */ // ensure this library description is only included once @@ -84,8 +85,14 @@ class Stepper { public: // constructors: Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2); + Stepper(int number_of_steps, bool micro_stepping, int micro_steps, + int motor_pin_1, int motor_pin_2, + int motor_pwm_pin_1, int motor_pwm_pin_2); Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4); + Stepper(int number_of_steps, bool micro_stepping, int number_of_micro_steps, + int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4, + int motor_pwm_pin_1, int motor_pwm_pin_2); Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4, int motor_pin_5); @@ -96,16 +103,24 @@ class Stepper { // mover method: void step(int number_of_steps); + // turns off the coils of the motor + void off(); + int version(void); private: void stepMotor(int this_step); + void microStepMotor(int this_step, int this_micro_step); int direction; // Direction of rotation unsigned long step_delay; // delay between steps, in ms, based on speed int number_of_steps; // total number of steps this motor can take int pin_count; // how many pins are in use. int step_number; // which step the motor is on + bool micro_stepping{ false }; //is microstepping enabled + int number_of_micro_steps; //holds the number of microsteps + int micro_step_number; // which micro step the motor is on + unsigned long micro_step_delay; //delay between microsteps // motor pin numbers: int motor_pin_1; @@ -114,8 +129,18 @@ class Stepper { int motor_pin_4; int motor_pin_5; // Only 5 phase motor + int motor_pwm_pin_1; + int motor_pwm_pin_2; + unsigned long last_step_time; // time stamp in us of when the last step was taken + + static int const microstepping_1_2 [4][2][2]; + + static int const microstepping_1_4 [4][4][2]; + + static int const microstepping_1_8 [4][8][2]; }; + #endif