Coding Troubles for Multiple Stepper Motors using Joystick Control

Hi!
I’m working on a project to use multiple stepper motors to move a gantry using joysticks in multiple axis (X, Y, Z, and a rotation). I am using an Arduino Mega 2560 and TB6600 Stepper Motors for this project for reference. I am also using both the AccelStepper and MultiStepper header files.

Currently, I am trying to use 1 joystick(3-axis joystick, with X, Y, and a rotation) to move two individual stepper motors. So in a sense, I’m using it to move in the “X” and “Y” planes. After multiple failed attempts, I came across the YouTube channel, Brainy-Bits, who provided what I thought I needed to move the gantry with the joystick. Here is the video:Arduino Stepper 2 Axis Camera Slider - Set IN and OUT points using a Joystick - Tutorial Part 2 - YouTube

Based on that video, I created this code:

#include <AccelStepper.h>
#include <MultiStepper.h>

AccelStepper X(1, 22, 26);
AccelStepper Y(1, 28, 32);


MultiStepper StepperControl;

//joystick set up
int X_Pin = A0; //analog pin for X
int Y_Pin = A1;


int JoyX =0;
int JoyY =0;

long joystep_x = 0;
long joystep_y = 0;


void setup() {
  X.setEnablePin(24);
  Y.setEnablePin(30);
  
  
  X.setMaxSpeed(50000);
  X.setAcceleration(50000.0);
  X.enableOutputs();
  
  Y.setMaxSpeed(50000);
  Y.setAcceleration(50000.0);
  Y.enableOutputs();

  
  StepperControl.addStepper(X);
  StepperControl.addStepper(Y);

  pinMode (X_Pin, INPUT);
  pinMode (Y_Pin, INPUT);
}

void loop() {
  JoyX = analogRead(X_Pin);
  JoyY = analogRead(Y_Pin);
  
  if(JoyX < 450){
    joystep_x = X.currentPosition();
    joystep_x = joystep_x -20;
  }
  if(JoyX > 550){
    joystep_x = X.currentPosition();
    joystep_x = joystep_x +20;
  }
  if(JoyY < 450){
    joystep_y = Y.currentPosition();
    joystep_y = joystep_y -20;
  }
  if(JoyY > 550){
    joystep_y = Y.currentPosition();
    joystep_y = joystep_y +20;
  }

  X.moveTo(joystep_x);
  Y.moveTo(joystep_y); 

  while ((X.distanceToGo() != 0) || (Y.distanceToGo() != 0)){
    X.runSpeedToPosition();
    Y.runSpeedToPosition();
  }
}

My current problem:
Before I added the Y, X could go in either direction. Once I added Y, this was not the case. My X-axis only goes in 1 direction, and the Y can go in both directions, but to change directions, the joystick has to go diagonal to do so,which gets the X involved, which is ok, if they could change directions on their own, or in X case, just change directions. When I delete all the code for Y, however, X will now only go in 1 direction, even though it is the same code that originally had it going either way with movement from the joystick.
I have checked how I wired the circuit, and so has other people, and we concluded that it is probable it is not the wiring, but the code.

Thank you to those who read and help me in advance! :slight_smile:

Ok. I have a project working that among other things can controll X, Y and Z axles by using 3 pots. I use home made stepper functions, not any library stuff.

Your system: Look at Your project as 4 different logic chains, X, Y, Z and rotation. Make them work one at the time. X did work in the beginning. You added more channels and problems occured. Step back to the working X version and add just Y and see what happends. I have no idea how things could get tangled, not knowing those libraries.

Any mistyping somewhere in the code? What do You want to happend when X- or Y- pot gives a value in the interval of 450 - 550? What is the value of joystep_x and joystep_y then? The same as in previous run of loop.

Any help from this?

This is completely inappropriate

  while ((X.distanceToGo() != 0) || (Y.distanceToGo() != 0)){
    X.runSpeedToPosition();
    Y.runSpeedToPosition();
  }

The function runSpeedToPosition() blocks the Arduino until it reaches its position so the motors can only move one a time. The use of WHILE creates another level of blocking.

Try replacing all of that with

X.run()
Y.run()

Also you should encapsulate this code

  if(JoyX < 450){
    joystep_x = X.currentPosition();
    joystep_x = joystep_x -20;
  }
  if(JoyX > 550){
    joystep_x = X.currentPosition();
    joystep_x = joystep_x +20;
  }
  X.moveTo(joystep_x);

in an IF statement like this

if (X.distanceToGo() == 0) {


}

and do the same for the other axis.

Then tell us in detail what happens, and whether it is satisfactory

