Limit switch triggering too slowly / Actuator with max/min adjustment 2 limits

Introduction:

Hi all, I have been reading through endless amounts of related or similar projects to mine. While I did learn a lot, I am still having some issues with coding it seems. I have read through the “How to get the best out of this forum (short version)” and will try to follow it religiously to help avoid generating headaches for anyone. I am a beginner and will be grateful if I was treated as such. I am eager to learn and hope to become a productive and useful member of the forum one day.

Note: I know the guided stated NOT to use “Fritzing diagrams.” However, I think the wiring schematic is simple enough that it should not cause any confusion. Also, please recommend a good software replacement. I have attached the Fritzing diagram along with the LM393 IR speed sensor as the one I can for the Fritzing software only had a 4-pin variant. I am willing to learn, just let me know if anything that I wrote was confusing or can be further clarify to help you guys out. :slight_smile: :slight_smile:

Choose the right section of the Forum:

I am pretty sure my issue is regarding the code hence I use the “Programing Questions”

Hardware:

  • Arduino Uno (Rev.3) (x1)

  • 30 KG Digital Servo (x1)

  • Dual channel 5v relay module (x1)

  • DC to DC converter (x1)

  • 30 watt DC motor (x1)

  • LM393 IR speed sensor module (3-pin type) (x2)

  • 12V DC power supply (x1)

  • Push Button (2-pins) (x1)

Code problems:

Expected from code:

I am currently trying to build an actuator that can have its maximum and minimum stroke length adjusted by two limit switches located on the outside of the cylinder. The actuator will be powered by a dc motor which will then have its direction controlled by two relays depending on the state of the two limit switches and the push button (cycle button). A servo is also part of the assembly. One full “cycle” should look something like the following.

1: Cycle button pressed

2: Servo moves from 0* to 180* (short delay of 500ms)

3: Motor rotates CW to drive the actuator rod forwards

4: Front Limit switch is triggered

5: Motor STOPS

6: Servo Moves from 180* to 0* (short delay of 500ms)

7: Motor rotates CCW to drive the actuator rod backwards

8: Back Limit switch is triggered

9: Motor STOPS

10: Wait for Cycle button to be pressed

What actually happens:

The program actually works for the most part, however, it seems that at times the front limit sensor would trigger too slowly causing the triggering nub to smash right into the limit sensor. What is confusing to me is that it would work as coded for maybe 8 cycles and then it would suddenly just run past the sensor. The light on the sensor flickers on and off which shows that the sensor senses movement but does nothing or does not do it in time to prevent a collision. I would appreciate any kind of help; I am at my wits end. I am well versed in mechanical design and systems; programing has been quite a difficult process.

The following is the code

#include <Servo.h>
Servo servo;


//Variables

const int relay1 = 2;
const int relay2 = 3;
const int cycleButton = 4;
const int LMF = 6;
const int LMB = 7;
int m;


//PROGRAM FUNCTIONS

void motorCW() // function to make motor turn CW
  {
    digitalWrite(relay1, LOW);
    digitalWrite(relay2, HIGH);
  }

void motorCCW() // function to make motor turn CCW
  {
    digitalWrite(relay1, HIGH);
    digitalWrite(relay2, LOW);
  }

void motorSTOP() // function to make motor stop
  {
    digitalWrite(relay1, HIGH);
    digitalWrite(relay2, HIGH);
  }


void setup()

{
  pinMode(cycleButton, INPUT_PULLUP); // set pin 4 as INPUT_PULLUP for cycle button
  pinMode(LMF, INPUT); // set pin 6 as INPUT for Front IR Sensor Limit
  pinMode(LMB, INPUT); // set pin 7 as INPUT for Front IR Sensor Limit
  pinMode(relay1, OUTPUT); // set pin 2 as output for relay 1
  pinMode(relay2, OUTPUT); // set pin 3 as output for relay 2
  servo.attach(5); // attach Servo to pin 5
  digitalWrite(relay1, HIGH); // set relay 1 OFF State
  digitalWrite(relay2, HIGH); // set relay 2 OFF State
}


