Programing motor with encoder

I think you would benefit from reading Nick Gammon's excellent tutorial on interrupts. It will help explain what is being talked about. It will also explain why delay(10000) in the isr did not do what you wanted.
https://gammon.com.au/interrupts

1 Like

I'm reading the tutorial, but I have a few questions. First thank you for the help I didn't know interrupts were a thing and I think i can benefit from using them in my machine.

Im thinking of using it to check for a stop button press, because in the passed I've always had to hold the button till the code got to a point that called for a check of the value of the button. this seems like a better way of doing this. But will it bee too much to do that and the counter?

it says in the tutorial that you need to keep things simple and that if you are running one interrupt you might miss another interrupt. So I'm worried if I'm running the counter interrupt ill miss the button press interrupt. so is there another way to run the counter without using an interrupt?

I'll be using a state machine style code will the interrupt still work?

Your are describing "blocking" code and using and interrupt is the wrong solution. You need to structure the code to be "non-blocking" so that the loop() repeats so frequently that the code is responsive to inputs.

delay(), for() loops, and while() loops can all be blocking.

Here is a good discussion of blocking code.
https://www.programmingelectronics.com/delay-vs-millis-arduino/

One key tutorial which shows you how to use millis() for timing instead of delay() is
https://forum.arduino.cc/t/using-millis-for-timing-a-beginners-guide/483573

1 Like

thank you I'll take a look at the blocking and the millis() for timing.

I was using delay in my code above for ease of use and to break up each rotation not necessarily for timing. but the millis() will come in handy.

There are certainly times when it makes your brain hurt less to use delay() and it's fine to use if you are not blocking something else which needs to be happening. The main point is to not use an interrupt to deal with issues arising from blocking code.

I'm not clear why you would need button input in the process you posted in reply #69.

It is possible that you will use an interrupt for the groove finding sensor but checking that sensor in a tight loop is not out of the possibility. You'll see more clearly what to do when you get to that part of the program.

let me put together a bit more of the program and I'll post it. the code i used before (#69 and #70) were just for trouble shooting. that code has been retired and now I'm trying to implement what i learned into a state machine.

I put this together, it's definitely not complete but might help you visualize more of what I'm doing. The current way it is set up is how I've done other machines for my company in the past.

There will be more states and actions in the final iteration of the code but this is the extremely simplified version.

In the past when I have needed to use a motor I've only used steppers which to me seem way more simple (easier to understand) than the geared motor setup I'm using now. But with the space constraints that I have I chose to go with a dc geared motor with encoder.

As you can see I've yet to implement the counting portions of the code that controls the distance traveled of the dc motor, but I have set the relay that controls the motor HIGH and LOW to show when it will be on and off. I just haven't quite figured out how i want to add the count++ part, if i should still use that as an interrupt or not.

In regards to the stop button you can see there is a stopButton check in state 10. This is how I've done button checks in the past and it has worked so far. Having a state at the end of a loop sequence right before the the machine cycles to the next part. This would function as a "none emergency stop" feature where the operator wanted to stop the machine before it cycles but doesn't think its an emergency or critical to stop the machine immediately. This requires the operator to press and hold the stop button till it gets to that state were it then checks for a button press and does the appropriate action.

for emergence stops I usually include a larger button on the front of the machine, using a button that locks when pressed, like one you would see on mills, lathes, drill presses, etc. that cuts all power to the arduino. This has worked in the passed as well.

I'm not sure if this is the proper way of doing things, but it has worked int the passed. That being said every time I build one of these machines I try and learned new things and make it function better than the last. That is why i was wondering if the button checks should be an interrupt.

since the code Isn't complete I'll give a break down of the states,

state 0 - reset state
state 1 - checks the irSensor t make sure the machine is loaded and turnes on an LED
state 2 - Checks to make sure the Load LED is on
state 3 - waits for the start button to be pressed
state 4 - start button debounce phase 1
state 5 - start button debounce phase 2
state 6 - activates pusher to load a turbo into machine
state 7 - checks groove locator switch if its not triggered rotate the turbo suing geared motor and then check again, if still not located rotate and check till switch is triggered
state 8 - rotate turbo using geared motor so one of the pads is under dial indicator then trigger relay to lower dial indicator
state 9 - trigger relay to take data reading, rotate motor to next pad then trigger relay to take date reading, do this so you have three data readings
state 10 - check to see if stop button is pressed
state 11 - check to see if full switch is triggered and check to see if Load LED is still on
state 12 - set pusher relay LOW so it pulls back the pusher so another turbo drops in then cycle to state 6 to repeat
state 13 - (place holder if needed)
state 14 - stop button debounce phase 1
state 15 - stop button debounce phase 2 cycle to state 0 if pressed cycle to state 10 if not pressed

there will be more to this code because at the end of the machine there is a shoot with a carriage that the turbos will be pushed onto then lowered each cycle using an acme threded rod and stepper motor.