…R

So for this code:

while ((X.distanceToGo() != 0) || (Y.distanceToGo() != 0)){
    X.runSpeedToPosition();
    Y.runSpeedToPosition();
  }

have none of it, just

X.run()
Y.run()

no while loop, correct?

jgoloco: no while loop, correct?

Yes

The Arduino is a great system for learning-by-doing.

...R

Thanks, this helped a lot, but not I am trying to understand what the max speed of what my stepper motor can do.

My stepper motor's specifications are these: Voltage: 24V Current/Phase: 1.3A Resistor/Phase : 2.1 Ohms Inductance/Phase: 2.5 mH Step angle: 1.8 degrees

My stepper motor driver has made it so that: Current: 1A Step Angle: .1125 Degrees.

What number should I put in setMaxSpeed() ?

Also, based on that, what is the highest value I can put in to joystep_x = joystep_x +/- (What value here?)

Thanks in advance!

jgoloco: What number should I put in setMaxSpeed() ?

Start with a slow speed such as 10 steps per second. Assuming that works fine then try a higher number. Eventually you will get to a number that is too high. Then go back about 10%.

joystep_x = joystep_x +/- (What value here?)

Again, try the 20 that is in the earlier example and experiment with other values.

...R

Ok, I believe I have gotten the Max Speed set. I have added a fourth stepper motor which should rotate an object. Here is the code for that part (the set up such as pins and variable are the same as the other motors):

if (R.distanceToGo() == 0) { // responds better i think, but cant move the piece. too heavy?
    if (analogRead(Rotate) < 9) {
      rot = R.currentPosition();
      rot - rot - 20;
    }
    if (analogRead(Rotate) > 15) {
      rot = R.currentPosition();
      rot = rot + 20;
    }
    R.moveTo(rot);
  }

  X.run();
  Y.run();
  Z.run();
  R.run();

The values are different because when I measure the values for the rotate using this code:

Serial.print("R-axis: ");
  Serial.println(analogRead(R_pin));

The serial monitor puts value of between 6(which is consistent) to anywhere from 16-20(inconsistent). However, when I set up the motor, the motor only starts to turn when I go in the higher end (>15) and turns off whenever in neutral or going to the lower end (<8). I have switched polarities in the circuit to see if I put the wrong wires in the wrong port for the Server Motor Driver, but the same result. I have tried to vary the range of the values, but I get the same result.

If asked, the rotation is linked to the joystick controlling the X and Y axis, as the Joystick has a 3rd axis(rotation). Using X or Y does not affect the rotation server motor though.

What can I do to troubleshoot this problem? Thanks again in advance.

jgoloco:
The serial monitor puts value of between 6(which is consistent) to anywhere from 16-20(inconsistent). However, when I set up the motor, the motor only starts to turn when I go in the higher end (>15) and turns off whenever in neutral or going to the lower end (<8 ). I have switched polarities in the circuit to see if I put the wrong wires in the wrong port for the Server Motor Driver, but the same result. I have tried to vary the range of the values, but I get the same result.

If asked, the rotation is linked to the joystick controlling the X and Y axis, as the Joystick has a 3rd axis(rotation). Using X or Y does not affect the rotation server motor though.

Sorry but I can’t make sense of that.

It seems that the code is doing what is intended - move above 15 and below 9

If you are worried that there is some interaction with the joystick for a different axis then you need to post the complete program.

…R

Hi,
What are you using as a power supply?

Thanks… Tom… :slight_smile:

Here is the code:

#include <AccelStepper.h>
#include <MultiStepper.h>
//86.4 rotations per minute for XYZ
//49.68 rotations per minute for R

AccelStepper X(1, 22, 26); // AccelStepper constructor for X-axis, assigns pins 22(Pulse) and 26(Direction)
AccelStepper Y(1, 28, 32); // AccelStepper constructor for Y-axis, assigns pins 28(Pulse) and 32(Direction)
AccelStepper Z(1, 34, 38); // AccelStepper constructor for Z-axis, assigns pins 34(Pulse) and 38(Direction)
AccelStepper R(1, 40, 44); // AccelStepper constructor for Rotation, assigns pins 40(Pulse) and 44(Direction)

//Remember to ask Dad about which model is the stepper motor he used for R

MultiStepper StepperControl; // MultiStepper constructor, so we can use multiple stepper motors at once

//joystick set up
#define JoyX A0 //Assigns X-axis of joystick to analog pin 0
#define JoyY A1 //Assigns Y-axis of joystick to analog pin 1
#define JoyZ A2 //Assigns Z-axis joystick to analog pin 2
#define Rotate A3 //Assigns Rotation to analog pin 3

