Write code to control Steppers via DM542 with using EEPROM to memorise locations

Ok, I've got to the point where I need some help please.

I have put together code structure for controlling 2 axis stoppers via DM542 digital drivers with some added features.

all is not working as intended! except however, as you will see in the code, I need the Arduino UNO to store locations of both axis, when I get both axis independently move to a new location (by rolling the MPG encoder wheel) and store that location by pressing the store button and that should memories that location, I then move both axis to another new location and do the same again to store that location etc etc... (roughly around 5 locations or much the EEPROM can handle)

Once all that is done I then need to be able to move both axis together to a specific location where I previously stored in the Arduino's EEPROM, by pressing the previous and next buttons (ie; cycle through to find the location I need - depending on how many clicks up or down I need to go). Optionally, I don't want them to have automatic permissive, until a latching (ON / OFF) is engaged to give the 'previous' and 'next' buttons the permissive to function.

So far that is not what's happening.

just to put other things in the mix, there are other functions to the code that is actually working now.

ie: Home button / E-stop / MPG activate & de-activate.

# Home button - first ever press on the store button soon after Arduino reset, I need it to be default 'home' position. every time the home button = pin 10 is pressed there after, I need both axis to move to that first ever stored position, so EEPROM to store and remember this location until a next Arduino reset. (that works OK)

# Store button - needs to store current locations of both axis, as they are moved by MPG wheel to their new locations and this button on pin 12 is high by pressing it. this should store up to 5 different locations (or however many EEPROM Can handle) for both axis, besides initial home location. so EEPROM needs store and remember this location until called upon by 'next' & 'prev' buttons.

# Recall Button - on pin 13, is a latching switch that when activated should enable the access to EEPROM's five different stored locations. This should be latched (when HIGH) to give permissive for either next or prev buttons (or Pins 0 & 1), without the Recall button being activated, any accidental press on the Prev or Next buttons (when Recall pin LOW) will be dormant when pressed.

# Next button - by user pressing the 'nextButton' on pin 0 , that action should select up (cycle up) stored locations. each press should count up to 5 consecutive locations (or whatever the amount that EERPOM can store).

# Prev button - by user pressing the 'prevButton' on pin 1 , that action should select down (cycle down) stored locations. each press should count down to 5 consecutive locations.(or whatever the amount that EERPOM can store).

So the pushbutton wire connections to Arduino pins are on an external pull up resister architecture;

One end of the switch button is connected to a 10Kohm resister that is supplied from 5V supply and the other end of the resister is connected to Arduino pin (as shown in the diagram) the other End of the Switch Connected to Ground: When the switch is closed (pressed), it connects the input pin directly to ground, pulling the pin to a LOW state (0V). This change in state from HIGH to LOW is what the microcontroller detects as the switch being activated.

So, the actual problem I am having is that when I press the store button to store it seems to move to home location or where ever the last location, not sure it actually store the locations. Also, the recall/previous/next options aren't working at all!!

can anyone help please?

Thanks.

It would be appreciared if you were to post your code properly as requested in the how to get the best from the forum post.

should I just paste in my code? rather rather than attachment?

Its a 298 line code, so thought it would be best to attach it rather than pasting it in.

It is easier to copy the code to paste into the
IDE or a text editor if posted as requested in the get the best from the forum post. Using the attachment makes more work for potential helpers.

                                            
#include <AccelStepper.h>
#include <EEPROM.h>
#include <Bounce2.h>

#define encoder_pin_A 8
#define encoder_pin_B 9
int encoder_pin_A_last = LOW;
float encoder_pos = 0;
int n = LOW;

const int buttonPin = 12;          
const int homeButton = 10;         
const int recallButton = 13;       
const int nextButton = 0;          
const int prevButton = 1;          
const int mpgSwitchPin = A5;       
const int axisSelectionBPin = A0;  
const int axisSelectionCPin = A1;  
const int estopButtonPin = 11;    

int buttonState;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

#define B_axis_pin_step 2
#define B_axis_pin_dir  3
#define B_axis_pin_Enable 4
AccelStepper B_axis(AccelStepper::DRIVER, B_axis_pin_step, B_axis_pin_dir);
float steps_per_pulse_B_axis = 12;
int stored_positions_B_axis[6] = {0, 0, 0, 0, 0, 0};  // Increased size to store up to 5 positions
int currentPositionIndex_B_axis = 0;

