Go Down

Topic: Stop motor with a limit switch (Read 478 times) previous topic - next topic

sherzaad

#15
May 17, 2018, 01:15 am Last Edit: May 17, 2018, 01:20 am by sherzaad
OK, I have revamped things a little and included a couple of photos of a *very* rough little mockup.


Here is my overall goal -- open a box lid periodically as a rotating lever hits it, hold it open for 30 seconds by stopping the motor rotation. After 30 seconds begin the motor rotation again.

-- Start a motor when an LDR detects a dark transition (someone moving in front of it) Earlier I talked about this being a push button but have now changed it to an LDR. The LDR goes HIGH when darkened.

-- Have an LED (Pin13 in this case) to work in parallel to the motor to monitor its on and off stages.

-- Rotate the motor until the lever on its shaft depresses a lever that raises the box lid

-- The lid activates a microswitch indicating the lid is open and the motor should stop for 30 seconds.

-- The motor should wait 30 seconds, holding the lid open to display the contents of the box for 30 seconds.

-- At 31 seconds (approximate) the motor should start rotating again, allowing the lid to close until another rotation opens it again.

-- This should go on over and over again until I turn the power off. (Well, ideally for about 3 minutes and then stop. But I might be biting off more than I can chew by trying include this 'auto stop'.


Current problems:

1. The microswitch doesn't stop the motor (it's a button right now temporarily attached to pin 6 for testing, but you can see my plan in the photo) .

2. I can't figure out how to set a 30 second delay once it does stop. I don't think I can just set the pin HIGH because the microswitch will be physically depressed and active.

I implemented the a code based on the state machine diagram I mentioned in reply#7

did not account for debouce in it but it you could try it out would be good to see if that the outcome you expected.

Also since you are using and LDR and not a switch anymore might need to tweak the code a bit further since with an LDR detecting movement its not a steady HIGH or LOW but a momentary pulse while movement is detected.

anyhow would be interested to know how it goes! :)

Code: [Select]
#define LDR 2
#define LED 13
#define MOTOR 9
#define LimitSwitch 6
#define WaitTime 30000 //30s wait

uint8_t machine_state = 0;
unsigned long oldmillis;

void setup() {

  pinMode(LDR, INPUT);
  pinMode(LimitSwitch, INPUT_PULLUP); //microswitch switch pin to ground
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  pinMode(MOTOR, OUTPUT);
  digitalWrite(MOTOR, LOW);

}

void loop() {

  switch (machine_state) {

    case 0  :
      machine_state = digitalRead(LDR);
      digitalWrite(MOTOR, LOW);
    break;

    case 1  :
      if (digitalRead(LDR) == LOW) {
        machine_state = 0;
        digitalWrite(MOTOR, LOW);
      }
      else if (digitalRead(LimitSwitch) == HIGH) {
        digitalWrite(MOTOR, HIGH);
      }
      else if (digitalRead(LimitSwitch) == LOW) {
        machine_state = 2;
        digitalWrite(MOTOR, LOW);
        oldmillis = millis();
      }
    break;

    case 2:
      if (digitalRead(LDR) == LOW) {
        machine_state = 0;
        digitalWrite(MOTOR, LOW);
      }
      else if (millis() - oldmillis > WaitTime) {
        digitalWrite(MOTOR, HIGH);
        machine_state = 1;
      }
    break;

  }


}

DH12043

One problem i saw immediately was that in your second to last line you had:
  stopSwitchPinState == HIGH;
The problem with this is that == is used for comparing values. You would use a double "=" in things like an "if()" statement. When you want to set a variable to equal something, use a single equals.

callmebob

#17
May 17, 2018, 06:22 am Last Edit: May 17, 2018, 06:24 am by callmebob
Thanks sherzaad -- I'll look at the help you've provided -- I just hope my head doesn't explode trying to learn about states, switch, case, etc. I'm planning on not needing debounce for these two.

And DH12043 thanks -- I'll change that and see what happens...

UKHeliBob

Quote
2. I can't figure out how to set a 30 second delay once it does stop. I don't think I can just set the pin HIGH because the microswitch will be physically depressed and active.
If you still have that problem you can solve it by detecting when the switch becomes pressed rather than when it is pressed.  See the StateChangeDetction example in the IDE. 

Use millis() for the timing.  See Using millis() for timing.  A beginners guide,   Several things at the same time and look at the BlinkWithoutDelay example in the IDE.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Robin2

I believe your code would be much easier to develop if you use meaningful names for the states rather than numbers. Have a look at how I did it in the code in this Thread. I used an ENUM to establish the names.

