Hello guys! I’m pretty new to arduino and code, I’m trying to make a stand-alone jog controller for my project, manual pulse generator / encoder
I’ve found some code and tried different approaches and it seems to be working pretty good,
The problem I’m having is=
I want the mpg handwheel (100p/r) to turn the stepper 1 revolution, and that works.
But then I wanted a switch/button to change the output pulses to double the jog speed,
This is the code the button will have to change
steps_per_pulse 4 (1rev) to
steps_per_pulse 8 (2rev)
It also works! But when I’m switching and starting to rotate the mpg the motor starts to spin uncontrollably for a few secounds at full speed and after that it works at set jog rate? It happens every time I switch
The code is probably not right at all! That’s why I’m asking for help, and maybe to learn something new!
#include <AccelStepper.h>
#define encoder_pin_A 8
#define encoder_pin_B 9
int encoder_pin_A_last = LOW;
int encoder_pos = 0;
int n = LOW;
/////////////////////////////////////////////////////////////////////
const int buttonPin = 2; // the number of the pushbutton pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
/////////////////////////////////////////////////////////////////////
#define stepper_pin_step 6
#define stepper_pin_dir 5
// Enc have 100 steps per revolution
// The motor have 400 steps per revolution
// Want: 1 encoder rev = 1 stepper rev
// 400 / 100 = 4...
float steps_per_pulse = 4;
AccelStepper stepper(AccelStepper::DRIVER, stepper_pin_step, stepper_pin_dir);
void setup() {
stepper.setMaxSpeed(3000.0);
stepper.setAcceleration(30000.0);
pinMode(encoder_pin_A, INPUT_PULLUP);
pinMode(encoder_pin_B, INPUT_PULLUP);
pinMode(buttonPin, INPUT);
}
void loop() {
// read encoder
n = digitalRead(encoder_pin_A);
if ((encoder_pin_A_last == LOW) && (n == HIGH)) {
if (digitalRead(encoder_pin_B) == LOW) {
encoder_pos--;
} else {
encoder_pos++;
}
// set stepper to the new calculated position
stepper.moveTo((long) round(encoder_pos*steps_per_pulse));
}
encoder_pin_A_last = n;
stepper.run();
////////////////////////////////////////////////////////////////////////
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
steps_per_pulse = 8;
} else {
steps_per_pulse = 4;
}
}
}
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
I can’t figure out why the motor spins at full speed without any encoder signal (buffer should be empty)
I only happens when I change state of the button, could be electromagnetic interference due to the motor/driver being that close to the wires/arduino but I doubt that,
Maybe add code for delay/pause when the state of the button changes? I cloud upload a video on YouTube or something and show it in action?
Without any signal connected..... That could very well be a great mistake. If You disconnect signals You need to connect those emptied pins to gnd, or Vcc. Leaving pins without a defined voltage level is really bad practise, asking for trouble.
Start using Serial monitor and serial.print in the code to tell what's going on inside there.
Yes it’s not a good practice having floating I/Os The A & B connections are always connected, but the encoder itself maybe doesn’t have pull up/down resistor built in, I’ll try a pull down/up resistor tied to both A-B (D8 - D9)
Know that Arduinos do take som time before executing Your code, after powered up or resetted. In order to avoid unintended action during that internal work measures might have to be taken.
No success, all the numbers shown in serial monitor seems to behave as expected,
Is counting but do never reset, in either way with or without pull-up it counts as I should,
I also tried to delete all existing code for the push button and edit in new code with delays and such without any success, same problem when changing the value while powered on,
I have just started playing with something similar to this and learning the Accelstepper functions.
My project is a self leveling plate function which is working really well, I set up my CW5045 controller to 250 microstepping for what I need.
This is the testing code that I've set up and using.
Hopefully you will get to understand it,
It give serial data out when enabled, Just change it to zero when when not needed.
You can change the step counter multiplier values (I've set mine to 1,10,50,100).
You just press the encoder button and it steps it up to 100 then back to 1.
There is a denounce function to take care of the encoder button.
When you turn the rotary encoder clockwise it increase the steps and moves the motor in the clockwise direction on each click and When you turn the rotary encoder anti-clockwise it decreases the steps and moves the motor in the anti- clockwise direction on each click
//AccelStepper
#include <AccelStepper.h>
#include <Rotary.h>
AccelStepper stepper(1, 8, 9);// direction Digital 9 (CCW), pulses Digital 8 (CLK)
#define stepPin3 3 // Set 'Step' rotary encoder pins, Interrupt pin 0 must be used
#define stepPin4 2 // Set 'Step' rotary encoder pins,Interrupt pin 1 must be used
#define ECHO_TO_SERIAL 1 //change to zero = no serial output
const int Step_multiyplier = 6; //SW pin on the rotary encoder (Button function)
//Defining variables
int ButtonCounter = 0;
volatile int RotateCounter = 0;
Rotary Volts_Rotary = Rotary(stepPin3, stepPin4);
//Statuses
int stepperRotarySteps; // This keeps track of the steps done with the rotary encoder
//###################
const byte Step_multipliers[] = { 1, 10, 50, 100 }; //This moves the stepper motor by 1,10,50,100
const byte stepCount = sizeof(Step_multipliers) / sizeof(Step_multipliers[0]); //holds the multipliers
volatile byte currentStep = 0;
//###########################################
//# PRINT DATA TO SERIAL MONITOR IF ENABLED #
//###########################################
void printRecord(Print* pr, char sep = ',') {
pr->print("STEP MULTUPLIER: "); // Print btye 0
pr->print(Step_multipliers[currentStep]);
pr->print(sep);
pr->print("STEPPING COUNTER: ");
pr->print(RotateCounter);
pr->println();
}
void setup()
{
Serial.begin(115200);
pinMode(stepPin3, INPUT_PULLUP); // Pins for step rotary encoder on analogue pins A2, A3
pinMode(stepPin4, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(stepPin3), Volts_encoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(stepPin4), Volts_encoder, CHANGE);
pinMode(Step_multiyplier, INPUT_PULLUP);
stepper.setMaxSpeed(1000); //SPEED = Steps / second
stepper.setAcceleration(500); //ACCELERATION = Steps /(second)^2
}
void loop()
{
#if ECHO_TO_SERIAL // Send debug to serial port if enabled
printRecord(&Serial); //Send the data to print function
#endif //ECHO_TO_SERIAL
Buttons() ; //Check the roatry encdoe button
RunTheMotor(); // run the motors
}
void RunTheMotor() //function for the motor
{
stepper.enableOutputs(); //enable pins
stepper.moveTo(RotateCounter); //-1 is to match the rotation of the encoder with the rotation of the stepper
while (stepper.distanceToGo() != 0)
{
stepper.runToNewPosition(RotateCounter);
}
}
void Volts_encoder() {
unsigned int result = Volts_Rotary.process();
///Rotary encoder 1 for setting the volts
if (result) {
if (result == DIR_CW) {
RotateCounter += Step_multipliers[currentStep] ;
} else {
RotateCounter -= Step_multipliers[currentStep] ;
}
}
}
void Buttons() {
#define buttonPressed LOW // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
uint32_t currentMillis = millis(); // Millis times uses to debounce the button
static uint32_t lastMillis; // Start of the debounce timeout
const uint32_t BOUNCETIMEOUT = 20; // Debounce time in milliseconds
bool currentButtonState = digitalRead(Step_multiyplier); // Reads the current state of the button and saves the result in a bool
static bool lastButtonState; // Holds the previous debounced state of the button
if (lastButtonState != currentButtonState) { // Checks to see if the button has been pressed or released, at this point the button has not been debounced
if (currentMillis - lastMillis >= BOUNCETIMEOUT) { // Checks to see if the state of the button has been stable for at least bounceTimeout duration
lastButtonState = currentButtonState; // At this point the button has been debounced, so save the last state
if (currentButtonState == buttonPressed) {
currentStep++;
if ( currentStep >= stepCount ) currentStep = 0;
}
}
} else {
lastMillis = currentMillis; // Saves the current value of millis in last millis so the debounce timer starts from current millis
}
}
You may have to play around with the pins depending on how yours is wired and change the speeds to suit yours.