How to smoothly run steppers and multiple inputs

So i have been working on a project using the Nano and stepper and servo motors which i think has naturally reached its limit. And would like to know how to develop my project further.

What im building can be thought of exactly like a 3d printer. And id like my project to run just as smoothly

The loop is just running too slowly now i have built my full circuit.

I have all digital inputs in use and a 74HC165 for 8 additional inputs that reads 8 push buttons.

I have two A4988 on nema 17s that i want to run at 1/16th step which i think is already far to many pulses for a arduino nano to cover while listening for buttons and controlling motors.

Then a 3rd SG90 servo for a small moving arm.

I have an LCD screen with I2C.

2 limit switches

I have no even tried sending it a plotting language design yet which i image will hugely tax the system converting it and running it.

So im wondering do i go on with arduino or should i start designing a custom microcontroller or find a off the shelf product i can still code.

I like the nano because they are easy to solder into circuit boards and then i can always update them and not waste the board. But could use a bigger one if that would work.

Can i just ramp up the baud rate to something high on a powerful board?

Maybe i can master slave some nanos and have one run the buttons and the other run the motors?

Sorry if this is not a great stack overflow question. Im just trying to get some ideas together to see how to evolve my project.

Thanks for any help.
Tom

I dont have a full code for it yet, i built all the components seperately and now am bringing them together, which is where i started to see the problem. So this is some basic test code im running but has my motors running poorly.

Code

include <Arduino.h>
#include <AccelStepper.h>
#include <Servo.h>

// Stepper motor connections
constexpr int dirPinMotorX = 2;
constexpr int stepPinMotorX = 3;
constexpr int dirPinMotorY = 4;
constexpr int stepPinMotorY = 5;

// Stepper motor configurations
AccelStepper stepperX(AccelStepper::DRIVER, stepPinMotorX, dirPinMotorX);
AccelStepper stepperY(AccelStepper::DRIVER, stepPinMotorY, dirPinMotorY);

// Define Connections to 74HC165
constexpr int shiftRegLoad = 8;
constexpr int shiftRegClockEnablePin = 7;
constexpr int shiftRegDataIn = 10;
constexpr int shiftRegClockIn = 9;

// Button binary codes on 74HC165
constexpr auto X_AXIS_BINARY = 0b11110111;
constexpr auto Y_AXIS_BINARY = 0b11111011;
constexpr auto START_X_MOTOR = 0b01111111;
constexpr auto START_Y_MOTOR = 0b10111111;
constexpr auto REVERSE_X_MOTOR = 0b11011111;
constexpr auto REVERSE_Y_MOTOR = 0b11101111;

// New button for manual mode
constexpr auto MANUAL_MODE = 0b11111110;  // Example bitmask, set your actual value

constexpr int enablePinMotorX = 11;  // Enable pin for X motor driver
// constexpr int enablePinMotorY = undefined;  // Enable pin for Y motor driver
// Servo setup
Servo sg90Servo;
constexpr int servoPin = 12;

// Variable to store the previous state of the inputs
byte previousState = 0;

void setup() {
  Serial.begin(9600);

  // Initialize stepper motors
  stepperX.setMaxSpeed(500);      // Reduced speed
  stepperX.setAcceleration(200);  // Reduced acceleration
  stepperY.setMaxSpeed(500);
  stepperY.setAcceleration(200);

  // Initialize 74HC165 pins
  pinMode(shiftRegLoad, OUTPUT);
  pinMode(shiftRegClockEnablePin, OUTPUT);
  pinMode(shiftRegClockIn, OUTPUT);
  pinMode(shiftRegDataIn, INPUT);

  // Initialize servo
  sg90Servo.attach(servoPin);
}