Also, I would not use this style of code to change the state
Code: [Select]
machine_state = digitalRead(LDR);
I would have more explicit code so I (as programmer) had no doubt about what war supposed to happen - for example
Code: [Select]
LDRstate = digitalRead(LDRpin);
if (LDRstate == HIGH) {
   machineState = <next machine state>
}


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

callmebob

#20
May 20, 2018, 04:32 pm Last Edit: May 20, 2018, 06:06 pm by callmebob Reason: Added LDR module fact at end of first paragraph
Well, I studied your code and was able to understand a lot of it, but sadly, the motor didn't start. The motor driver (L298) requires two inputs to run the motor and I discovered that IN_1 references weren't included in your example. I put them in (my addition below yours) and I got the motor to start, but it ran at two different speeds and sometimes stopped as I ran my hand over the LDR (or replaced the LDR with a wire to +5 and plugged in and out to be sure it wasn't a failing LDR). BTW my LDR is module that goes from LOW to HIGH

The stop switch stopped the motor but the motor did not start again (I changed your delay to 1000).

I have also poured over Robin2's and UKHeliBob's tutorials with no luck. Have I missed something in those? All I see in those tutorials are examples of making things flash and sweep infinitely. I can't find any examples of running and stopping two things at different times, with different waiting periods.

I'd sure like to get this to work as it will be so useful to me in many projects!

I implemented the a code based on the state machine diagram I mentioned in reply#7

did not account for debouce in it but it you could try it out would be good to see if that the outcome you expected.

Also since you are using and LDR and not a switch anymore might need to tweak the code a bit further since with an LDR detecting movement its not a steady HIGH or LOW but a momentary pulse while movement is detected.

anyhow would be interested to know how it goes! :)

Code: [Select]
#define LDR 2
#define LED 13
#define MOTOR 9
#define LimitSwitch 6
#define WaitTime 30000 //30s wait

uint8_t machine_state = 0;
unsigned long oldmillis;

void setup() {

  pinMode(LDR, INPUT);
  pinMode(LimitSwitch, INPUT_PULLUP); //microswitch switch pin to ground
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  pinMode(MOTOR, OUTPUT);
  digitalWrite(MOTOR, LOW);

}

void loop() {

  switch (machine_state) {

    case 0  :
      machine_state = digitalRead(LDR);
      digitalWrite(MOTOR, LOW);
    break;

    case 1  :
      if (digitalRead(LDR) == LOW) {
        machine_state = 0;
        digitalWrite(MOTOR, LOW);
      }
      else if (digitalRead(LimitSwitch) == HIGH) {
        digitalWrite(MOTOR, HIGH);
      }
      else if (digitalRead(LimitSwitch) == LOW) {
        machine_state = 2;
        digitalWrite(MOTOR, LOW);
        oldmillis = millis();
      }
    break;

    case 2:
      if (digitalRead(LDR) == LOW) {
        machine_state = 0;
        digitalWrite(MOTOR, LOW);
      }
      else if (millis() - oldmillis > WaitTime) {
        digitalWrite(MOTOR, HIGH);
        machine_state = 1;
      }
    break;

  }


}

.
.


I added references to IN_1 up to the first 'if' statement in case 1

Code: [Select]

#define LDR 2
#define LED 13
#define MOTOR 9   //HIGH runs motor
#define IN_1 3  //to Input 1 on L298N. HIGH runs motor
#define LimitSwitch 6
#define WaitTime 1000 //30s wait

uint8_t machine_state = 0;
unsigned long oldmillis;

void setup() {

  pinMode(LDR, INPUT);
  pinMode(LimitSwitch, INPUT_PULLUP); //microswitch switch pin to ground
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  pinMode(MOTOR, OUTPUT);
  digitalWrite(MOTOR, LOW);
  pinMode(IN_1, OUTPUT);

}

void loop() {

  switch (machine_state) {

    case 0  :
      machine_state = digitalRead(LDR);
      digitalWrite(MOTOR, LOW);
      break;

    case 1  :
      if (digitalRead(LDR) == HIGH) {
        machine_state = 0;
        digitalWrite(MOTOR, HIGH);  // 1st input need to run motor
        digitalWrite(IN_1, HIGH);      // 2nd input needed run motor
      }
      else if (digitalRead(LimitSwitch) == HIGH) {
        digitalWrite(MOTOR, HIGH);
      }
      else if (digitalRead(LimitSwitch) == LOW) {
        machine_state = 2;
        digitalWrite(MOTOR, LOW);
        oldmillis = millis();
      }
      break;

    case 2:
      if (digitalRead(LDR) == LOW) {
        machine_state = 0;
        digitalWrite(MOTOR, LOW);
      }
      else if (millis() - oldmillis > WaitTime) {
        digitalWrite(MOTOR, HIGH);
        machine_state = 1;
      }
      break;

  }
}