long joystep_x = 0; // variable for changing how many steps ahead to go
long joystep_y = 0; // variable for changing how many steps ahead to go
long joystep_z = 0; // variable for changing how many steps ahead to go
long rot = 0; // variable for changing how many steps ahead to go


void setup() {
  X.setEnablePin(24); //Sets X enable pin at pin 24
  X.setMaxSpeed(4147.2); //Remember 4608. Sets the max speed at 4608 steps per second(this is around the max I could get up to to see any substantial changes)
  X.setAcceleration(4147.2); //these values are 4608, bc based on the stepper motor and stepper motor driver used, this is the max it can go
  X.enableOutputs(); //Enables all pins for X stepper motor to be outputs

  Y.setEnablePin(30); //Sets Y enable pin at pin 30
  Y.setMaxSpeed(4147.2); 
  Y.setAcceleration(4147.2);
  Y.enableOutputs(); //Enables all pins for Y stepper motor to be outputs

  Z.setEnablePin(36);
  Z.setMaxSpeed(4147.2);
  Z.setAcceleration(4147.2);
  Z.enableOutputs();

  R.setEnablePin(42);
  R.setMaxSpeed(599.6);
  R.setAcceleration(599.6); 
  R.enableOutputs();


  StepperControl.addStepper(X); //adds all the stepper motors into an array, will allow for multiple stepper motor use
  StepperControl.addStepper(Y);
  StepperControl.addStepper(Z);
  StepperControl.addStepper(R);


}

void loop() {
  if (X.distanceToGo() == 0) { //if the distance for the X's current position and target position(where the joystick is moved to) is 0
    if (analogRead(JoyX) < 450) { //if joystick is going to the left)
      joystep_x = X.currentPosition(); //joystep_x assigned to the current position
      joystep_x = joystep_x - 100; //joystep_x goes -100 from current position
    }
    if (analogRead(JoyX) > 574) { //if joystick is going to the right
      joystep_x = X.currentPosition(); //joystep_x assigned to the current position
      joystep_x = joystep_x + 100; //joystep_x goes +100 from current position
    }
    X.moveTo(joystep_x); //moves to the new position set
  }

  if (Y.distanceToGo() == 0) {
    if (analogRead(JoyY) < 450) {
      joystep_y = Y.currentPosition();
      joystep_y = joystep_y + 100;
    }
    if (analogRead(JoyY) > 574) {
      joystep_y = Y.currentPosition();
      joystep_y = joystep_y - 100;
    }
    Y.moveTo(joystep_y);
  }

  if (Z.distanceToGo() == 0) {
    if (analogRead(JoyZ) < 100) {
      joystep_z = Z.currentPosition();
      joystep_z = joystep_z + 100;
    }
    if (analogRead(JoyZ) > 900) {
      joystep_z = Z.currentPosition();
      joystep_z = joystep_z - 100;
    }
    Z.moveTo(joystep_z);
  }

  if (R.distanceToGo() == 0) { // responds better i think, but cant move the piece. too heavy?
    if (analogRead(Rotate) < 10) {
      rot = R.currentPosition();
      rot - rot - 100;
    }
    if (analogRead(Rotate) > 14) {
      rot = R.currentPosition();
      rot = rot + 100;
    }
    R.moveTo(rot);
  }

  X.run();
  Y.run();
  Z.run();
  R.run();

}

The problem I am having is figuiring out the values for the “R” stepper motor. When centered, the analogRead reads the middle as 9-11 ish. When I turn the knob of the joystick counterclockwise, it goes as low as 6. When I turn clockwise however, it can go from as low as 15 to as high as 23. And, with the way the function is set up now, it only recognizes when I turn it clockwise. I tried once on a very slow speed, way slower than the Steps Per Second I calculated this motor can go in my set up, and it seemed to work. When I bumped it up to just slightly under the Steps Per Second, it no longer recognizes the counter-clockwise turn. What gives? Thanks in advance for any advice.

And Tom, I am using a 24V external power supply.

I don’t like this style of coding

  if (R.distanceToGo() == 0) { // responds better i think, but cant move the piece. too heavy?
    if (analogRead(Rotate) < 10) {
      rot = R.currentPosition();
      rot - rot - 100;
    }
    if (analogRead(Rotate) > 14) {
      rot = R.currentPosition();
      rot = rot + 100;
    }
    R.moveTo(rot);
  }

