MAybe a dumb ? Steppers and serial print

Status
Not open for further replies.

Buzz

Well-known member
I have a stepper running in a closed loop using a air pressure sensor (0.5-4.5vdc output) and stepper motor attached to a manual air pressure regulator , when the stepper is running I get no update of the values from the sensor and a pot I use as a setpoint.

the question ? Does the Teensy 3.5 still read the analog inputs while the stepper is running even though the serial port does not print it out ? My stepper seems to over run the setpoint if it has to move very far.
Thanks < If I missed any info let me know please. I may be doing something completely wrong !

Code:
#include <Arduino.h>
//#include "BasicStepperDriver.h"
#include "A4988.h"
#include <MovingAverage.h>
MovingAverage average(0.1f);

const int ANALOG_PIN0 = A2;
const int ANALOG_PIN1 = A3;

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 400
#define RPM 10
int sensorValue0 = analogRead(A2); // sensor
int sensorValue1 = analogRead(A3); // pot
int val0 = 0;
int val1 = 0;
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

// All the wires needed for full functionality
#define DIR 8
#define STEP 9
//Uncomment line to use enable/disable functionality
#define ENABLE 13

//Uncomment line to use enable/disable functionality
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP, ENABLE);
float deadBand;
double error;

void setup() {
    Serial.begin(9600);
    average.reset( analogRead(A3) );
  stepper.begin(RPM, MICROSTEPS);

  deadBand = 35.0;  //stop moving when error < deadBand
}
void measurePressure() {
  int raReading = analogRead(A2);

  float psi0 = ((30 - 0) / (920.7 - 157.3)) * (raReading - 156.3);
  Serial.println(psi0);
  Serial.println(" ");
}
void loop() {
  //analogReadResolution(12);// set to 12bit ACD 
  
   
  val0 = analogRead(A2);     // read the input pin
  Serial.println(val0);             // debug value
  Serial.println("val0");
  val1 = analogRead(A3);     // read the input pin
  Serial.println(val1);             // debug value
  Serial.println("val1");

  
  error = val0 - val1;
  if (abs(error) < deadBand ) error = 0;

  measurePressure();
  delay (50);

  // energize coils - the motor will hold position
  stepper.enable();

  // stepper.rotate(1080);

  stepper.move(-error);
 
  // pause and allow the motor to be moved by hand
  stepper.disable();

  delay(150);
}
 
I don't know your stepper library, but the stepper.move() function seems to be blocking. I.e., it only returns after the motor reached its target. You need to use the non blocking version of this function. Here is an example of how use it: https://github.com/laurb9/StepperDriver/tree/master/examples/NonBlocking