void loop() {
  // Read inputs from 74HC165
  digitalWrite(shiftRegLoad, LOW);
  delayMicroseconds(5);
  digitalWrite(shiftRegLoad, HIGH);
  delayMicroseconds(5);

  digitalWrite(shiftRegClockIn, HIGH);
  digitalWrite(shiftRegClockEnablePin, LOW);
  byte incoming = shiftIn(shiftRegDataIn, shiftRegClockIn, LSBFIRST);
  digitalWrite(shiftRegClockEnablePin, HIGH);

  // Handle manual mode toggle
  if (incoming == MANUAL_MODE) {
    Serial.println("HIT");
    static bool manualEnabled = false;
    manualEnabled = !manualEnabled;                             // Toggle state
    digitalWrite(enablePinMotorX, manualEnabled ? HIGH : LOW);  // Disable or enable X motor
    // digitalWrite(enablePinMotorY, manualEnabled ? HIGH : LOW);  // Disable or enable Y motor
  }

  // Control logic for stepper motors based on input
  if (incoming == X_AXIS_BINARY) {
    stepperX.stop();  // Stop X Axis Motor
  } else if (incoming == START_X_MOTOR) {
    stepperX.move(400);  // Move X motor 400 steps (adjust as needed)
  } else if (incoming == REVERSE_X_MOTOR) {
    stepperX.setSpeed(-stepperX.speed());  // Reverse X motor direction
  }

  if (incoming == Y_AXIS_BINARY) {
    stepperY.stop();  // Stop Y Axis Motor
  } else if (incoming == START_Y_MOTOR) {
    stepperY.move(400);  // Move Y motor 400 steps (adjust as needed)
  } else if (incoming == REVERSE_Y_MOTOR) {
    stepperY.setSpeed(-stepperY.speed());  // Reverse Y motor direction
  }

  // Execute stepper commands
  stepperX.run();  // Respects both speed and acceleration
  stepperY.run();

  // Rotate the servo back and forth between 0 and 180 degrees
  static bool direction = true;
  static unsigned long lastMoveTime = 0;

Are you ONLY displaying values when they change? Or are you displaying every time through loop()?

1 Like

Constantly displaying a running or % complete message on screen. The menu has options such as stop and pause. So i need to be able to run through it while the device is running.

Then that is certainly taking a lot of your loop() time. If you are serious about the time, then rework the logic right there.

1 Like

Thats why i was thinking a master slave set up, one to manage input and the other just to control the motors. I am very new to machine programming so i apologise im not very clear.

I think that way you will create more problems and difficulties for yourself instead of making your life easier.

What you want to do is not that easy, and I think it might be better instead of reinventing hot water is worth looking into a GRBL and possibly setting it up for your needs.

You should figure out where your code is spending most of your time.

Some folks toggle a pin at the beginning and end of portions of code and read the duty cycle of the pin to identify what is bogging down the system.

To my eye, it looks like you spend every loop reading the shift register and checking the buttons. I can't imagine needing human-button-pushing information at the microsecond-scale latency that loop() could possibly run, and I'd wrap that chunk in a BlinkWithoutDelay-like 'if (millis() - last >= interval){...}' to rate-limit the UI polling.

And yes, increase the baud rate to 115200 or more.

That is a very interesting idea!
I will look into it! I had not heard of that. I work for the people who own GPGL but we all hate it so i was half writing my own!

Im still concerned about a controller that can handle everything

Thank you for the info.
So glad you said increase the baud rate and not 'nooo thats a n00b move'
I will have a play around with what you suggest.

Master slaving i also had the same thought about. They still need to communicate and will interupt each other. And i get low transfer rates with my skills

Moving steppers smoothly with inputs is possible:

Big problems with smoothly running multiple steppers is moving them in coordination, especially with acceleration. The above sim doesn't do acceleration. But you could drive one controlling axis with acceleration and make the motions of the others dependent on steps on that axis.

GRBL and 3D Printers do acceleration and coordination well, and at high speed. Accelstepper does not.

I dont actually need acceleration. I need adjustable speed but not acceleration. Im a noob and read that this was just the best library.

Do you still believe the job can be done on a nano if done correctly?

Apparently it is possible - after all, GRBL does exactly that. But GRBL is written by people who are very good programmers and know the hardware very well in order to get the most out of it. Why not just use a GRBL that is ready and running and with options to adjust to your needs - just look on the internet to see what different machines are running powered by it.

1 Like

Depends on the job. I don't see that your code allocated hookups for the servo, other IO, I2c or limit switches.

There's a Nano GRBL shield that looks like it might have 9 pins left after two steppers with limit switches:

https://wiki.keyestudio.com/Ks0152_keyestudio_CNC_Shield_V4#Pinout_Instructions

If you've got enough IO pins for everything, and the speeds your job requires fit, a Nano can work.

The codes a bit basic but wont end up doing much more than running the code to move and stop and having a display screen.

That looks like a really decent shield. I will pick one up. Seems like i can get away with a nano if i am sensible

Good idea. Will start with it and then see what i need to modify.

I have upgraded to a mega just to make life easier

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.