232

It would  probably help YOU to go back to commenting you code.
I am not going to ask why you quit commenting your code, but it is not a good idea to do so.

For example this digitalRead(LDR); line at  state  0 can only be 0 or 1 , hence as code machine_state 0 or 1 .
It probably works at start  in machine_state 0  , but will  be questionable in other states.

machine_state = digitalRead(LDR);

BTW
State machine  code should maintain control of all states - relying on loop() to do the job for you - falling thru to state 0  will work , but it is not always a good idea, especially when the code is not commented.
Thunder is good, thunder is impressive; but it is lightning that does the work.

Robin2

#22
May 20, 2018, 07:50 pm Last Edit: May 20, 2018, 07:56 pm by Robin2
Well, I studied your code and
Whose code are you referring to? It is always a good idea to mention the number of the Reply you are referring to.


Quote
I'd sure like to get this to work as it will be so useful to me in many projects!
In your program what does "machine_state" mean? I am not asking what values it can have but what are the activities you are trying to manage?  And I am posing this question for the value to you of answering it - as well as helping me to understand your thinking.

Quote
I have also poured over Robin2's and UKHeliBob's tutorials with no luck. Have I missed something in those? All I see in those tutorials are examples of making things flash and sweep infinitely. I can't find any examples of running and stopping two things at different times, with different waiting periods.
What is the difference there in common between a timing event that is repeated and one that only happens once?

My guess is that you are too much focused on how to write code and not enough on the simple logic of the system you want to create. Try writing down all the steps the system needs to go through with each step on a new line.

...R

Two or three hours spent thinking and reading documentation solves most programming problems.

callmebob

Whose code are you referring to? It is always a good idea to mention the number of the Reply you are referring to.
Good point about the message number -- I'll do that from now on. I was referring to sherzaad's code in message #15. I quoted him, but guess the quote wound up too far away from my prelude.
.
.
.
In your program what does "machine_state" mean? I am not asking what values it can have but what are the activities you are trying to manage?  And I am posing this question for the value to you of answering it - as well as helping me to understand your thinking.
I'm trying to understand machine_state myself -- it is code that sherzaad posted for me to try out in post #15 (And he didn't reproduce much of my commenting, so that's why there are fewer comments now than in my post #14).
.
.
.
My guess is that you are too much focused on how to write code and not enough on the simple logic of the system you want to create. Try writing down all the steps the system needs to go through with each step on a new line.
I don't doubt that a bit. I pretty much did write it all out in message #14. I'll go back to that and see if I can sort out the forest for the trees.

sherzaad

#24
May 20, 2018, 11:05 pm Last Edit: May 20, 2018, 11:06 pm by sherzaad
I don't doubt that a bit. I pretty much did write it all out in message #14. I'll go back to that and see if I can sort out the forest for the trees.
If I may, does this summerise what you would like to build/code

1. detect movement infront of object (using LDR)
2. open box (motor operated)
3. leave box open for 30s (limit switch operated once box is fully open)
4. close box after 30s (just guessing here... :) )

callmebob

Yes, that's what I want to do. -- Seems so simple...
If I may, does this summerise what you would like to build/code

1. detect movement in front of object (using LDR) [LDR module is digital -- it changes directly from low to high]
2. open box (motor operated)
3. leave box open for 30s (limit switch operated once box is fully open)
4. close box after 30s (just guessing here... :) )


sherzaad

#26
May 21, 2018, 12:09 am Last Edit: May 21, 2018, 12:09 am by sherzaad
Yes, that's what I want to do. -- Seems so simple...
ok great... now the specs are clear!

this means that  your motor needs to operated forward AND Backwards to be able to open and close the box... there's a few steps you probably need to add to both code and hardware... can you think what they could be? :)

lastchancename

Just to throw some fuel on the flame fire..
For the doubters...
Quote
'm using a little gearhead motor at 12V. Yes a servo would be a good solution
Believe it or not - you have created a 'servo'!
An actuator (the motor) with feedback (the switch) is a simple servo!

And it's all you need in this project, so you've created exactly the straightest line between the two points of your requirement and the solution.
Ask the right question, which can be hard for beginners, but this doesn't mean that google is broken.
Experienced responders have a nose for laziness, (they were beginners once)... expecting the poster to contribute to the learning experience.

callmebob

OK I give up for now. I want to get better at controlling motors, but this project just isn't working out.

I'll see if I can make this work with a servo for now and come back to the motor idea another day. Thanks everyone for your help.

Go Up