void loop(){  
  if (digitalRead(cycleButton) == LOW) {
    m = 0; 
  }
  if (digitalRead(LMF) == HIGH) {
    m = 1;
  }
  if (digitalRead(LMB) == HIGH) {
    m = 2;
  }
  if (digitalRead(cycleButton) == LOW && digitalRead(LMB) == HIGH) {
    m = 3;
  }
  switch(m) {
    case 0: {
      servo.write(180);
      delay(500);
      motorCW();
      break;
    }

// Ideally for case 1 would be 1: motorSTOP 2: Servo to 0 3: Delay (500) to give time for servo 4: motor CCW; this does not work however. The moment I use motorSTOP it will not start again

    case 1: {
      motorCCW();
      servo.write(0);
      break;
    }
    case 2: {
      motorSTOP();
      break;
    }

// Case 3 is here because the Cycle button wont work once it has run its first cycle as LMB will be triggered HIGH and hence it will trigger function motorSTOP()

    case 3: {
      servo.write(180);
      motorCW();
      break;
    }
  }
}

61nwYSL-auL.SL1100.jpg

61nwYSL-auL.SL1100.jpg

This is a quick answer because I am posting on a mobile phone.

In switch case 0 you have half a second where nothing happens, plenty of time for the motor to drive past the limit. There's plenty on this website about timing without delay, both in tutorials and replies to questions, including by me in the past few days. Do some searching.

As for software to produce a proper schematic I am sure I mentioned KiCAD and Eagle in the tutorial and I am sure I mentioned hand drawn and photographed. Personally I find your fritzy thing difficult to read.

Otherwise nicely presented post.

Hi Perry, it is an honor to have you reply personally and so quickly :fearful: I apologize for the use of fritzing for the diagram. It is just that I am super new to this and fritzing seemed to be the simplest software to quickly get a visual reference to what was written. I will try to learn KiCAD right after this project has completed.

**"*In switch case 0 you have half a second where nothing happens, plenty of time for the motor to drive past the limit." From my understanding is that once the button is pressed the servo will require some time to actually move to its requested position, so while this movement is happening I added the delay. Once the servo has fully stopped at the requested position in this case 180, the motor should then move. I tried it without the delay also; same result, the nub still sometimes run passes the front limit switch. Also, it typically takes at least a few seconds for the nub to reach the Front Limit when driven from the Back Limit. So I do not see how this can be an issue.

I am not sure if my understanding is correct. Though I think that once the "cycle button" is pressed no other cases are true, hence the arduino must be consistently reading the "if statements" looking for a trigger to happen for it to then refer to a case #. If I am not mistaken then while the motor is in motion there should not be anything stopping the arduino for being prepared for a trigger, either from the front or back limits.

"There's plenty on this website about timing without delay, both in tutorials and replies to questions, including by me in the past few days. Do some searching." - You are referring to the use of the millis() function correct? I have honest to god did many searches (I have been at this for a little over one month); and am still left a little unsure of how to proceed forward from the point I am currently at. I have actually watched a lot of tutorials online also. However, I must say that the examples are rather vague or very specific to their example that it makes it hard to apply the code else where. Please also send me a link in regards to where I should start. The concepts are fairly simple, but the implementation is quite difficult to be honest, but I am trying.

"Otherwise nicely presented post."
Thanks :grinning: I want the post to be useful for others who could potentially be interested in making a similar actuator in the future; and to learn from a very detailed post to answer any potential lingering questions they might have.

I eagerly wait for a reply, thanks for giving me hope Perry, much appreciated.

once you enable the motor, in either direction, the code needs to constantly monitor the limit switches.

when you reposition the servo and give it time to move, the motor should probably be stopped unless it is guaranteed not to hit the limit switch during that delay.

in case 1, when it hits the LMF, the motor should be stopped, the servo can be commanded to a new position, there can be a delay and finally the motor enabled for CCW.

