CW/CCW is not possible with constant rotation and problem with enable/disable stepper motor

425 views
Skip to first unread message

Jakster Fransiscus

unread,
Jan 4, 2022, 3:35:45 PM1/4/22
to accelstepper
Hi all, 

Thanks a lot for this awesome library! This makes things a lot easier! 

I'm currently making a followup tutorial on how to control a stepper motor using Touchdesigner. The goal is to have a default block that anyone can use: move the motor to a certain position, move the motor at a constant speed, a sine wave movement, ... 

This will be the interface:

2022-01-04 21_20_01-TouchDesigner 2021.15800_ E__TouchDesigner_69_StepperMotor_69_StepperMotor.35.to.png

With buttons 0 - 4 correspoding with a certain movement: constant speed, lfo, manual, ...

I wired my motor in the following way: 
2022-01-04 21_21_38-StepperMotorConnections.psd @ 54.9% (RGB_8#).png

This is the code: 

//
// Parse incoming messages consisting of four decimal values followed by a carriage return
//  Example  "2 10000 6000 6100\n"
//  In TouchDesigner:     op('serial1').send("2 10000 6000 6100", terminator="\n")
//

#include <AccelStepper.h>

// Define a stepper and the pins it will use: 1 is enable pin, 8 is pulse pin, 9 is direction
AccelStepper stepper(1, 8, 9);

char buffer[32];   //maximum expected length
int len = 0; //necessary for the overflow.

bool newData, runallowed = false; // booleans for new data from serial, and runallowed flag


int stateMotorGlobal; //motor state: 0 = stop motor, 1 = run at constant speed, 2 = run ccw, 3 = run cw
int speedMotorGlobal; //speed of the motor
int accelerationMotorGlobal; //acceleration of the motor
int stepsMotorGlobal; // number of steps

void setup()
{
  Serial.begin(19200); //baud rate. Should be the same in 'Serial' dat: baud rate.
  stateMotorGlobal = 0;
  speedMotorGlobal = 0;
  accelerationMotorGlobal = 0;
  stepsMotorGlobal = 0;

  stepper.setMaxSpeed(0); // MAX SPEED = steps/second
  stepper.setAcceleration(0); // ACCELERATION = steps/seconds²
  stepper.disableOutputs(); // Disable outputs, so no heating of the motor at idle


}
void loop()
{
  checkSerial(); //check the serial communication and save variables
  controlMotor(); //run motor
}

void controlMotor() {
  if (stateMotorGlobal == 3) {
    stepper.setMaxSpeed(speedMotorGlobal); // MAX SPEED = steps/second
    stepper.setAcceleration(accelerationMotorGlobal); // ACCELERATION = steps/seconds²
    stepper.enableOutputs(); //enable output pins
   
    stepper.moveTo(-stepsMotorGlobal); //move the motor CW
    stepper.run();
  }
  else if (stateMotorGlobal == 2) {
    stepper.setMaxSpeed(speedMotorGlobal); // MAX SPEED = steps/second
    stepper.setAcceleration(accelerationMotorGlobal); // ACCELERATION = steps/seconds²
    stepper.enableOutputs(); //enable output pins
   
    stepper.moveTo(stepsMotorGlobal); //move the motor CCW
    stepper.run();
  }
  else if (stateMotorGlobal == 1) {
    stepper.setMaxSpeed(speedMotorGlobal); // MAX SPEED = steps/second
    stepper.setAcceleration(accelerationMotorGlobal); // ACCELERATION = steps/seconds²
    stepper.setSpeed(speedMotorGlobal); // MAX SPEED = steps/second
    stepper.enableOutputs(); //enable output pins
   
    stepper.runSpeed();
    stepper.run();
  }
  else {
    stepper.disableOutputs(); //disable power
    stepper.setCurrentPosition(0); // reset position
    stepper.stop(); //stop motor    
  }

}

void checkSerial() {

  if (Serial.available() > 0)
  {
    int incomingByte = Serial.read();
    buffer[len++] = incomingByte;
    newData = true; //flag
    //
    // check for overflow
    //
    if (len >= 32)
    {
      // overflow, resetting
      len = 0;
    }
    //
    // check for newline (end of message)
    //
    if (newData == true) {
      if (incomingByte == '\n')
      {
        int stateMotor;
        int speedMotor;
        int accelerationMotor;
        int stepsMotor;

        int n = sscanf(buffer, "%d %d %d %d",&stateMotor, &speedMotor, &accelerationMotor, &stepsMotor);
        if (n == 4)
        {
          stateMotorGlobal = stateMotor;
          speedMotorGlobal = speedMotor;
          accelerationMotorGlobal = accelerationMotor;
          stepsMotorGlobal = stepsMotor;

        }
        else
        {
          // parsing error, reject
        }
        len = 0; // reset buffer counter
      }
    }
  }
  newData = false;
}


You get 4 values from Touchdesigner which will control the motor. 
int stateMotorGlobal; //motor state: 0 = stop motor, 1 = run at constant speed, 2 = run ccw, 3 = run cw
int speedMotorGlobal; //speed of the motor
int accelerationMotorGlobal; //acceleration of the motor
int stepsMotorGlobal; // number of steps

Based on these 4 values, the motor will either stop, run at a constant speed, move ccw or move cw. 

It all works fine except for 3 things: 

1. The stepper.disableOutputs() does not work. There is still some torque on the motor. I think this is due to the enable needing a LOW to be switch off instead of a HIGH. Can this be fixed? 
 2. When I upload the code, i get a weird noise: YouTube link Is this normal or is my wiring incorrect? 
3. When I want to rotate at a constant speed, I cannot make a difference between CW and CCW. How can I program this? 

Thanks a lot! If you have any suggestions on improving it or adding extra features, let me know! I just want to share this to everyone so they can use it in their projects :-)