the code below has been verified and formatted. There may be some "odd" things in there because this was built off an old code I wrote about a year ago. Its practically all new but I used as a template. (like the wire library I don't remember what it is for, I'm pretty sure I don't need it, but I also don't think it's hurting anything so I left it)

#include <Stepper.h> //stepper library
#include <Wire.h>

#define grooveTarget = 1000 //target to move the turbo when trying to find the groove
#define ENCA = 18 //yellow
#define ENCB = 19 //white
#define initialpadrotationTarget = 2000 //target when rotating from groove to pad
//declairing pins
int irSensor = 56;
int LED = 53;
int startButton = 52; //start button callout
int stopButton = 51; //stop button callout
int resetButton = 50; //reset button callout
int upButton = 49; //up button callout
int downButton = 48; //down button callout
int homeSwitch = 47; //home switch callout
int fullSwitch = 46; //full switch callout
int grooveSwitch = 45; //groove switch callout
int relay1 = 4; //pusher relay
int relay2 = 5; //dial indicator relay
int relay3 = 6; //motor relay
int relay4 = 7; // data relay
int detect;
int val_startButton = 0; //value of start button
int val_stopButton = 0; //value of stop button
int val_resetButton = 0; //value of reset button
int val_upButton = 0; //value of up button
int val_downButton = 0; //value of down button
int val_LED = 0; //value of power led
int val_homeSwitch = 0; //value of home switch
int val_fullSwitch = 0; //value of full switch
int val_grooveSwitch = 0; //value of groove switch
int state = 0; //setting state to zero at start up
int statePrev = 0; //setting statePrev to zero at start up

//declaring unsigned long
unsigned long t_startButton = 0; //variables for debouncing button
unsigned long t_0_startButton = 0; //variables for debouncing button
unsigned long t_stopButton = 0; //variables for debouncing button
unsigned long t_0_stopButton = 0; //variables for debouncing button
unsigned long t_resetButton = 0; //variables for debouncing button
unsigned long t_0_resetButton = 0; //variables for debouncing button
unsigned long t_upButton = 0; //variables for debouncing button
unsigned long t_0_upButton = 0; //variables for debouncing button
unsigned long t_downButton = 0; //variables for debouncing button
unsigned long t_0_downButton = 0; //variables for debouncing button
unsigned long bounce_delay = 5; // debouncing timer 5ms

void setup() {
  //declaring inputs
  pinMode (irSensor, INPUT);
  //declaring outputs
  pinMode (LED, OUTPUT);
  pinMode (relay1, OUTPUT);
  pinMode (relay2, OUTPUT);
  pinMode (relay3, OUTPUT);
  pinMode (relay4, OUTPUT);
  //calling pullup resistors
  pinMode (startButton, INPUT_PULLUP);
  pinMode (stopButton, INPUT_PULLUP);
  pinMode (resetButton, INPUT_PULLUP);
  pinMode (upButton, INPUT_PULLUP);
  pinMode (downButton, INPUT_PULLUP);
  pinMode (homeSwitch, INPUT_PULLUP);
  pinMode (fullSwitch, INPUT_PULLUP);
  pinMode (grooveSwitch, INPUT_PULLUP);

  digitalWrite (relay1, HIGH);
  digitalWrite (relay2, HIGH);
  digitalWrite (relay3, HIGH);
  digitalWrite (relay4, HIGH);

}

void loop() {
  SM_LM (); //calling state machine
  if (state == 1) {
    int detect = digitalRead(irSensor);
    if (detect == LOW) {
      digitalWrite(LED, LOW);
      state = 0;
    }
    if (detect == HIGH) {
      digitalWrite (LED, HIGH);
      state = 2;
    }
  }

  if (state == 6) { //pushing turbo into machine phase
    int detect = digitalRead(irSensor); //checking irSensor again to know if its still loaded
    if (detect == LOW) {
      digitalWrite(LED, LOW);
    }
    if (detect == HIGH) {
      digitalWrite (LED, HIGH);
    }
    digitalWrite(relay1, LOW); //setting relay low to push turbo into machine
    delay (1000);
    state = 7;
  }

  if (state == 7) {
    val_grooveSwitch = digitalRead(grooveSwitch); //checking the groove switch to see if it has found a groove
    if (val_grooveSwitch == LOW) {
      state = 8;
    }
    if (val_grooveSwitch == HIGH) {
      digitalWrite (relay3, HIGH); //turning on the motor to spin the turbo to find the groove
      //more lines of code
      //needs to rotate the motor till groove switch is triggered
    }
  }

  if (state == 8) {
    digitalWrite (relay3, HIGH); //turning on motor to rotate turbo to locate a pad under dial indicator
    //more line of code
    //counting till it reaches the targe then turning off the motor
    digitalWrite (relay3, LOW); //stop motoer when it reaches its target
    digitalWrite (relay2, HIGH); //lowering dial indicator
    state = 9;
  }

  if (state == 9) {
    digitalWrite (relay4, HIGH); //triggering data relay to taking reading from dial indicator
    //timmer
    digitalWrite (relay4, LOW); //turning of data relay

    digitalWrite (relay3, HIGH); //turning on motor to rotate to next pad location
    //more lines of code
    //rotating till target is reached then turning off motor
    digitalWrite (relay3, LOW); //turning off motor

    state = 10;

  }
  if (state == 10) {
    val_stopButton = digitalRead (stopButton);
    if (val_stopButton == HIGH) {
      state == 11;
    }
    if (val_stopButton == LOW) { //stop button is pressed and goes to debouncing
      state = 14;
    }
  }
}
void SM_LM () {
  statePrev = state;

  switch (state) {

    case 0: //reset
      statePrev = 0;
      state = 1;
      break;

    case 1: //checking if hot stamp machine is loaded
      break;

    case 2:
      val_LED = digitalRead(LED);
      if (val_LED == LOW) {
        state = 0;
      }
      if (val_LED == HIGH) {
        state = 3;
      }
      break;
    case 3: //checking for button press
      val_startButton = digitalRead(startButton);
      if (val_startButton == LOW) {
        state = 4;
      }
      break;

    case 4: //button timer
      t_0_startButton = millis ();
      state = 5;
      break;

    case 5: //button debounce
      val_startButton = digitalRead(startButton);
      t_startButton = millis();
      if (val_startButton == HIGH) {
        state = 0;
      }
      if (t_startButton - t_0_startButton > bounce_delay) {
        state = 6;
      }

    case 6: //activate pusher
      break;

    case 7: //check groove locator switch check
      break;

    case 8: //rotate to pad and lower dial indicator
      break;

    case 9: //taking data readings and rotating
      break;

    case 10: //checks before cycling
      break;

    case 11: //cycle Phase
      break;

    case 14: //debouncing stop button timer
      t_0_stopButton = millis();
      state = 15;
      break;

    case 15: //debouncing stop button timer 2
      val_stopButton = digitalRead(stopButton);
      t_stopButton = millis();
      if (val_stopButton == HIGH) {
        state = 10;
      }
      if (t_stopButton - t_0_stopButton > bounce_delay) {
        state == 0;
      }
      break;
  }
}

so I've added what I've learned here into another test code, but I'm having a hard time. It seams like its starting to do the right thing it checks the groove switch sees that its not triggered and runs the motor but it seams as if the code is cycling so fast and rechecking the switch that it doesn't allow it to count passed 0 and then reads the groove switch trigger but then drifts passed the groove and then checks again and sees its not in a groove anymore so it rotates again and it does this non stop.

here is the serial monitor:

here is the code:

#include <util/atomic.h> 
int ENCA = 18; //yellow
int ENCB = 19; //white

int irSensor = 5;
int LED = 53;
int detect = 0;
int state = 0; //setting state to zero at start up
int statePrev = 0; //setting statePrev to zero at start up
int dataReading = 0;
int dataTotal = 0;
int relay3 = 4; //motor relay
int grooveSwitch = 3;
int target = 10;
volatile unsigned long  count = 0;
int val_grooveSwitch = 0;

void setup() {
  //declaring inputs
  pinMode (irSensor, INPUT_PULLUP);
  //declaring outputs
  pinMode (LED, OUTPUT);
  pinMode (grooveSwitch, INPUT_PULLUP);
  pinMode (relay3, OUTPUT);
  digitalWrite (irSensor, HIGH);
  pinMode(ENCA, INPUT);
  pinMode (18, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCA), isrCount, RISING);
  Serial.begin (115200);
}