shouldn't cases 1 and 3 be the same? presumably the need for case 0 is to start the device when the motor in between limit switches.

each iteration thru loop reinvokes the switch machine so after invoking a switch case, it will be repeated. while the servo should not do anything different, the delay will prevent checking the limit switch

you've implemented a state machine the repeats some action in each case. a more convention state machine would be to look for an event, in you case, look for a cycle button or limit switch to become active. when they do, perform some action (i.e. move servo, enable motor) and then change state to look for a new event. in your case, the code expects a specific event but could look for multiple events.

Hi gcjr :smiley:

"once you enable the motor, in either direction, the code needs to constantly monitor the limit switches." - I read this somewhere and implemented it in a way that I understood (perhaps wrongly). This is what I understand from my own code. Once a specific Case # is met, the action under the Case # is preformed, and then after all the requested actions are preformed the arduino then “leaves” the Case # to go constantly read the “IF statements” above to until another Case # can be triggered. Therefore in my head I do not see how the trigger can be missed. as it will already be constantly reading the “IF statements” above.

"when you reposition the servo and give it time to move, the motor should probably be stopped unless it is guaranteed not to hit the limit switch during that delay." - Yes this is correct. Notice Case 0 where I have written a specific order of events, so in my mind it should work something like this. Servo is told to move from 0* - 180*. While this is happening the next command is to wait for half a second which from visual inspection of the movement is enough for the Servo to position itself. Then the function “motorCW()” is called for to move the motor forward. Once the motor is in motion then the arduino breaks out of Case 1. Then it should theoretically go on the monitor the “IF statements” above as neither LMF (Front Limit) or LMB (Back Limit) is HIGH, “Cycle button” would have already been let go of so it would read HIGH (due to INPUT_PULLUP). So Cases 0, 1, 2 will not activate. For Case 3 to happen the nub would have to have already completed the cycle and stop at LMB and have “Cycle button” be pressed to work. I added this due to the fact that initially once the cycle completed it would just not move again due to Case 2 being constantly True.

"in case 1, when it hits the LMF, the motor should be stopped, the servo can be commanded to a new position, there can be a delay and finally the motor enabled for CCW." - I tried implementing this exactly like Case 0. However, Once I call for the function “motorSTOP()” the arduino stops the motor and does nothing else. It does not follow any command after than point. Which is very confusing as from my understanding it should not simply stop and do nothing. For example.

Case 1: {
motorSTOP();
servo.write(0);
delay(500);
motorCCW();
break;
}

This would be ideal, but somehow it does not work. It just stops and that’s it. So I had to simply make due with the servo trying to move to its requested position as the motor suddenly changes its direction.

"shouldn’t cases 1 and 3 be the same? presumably the need for case 0 is to start the device when the motor in between limit switches." - This is correct. Case 0 is to start the device between the limits. However, a strange anomaly where the moment I power the arduino it always run Case 0 right away. A fix would be nice lol.

"each iteration thru loop reinvokes the switch machine so after invoking a switch case, it will be repeated. while the servo should not do anything different, the delay will prevent checking the limit switch" - This I understand, hence I have tried only to implement the short delay while the motor has stopped to give the servo time to rotate. So therefore the delay time would have already been up before the motor nub was able to trigger LMB anyways.

"you’ve implemented a state machine the repeats some action in each case. a more convention state machine would be to look for an event, in you case, look for a cycle button or limit switch to become active. when they do, perform some action (i.e. move servo, enable motor) and then change state to look for a new event. in your case, the code expects a specific event but could look for multiple events." - I understand what you are saying, though I still do not understand why sometimes the sensor triggers too slowly even without any delay functions at all I have tried it. As mentioned in my previous reply to Perry, the code works; however, sometimes it runs pass the limit and smashes into the other side and does not switch to another Case #. For example, imagine the motor already in motion going forward and the servo has already positioned itself. Now as no “IF statements” are true the arduino should constantly cycle through all the “IFs,” therefore it should already be constantly checking the LMF (Front Limit) while actually checking all the other limits also. Therefore LMF should trigger HIGH and start Case 1 right away. Which it does to an extend and then it fails at random almost as if the nub went by too quickly for sensor to catch it. Would reading 1 specific limit help speed things up? Though I doubt that its the issue as the arduino should be quick enough to read all “IF statements” in time. Maybe the forum would benefit from a video reference lol.

