Looking for help with AccelStepper library.

quick background:

I have a robot with four stepper motors and mechanum wheels. Basically, this means the robot can move in one of 8 directions without changing it’s orientation on the z axis. I’ve attached a picture for reference, excuse the very messy work table.

The direction the robot travels in will be dictated by an Nvidia TX2 setup with autonomous navigation code. The TX2 will send commands to an MQTT queue to indicate which direction the robot should move.

The mega is simply listening to the serial port for characters 0-9 (and L or R for left rotation or right rotation) and spinning the proper motors in the appropriate direction.

I have tried:

my own code to run the steppers by just setting pins high and low (this moves the steppers but blocks the loop function and can’t detect direction changes - so does not satisfy my requirements)

MutliStepper library - I got this to turn the motors as well, however it requires the steppers have a position to move to and I can’t find a way to get continuous movement - I tired dynamically changing the position to move to but it sets motor speed to 0. (code example at the end of this post).

AccelStepper library - I can’t seem to get this to work at all - as in, the motors simply won’t turn. I don’t know why the settings in MultiStepper work, but not in AccelStepper since MultiStepper uses the AccelStepper library. (code example for this also at the end of this post.)

I am looking for advice on how to get the AccelStepper code working - or suggestions on a new architecture entirely. Been spinning my wheels on this for weeks (pun intended :slight_smile: )

MultiStepper code

/*
||
|| @file propulsion.pde
|| @version 1.0
|| @author Chris Burns
|| @contact christopheraburns@gmail.com
||
|| @description
|| |  
|| |             
|| |            
|| #
||
*/

//Forward (Direction #1 or 90 degrees) = M1-F, M2-F, M3-F, M4-F
//Forward+Left (Direction #2 or 45 degrees) = M2-F, M3-F
//Left (Direction #3 or 0 degrees) = M1-R, M2-F, M3-F, M4-R
//Reverse+Left (Direction #4 or 315 degrees) = M1-R, M4-R
//Reverse (Direction #5 or 270 degrees) = M1-R, M2-R, M3-R, M4-R 
//Reverse+Right (Direction #6 or 225 degrees) = M2-R, M3-R
//Right (Direction #7 or 180 degrees) = M1-F, M2-R, M3-R, M4-F
//Forward+right (Direction #8 or 135 degrees) M1-F, M4-F
//Rotate Left (Direction #10) M1-R, M2-F, M3-R, M4-F
//Rotate Right (Direction #11) M1-F, M2-R, M3-F, M4-R

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

float TargetPosition = 2000;
float MotorMaxSpeed = 1600;
char newDirection;
boolean alterDirection = false;
char currentCommand = '-1';


AccelStepper stepper1(AccelStepper::FULL2WIRE, 6, 7);


// Up to 10 steppers can be handled as a group by MultiStepper
MultiStepper steppers;

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

  // Configure each stepper
  stepper1.setMaxSpeed(MotorMaxSpeed);


  // Then give them to MultiStepper to manage
  steppers.addStepper(stepper1);

}

//Forward (Direction #1 or 90 degrees) = M1-F, M2-F, M3-F, M4-F
void dir_one(){
  long positions[4]; // Array of desired stepper positions

  positions[0] = TargetPosition;  //"+" = Forward, "-" = Reverse
  positions[1] = -TargetPosition; //"-" = Forward, "+" = Reverse
  positions[2] = TargetPosition;  //"+" = Forward, "-" = Reverse
  positions[3] = -TargetPosition; //"-" = Forward, "+" = Reverse
  
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);
}

//methods 2-9 omitted to fit post


void showNewDirection(){
  String dir = "";
  if (alterDirection == true){
    switch(newDirection){
      case '0':
        currentCommand = '0';
        dir = "Nuetral";
        Serial.println(dir);
        break;
     //rest of switch statement omitted to fit post on the Forum
    }
  }
}

void checkSerial(){
  if(Serial.available() > 0){
    newDirection = Serial.read();
    Serial.print('Serial port data detected: ');
    Serial.println(newDirection);
    
    if (currentCommand == '-1'){ //This is the first command since boot
      currentCommand = newDirection;
    }
    else{
      if(currentCommand != newDirection){ //This is a change in direction
        alterDirection = true;
        showNewDirection();
      }
    }
  }
  else{
    //Continue last command
    switch(currentCommand){
      case '0':
        break;
      case '1':
        dir_one();
        break;
       //rest of switch statement omitted to fit post on the Forum
    }
  }
}

void loop() {
  checkSerial();
}

AccelStepper code - does not work, tried countless variable changes:

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::DRIVER, 6, 7);


float TargetPosition = 2000;
float MotorMaxSpeed = 450;
char newDirection;
boolean alterDirection = false;
char currentCommand = 'z';

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  // Configure each stepper
  stepper1.setMaxSpeed(MotorMaxSpeed);
  stepper1.distanceToGo() == 0;
}

void loop() {
  Serial.print("Stepper1 current position = ");
  Serial.println(stepper1.currentPosition());
  if (stepper1.distanceToGo() == 0)
  {
    //float move_to = rand() % 200;
    stepper1.moveTo(TargetPosition);
    Serial.print("Moving to position: ");
    Serial.println(TargetPosition);
    
    //float max_speed = (rand() % 200) + 1;
    Serial.print("Setting max_speed at ");
    Serial.println(MotorMaxSpeed);
    stepper1.setMaxSpeed(MotorMaxSpeed);

    float set_accel = (MotorMaxSpeed / 2);
    Serial.print("Setting acceleration at ");
    Serial.println(set_accel);
    stepper1.setAcceleration(set_accel);
  }
  
  stepper1.run();
  delay(1000);
}

I forgot to post a link to the Motors and Drivers:

https://www.omc-stepperonline.com/cnc-kit/1-axis-stepper-kit-40nm566ozin-nema-24-stepper-motor-and-driver-1-m542t-24hs39.html?search=24HS39

I am using custom batteries that I put together. 18650 @ 4volts & 9000mAh X6 in a series and two series in Parallel so I have two 24volt, 20000mAh batteries. Each battery powers 2 motors.

Firstly the delay(1000) is totall breaking your sketch, no delay calls anywhere if you want to use
AccelStepper.

At the end of setup() you do:

  stepper1.distanceToGo() == 0;

Which is a pointless comparison of a value known to be zero to zero, throwing away the result.

To use AccelStepper call setMaxSpeed() and setAcceleration() in setup, call run() everytime
through loop(), strip out any use of delay, and then use move() or moveTo() calls to fire it
into action. stop() can be useful to cancel a previous action.

Never busy-wait either - unless you call run() inside the wait loop body.

The value for setAcceleration has to be experimentally determined, note, it depends on many
factors. Too high and the motor will miss-step, so turn it down 25% or so until its reliable.
Same for MaxSpeed.

Can I just ask why you chose steppers for a traction application? Its so inefficient.

I needed precision. I experimented with DC motors, but the robot will be around 70lbs and I couldn't get the exact movements I wanted.

MarkT, do you think DC motors would work better? I am definitely keeping the Mechanum wheels but I would be open to changing the motors.

Given that the robot is expected to weigh 70lbs, each motor would need to support 35lbs (regardless of direction there is a minimum of 2 motors moving the robot).

I was able find Steppers that could support the weight requirements.

Thanks!

christopheraburns:
I needed precision. I experimented with DC motors, but the robot will be around 70lbs and I couldn't get the exact movements I wanted.

There are devices called encoders that can give way more precision than a stepper and are immune to
miss-stepping. Traction for a heavy robot like that is a large proportion of the power budget, so steppers
are going to limit your endurance a lot I fear.