void loop() {
  SM_LM (); //calling state machine
  if (state == 1) {
    Serial.println ("state = 1");
    int detect = digitalRead(irSensor);
    Serial.println ("checking ir sensor");
    if (detect == HIGH) {
      Serial.println ("machine not loaded");
      state = 0;
    }
    if (detect == LOW ) {
      Serial.println ("machine loaded");
      state = 2;
    }
  }



}
void isrCount()
{
  count++;
}

void SM_LM () {
  statePrev = state;

  switch (state) {

    case 0: //reset
      statePrev = 0;
      state = 1;
      break;

    case 1: //checking if hot stamp machine is loaded
      break;

    case 2:
      val_grooveSwitch = digitalRead(grooveSwitch);
      Serial.println ("state = 2");
      if (val_grooveSwitch == LOW) {
        Serial.println ("disk under groove switch");
        state = 3;
      }
      break;

    case 3:
      val_grooveSwitch = digitalRead (grooveSwitch);
      Serial.println ("state = 3");

      if (val_grooveSwitch == LOW) {
        Serial.println ("groove not found");
 if (count < target) {
   digitalWrite (relay3,HIGH);
  interrupts();
  Serial.println (count);
 }

  if (count > target) {
  digitalWrite (relay3, LOW);
   delay(5000);
  count = 0;
  }
      }
      if (val_grooveSwitch =! LOW) {
        Serial.println("groove located");
        digitalWrite (LED, LOW);
        Serial.println ("LED");
      }

      break;
  }
}

That doesn't look like code that could print that output.

youre right i copied the wrong one haha

UPDATED CODE^

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.