#define C_axis_pin_step 5
#define C_axis_pin_dir  6
#define c_axis_pin_Enable 7
AccelStepper C_axis(AccelStepper::DRIVER, C_axis_pin_step, C_axis_pin_dir);
float steps_per_pulse_C_axis = 12;
int stored_positions_C_axis[6] = {0, 0, 0, 0, 0, 0};  // Increased size to store up to 5 positions
int currentPositionIndex_C_axis = 0;

bool mpgActive = false;  
bool estopActive = false;  

const int speedSelectPinX1 = A2;  
const int speedSelectPinX10 = A3;  
const int speedSelectPinX100 = A4;  

void reduceMotorCurrent(AccelStepper& stepper) 
{
  // Reduce motor current to a lower value during idle
  stepper.disableOutputs();
}

void storeCurrentPositions() 
{
    // Store the current positions in EEPROM
    EEPROM.put(0 * sizeof(int), stored_positions_B_axis);
    EEPROM.put(1 * sizeof(int), stored_positions_C_axis);
}

void setup() 
{
  B_axis.setMaxSpeed(3000.0);
  B_axis.setAcceleration(4000.0);

  C_axis.setMaxSpeed(3000.0);
  C_axis.setAcceleration(4000.0);

  pinMode(encoder_pin_A, INPUT_PULLUP);
  pinMode(encoder_pin_B, INPUT_PULLUP);
  pinMode(buttonPin, INPUT);
  pinMode(homeButton, INPUT_PULLUP);
  pinMode(recallButton, INPUT_PULLUP);
  pinMode(nextButton, INPUT_PULLUP);
  pinMode(prevButton, INPUT_PULLUP);
  pinMode(mpgSwitchPin, INPUT_PULLUP);
  pinMode(axisSelectionBPin, INPUT_PULLUP);
  pinMode(axisSelectionCPin, INPUT_PULLUP);
  pinMode(estopButtonPin, INPUT_PULLUP);
  pinMode(speedSelectPinX1, INPUT_PULLUP);
  pinMode(speedSelectPinX10, INPUT_PULLUP);
  pinMode(speedSelectPinX100, INPUT_PULLUP);

  // Load the initial home positions from EEPROM
  EEPROM.get(0 * sizeof(int), stored_positions_B_axis[0]);
  EEPROM.get(1 * sizeof(int), stored_positions_C_axis[0]);
}