Peace, 
Jakster!

Jim Larson

unread,
Jan 4, 2022, 4:20:32 PM1/4/22
to accelstepper
Although I'm not very familiar with your stepper driver, I might still be able to help a little.
First, I don't see any definition of an Enable pin. That is, you aren't calling setEnablePin(1) anywhere. Without doing that, AccelStepper will not control that pin to disable your interface. (I'm also concerned about using D1 for an enable. Won't the Serial interface interfere with it?)
Further, I don't understand the placement of run() and runSpeed() in your program.
I've recently created a document you may find very useful.
In it, I provide a complete guide to using AccelStepper - including how to use the Enable pin functions - and some examples that may be useful. I'm working on an Instructable that will provide some more advanced tutorial material. Any feedback you might have is most appreciated. In the meantime, I hope it will help you.
        -jim

Jakster Fransiscus

unread,
Jan 5, 2022, 3:30:38 PM1/5/22
to accelstepper
Hi Jim, 

Thanks a lot for your very fast reply! It worked! 

For the enable pin: I thought the first integer was the pin on the Arduino board. But it's not.
This also worked: 

2022-01-05 21_14_48-StepperMotor_TD_4 _ Arduino 1.8.19 (Windows Store 1.8.57.0).png

I found some examples where it was just a number: https://www.pjrc.com/teensy/td_libs_AccelStepper.html 
2022-01-05 15_15_51-AccelStepper Arduino Library, connecting Stepper Motors to Teensy.png
Perhaps something to include in your manual as well? 

For the continous movement: 

I tried this code: 
2022-01-05 21_22_27-StepperMotor_TD_4 _ Arduino 1.8.19 (Windows Store 1.8.57.0).png

If I understood your manual correctly, it should use the acceleration to get to its speed, but it does not. The motor will stall at high speeds. Is there another solution? 

The manual was indeed very useful! This is a piece of documentation that is missing with this library!
The only thing I would improve is adding some pictures or even videos to explain some functions.  

This graph for example: 
2022-01-05 21_27_11-acceleration speed curve - Google Search.png

But thanks a lot for your fast and accurate reply! I'll show you the tutorial once it's finished ;-)

Kind regards, 
Jakster

Jim Larson

unread,
Jan 5, 2022, 7:25:09 PM1/5/22
to accelstepper
I'm so glad that my comments helped you and that the "Missing Manual" was of use!
Regarding syntax for creating a stepper object, as I discuss in the Manual, I highly recommend doing it this way;
// Define pin connections
const int dirPin = 9;
const int stepPin = 8;
// Creates an instance
AccelStepper myStepper(AccelStepper::DRIVER, stepPin, dirPin);

Using an integer for the interface type is confusing and can be inaccurate. For example, the values shown from the PJRC site are not correct! A bipolar stepper controlled by an HBridge should be a 4, not a 2. Using AccelStepper:FuLL4WIRE would avoid that problem and make clear the desired interface. Obviously, I don't plan to include the numbers in the manual. Rather, my recommendation to use the symbols.

Regarding your code and expectation of constant speed: If you call run(), it will attempt to accelerate to speed set by setMaxSpeed(your_speed) and will ignore any speed set by setSpeed(your_speed). I've tried to explain this in more than one spot in the Manual. Maybe I need to emphasize it more?

If your motor is not going as fast as you want it, it could be that your acceleration is too high, or your motor simply can't go that fast. I'm sorry I can't be more definitive, but it depends on your hardware.

One other point which is not in the Manual, but will be in the Instructable I'm working on. You will get better performance from a dual state machine. That means that one machine will only happen if there is front panel input. It will set up the conditions (speed, distance, acceleration, etc.). The second machine will then run and will only call run() or runSpeed() until motion is complete. Then, the front panel will be read again and the cycle will happen again. This will result in the fastest possible operation of your motor.

Thanks for your suggestions about the Manual!
         -jim
Reply all
Reply to author
Forward
0 new messages