Thanks for your reply gcjr.

it seems that you have the impression that the switch statement is only invoked when the cycle button or limit switch become active and set m.

the switch is invoked each iteration thru loop() and unless m is changed or set to a value that is not one of the case, some action will be performed/repeated.

Ohh, I am starting to get it. So the potential reason that the limits are triggering so slowly or not always is because it keeps running the specific Case over and over until another case happens. If the specific case has a lengthy command for example Case 0 the nub could have already passed the limit sensor correct? The arduino however is quick enough that at times it is able to compensate for this repeating the Case over and over and still managing to catch the triggering and changing of m. Is my understanding correct? If so how would I implement change. I would really appreciate a reference code of some sort. The theory and concepts I have no problem wrapping my head around. However if I were to do this on my own it would no doubt take me a least another month (hopefully that does not happen lol).

consider
bear in mind that when just checking for switch presses, loop() is running 100,000s / sec

#if 0       // my hardware
struct Servo {
    void attach (int pin)  {};
    void write  (int ang)  {
        Serial.print   ("  servo ");
        Serial.println (ang);
    };
};

const int relay1 = 10;
const int relay2 = 11;
const int cycleButton = A1;
const int LMF = A2;
const int LMB = A3;

enum { LM_ON = LOW, LM_OFF = HIGH };

// -------------------------------------
#else
#include <Servo.h>
//Variables
const int relay1 = 2;
const int relay2 = 3;
const int cycleButton = 4;
const int LMF = 6;
const int LMB = 7;

enum { LM_ON = HIGH, LM_OFF = LOW };
#endif

Servo servo;
int m;

// -----------------------------------------------------------------------------
//PROGRAM FUNCTIONS
void motorCW () // function to make motor turn CW
{
    motorSTOP ();
    servo.write (180);
    delay (500);
    digitalWrite (relay1, LOW);
    digitalWrite (relay2, HIGH);
}

void motorCCW () // function to make motor turn CCW
{
    motorSTOP ();
    servo.write (0);
    delay (500);
    digitalWrite (relay1, HIGH);
    digitalWrite (relay2, LOW);
}

void motorSTOP () // function to make motor stop
{
    digitalWrite (relay1, HIGH);
    digitalWrite (relay2, HIGH);
}


// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    pinMode (cycleButton, INPUT_PULLUP);
    pinMode (LMF,         INPUT_PULLUP);
    pinMode (LMB,         INPUT_PULLUP);

    pinMode (relay1, OUTPUT); // set pin 2 as output for relay 1
    pinMode (relay2, OUTPUT); // set pin 3 as output for relay 2

    servo.attach (5); // attach Servo to pin 5

    digitalWrite (relay1, HIGH); // set relay 1 OFF State
    digitalWrite (relay2, HIGH); // set relay 2 OFF State
}

// -----------------------------------------------------------------------------
void loop (){
    switch (m) {
        case 0: {
            if (digitalRead (cycleButton) == LOW) {
                motorCW ();
                m = 1;
                Serial.println (" case 1");
            }
            break;
        }

        case 1: {
            if (digitalRead (LMF) == LM_ON) {
                motorCCW ();
                m = 2;
                Serial.println (" case 2");
            }
            break;
        }

        case 2: {
            if (digitalRead (LMB) == LM_ON) {
                motorSTOP ();
                m = 0;
                Serial.println (" case 0");
            }
            break;
        }
    }
}

Learning to use millis is a fundamental tool in getting Arduino programs to be responsive. State machines are useful too. Both take a little time to click in your head though.