because you cannot print the value from analogRead() for debugging purposes. And in this case you are reading the joystick twice so you may get two separate readings. Try this

  if (R.distanceToGo() == 0) { // responds better i think, but cant move the piece. too heavy?
    int rVal = analogRead(Rotate);
        // comment out the next 3 lines when you know the range of values
    Serial.print("Rotate val ");
    Serial.println(rVal);
    delay(1000);
    
    if (rVal < 10) {
      rot = R.currentPosition();
      rot - rot - 100;
    }
    if (rVal > 14) {
      rot = R.currentPosition();
      rot = rot + 100;
    }
    R.moveTo(rot);
  }

…R

With the code you gave me, this was the output:

Rotate value 9
Rotate value 9
Rotate value 9
Rotate value 8
Rotate value 7
Rotate value 6
Rotate value 7
Rotate value 6
Rotate value 6
Rotate value 5
Rotate value 5
Rotate value 10
Rotate value 10
Rotate value 20
Rotate value 19
Rotate value 20
Rotate value 19
Rotate value 23
Rotate value 12
Rotate value 10
Rotate value 10
Rotate value 10

Why does it center around 10, but the counter clockwise only goes to 5, and clockwise can vary from 19-23? I do not know what to put for range, but I ended up putting <8 and >16. It still only recognized clockwise rotation.

Also, when I feel the motor, instead of a continuous movement, it feels like it vibrates/pulses a few times, then stops for a moment, then starts pulsing again (this is when I turn it clockwise, doesn’t do anything when left alone).

Here is the current code:

if (R.distanceToGo() == 0) { // responds better i think, but cant move the piece. too heavy?
   int rVal = analogRead(Rotate);
   // comment out the next 3 lines when you know the range of values
   //Serial.print("Rotate val ");
   //Serial.println(rVal);
   //delay(1000);

   if (rVal < 8) {
     rot = R.currentPosition();
     rot - rot - 100;
   }
   if (rVal > 14) {
     rot = R.currentPosition();
     rot = rot + 100;
   }
   R.moveTo(rot);
 }

Also, I have been using the site to calculate the Steps Per Second (I multiple the revolutions per second result by the amount of steps per revolution) using this site : https://www.daycounter.com/Calculators/Stepper-Motor-Calculator.phtml

For the voltage, what should I put here. I am using a 24V battery supply, but through the Stepper Motor Drivers, I have dropped it to 5V across each driver. Does this matter? Should I be putting 24? 5? Maybe even 12? Just a secondary question to the coding question for this project.

jgoloco: Why does it center around 10,

What is connected to the Rotate pin?

I was expecting to see values from 0 to 1023 - certainly a very much larger range than a minimum of 5 and a max of 23. Maybe something is not connected properly.

That range of 18 is only about 2% of the full ADC range.

...R

I assume you are talking about what is connected to in the joystick. It is connected to the "Z" potentionmeter of this joystick: https://www.amazon.com/Joystick-Potentiometer-JH-D300X-R3-220%C2%B0ohm-Thermistor/dp/B07CVGPMDP/ref=sr_1_1?keywords=jh-d300x&qid=1559670755&s=gateway&sr=8-1

And in the Arduino, it is connected to the Analog 3 Pin.

One thing I can think of is that the potentiomenter for the rotation/Z in the joystick has a different resistor value to the one for X and Y. The Z potentiometer is built in, and I cannot find a datasheet that says it is the same type of potentiometer as X and Y. Is there a way to measure the internal resistor to see if they are the same?

The Joystick I am using is the JH-D300X-R1 for reference.

The only solutions I can think of are to find another Joystick that will tell me all the resistors in each potentiometer, or connect the R motor to the other axis my 2nd Joystick(It's like a PS2 joystick) that I am not using. (I am using the Y-axis for the PS2 joystick to control the Z motor).

I know this is confusing, so I'll write which Joystick controls which motor: Joystick JH-D300X-R1 X-Axis: X Motor Joystick JH-D300X-R1 Y- Axis: Y Motor Joystick JH-D300X-R1 Z- Axis: R Motor PS2 Like Joystick: Y-Axis: Z Motor

Looking at the link you gave in Reply #15 I cannot see where are the three connections for the Z potentiometer.

And the link seems to be for an -R3 device whereas you say you have an -R1 device.

I think the most likely explanation is incorrect connections. Please make a clear pencil drawing showing all of the connections to your Arduino and post a photo of the drawing. See this Simple Image Guide

If this was my problem I would write a very short program just to read the values from the Z potentiometer and display them on the Serial Monitor.

...R

It was the connection. I switched the sweeping wire and one side of the potentionmeter, which is why my z axis is not working. I will switch things around and I will post back here if the readings are correct or not.

Thanks for helping me so far Robin!