Go Down

Topic: blink without delay plus a stepper motor? (Read 352 times) previous topic - next topic

nofed

I'm trying to use millis to make a program that will turn a stepper motor some degree one direction and then stop when a button is pushed in a certain time window. And if a button is pushed within another time window,  (the time between button pushes actually), is too long then I want the motor to spin the other way and then stop. Please ignore the Servo stuff. Even without the servo involved the code doesn't seem to work. The code:

#include <Servo.h>
Servo myservo;

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

const int inPin = 2;
const int outPin= 13;
unsigned long elapsedtime=0;

int ledstate =LOW;
int switchstate = LOW;
int previous = LOW;

unsigned long prevtime = 0;
unsigned long debounce = 200;
unsigned long dur_on = 0; //duration between on/off

void setup(){
  myservo.attach(9);
  pinMode(inPin,INPUT);
  pinMode(outPin,OUTPUT);
  Serial.begin(9600);

  AFMS.begin();
  myMotor->setSpeed(10);
}

void loop()
{
  ReadSensor();
  MotorActionForward();
  MotorActionBackward();
  delay(200);
}

void ReadSensor()
{
  switchstate=digitalRead(inPin);
  if ((millis()-prevtime)>debounce){
    if(switchstate!=previous && switchstate==HIGH){
      if (ledstate==LOW){
        digitalWrite(outPin,HIGH);
        prevtime=millis();
        ledstate=HIGH;
      }
      else if(ledstate==HIGH){
        digitalWrite(outPin,LOW);
        ledstate=LOW;
        Serial.print("time between drips ");
        elapsedtime=((millis()-prevtime));
        Serial.println(elapsedtime);
        prevtime=millis();
      }
    }
  }
}