In this case, I think you can leave millis out of it, you can expand your state machine instead.

Currently, when you press the cycle button, you go to state zero to kick things off. Sadly, you stay there and that means that the delay in state one gets run over and over again. You're also commanding the servo repeatedly but as you're sending it to the same place, it doesn't really matter.

Once the motor is running CW , you're looking for LMF to be HIGH. Make a new state that does that. At the end of state zero, set your state variable to the new state. You can even keep your delay(500) because now it will only run once.

Get rid of the if that checks for LMF, the new state should be doing that check now. When it sees that the limit was hit, stop the motor, move the servo, delay 500 start the motor CCW and go to another new state that looks for LMB to go high.

This way, all the logic is in your states and you're only using delays once when you need them.

Millis can come later - one mind bending problem at a time.

Please change the name of your global m variable. Single character names are so sixties :wink:

redneckcrake
I'm on my PC now.

++Karma; // For a good first post.

Also well done on implementing a state machine, you are getting close to what you need with that.

I think you have had some good answers from others and I don't really have anything to add. My opinion is that you should get rid of delay as soon as possible, although not everyone will agree with me. Delay is insidious, at first you use it and your code does what you want, so you use it more and your code gets slower and less responsive and harder to get right. Without delay loop goes round a zillion (well, OK, maybe 100000) times in a second, with half a second delay it goes round twice, a huge difference and so much that could be done if only the delay was not there.

Good luck.

Reply to gcjr,

IT WORKS!!! (sorry for shouting :fearful: :stuck_out_tongue: :stuck_out_tongue_closed_eyes:), I don’t know how to thank you enough gcjr. You have really saved me a another few weeks of headache. I will go over your code until everything clicks in my brain. The way you restructured the code also made it so much clearer; I will try to replicate your format for my next project(s). On that note, I have another question; well three actually.

Question #1

I noticed that you included all sequence into one single function (why didn’t I think of doing this :smiley: :cold_sweat: ). This is practically done to help make the code cleaner to read and to make it run only once correct? Another thing I just learned is that you could call for a function inside of a function (function-ception lol)

void motorCW () // function to make motor turn CW
{
    motorSTOP ();
    servo.write (180);
    delay (500);
    digitalWrite (relay1, LOW);
    digitalWrite (relay2, HIGH);
}

void motorCCW () // function to make motor turn CCW
{
    motorSTOP ();
    servo.write (0);
    delay (500);
    digitalWrite (relay1, HIGH);
    digitalWrite (relay2, LOW);
}

Question #2

I actually saw a lot of “enum” while I was on my learning quest. I know I should not post links but (Arduino Playground - Enum Resource) I read this and was really confused. what exactly does this “enum” do? I noticed that after the “#else” statement the “enum” logic is inverted (side note: why is there a # in front of else?). Also I noticed that you reassigned the pins for example LMF and LMB to A2 and A3; are these not analog pins on the arduino? what is the purpose of this? I see LM_ON being used but not LM_OFF. I am so very sorry if I come off as rambling non-sense, but I really have no idea what I am reading. To me it seems like you have assigned 2 sets of peripheral for the arduino. for example.

const int relay1 = 10; //relay1 set A

const int relay2 = 11; //relay2 set A

and
const in relay1 = 2; // relay1 set B

const int relay2 = 3; //relay2 set B

const int relay1 = 10;
const int relay2 = 11;
const int cycleButton = A1;
const int LMF = A2;
const int LMB = A3;

enum { LM_ON = LOW, LM_OFF = HIGH };

// -------------------------------------
#else
#include <Servo.h>
//Variables
const int relay1 = 2;
const int relay2 = 3;
const int cycleButton = 4;
const int LMF = 6;
const int LMB = 7;

enum { LM_ON = HIGH, LM_OFF = LOW };
#endif

Servo servo;

I would really appreciate an in-depth line by line explanation if that’s not too much to ask :o :blush: . I am eager to learn, I just need the right hole to run down. I believe that this post will be ideal for anyone looking to truly understand some state machine programing.