void loop() 
{
    // Read the current state of the e-stop button
    bool estopPressed = digitalRead(estopButtonPin) == HIGH;

    // Check if E-stop is pressed and already active
    if (estopPressed && estopActive) 
    {
        // E-stop is pressed and already active, do nothing
    } 
    // Check if E-stop is not pressed and currently not active
    else if (!estopPressed && estopActive) 
    {
        // E-stop has been released, deactivate e-stop condition
        estopActive = false;
        
        // Re-enable outputs to resume operation
        B_axis.enableOutputs();
        C_axis.enableOutputs();
        
        // Here, you may need to set the desired position or speed
        // as the motors were stopped and disabled
    }
    // Check if E-stop is pressed and not already active
    else if (estopPressed && !estopActive) 
    {
        // E-stop has been pressed, activate e-stop condition
        estopActive = true;
        
        // Immediately stop the motors
        B_axis.stop(); 
        C_axis.stop(); 
        
        // Optionally, disable outputs for power saving
        B_axis.disableOutputs(); 
        C_axis.disableOutputs();
    }

    // Include other operational logic here, ensuring it's only executed if !estopActive
    if (!estopActive) 
    {
        // Existing code for motor control, button handling, etc.
        // Ensure this code executes only when E-stop is not active

        // Read encoder input for MPG functionality
        int reading = digitalRead(buttonPin);
        n = digitalRead(encoder_pin_A);

        float speedMultiplier = 1.0;   // Declare speedMultiplier here

        if ((encoder_pin_A_last == LOW) && (n == HIGH)) 
        {
            if (digitalRead(encoder_pin_B) == LOW) 
            {
                encoder_pos -= steps_per_pulse_B_axis;
            } 
			else 
            {
                encoder_pos += steps_per_pulse_B_axis;
            }

            if (mpgActive) 
            {
                if (digitalRead(axisSelectionBPin) == HIGH) 
                {
                    if (digitalRead(mpgSwitchPin) == HIGH) 
                    {
                        B_axis.moveTo((long)round(encoder_pos));
                    }
                } else if (digitalRead(axisSelectionCPin) == HIGH) 
                {
                    if (digitalRead(mpgSwitchPin) == HIGH) 
                    {
                        C_axis.moveTo((long)round(encoder_pos));
                    }
                }
            }
        }

        // Check if the motors are not moving and reduce current
        if (!B_axis.isRunning() && !C_axis.isRunning()) 
        {
            reduceMotorCurrent(B_axis);
            reduceMotorCurrent(C_axis);
        }

        encoder_pin_A_last = n;

        B_axis.run();
        C_axis.run();

        if (reading != lastButtonState) 
        {
            lastDebounceTime = millis();
        }

        if ((millis() - lastDebounceTime) > debounceDelay) 
        {
            if (reading != buttonState) 
            {
                buttonState = reading;

                if (buttonState == HIGH) 
                {
                    // Save the current position when the store button is pressed
                    stored_positions_B_axis[currentPositionIndex_B_axis] = B_axis.currentPosition();
                    stored_positions_C_axis[currentPositionIndex_C_axis] = C_axis.currentPosition();
                    storeCurrentPositions();
                } 
                else 
                {
                    // Move both steppers back to the stored positions when the button is released
                    B_axis.moveTo(stored_positions_B_axis[currentPositionIndex_B_axis]);
                    C_axis.moveTo(stored_positions_C_axis[currentPositionIndex_C_axis]);
                }
            }
        }

        if (buttonState == HIGH && lastButtonState == LOW) 
        {
            // Increment position index on each press after reset
            currentPositionIndex_B_axis = (currentPositionIndex_B_axis + 1) % 6;
            currentPositionIndex_C_axis = (currentPositionIndex_C_axis + 1) % 6;
        }

        // Call handleButton() function for each button
        handleButton(homeButton, B_axis, C_axis, stored_positions_B_axis, stored_positions_C_axis, currentPositionIndex_B_axis, currentPositionIndex_C_axis, 0);
        handleButton(recallButton, B_axis, C_axis, stored_positions_B_axis, stored_positions_C_axis, currentPositionIndex_B_axis, currentPositionIndex_C_axis, -1);
        handleButton(nextButton, B_axis, C_axis, stored_positions_B_axis, stored_positions_C_axis, currentPositionIndex_B_axis, currentPositionIndex_C_axis, 1);
        handleButton(prevButton, B_axis, C_axis, stored_positions_B_axis, stored_positions_C_axis, currentPositionIndex_B_axis, currentPositionIndex_C_axis, -1);
    
        // Toggle MPG activation when the button is pressed
        if (digitalRead(mpgSwitchPin) == HIGH) 
        {
            // Activate MPG functionality
            mpgActive = true;
        } 
        else 
        {
            // Deactivate MPG functionality
            mpgActive = false;
        }

        lastButtonState = reading;

        if (digitalRead(speedSelectPinX1) == LOW) 
        {
            speedMultiplier = 1.0;
        } 
        else if (digitalRead(speedSelectPinX10) == LOW) 
        {
            speedMultiplier = 10.0;
        } 
        else if (digitalRead(speedSelectPinX100) == LOW) 
        {
            speedMultiplier = 100.0;
        }

        B_axis.setMaxSpeed(3000.0 * speedMultiplier);
        B_axis.setAcceleration(4000.0 * speedMultiplier);

        C_axis.setMaxSpeed(3000.0 * speedMultiplier);
        C_axis.setAcceleration(4000.0 * speedMultiplier);
    }
}

void handleButton(int button, AccelStepper& stepperB, AccelStepper& stepperC, int storedPositionsB[], int storedPositionsC[], int& currentIndexB, int& currentIndexC, int indexChange) 
{
    int buttonReading = digitalRead(button);

    if (buttonReading != HIGH) 
    {
        //delay(50);
        if (digitalRead(button) != HIGH) 
        {
            if (button == homeButton) 
            {
                // Move both steppers to the initial home position
                stepperB.moveTo(storedPositionsB[0]);
                stepperC.moveTo(storedPositionsC[0]);
            } 
            else if (button == recallButton) 
            {
                // Recall the stored positions
                stepperB.moveTo(storedPositionsB[currentIndexB]);
                stepperC.moveTo(storedPositionsC[currentIndexC]);
            } 
            else if (button == nextButton || button == prevButton) 
            {
                // Allow cycling through stored positions
                if (digitalRead(recallButton) == HIGH) 
                {
                    if (button == nextButton) 
                    {
                        currentIndexB = (currentIndexB + indexChange) % 6;
                        currentIndexC = (currentIndexC + indexChange) % 6;
                    } 
                    else if (button == prevButton) 
                    {
                        currentIndexB = (currentIndexB + 6 + indexChange) % 6;
                        currentIndexC = (currentIndexC + 6 + indexChange) % 6;
                    }
                }
            }
        }
    }
}