void MotorActionForward()
{
  if (elapsedtime > 5500){
    myMotor->step(10, FORWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
  }
}

void MotorActionBackward()
{
  if (elapsedtime < 4500 && elapsedtime > 200 && elapsedtime != 0){
    myMotor->step(10, BACKWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
  }
}


???????????????????????????
I can get the program to work as expected with the void MotorActionForward() alone. But when I add void MotorActionBackward() it doesn't increment the motor and stop. Instead it performs the increment of 10 about 8x and then stops. And during that time it will no longer read a button push. And if I just try to used MotorActionBackward() without MotorActionForward() the motor still does the 8x BACKWARD thing.
-------------------------------------------------
I've also tried combining MotorActions together and using two if statements, but the Backwards still acts goofy. Code:
if (elapsedtime > 5500){
    myMotor->step(10, FORWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
  }
   if (elapsedtime < 4500){
    myMotor->step(10, BACKWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
  }
------------------------------------------------
I'm not a programmer and am new to arduino.
Does anyone know how to proceed? Is this program possible without writing interrupts? Why is Backwards not working in one increment and then stopping as expected? Thanks to anyone that will reply.




PaulS

Code: [Select]
if (elapsedtime < 4500 && elapsedtime > 200 && elapsedtime != 0){
If the value is greater than 200, it can't possibly be 0, can it?

Quote
Instead it performs the increment of 10

Say what? What does this mean?

Code: [Select]
      if (ledstate==LOW){
        digitalWrite(outPin,HIGH);
        prevtime=millis();
        ledstate=HIGH;
      }
      else if(ledstate==HIGH){

Besides LOW and HIGH, what other values can ledstate contain? If you say none (which is the right answer), then why do you need to test for both values? If it isn't one, it MUST be the other.

More Serial.print() statements are needed.

nofed

Quote
If the value is greater than 200, it can't possibly be 0, can it?

Yeah, true. It was just one of the many things I've tried to make it work.

Quote
Say what? What does this mean?

The increment of 10 can be any number right now. Its how many steps the stepper will turn.  It is used in this part of the code:
myMotor->step(10, FORWARD, DOUBLE);
or
myMotor->step(10, BACKWARD, DOUBLE);

Quote
Besides LOW and HIGH, what other values can ledstate contain? If you say none (which is the right answer), then why do you need to test for both values? If it isn't one, it MUST be the other.

I guess that is how in my head if its not one I am making dare sure its the other. You think too redundant? Or messing up the program?

For some reason I thought the Serial.print () slowed down or messed with a programs timing. I'll try some rearranging.  Thank you.

PaulS

Quote
For some reason I thought the Serial.print () slowed down or messed with a programs timing.

It does. But, the program has to work correctly first, then quickly.

nofed

So with the slightly changed code and some more Serial.println statements I've solved the forward and backward problem. Now just for experiments sake, I want to have the servo go for a lot longer, but when I do the arduino no longer recognizes the button pushes while the stepper is moving. Here is the code and some example output:

#include <Servo.h>
Servo myservo;

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

const int inPin = 2;
const int outPin= 13;
unsigned long elapsedtime=0;

int ledstate =LOW;
int switchstate = LOW;
int previous = LOW;

unsigned long prevtime = 0;
unsigned long debounce = 200;
unsigned long dur_on = 0; //duration between on/off

void setup(){
  myservo.attach(9);
  pinMode(inPin,INPUT);
  pinMode(outPin,OUTPUT);
  Serial.begin(9600);

  AFMS.begin();
  myMotor->setSpeed(10);
}

void loop()
{
  ReadSensor();
  MotorActionBlocked();
  MotorActionForward();
  MotorActionBackward();
  delay(10);
}

void ReadSensor()
{
  switchstate=digitalRead(inPin);
  if ((millis()-prevtime)>debounce){
    if(switchstate!=previous && switchstate==HIGH){
      if (ledstate==LOW){
        digitalWrite(outPin,HIGH);
        prevtime=millis();
        ledstate=HIGH;
      }
      else if(ledstate==HIGH){
        digitalWrite(outPin,LOW);
        ledstate=LOW;
        Serial.print("time between button ");
        elapsedtime=((millis()-prevtime));
        Serial.println(elapsedtime);
        prevtime=millis();
      }
    }
  }
}

void MotorActionBlocked()
{
  if (elapsedtime > 10000){
    myMotor->step(100, BACKWARD, DOUBLE);
    myMotor->step(100, FORWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
    Serial.print("Blocked!! ");
    Serial.println(elapsedtime);
  }
}

void MotorActionForward()
{
  if (elapsedtime > 5500){
    myMotor->step(2, FORWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
    Serial.print("Foward ");
    Serial.println(elapsedtime);
  }
}

void MotorActionBackward()
{
  if (elapsedtime < 4500 && elapsedtime > 100){
    myMotor->step(2, BACKWARD, DOUBLE);
    elapsedtime=((millis()-prevtime));
    Serial.print("Back ");
    Serial.println(elapsedtime);
  }
}


------------------------------------------
sample output
------------------------------------------
time between button 1273
Back 67
time between button 1162
Back 67
time between button 1202
Back 67
time between button 8478
Foward 67
time between button 12715
Blocked!! 6761
Foward 6830
Foward 6908
Foward 6985
Foward 7063
Foward 7142
Foward 7220
Foward 7298
Foward 7376
Foward 7454
Foward 7532
Foward 7610
Foward 7688
Foward 7766
Foward 7845
Foward 7922
Foward 8000
Foward 8078
Foward 8156
Foward 8235
Foward 8312
Foward 8390
Foward 8468
Foward 8547
Foward 8625
Foward 8703
Foward 8780
Foward 8858
Foward 8937
Foward 9015
Foward 9093
Foward 9171
Foward 9249
Foward 9327
Foward 9405
Foward 9483
Foward 9561
Foward 9640
Foward 9717
Foward 9795
Foward 9873
Foward 9952
Foward 10030
Blocked!! 16801
Foward 16869
Blocked!! 23642
Foward 23709
Blocked!! 30481
Foward 30550
Blocked!! 37321
Foward 37390
Blocked!! 44162
Foward 44230
Blocked!! 6761
Foward 6829
Foward 6907
Foward 6985
time between button 6996
Foward 67

PaulS

Code: [Select]
if (ledstate==LOW){
        digitalWrite(outPin,HIGH);
        prevtime=millis();
        ledstate=HIGH;
      }

If you set ledstate first, and then write ledstate to the pin, it will be impossible for the value in the variable and the state of the pin to get out of sync. Doing it this way, sooner or later, you'll copy and paste that code, and forget to change one of the lines, and you'll be out of sync.

Quote
Now just for experiments sake, I want to have the servo go for a lot longer, but when I do the arduino no longer recognizes the button pushes while the stepper is moving.

Because the step() method blocks until the stepping is complete. You have two choices. Step a smaller number of times in each call, repeating the call, after checking the switch, until the desired number of steps has happened. Or, use the AccelStepper library, where stepping is a good idea, not mandatory. No, seriously, stepping is non-blocking. You do have to change the whole approach to using the library, and there is a target position and a current position (number of steps), and you need to periodically tell the class that it might be time to step again. There are examples with the library that should make it clear how to use the library.

nofed

Quote
Or, use the AccelStepper library, ...


Hopefully, I will soon learn the AccelStepper library this week, but first I might play around with multiple calls to the function before I do that.

Quote
If you set ledstate first, and then write ledstate to the pin, it will be impossible for the value in the variable and the state of the pin to get out of sync. Doing it this way, sooner or later, you'll copy and paste that code, and forget to change one of the lines, and you'll be out of sync.


I'm just still not getting what the suggested code would look like. I thought:
-----
if (ledstate==LOW){
        digitalWrite(outPin,HIGH);
        prevtime=millis();
        ledstate=HIGH;
-----
was "setting ledstate and then writing to the pin,..." Are you suggesting something different. Could I trouble you for suggested example code?

PaulS

Quote
I thought...was "setting ledstate and then writing to the pin,..."

Really? Since you write to the pin first, how can that sequence of events possibly be true?

It is writing a value to a variable and writing a value to the pin. And, they happen to be the same value. But, if you copy that code, and only change one line, you have an out-of-sync condition. If, on the other hand, the code looked like:
Code: [Select]
if (ledstate == LOW)
{ // Down here where it belongs!
        ledstate = HIGH;
        digitalWrite(outPin, ledstate);
        prevtime = millis();
}

then, a value is written to the variable, and then the contents of that variable are used to set the pin state. Now, if you copy this code, and only change one line, the contents of the variable and the state of the pin will still be the same.

Notethespacesadded,too,tomakethecodeeasiertoread. (And why they are needed.)

Go Up