From my understanding of your “void loop” is that you first integrated the “IF statements” directly into the Case # itself and the second difference is that after each case you have m = to the next state that the arduino should look for. While my original “void loop” basically said to constantly read all three “IF Statements” which sometimes would make the loop overshoot a critical triggering moment (lol triggering moment) of the limit switch. So to clarify. Once the “cycle button” is already pressed and the motor is already going forward; there is really no point in checking the “cycle button” or “LMB” as these will be impossible for the nub to trigger. Therefore by setting the state of m = 1 will have the loop constantly checking case #1 correct? Please let me know if my understanding is correct.

Question #3

If there were two LMF as oppose to one, and there is an equal chance for LMF1 and LMF2 to trigger and I want to implement something for this; would the following work?

    case 1: {
        if (digitalRead (LMF) == LM_ON || (digitalRead (LMF2) == LM_ON)) {
          motorCCW ();
          m = 2;
          Serial.println (" case 2");
        }
        break;
      }

Reply to wildbill
Hi wildbill, it is all starting to make sense to me now. Thank you so much. I think I understood enough of what was happening to arrive to your explanation also. :smiley: :smiley: Would you mind giving my questions a quick glance and confirm if my understanding is correct?

"Millis can come later - one mind bending problem at a time." - Would you have implemented millis() as oppose to a state machine? If so why? In which case(s) would one be a more powerful than the other? State machine logic just seems so much more conceptually natural. I guess millis() would also if I understood it :cold_sweat: :smiley: .

"Please change the name of your global m variable. Single character names are so sixties ;) " - LOL, to be honest, I was not even around yet during the sixties :cold_sweat: :D. However, I will keep this in mind as logically it makes sense to give global variables are more meaningful name.

To both wildbill and gcjr, both of you guys are super awesome, I learned so much in just a few post. Thanks again guys. :smiley: :smiley: :smiley:

redneckcrake:
I will go over your code until everything clicks in my brain.

you should understand the code you're working with