This will allow you to read out values while the motor moves. Note: you then need to make sure that your library allows to change the target position while the motor moves. Generally using steppers in a closed loop is possible but somehow difficult to implement. You might be better off using a cheap servo (DC Motor with Encoder) and the PID library (You'll find a lot of examples how to do this in the net)
 
Last edited:
Also potentially helping to get things slowing more smoothly would be something like ellapsedmillis
https://www.pjrc.com/teensy/td_timing_elaspedMillis.html

Cut down the serial sends to once every second or so to avoid choking the USB with traffic but do ADC reads faster. And possibly use pin 13 (or an LED on a spare pin) to indicate when stepper is in motion to new position. You may also have trouble since the Teensy 3.5 is only 5V tolerant and not capable of usefully reading analog signals above 3.3. They will always read as max value which may not end well if stepper tries to keep driving. Depending on desired range you may need to use a voltage divider.
 
Thanks guys !! , I used Accelstepper and now non blocking works BUT I have some other issues.
when I used the Arduino stepper library the enable worked great , when my motor got to position it disabled the motor until a new analog value was present from the POT , I cannot get this function to work in Accelstepper ?? what the hell am I doing wrong or missing ? for analog input scaling I am using a 2.2k to 3.3k res. scaling from my sensor.

I tried deadband but it did not work either ? the motor just sits there and jitters I tried everything I could to get it to stop but no luck

this code has the feedback from the sensor and pot input compared to control motor position


Code:
// ProportionalControl.pde
// Make a single stepper follow the analog value read from a pot or whatever
// The stepper will move at a constant speed to each newly set posiiton,
// depending on the value of the pot.
//


#include <AccelStepper.h>

// Define a stepper and the pins it will use
AccelStepper mystepper(1, 9, 8); // step/dir pins 9,8

// This defines the analog input pin for reading the control voltage
//#define ANALOG_IN A3
const int ANALOG_IN = A3;  //pot
const int ANALOG_PIN1 = A2;  //sensor
int sensorValue0 = analogRead(A2); // sensor
int sensorValue1 = analogRead(A3); // pot
int val0 = 0;
int val1 = 0;
double error;

void setup()
{ Serial.begin(9600);
  mystepper.setMaxSpeed(1250.0);
  mystepper.setAcceleration(1000.0);
  //mystepper.setEnablePin(13);
}
void measurePressure() {
  int raReading = analogRead(A2);

  float psi0 = ((30 - 0) / (920.7 - 157.3)) * (raReading - 156.3);
  Serial.println(psi0);
  Serial.println(" ");
}
void loop()
{
  val0 = analogRead(A2);     // read the input pin
  Serial.println(val0);             // debug value
  Serial.println("val0");
  val1 = analogRead(A3);     // read the input pin
  Serial.println(val1);             // debug value
  Serial.println("val1");
  error = val0 - val1;

  //mystepper.enableOutputs();
  // Read new position
  int analog_in = analogRead(ANALOG_IN);
  mystepper.moveTo(-error);
  mystepper.setSpeed(180);
  mystepper.runSpeedToPosition();
  //mystepper.disableOutputs();
  Serial.println(analog_in);
  delay(10);
  //Serial.println("ANALOG_IN");

}
 
Last edited:
I used Accelstepper and now non blocking works
Accelstepper requires that you call runSpeedToPosition() as often as possible. Since you have a delay(10) in loop it will be called with 100Hz only which is too slow for your 180Hz pulse frequency requirement.

when I used the Arduino stepper library the enable worked great , when my motor got to position it disabled the motor until a new analog value was present from the POT, I cannot get this function to work in Accelstepper
AccelStepper doesn't have a disable function. Just use digitalWriteFast() to write to the enable pin directly (Looks like you use pin 13 as enable pin? If possible better not use the LED pin (13) in your sketches)


the motor just sits there and jitters
Did you check the "error" values? How large are they?

Here some possible changes to your code which might be helpful. I didn't have time to test it so there probably are some bugs in it but it compiles and should be good enough to get you going.


Code:
// ProportionalControl.pde
// Make a single stepper follow the analog value read from a pot or whatever
// The stepper will move at a constant speed to each newly set posiiton,
// depending on the value of the pot.
//


#include <AccelStepper.h>

// Define a stepper and the pins it will use

constexpr int stp = 9;
constexpr int dir = 8;
constexpr int en = 10;  // change to your value, try to avoid pin13

AccelStepper mystepper(1, stp, dir); // step/dir pins 9,8

void setup()
{ 
  Serial.begin(0);  // no need to set baudrate, will be ignored for USB anyway
  mystepper.setMaxSpeed(1250.0);
  mystepper.setAcceleration(1000.0);
  //mystepper.setEnablePin(13);

  pinMode(en,OUTPUT);
  pinMode(LED_BUILTIN,OUTPUT);  
}

void measurePressure() {
  int raReading = analogRead(A2);

  float psi0 = ((30 - 0) / (920.7 - 157.3)) * (raReading - 156.3);
  Serial.println(psi0);
  Serial.println(" ");
}

elapsedMillis stopWatch = 0; 

void loop()
{
  mystepper.runSpeed();       // call this as often as possible (avoid to block loop() by delay() or something similar)

  int sensor = analogRead(A2);
  int pot = analogRead(A3);
  int error = sensor - pot;              
    
  if(error != 0)                                         // we need to move
  {
    int speed = error < 0 ? 180 : -180;                  // sign of speed determines the rotation direction in accelStepper, 
    Serial.printf("Error: %d Speed: %d\n", error,speed); // debug
    
    digitalWriteFast(en,HIGH);                           //ENABLE STEPPER (depending on your driver LOW might be needed for enabling)
    mystepper.moveTo(-error);
    mystepper.setSpeed(speed);     
  }
  else if(mystepper.distanceToGo() == 0) 
  {
    digitalWriteFast(en,LOW);                             //DISABLE STEPPER (depending on your driver HIGH might be needed for disabling)
    Serial.println("Stepper disabled");
  }    

  // How to achieve a delay in loop w/o blocking:
  if(stopWatch > 500)   
  {
    stopWatch = 0; 
    digitalWriteFast(LED_BUILTIN,!digitalReadFast(LED_BUILTIN));  // Toggle LED
  }
 
  
}
 
Thanks Luni !! very much appreciated
1. i'll fix that delay or remove it
2. got it , I will try your code and see how it does
3. the error was due to noise on my ref. POT put a cap on it , then changed to a lower value pot , that fixed it

I will try your code and see how it preforms
Again THANK YOU !

I tested your code , It works with some issues

1. the motor jitters at position , there is error data so it seems to be searching , I tried adding my DEADBAND code but could not get it to work ?
2. the disable function keeps the enable pin high all the time , I moved it to pin 10 to test it , I think the noise is causing it to not go into disable mode ? this chip is ACTIVE LOW for enable
3. I need a deadband or really good filtering on my analog input , can this statement be used

if(error != 0) // we need to move ??

4. THANK you !

Error data
Error: 1 Speed: -580
Error: -1 Speed: 580
Error: 1 Speed: -580
Error: -1 Speed: 580
Error: 2 Speed: -580
Error: 1 Speed: -580
Error: 1 Speed: -580
Error: 2 Speed: -580
Error: 1 Speed: -580
Error: 1 Speed: -580
Error: -3 Speed: 580
Error: 1 Speed: -580
Error: -1 Speed: 580
Error: -1 Speed: 580
Error: 12 Speed: -5
 
Last edited:
1. the motor jitters at position , there is error data so it seems to be searching , I tried adding my DEADBAND code but could not get it to work ?

You are using raw analog values to calculate the control deviation, (your error variable). Thus the value you use as target for the motor is somehow accidental. I.e. if you get an error value of say 50, do you really need to move the motor -50 steps to compensate the error? Usually you would need to multiply the error by some constant to translatete from the measured deviation to the required steps. E.g. If you need to move say 10 steps to compensate a measured error of say 100 you'd have to divide the error variable by a constant value of at least 10. Otherwise your control loop will start oscillating.

Anyway, if you just need smoother analog readings you can use the ResponsiveAnalogRead library. https://github.com/dxinteractive/ResponsiveAnalogRead. It is easy to use and has a good documentation in the readme.

2. the disable function keeps the enable pin high all the time , I moved it to pin 10 to test it , I think the noise is causing it to not go into disable mode ? this chip is ACTIVE LOW for enable
Yes, it disables the motor only if there is nothing to move. Disabling while it moves would be somehow counterproductive? So, if you have "error noise" it will never be disabled. For an active low chip you need to change HIGH to LOW and vice versa in the code which sets the enable pin as commented.

3. I need a deadband or really good filtering on my analog input , can this statement be used
if(error != 0) // we need to move ??

Yes, that would be the place to define a deadband. E.g.
Code:
if(abs(errror) > 5) 
{
...
}
would not move the motor for error values <= 5.
 
Last edited:
No luck , thanks ! I tried everything but could not get it to stop jittering ?? I went back to my old code but have a jitter issue in it to LOL !

Today at 12:36 am
I have a stepper motor driving a air pressure reg. with a pressure sensor as feedback in a closed loop , right now I am using a pot to 3.3vdc for the set point , it works good BUT the motor jitters after it sleeps for a while ( I use a deadband to disable the motor after it hits its target ) after waking up it jitters to position , after 3-5 changes in setpoint it clears up ??

Any idea what is causing this to happen ?? ( I have tried not serialprinting anything and that makes no
difference )

any ideas ??
Code:
#include <Arduino.h>
#include "BasicStepperDriver.h"
#include "A4988.h"
#include <MovingAverage.h>
MovingAverage average(0.1f);

#define MOTOR_STEPS 200
#define RPM 80
#define MICROSTEPS 1
#define DIR 8
#define STEP 9
#define ENABLE 10
//#define MOTOR_ACCEL 200
//#define MOTOR_DECEL 1000

A4988 stepper(MOTOR_STEPS, DIR, STEP, ENABLE);

const int ANALOG_PIN0 = A2;  // sensor
const int ANALOG_PIN1 = A3;//pot
int sensorValue0 = analogRead(A2); // sensor
int sensorValue1 = analogRead(A3); // pot
int val0 = 0;
int val1 = 0;
float deadBand;
double error;

void setup() {
  Serial.begin(115200);
  average.reset( analogRead(A2) );
    
  stepper.begin(RPM, MICROSTEPS);
//   stepper.setSpeedProfile(stepper.LINEAR_SPEED, MOTOR_ACCEL, MOTOR_DECEL);
  
  deadBand = 25.0;  //stop moving when error < deadBand
}
void measurePressure() {
  int raReading = analogRead(A2);

  float psi0 = ((30 - 0) / (902.0 - 127.3)) * (raReading - 20);
  Serial.println(psi0);
  Serial.println("psi");
}
void loop() {
  //analogReadResolution(12);// set to 12bit ACD
  ( average.update( analogRead(0) ) );

  val0 = analogRead(A2);     // read the input pin
  Serial.println(val0);             // debug value
  //Serial.println("sensor");
  val1 = analogRead(A3);     // read the input pin
  Serial.println(val1);             // debug value
  //Serial.println("pot");

  error = val0 - val1;
  Serial.println(error);
  if (abs(error) < deadBand ) error = 0;

  measurePressure();
  delay (1);

  stepper.enable();
  stepper.move(-error);
  
  stepper.disable();

  delay(1);
}
 
I figured it out , I had the current set to MAX on the A4988 driver ! all good now

FYI check your current settings
 
Status
Not open for further replies.
Back
Top