First of all, don't use pins 0 and 1 on an UNO as they are used for uploading and debugging with Serial.

yeah, I am aware of that, it may not be good practice, however, I am using UNO and not MEGA or not really wanting to go down the road to using Shift registers chips MCP23S17 or the MCP23017 to get extra pins. as you can see, I was rapidly diminishing available pins to use.

But it makes it really hard to debug your code.

You will never store more than one position pair. With every call of 'storeCurrentPositions' the previous values will be overridden. And apart from setup() I don't see that you ever read them back.

And I don't see any homing of your steppers with a reference switch to move them to a known mechanical position ( reference point ) at startup.

Ah....ok. I think I am seeing that, it does seems to overriding my previous positions every time a 3rd one being stored.

The Prev & Next (pins 1 & 0 aren't really seeing the input!) I have called those pins to set as digital pins.

This can't be an EEPROM issue, is it? how do I solve that?

No, it's an issue of your code. You must create an index for your positions and calculate a corresponding EEPROM address when saving

N.B. Positions are long, not int.

These pins are internally connected to the serial-USB converter on the board via an 1K resistor. That obviously conflicts with your inputs. As already mentioned, it's not a good idea to use them ...

Ok yes, I see it, that makes sense. I will try modifying the code for that.

ah...damn, OK, what would be your suggestion?

There are various options:

  • Put your buttons into a matrix.
  • Use a port expander board, e.g. with I2C or SPI.
  • Use a Leonardo ( where pins 0 and 1 can be freely used )
  • Use a Mega with much more IO

N.B. Your code is very cluttered. You should tidy it up. The switch - case statement would be very suitable for your different operating modes.

Putting the buttons into a matrix sounds good, for now. I will look at other options you've mentioned. If I can solve it with Matrix options, that would be great.

so, how would I go about doing that, putting the buttons into matrix?

So, I've tried this code mod...... it seems to gives me more storing options, but, can't really tell.
can you suggest anything please?


void storeCurrentPositions() 
{
    // Store the current positions in EEPROM
    for (int i = 0; i < 6; i++) 
{
        EEPROM.put(i * sizeof(long), stored_positions_B_axis[i]);
        EEPROM.put((i + 6) * sizeof(long), stored_positions_C_axis[i]);
    }
}

void homeStepper(AccelStepper& stepper, int homePin) 
{
    stepper.setMaxSpeed(1000); // Adjust speed as needed for homing
    stepper.setAcceleration(500); // Adjust acceleration as needed for homing
    stepper.setCurrentPosition(0);
    while (digitalRead(homePin) == HIGH) 
{
        stepper.moveTo(-1);
        stepper.run();
    }
    stepper.setCurrentPosition(0);
    stepper.moveTo(0);
    while (stepper.distanceToGo() != 0) {
        stepper.run();
    }
}

void setup() 
{
    // Motor setup code...

    // Load the initial home positions from EEPROM
    for (int i = 0; i < 6; i++) 
{
        EEPROM.get(i * sizeof(long), stored_positions_B_axis[i]);
        EEPROM.get((i + 6) * sizeof(long), stored_positions_C_axis[i]);
    }

    // Homing both steppers
    homeStepper(B_axis, homeButton);
    homeStepper(C_axis, homeButton);
}

its Ok, no worries......

I've just seen this post: which explains how to do button matrix

Looks good. But do you need to store all positions with every call? At least I would prefer tu use .update instead of .put. .update only writes to the EEPROM if the value has really changed.

Is there really the same home switch for both steppers? How will that work?
N.B. your homeStepper will not work that way:

[Edit]: Maybe it's more easy to switch from AccelStepper to the MoToStepper class of the MobaTools library. MobaTools als contains a class to read/evaluate and debouce buttons - even if they are arranged in a matrix.

just looking at the button matrix set up, how would you designate each buttons to on pin? the diodes are only stopping the forward voltage drops, but they won't decide the pin designation!