redneckcrake:
what exactly does this "enum" do? I noticed that after the "#else" statement the "enum" logic is inverted (side note: why is there a # in front of else?). Also I noticed that you reassigned the pins for example LMF and LMB to A2 and A3; are these not analog pins on the arduino? what is the purpose of this? I see LM_ON being used but not LM_OFF.

The #if/#else/#endif are preprocessor commands the effectively comment out code.

i post code i've tested. i can do lot with a multifunction board having a few LEDs and buttons. the #if/#else allow me to redefine I/O pin and polarities (enum) for my hardware while maintaining your definitions. I tested the code with #if 1.

the enum is another way of defining constants that are closely related to one another and often sequential. i could have defined LM_ON using constant byte or #define

redneckcrake:
I am so very sorry if I come off as rambling non-sense, but I really have no idea what I am reading.

i learned a lot from Elements of Programming Style that explained the flaws in programs and fixed them

redneckcrake:
From my understanding of your "void loop" is that you first integrated the "IF statements" directly into the Case # itself and the second difference is that after each case you have m = to the next state that the arduino should look for.

your code is an awkward state machine. a state machine has a number of states and moves between states based on events and performs some action some events may cause it to return to the same state. in other cases, no event causes it to remain in the state.

there are 2 types of state machines: one where the action is determined by the state and the other, where the action is associated with the event

the code i posted implements a sequencer, a simple state machine because each state handles a specific event and only transitions to one other state.

redneckcrake:
So to clarify. Once the "cycle button" is already pressed and the motor is already going forward; there is really no point in checking the "cycle button" or "LMB" as these will be impossible for the nub to trigger.

true

redneckcrake:
Therefore by setting the state of m = 1 will have the loop constantly checking case #1 correct?

no, your code will constantly perform the action for that state which is defined by case 1:

redneckcrake:
If there were two LMF as oppose to one, and there is an equal chance for LMF1 and LMF2 to trigger and I want to implement something for this; would the following work?

    case 1: {

if (digitalRead (LMF) == LM_ON || (digitalRead (LMF2) == LM_ON)) {
         motorCCW ();
         m = 2;
         Serial.println (" case 2");
       }
       break;
     }

sounds right

this is an example of where two different events are handled, although they both transition to the same next state

Hi all, I have just recently had the time to really test out the code and the machine I am trying to build. Well… just to cut to the chase, I have ran into a few problems regarding the machine and have no idea where to trouble shoot. The following are the issues related to the machine.

Known Issues:

1: Sometimes the program skips the delay function on return after triggering the front limit Switch (not a big deal but why is this happening?).

2: Sometimes it auto starts the second cycle without any inputs from the “cycle start” button and just runs through the whole code (typically only happens twice.

3: Sometimes the code would simply stop at the front limit switch (must press “cycle start” button for it to complete it’s cycle);

4: Sometimes the Servo would stop working altogether until the reset button on the arduino is pressed while other parts of the code functions properly (i.e. the cycle start input / motor / relays all work).

5: Sometimes the machines still crashes into the limit switches.

All of the above mentioned issues are very unpredictable, they are very erratic. The Machine would perform flawlessly for a bit and then all the sudden act out of the above issues. The worse being the crashing into the limit switches. Please let me know if I can provide any other essential information.

redneckcrake:
Would you have implemented millis() as oppose to a state machine? If so why? In which case(s) would one be a more powerful than the other?

State machine (FSM) and millis() are not different techniques to solve the same problem. A series of if/else statements can substitute for switch/case to build an FSM but millis() cannot. The FSM organizes/controls the progression of a task while millis() essentially keeps track of elapsed time from some reference point.

This tutorial - one of many on this site - illustrates, among other things, millis() and an FSM working hand in hand to blink an LED.

Reply dougp.

Hi dougp, thanks for one of the most straight forward explanations regarding the difference between a State Machine (FSM) and millis(). I have a general idea of the different use case, but your explanation really made it clear. I also already checked your "This tutorial" and will defiantly find time to read everything. Thank you for your contribution to helping the Arduino community :smiley: :smiley: From your explanation a machine such as mine would be best suited to a FSM style code due to the finite amount of states it could be in at any given time (i.e checking for "cycle button" ==> check front limit switch ==> check back limit switch ==> check for "cycle button").

However, I am curious as to why the machine is acting out all the strange and erratic "failure" as mentioned above? I have no idea where I should even begin; because in my mind, if a code works then it should continue to work after it's first cycle of task. Then it should continue to follow the previous cycle. However, it seems that my machine would function properly and then suddenly come to some erratic failure, some smaller and less catastrophic than others. Is it simply the nature of arduino; or is there something definitely wrong happening in the code? Again, thanks for your comment dougp, I will give your link a good read. ;D

Please post your latest code and a schematic.

Hi wildbill

Nothing has change from what I got from gcjr, in terms of the code.

#if 0       // my hardware
struct Servo {
    void attach (int pin)  {};
    void write  (int ang)  {
        Serial.print   ("  servo ");
        Serial.println (ang);
    };
};

const int relay1 = 10;
const int relay2 = 11;
const int cycleButton = A1;
const int LMF = A2;
const int LMB = A3;

enum { LM_ON = LOW, LM_OFF = HIGH };

// -------------------------------------
#else
#include <Servo.h>
//Variables
const int relay1 = 2;
const int relay2 = 3;
const int cycleButton = 4;
const int LMF = 6;
const int LMB = 7;

enum { LM_ON = HIGH, LM_OFF = LOW };
#endif

Servo servo;
int m;

// -----------------------------------------------------------------------------
//PROGRAM FUNCTIONS
void motorCW () // function to make motor turn CW
{
    motorSTOP ();
    servo.write (0);
    delay (500);
    digitalWrite (relay1, LOW);
    digitalWrite (relay2, HIGH);
}

void motorCCW () // function to make motor turn CCW
{
    motorSTOP ();
    servo.write (180);
    delay (500);
    digitalWrite (relay1, HIGH);
    digitalWrite (relay2, LOW);
}

void motorSTOP () // function to make motor stop
{
    digitalWrite (relay1, HIGH);
    digitalWrite (relay2, HIGH);
}


// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    pinMode (cycleButton, INPUT_PULLUP);
    pinMode (LMF,         INPUT_PULLUP);
    pinMode (LMB,         INPUT_PULLUP);

    pinMode (relay1, OUTPUT); // set pin 2 as output for relay 1
    pinMode (relay2, OUTPUT); // set pin 3 as output for relay 2

    servo.attach (5); // attach Servo to pin 5

    digitalWrite (relay1, HIGH); // set relay 1 OFF State
    digitalWrite (relay2, HIGH); // set relay 2 OFF State
}

// -----------------------------------------------------------------------------
void loop (){
    switch (m) {
        case 0: {
            if (digitalRead (cycleButton) == LOW) {
                motorCW ();
                m = 1;
                Serial.println (" case 1");
            }
            break;
        }

        case 1: {
            if (digitalRead (LMF) == LM_ON) {
                motorCCW ();
                m = 2;
                Serial.println (" case 2");
            }
            break;
        }

        case 2: {
            if (digitalRead (LMB) == LM_ON) {
                motorSTOP ();
                m = 0;
                Serial.println (" case 0");
            }
            break;
        }
    }
}

The code makes perfect sense in my head which just adds to more confusion. The schematic has remained the same except that I have added a “D-Sun 3A Step Down Switching Voltage Regulator” to step down the power supply voltage of 12V to around 8V which is directly hooked up the arduino’s VIN pin (could this be the potential problem? am I not giving it enough Voltage into the VIN?). The servo is given 8.4 V from the step down which can handle more current.

I would be super grateful to finally understand what is wrong with it, just when I was about sure I understood simple state machines, its starts acting up in such an erratic behavior.

redneckcrake:
in my mind, if a code works then it should continue to work after it's first cycle of task. Then it should continue to follow the previous cycle. However, it seems that my machine would function properly and then suddenly come to some erratic failure, some smaller and less catastrophic than others. Is it simply the nature of arduino; or is there something definitely wrong happening in the code?

your code expect reliable transmission of data. but part of the issue is recognizing a transmission error doesn't prevent the mechanism from overshooting.

it may make sense to stop the motor immediately if a bad message is recognized

even the best of systems may encounter unexpected behaviors and has code to deal with them

Reply gcjr,

Hi :slight_smile: :slight_smile: so you are suggesting that it has something to do with all the wires going everywhere? For example, I should not have the servo wires running over the arduino (or does this not matter)? I am not quite sure where to trouble shoot.

"even the best of systems may encounter unexpected behaviors and has code to deal with them"
So typically a program will generally have a "fail safe" code to run when some erratic behavior is found to prevent catastrophic failure correct? I would imagine that such a program would be necessary for complex machinery not something as simple as an actuator consisting of a few simple parts, relays and a servo though.

What would you suggest I check physically gcjr? As for the code, I would not even know what to add to what has already been written. As it all makes sense to me, I read more about State Machines and learned quite a bit regarding the concepts and how a program should function. A good example I came across was one using a state machine concept for the ghosts in Pac-Man (which depending on the current state of something the ghost would perform a specific task until another state is triggered). All this makes sense, its just that I have no idea why my machine is not functioning properly. :confused: :confused: :confused:

The more I read into FSM the more I am reminded of Aristotle's quote, "The more you know, the more you realize you don't know."

Your code is pretty simple so I would be more inclined to suspect an electrical issue. Put a serial.print in setup so that you can see if the Arduino is getting reset.

Perhaps disconnect the relays and test the limit switches manually and check resulting serial messages to see if it behaves. Unhook the servo too if you have to.