I want speed control for my stepper motors and found a great little sketch by Ground Fungus that works very well. Here it is, with my numbers:
include <AccelStepper.h>
// change pins to match your setup. enable pin just for my CNC shield
const byte stepPin = 10;
const byte dirPin = 11;
const byte potPin = A0;
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
void setup()
{
Serial.begin(115200);
// pinMode(enablePin, OUTPUT); // for CNC shield
// digitalWrite(enablePin, LOW); // enable stepper(s)
stepper.setMaxSpeed(2000);
stepper.setAcceleration(1000);
stepper.setSpeed(0);
}
void loop()
{
int potValue = analogRead(potPin);
Serial.println(potValue);
//if (potValue >= 487 && potValue <= 537) // ±25 hysteresis for center (0 speed)
if (potValue >= 450 && potValue <= 500) // ±25 hysteresis for center (0 speed)
{
stepper.setSpeed(0);
}
else if (potValue < 450)//487
{
stepper.setSpeed((450- potValue) * 10); // your choice of multiplier
}
else if(potValue > 500)//537
{
stepper.setSpeed((500 - potValue) * 10); // your choice of multiplier
}
stepper.runSpeed();
}
When I put the exact same code in MY program the stepper jitters and shakes and has no speed control whatsover and even reverses. The motor runs very smooth and stops at center of the pot as it should in the SIMPLE program. I commented out much of the code that I thought may be interfering, but it still doesn't work. Any ideas? Timing issue? It's running in an UNO. The rotary encoder stuff works when it's not commented out. (I'm using interrupts and rotary encoders for another function.) MY code is here:
//#include <XP_Button.h> //this library controls state logic, debounce, pullup resistor use
#include <Wire.h>
//#include <Stepper.h>
#include <AccelStepper.h>
#include <LiquidCrystal_I2C.h>
//*******************DisplayNoDelay defs
long previousLCDMillis = 0; // for LCD screen update
long lcdInterval = 2000;
int screen = 0;
int screenMax = 3;
bool screenChanged = true;
//*********************
const int stepPin1 = 10; // All these pins for FE V2.0 Stepper driver shield, arranged for simple PCB layout
const int dirPin1 = 11; //low is one direction, high is other direction
const int stepPin2 = 8; //all pins are constant: they do not change
const int dirPin2 = 9;
const int stepsPerRevolution = 200;
#define STEPS 200 //may not need
#define motorInterfaceType 1 //may not need
int Pot1 = 0; //variable, not constant
int Pot2 = 0;
int x = 0;
int speedlcd1, speedlcd2, speedDelay1, speedDelay2;
volatile boolean TurnDetected1; // need volatile for Interrupts
volatile boolean TurnDetected2;
volatile boolean rotationdirection; // CW or CCW rotation
// Rotary Encoder Module connections
const int
CLK1(2), // Generating interrupts using CLK signal from rotary encoder Interrupt 0
CLK2(3), // Generating interrupts using CLK signal from rotary encoder Interrupt 1
DT1(4), // Reading DT signal data from rotary encoder 1
DT2(6); // Reading DT signal
const byte
RotaryPB1(5), //not used at this time. This is rotary encoder PB Not used for jog which is controlled by interrupts
RotaryPB2(7), //rotary encoder PB
LED1(12),
LED2(13);
//Button RPB1(RotaryPB1);
//Button RPB2(RotaryPB2);
bool tog1 = 0; // Jog/Continuous switch H=continuous, L=default jog
bool tog2 = 0;
int StepperPosition = 0; // To store Stepper Motor Position
int StepsToTake = 25; // Controls the step taken when turning encoder 50/200*360=90 degrees 25/200*360=45 degrees
int direction; // Variable to set Rotation (CW-CCW) of stepper
LiquidCrystal_I2C lcd(0x27, 16, 2); //default for 2x16 LCD
AccelStepper stepper1(AccelStepper::DRIVER, stepPin1, dirPin1);
/************************ Interrupt detection for both encoders *************/
void rotarydetect1() {
delay(4); // delay for Debouncing
if (digitalRead(CLK1))
rotationdirection = digitalRead(DT1);
else
rotationdirection = !digitalRead(DT1);
TurnDetected1 = true; // this is the flag that is set if there was an interrupt. Flag is tested in Loop function.
} //END isr0
void rotarydetect2() {
delay(4); // delay for Debouncing
if (digitalRead(CLK2))
rotationdirection = digitalRead(DT2);
else
rotationdirection = !digitalRead(DT2);
TurnDetected2 = true;
} //end ISR1
/*************************SETUP*****************************/
void setup() {
stepper1.setMaxSpeed(2000);
stepper1.setAcceleration(1000);
stepper1.setSpeed(0);
//RPB1.begin(); //initialize pushbuttons, in XP_button library function
//RPB2.begin();
Serial.begin(19200);
Wire.begin();
lcd.begin(16, 2);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
//pinMode(RotaryPB1, INPUT);
// pinMode(RotaryPB2, INPUT);
//A4988 stepper driver
pinMode(stepPin1, OUTPUT);
pinMode(dirPin1, OUTPUT);
pinMode(stepPin2, OUTPUT);
pinMode(dirPin2, OUTPUT);
pinMode(tog1, INPUT);
pinMode(tog2, INPUT);
//************rotary encoder***********
pinMode(CLK1, INPUT);
pinMode(DT1, INPUT);
pinMode(CLK2, INPUT);
pinMode(DT2, INPUT);
showWelcome(); //Display Welcome (FE) message
// attachInterrupt(0, rotarydetect1, FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO
// attachInterrupt(1, rotarydetect2, FALLING); // interrupt 1 connected to pin 3
} //end Setup function
/***********************Loop Function***********************************/
void loop() {
/* unsigned long currentLCDMillis = millis();
if (currentLCDMillis - previousLCDMillis > lcdInterval) // save the last time you changed the display
{
previousLCDMillis = currentLCDMillis;
screen++;
if (screen > screenMax) screen = 0; // all screens done? => start over
screenChanged = true;
if (screenChanged) // -- only update the screen if the screen is changed.
{
screenChanged = false; // reset for next iteration
switch (screen) {
// case Speed:
lcdSpeed();
break;
// case DirFor:
lcdDirFor();
break;
// case DirRev:
lcdDirRev();
break;
default:
// cannot happen -> showError() ?
break;
}
}
}
*/
/*static bool ledState1;
static bool ledState2;
RPB1.read(); //read state of rotary pushbutton
RPB2.read();
*/
Pot1 = analogRead(A0); //read value of pot for motor 1
Pot2 = analogRead(A1);
tog1 = digitalRead(17); //read switch to determine mode
tog2 = digitalRead(16);
/*if (tog1) {
digitalWrite(LED1, HIGH);
// backforth1();
SpeedM1();
} else if (!tog1) {
digitalWrite(LED1, LOW);
}
if (tog2) {
digitalWrite(LED2, HIGH);
//backforth2();//works when switched
SpeedM2();
} else if (!tog2) {
digitalWrite(LED2, LOW);
}
*/
// Midpoint pot control from Forum
int potValue1 = analogRead(Pot1);
Serial.print("Pot1= ");
Serial.println(potValue1);
if (potValue1 >= 450 && potValue1 <= 500) // ±25 hysteresis for center (0 speed)
{
stepper1.setSpeed(0);
} else if (potValue1 < 450) {
stepper1.setSpeed((450 - potValue1) * 10); // your choice of multiplier
} else if (potValue1 > 500) {
stepper1.setSpeed((500 - potValue1) * 10); // your choice of multiplier
}
stepper1.runSpeed();
/*
//If rotation detected the ISR reads the switch and sets the TurnDetected1 flag to TRUE
// and also sets rotation direction. Was controlled turned? Which one? What direction?
if (TurnDetected1) {
TurnDetected1 = false; // do NOT repeat IF loop until new rotation detected
// Which direction to move Stepper motor
if (rotationdirection) { // Move motor CCW
digitalWrite(dirPin1, HIGH); // (HIGH = anti-clockwise / LOW = clockwise)
for (int x = 1; x < StepsToTake; x++) {
digitalWrite(stepPin1, HIGH);
delay(1);
digitalWrite(stepPin1, LOW);
delay(1);
} //end for
StepperPosition = StepperPosition - StepsToTake;
} //end if
if (!rotationdirection) { // Move motor CW
digitalWrite(dirPin1, LOW); // (HIGH = anti-clockwise / LOW = clockwise)
for (int x = 1; x < StepsToTake; x++) {
digitalWrite(stepPin1, HIGH);
delay(1);
digitalWrite(stepPin1, LOW);
delay(1);
} //end for
StepperPosition = StepperPosition + StepsToTake;
} //end if
} //end if TurnDetected1
//Runs if rotation was detected which triggers the interrupt TUNEDETECTED2
if (TurnDetected2) {
TurnDetected2 = false; // do NOT repeat IF loop until new rotation detected
// Which direction to move Stepper motor
if (rotationdirection) { // Move motor CCW
digitalWrite(dirPin2, HIGH); // (HIGH = anti-clockwise / LOW = clockwise)
for (int x = 1; x < StepsToTake; x++) {
digitalWrite(stepPin2, HIGH);
delay(1);
digitalWrite(stepPin2, LOW);
delay(1);
} //end for
StepperPosition = StepperPosition - StepsToTake;
} //end if
if (!rotationdirection) { // Move motor CW
digitalWrite(dirPin2, LOW); // (HIGH = anti-clockwise / LOW = clockwise)
for (int x = 1; x < StepsToTake; x++) {
digitalWrite(stepPin2, HIGH);
delay(1);
digitalWrite(stepPin2, LOW);
delay(1);
} //end for
StepperPosition = StepperPosition + StepsToTake;
} //end if
} //end if TurnDetected2
*/
} //end of loop function
/***********************M1 and M2 Variable Speed******************************************/
void SpeedM1() {
speedDelay1 = map(Pot1, 0, 1023, 0, 800); //higher value for speed delay= faster
digitalWrite(stepPin1, HIGH);
delayMicroseconds(speedDelay1);
digitalWrite(stepPin1, LOW);
delayMicroseconds(speedDelay1);
}
void SpeedM2() {
speedDelay2 = map(Pot2, 0, 1023, 0, 800);
digitalWrite(stepPin2, HIGH);
delayMicroseconds(speedDelay2);
digitalWrite(stepPin2, LOW);
delayMicroseconds(speedDelay2);
}
/**********************LCD functions*******************/
void showWelcome() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("FoundEngineering");
lcd.setCursor(0, 1);
lcd.print("IndianHarbour NS");
delay(3000);
lcd.setCursor(0, 0);
lcd.print("Starting Up ");
lcd.setCursor(0, 1);
lcd.print(" Running ");
// delay(1000);
//lcd.clear();
}
void lcdSpeed() {
lcd.clear();
speedlcd1 = map(analogRead(Pot1), 0, 1023, 0, 100);
lcd.setCursor(0, 0);
lcd.print("Speed M1 = ");
lcd.print(speedlcd1); // convert to RPM
speedlcd2 = map(analogRead(Pot2), 0, 1023, 0, 100);
lcd.setCursor(0, 1);
lcd.print("Speed M2 = ");
lcd.print(speedlcd2);
}
void lcdPosDeg() {
lcd.clear(); //from Dejan
lcd.print("Position: ");
// lcd.print(int(angle*(-1.8)));
lcd.print("deg");
lcd.setCursor(0, 0);
}
void lcdDirFor() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Forward");
}
void lcdDirRev() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Forward ");
}
/*******************M1 Forward/Reverse***********************/
void backforth1() {
digitalWrite(dirPin1, HIGH);
lcdDirFor();
for (int x = 0; x < 1600; x++) {
digitalWrite(stepPin1, HIGH);
delayMicroseconds(500);
digitalWrite(stepPin1, LOW);
delayMicroseconds(500);
} //end for loop
delay(1000); //delay to turnaround and go the other direction
digitalWrite(dirPin1, LOW);
lcdDirRev();
for (int x = 0; x < 1600; x++) {
digitalWrite(stepPin1, HIGH);
delayMicroseconds(500);
digitalWrite(stepPin1, LOW);
delayMicroseconds(500);
} //end of for loop
digitalWrite(LED1, LOW);
delay(1000);
} //end backforth1 function
/*******************M2 Forward/Reverse***********************/
void backforth2() {
digitalWrite(dirPin2, HIGH);
lcdDirFor();
for (int x = 0; x < 1600; x++) {
digitalWrite(stepPin2, HIGH);
delayMicroseconds(500);
digitalWrite(stepPin2, LOW);
lcdDirRev();
delayMicroseconds(500);
} //end for loop
delay(1000);
digitalWrite(dirPin2, LOW);
lcdDirRev();
for (int x = 0; x < 1600; x++) {
digitalWrite(stepPin2, HIGH);
delayMicroseconds(500);
digitalWrite(stepPin2, LOW);
delayMicroseconds(500);
} //end of for loop
digitalWrite(LED2, LOW);
delay(1000);
} //end backforth2 function