tinkerspy / Automaton

Reactive State Machine Framework for Arduino
https://github.com/tinkerspy/Automaton/wiki
MIT License
369 stars 63 forks source link

Specific Serial Com & Time Countdown Examples Needed #16

Closed Mike58501 closed 8 years ago

Mike58501 commented 8 years ago

I am hoping that the person most familiar with the inner workings of this promising Automaton can post the best way for the following two sets of code to be able to run properly within Automaton. It is so a bunch of coin operated washing machines in the USA, & around the world no longer waste unnecessary water & electricity. At this point, I am not seeing any examples within Automaton of how to specifically do what these two sets of code accomplishes. Based on my research, both of these sets of code avoids problematic types of polling &/or delays. Also these two sets of codes have been tested to be 100% reliable within smaller snippets of "spaghetti code" avoiding any Finite State Machine Library completely. At this point, I seem to have a pretty good handle of Automaton's onPress & longPress (for timely 0v 'pullup' digitalReads), & timed led on & offs (to drive pertinent 5V relay coils properly resistors etc.).

The below shows "serial com gathering & displaying" & "holding the accumulating credits" variable until a momentary button is pushed:

      // Arduino mainstream 20,4 lcd I2C properly declared & held in the needed scope etc.
    int b;
    int credits;

   if (mySerial.available() >= 0) {   
       b = mySerial.read();
    if (b != 255 || 0) {         
      credits = credits + b;    
      lcd.setCursor(16, 3);
      lcd.print(credits * .25);
      lcd.setCursor(4,0);
      lcd.print(credits);

The following "time countdown" continues to run until a trigger or another STATE turns the lcd countdown off &  possibly turns it back on a few times with new starting points by just Automaton just seeing updated pertinent variables.  The seconds do not have to display if it helps the coding.  There needs to be a provision within Automaton so some of these variable can have their values changed based on a specific trigger or a specific state change.

Arduino mainstream 20,4 lcd I2C properly declared & held in the needed scope etc.
int hours, minutes, seconds;
long counter, mytime, interval = 0;

 long preInterval = 180000;
  long pP = 120000;
  long interval = (preInterval-pP);
 timeLeft (interval);

void timeLeft (long interval){
   lcd.setCursor(0, 3);
  lcd.print("Est Time Left: ");
  if (millis() > mytime)
    mytime = millis() + interval;
  counter = (mytime - millis()) / 1000;
  hours = counter / 3600;
  //counter -= (hours * 3600);
  minutes = counter / 60;
  counter -= (minutes * 60);
  seconds = counter;
  if (minutes < 10) {
    lcd.print("0");
    lcd.print(minutes); }
  else
    lcd.print(minutes);
  lcd.print(":");
  if (seconds < 10) {
    lcd.print("0");
    lcd.print(seconds);   }
  else
    lcd.print(seconds);

This Automaton assistance could potentially help a great number of coin op washing machine owners worldwide & their customers who would otherwise throw out still good very costly stainless steel washing machines unnecesarily. I am looking forward to sharing the complete code on tinkerspy's github upon successful completion & other sites as an example of how Automaton could really shine in a real world extra worthwhile application.

tinkerspy commented 8 years ago

Hi Mike,

If I'm to help you, please make sure that you provide clearly indented code and that you place that code between c++ and code markers, like this (use the preview tab to double check):

int b;
int credits;

if (mySerial.available() >= 0) {
  b = mySerial.read();
  if (b != 255 || 0) {
    credits = credits + b;
  }
  lcd.setCursor(16, 3);
  lcd.print(credits * .25);
  lcd.setCursor(4,0);
  lcd.print(credits);
}

Note that I had to add two closing curly brackets "}" here, I 'm hoping I guessed right but that shouldn't be necessary.

tinkerspy commented 8 years ago

Mike,

Actually, let's stick to the coin acceptor bit for a while. I had a look at the Sparkfun spec:

https://www.sparkfun.com/products/11636

I guess you have it configured to send a serial code according to the value of the coin inserted. And now you want your code to calculate and record the resulting credit. You think that should be done with a Automaton state machine.

I agree that a state machine would be a good choice, but IMHO you shouldn't convert the whole code to a stae machine. Just the part that polls the serial port and manages the credit. Let's call it the Atm_acceptor machine and write some code as if it already existed:

#include <Automaton.h>

Atm_acceptor acceptor;  // We declare it

void setup() {
  // Setup mySerial here
  // Setup the lcd display here
  acceptor.begin( mySerial );  // Initialize the acceptor
  acceptor.onChange( acceptor_callback ); //And link it to a callback
}

void loop() {
  automaton.run();
}

And now for the callback:

void acceptor_callback( int idx, int v, int up ) {
  lcd.setCursor(16, 3);
  lcd.print( v * .25);
  lcd.setCursor(4,0);
  lcd.print( v );
}

Now all you need to do is write a state machine that provides that interface. It should take a serial Stream object as a parameter. It should check the serial port for characters on each cycle of the IDLE state. When characters are available to be read it could jump to a READ state where the character is read. In the byte read is in the valid range it should increment an internal variable and call the onChange method with that value as the 'v' parameter. You'd probably also want a way to reset or decrement the credit again.

That's all you need to do to solve this part of the puzzle in a multi-tasking event-driven way.

Mike58501 commented 8 years ago

Tinkerspy &/or others,

I am not sure if this zip was attached below in github properly as that process in github has never been done before by me. It did say drag & drop. I changed to small letters & removed the s "credit" to hopefully make it more consistent to how you "keep it simple as possible" code. The attached zip folder reflects the change. The failed attempt to make the while loop into a function was put in /* ...*/ comments temporarily. Delete to avoid clutter??? MS Visual Studio 2015 with the Atmel Visual Micro Plugin seems to provide a better working environment with real time monitoring etc. so that is where this minimum code needed for the coin acceptor - holding credit variable - lcd display is now. It should not be necessary to bring it into the Arduino 1.6.7 IDE but that lesser IDE is on standby within.seconds.

The zip folder contains the "save all" from the Microsoft - Atmel environment just in case that is helpful. The below ino file with the zip both compiles & does bring the proper $ 0.00 amount to my 20,4 lcd from either working environment. If we have file exchanges I would say that Revisions will be very important. That is why I put Rev1 at the end of the file. I am not sure what happened to the curly brackets & in the future I will make sure that I have the settings in Visual Studio - Atmel 2015 &/or Arduino IDE 1.6.7 to format the indents to hopefully what is the norm.

CoinsRev1.zip

Mike58501 commented 8 years ago

Tinkerspy,

Attached is CoinsRev2 where I deleted the relevant code & put in yours.

Your R2 really simple & straightforward code revision runs fine (no errors) even on the lcd screen compiled & uploaded from the VS - Atmel upload. So I don't think we should be too worried about what happened next. I am much more concerned about tying the rest of the ATM state machine &/or combination of state machines that will be necessary to avoid "spaghetti code"!

I made a copy of the CoinsRev2 ino & ran it in Arduino 1.6.7 & on line 29 it generated the following error: Arduino: 1.6.7 (Windows 7), Board: "Arduino/Genuino Uno"

CoinsRev2:29: error: 'Atm_acceptor' does not name a type

Atm_acceptor acceptor; // We declare it

^

C:\Users\MikeWinPro32\Documents\Arduino\CoinsRev2\CoinsRev2.ino: In function 'void setup()':

CoinsRev2:55: error: 'acceptor' was not declared in this scope

acceptor.begin(mySerial); // Initialize the acceptor

^

exit status 1 'Atm_acceptor' does not name a type

CoinsRev2.zip

tinkerspy commented 8 years ago

Hi Mike,

Don't paste everything I type into your program and see if it works, cause it won't. In the previous message I write:

    Let's call it the Atm_acceptor machine and write some code as if it already existed:

Because it doesn't. It needs to be written and preferably by yourself. You can't complete this project unless you have some understanding how things fit together. You need to:

  1. break it up in components
  2. identify the parts that could be state machines
  3. Design the interface for each state machine
  4. Build the state machine
  5. Test the state machine in a small sketch (not CoinsRev2!) to see if it performs as planned

In your start post you broke away two components. That was helpful. I took the coin acceptor component and helped you by doing steps 2 & 3. I identified the serial/credits counter as something that would make a good state machine. Then I designed the interface by creating some code that shows how the not-yet-existing Atm_acceptor would fit in your sketch.

I'm not prepared to write the whole thing for you, you'll have to grasp at least the basic concepts so you can finish the job yourself.

What you did right was breaking up the problem and showing me a code fragment (in the message - please learn how to format it, it's not that hard, just select the code and press the <> icon ) and description that made me understand what you want. Don't send me flow diagrams of the whole thing or even the whole CoinsRev2 thing. It's too much to digest.

Mike58501 commented 8 years ago

Hi Tinkerspy & possibly someone else chiming in a bit,

I sure hope you do not give up on me ... sorry about the CoinsRev2 fiasco & me forgetting about the <> feature. Nobody feels a greater need than myself for trying to understand more so the most ideal sequencing & calling of states can start to occur. Ideally, I will try to build on the work that you have already done for the serial streaming for like you say "needed minimal sketch" that limits itself to the reading & holding of the v = 1s for the coin mech quarters & the v = 4s for the dollar coins. Totals will at minimum will be credits == 7||8; where the first threshold range & a momentary button push could make it so the first wash choice is sequenced which would make the other sequenced pattern of events & states be skipped for that complete washing machine cycle on my completed prototype hardware UNO simulation setup.

What do think of me trying to pattern the needed creation of the minimal "Atm_acceptor" initial machine after what you have already done with your "command machine"? It looks like I should possibly use your "Machine template editor" with the command machine approach & use some new names & other tailoring. There are 4 distinct threshold ranges when the WATCH FOR the momentary button push applies ... I suppose that technicality could be adapted later??? to avoid too much initial complexity. Hopefully, I will be able to dedicate some quality time starting about 10 or 11 hours from now ... first thing in the morning our local time. I am afraid without a some further suggestions from you ... I could be guessing as how to tailor one or more of your command machine's methods ... possibly losing urgently needed valuable time than necessary.

Thanks again.

tinkerspy commented 8 years ago

Hi Mike,

Atm_command could be used for some inspiration, but it is also entirely different from what you want. A lot of the code is dedicated to parsing the received serial strings and you'll need none of that. You only need to check one byte at a time and - I gather - process it in a switch statement like this:

switch( mySerial.read() ) {
  case '1': 
    credit = credit + 1;
    return;
  case '2':
    credit = credit + 2;
    return;
}

This kind of thing goes in a action handler, by the way.

To check for conditions you could use the Atm_controller machine or just do in C++ in an Atm_button onPress callback. For the countdown timer, you can use a regular Atm_timer object. Possibly the acceptor is the only custom machine you'll be needing.

If I have time I'll try cooking up a screen recorder demo of how to create an Atm_acceptor machine with the Machine editor.

Mike58501 commented 8 years ago

Hi Tinkerspy,

The screen recorder demo sounds very worthwhile & possibly will shed more light for everyone on what the Machine editor can & what it can not help with. I was looking at the ATM_timer object also ... but have been concerned about how to be able to restart "the lcd minutes counting down" with 2 updated variables based on when 3 specific pins go to LOW at separate times. That part seems to lend itself to Automaton reaction capability well ... with a few simple 30 second durations of specific pin state change. Once I understand the simple pattern of one of these transfers to the nextState & then seeing its accompanying code action statements run on its ENT or in the case of timeLeft countdown in LOOP. I should be able to follow that pattern to apply throughout the code within a parent state machine.

It is premature for me to post a multipage pdf of a machine editor creation with just psuedo code as a "pre-prepare elimination of ambiguities" at this time. I hope to show the reasoning behind using the "else" column to skip to the next credit threshold & using an event to jump to a common path towards the end of whatever credit level path was previously run because of the credit level context of the single momentary button push. That would eliminate my "first blush" spreadsheet like layout that was very much way too repetitious.

tinkerspy commented 8 years ago

Hi Mike,

Well, there it is, my very first instructional YouTube video, in fact it's my first YouTube video ever:

https://www.youtube.com/watch?v=vKqEeH4OvqU

Please note a few things:

  case '1': // Quotes
    credit = credit + 1;

becomes:

  case 1: // No quotes!
    credit = credit + 1;

Good luck with it.

Rgrdz, Tinkerspy

Mike58501 commented 8 years ago

Hi Tinkerspy,

My understanding went way up as soon as the process of studying & following your YouTube began first thing this morning ... it is appreciated.

It does compile with the needed lcd adjustments & I really believe I included & declared the lcd & software serial related libraries properly. Based on past success substituting the serial monitor capability with lcd.print I am pretty sure my substitute words are not the problem. I have read that is a good idea to pay attention to anything in the compile screen that shows in red color. Since it compiles & uploads but does not show anything on the LCD screen those red printed words may give us enough information to correct the problem of nothing on the LCD screen??? Do these following error messages mean that some slight surgery on the liquidCrystal library may have to be done to make it 100% compatible with Automaton??? Below are the errors:

In file included from C:\Users\MikeWinPro32\Documents\Arduino\acceptor\acceptor.ino:4:0: C:\Users\MikeWinPro32\Documents\Arduino\libraries\LiquidCrystal/LCD.h:71:20: warning: unused parameter 'uSec' [-Wunused-parameter] inline static void waitUsec ( uint16_t uSec ) ^ C:\Users\MikeWinPro32\Documents\Arduino\libraries\LiquidCrystal/LCD.h:444:17: warning: unused parameter 'value' [-Wunused-parameter] virtual void setBacklightPin ( uint8_t value, t_backlighPol pol ) { }; ^ C:\Users\MikeWinPro32\Documents\Arduino\libraries\LiquidCrystal/LCD.h:444:17: warning: unused parameter 'pol' [-Wunused-parameter] C:\Users\MikeWinPro32\Documents\Arduino\libraries\LiquidCrystal/LCD.h:463:17: warning: unused parameter 'value' [-Wunused-parameter] virtual void setBacklight ( uint8_t value ) { }; ^ C:\Users\MikeWinPro32\Documents\Arduino\acceptor\acceptor.ino:27:6: warning: unused parameter 'idx' [-Wunused-parameter] void acceptor_callback( int idx, int v, int up ) { ^ C:\Users\MikeWinPro32\Documents\Arduino\acceptor\acceptor.ino:27:6: warning: unused parameter 'up' [-Wunused-parameter]

tinkerspy commented 8 years ago

Hi Mike,

These warnings do not indicate any incompatibility between lcd & automaton. They may indicate a problem in your code, but certainly not the last two errors concerning Automaton. It's perfectly fine not to use all (or any) of the callback arguments.

The standard Arduino IDE by default doesn't show these warnings, probably to avoid confusing people like you (or me for that matter). If I were you I'd stick to the standard IDE so that you encounter the standard problems for which solutions can be found more easily on the web.

Rgdz, Tinkerspy

tinkerspy commented 8 years ago

Some tips:

Rgrdz, Tinkerspy

Mike58501 commented 8 years ago

Hi TinkerSpy,

By following your suggestion of making the acceptor work first to the serial monitor & then bringing in the lcd ... I got what I needed to show on the I2C lcd screen. My libraries are the current & nothing fancy. The LiquidCrystal_I2C one was recommended by https://brainy-bits.com/shop/lcd_display/i2c-lcd-backpack/ The only problem was at the very end when I tried to compile after entering the additional atm_controller functionality. Within the below Arduino IDE folder within a zip ... it shows in the INO file via /* comments */ the group of code lines of "f1_ctl.begin() not declared problem??? I am sticking to the simpler Arduino IDE 1.6.7 & avoiding the Microsoft 2015 C++ Atmel vMicro environment like you suggested.

Once we get the above resolved ... hopefully we can do the best possible tinkering with the recurring resets needed for the "timeLeft" minutes. The variable values to correspond to the reset starting minutes that I need are set up on a simple spreadsheet (precalculated). But how to get the variable to change properly & be accessible seems like too much of a challenge without special Automaton Expertise. Since the number of total credit in combination with a single momentary button will go to 1 of 4 paths with a common path for any of them at the end ... I am leaning towards 5 additional custom state machines unless there is a better way to handle the 1. choice of path & 2. the lcd timeLefts & neg 5V switching with some control of time duration of both digitalReads & digitalWrites. There are still some patterns that I am not seeing clearly enough from your existing examples.

It helped me to look at previous issue discussions so hopefully this will be a worthwhile exchange for others also! Again, your involvement is very much appreciated!

acceptor8.zip

tinkerspy commented 8 years ago

Hi Mike,

Look very closely at the following text:

Atm_controller fl_ctl;

f1_ctl.begin()

Can you tell the difference? You really should be able to solve your own typos if you want to bring this project to a successful end.

hopefully this will be a worthwhile exchange for others also

Surely not this way ;-)

Rgdz, Tinkerspy

Mike58501 commented 8 years ago

Hi TinkerSpy,

Very sheepish ... on this end ... sorry ... You did have a chance to glance at how I rearranged the code some & changed to just two values coming in the mySerial reads to reflect the dollar coin(4) & quarter(1) needed at present.

I kid you not ... I kept looking at the l vs 1 & not seeing the difference for over an hour ... when I should have kept retyping with the proper thought in terms of consequences. So much for jumping to conclusions. I am so furious at myself!!*?!! Now if I can properly channel that energy into making sure it does not happen again. No excuse ... just be reassured that this somewhat beginner programmer has learned (burned into his brain) lesson. To think that I pride myself to being one of those people who talks about "net effects" instead of the more shallow "not my intentions". I really can't blame my eye doctor either! I can't blame my dear old dad either because he always would tell me about his high school motto being "don't make excuses ... make good". I did a stint as a coach in my younger years & I remember talking about not missing the easy stuff ... because the hard stuff might be a bit too tough! Shame on me.

Thanks & again I really do apologize especially since we both know that "unnecessary loss of valuable time" is very important to avoid if at all possible.

Mike58501 commented 8 years ago

TinkerSpy &/or other Automaton Expert,

This post is related to the code that I pasted in <> below.

My External Relay Board requires an "Active Low" from my Arduino UNO digital pins to turn on as shown in this specification: http://yourduino.com/sunshop2/index.php?l=product_detail&p=156

After extensive testing on my thorough & complete prototype hardware & even with trying to initialize the pin 4 as output & high in setup. The pin 4 & several others specifically going to the external relay board does not start out "off "& turn "on" as needed. I do observe with the UNO's test led pin 13 the code operates perfectly. What is the best way to get Automaton to do what is needed for these very common external relay boards using the negative 5 volts. Since they also allow bypass of the extra setup requirements of current limiting resistors ... they are a very elegant & useful way of switching based on 7 months of previous relay testing with the currently more common Arduino "spaghetti like non Automaton code". Surgery within the controller.cpp & a rename???

I also tried to setup my previously shared timeLeft function to work in place of the .led turn on code without success because of functions declaration problems. I am guessing there is a better way to do a changing variable driven display countdown (decrement) of minutes to an LCD based on within Automaton itself ... but I have not seen a clear enough example of that specific ability yet.

Thanks again.

`` f1_ctl.begin() .IF( acceptor, '+', 2 ) .led(13); f2_ctl.begin() .IF( acceptor, '+', 4 ) .led(4);`

tinkerspy commented 8 years ago

You ask for two things:

#include <Automaton.h>

Atm_timer countdown;
Atm_led relay;

void setup() {
  Serial.begin( 9600 );

  relay.begin( 4, true ); // Led (relay) on pin 4, active low

  countdown.begin( 1000 ) // Each step takes 1 second
    .repeat( 70 ) // Set to 70 seconds (steps)
    .onTimer( [] ( int idx, int v, int up ) {
      char buffer[50];
      sprintf( buffer, "Time left: %02d:%02d", v / 60, v % 60 );      
      Serial.println( buffer );
    })
    .onFinish( relay, relay.EVT_ON )
    .start();
}

void loop() {
  automaton.run();
}

The sketch above does both these things. It counts down in 70 steps of 1000 ms and displays the steps in a human readable way on the serial monitor. After the countdown finishes it turns a led on which is set to be 'active low' with the second parameter to begin(). The Atm_led machine is the usual way to control relays with Automaton.

Make sure you update to the latest master version because I had to make a small change to the Atm_timer machine so that it passes the remaining repeats in 'v', which is actually a useful new feature.

I leave the integration and customization of the code to you. Your changes to Atm_acceptor ( '1' -> 1, etc.) look OK to me.

Mike58501 commented 8 years ago

Hi TinkerSpy,

Below is where I actually make my momentary button green led ring go on at the right time & stay on until the button (class C dry contacts to pin 17 using built-in Arduino pullup resistor) is pushed. The commented areas explain where & when I would like the program to proceed to run one of 4 very similar but distinct sequences. The distinct sequences would be actually ... to be built State Machines from your Template Creator named Credit1, Credit2, Credit3, & Credit4. I am thinking that Automaton has a nifty way to route these paths ... until they come to a final trigger to go to a final State Machine (again pre-made sequences) called Com that would be common to whichever of the 4 Credit State Machine had been chosen. Your Timeleft code (adapted by me to work on my lcd which tests great) will exist along with ... lcd (in context with digitalReads) cursor sets & prints ... & some 2,6. or 3 second duration ActiveLow relays also in (context to 30 second duration digitalReads) in the 5 remaining "cookie cutter pre-made State Machines.

I might luck out on potential memory issues because of only one State Machine will actually be running at any one time it seems. Below is the pertinent code since we have already possibly have finalized what is needed in the global area ... at least while still in the Atm_acceptor Machine portion of the operational process. Note: I assume that it is OK to have the [.led(16);] before the [relay.off;] statement. It seemed to be the only way the Automaton Active LOW (Ext Relay) would function exactly like I needed while testing the green ring led. I put the .led(13) statement in repeatedly because that is the only way the price threshold statements [v] would compile before my includd // separate line comment statements.

Again ... below is the pertinent code (& the start of the next need stated in the comments) copied into the <>.

  relay.begin(16, true);

  f1_ctl.begin()
  .IF( acceptor, '-', 6 ) //This has the effect of turning on >6
  .led(16);
  relay.off();
  //if momentary button is pushed move to Credit1 sequences bypass SM Credit2,3 & 4.
  f2_ctl.begin()
  .IF( acceptor, '+', 9 )
  .led(13);
  //if momentary button is pushed move to Credit2 sequences bypass SM Credit1,3, & 4.
  f3_ctl.begin()
  .IF( acceptor, '+', 10 )
  .led(13);
  //if momentary button is pushed move to Credit3 sequences bypass SM Credit1,2, & 4.
  f4_ctl.begin()
  .IF( acceptor, '+', 12 )
  .led(13);
  //if momentary button is pushed move to Credit4 sequences bypass SM Credit1,2, & 3.
}
`void loop() {
  automaton.run();
}`

`

Mike58501 commented 8 years ago

Hi TinkerSpy,

I did go through tutorial of the process of creating your "to be continued" trafficlight full fledged State Machine & between that & your great first YouTube ... I am definitely growing in my understanding of your Automaton Framework. I took it a step further & put its cpp & h files into the Automaton->SRC folder along wit the cpp & h files of my lcd displayed version of your acceptor State Machine. In just the acceptor.ino file I then just added the needed # include & the _Atm_trafficlight trafficlight;_ global declaration & to the void setup the following lines.

trafficlight.begin( 4, 5, 6 ) // Pins 4, 5 & 6 .automatic( 5000, 2000, 5000 ); // Green 5s, yellow 2s, red 5s

The result of it running both State Machines was somewhat encouraging to my visualization of hopefully handing off a choice of one of four pre-done uniquely sequenced State machines with an additional final common pre-done full fledged sequenced State Machine.

The two full fledged State Machines together are running concurrently but it seems it would be better if the whole acceptor machine would no longer be taking Arduino UNO memory at the point of the hand-off to the new full fledged State Machine since most of its serial credit related functions will no longer be needed. Maybe just by making the SparkFun DG600F nonfunctional via the loss of ground on two of its inputs when the momentary switch button push determines the beginning of the choice of one of the four State Machines will be good enough to make sure there is no longer any polling or data going into the serial buffer.

Second thought ... I think as long as the acceptor functions are not being called .. memory is probably a non issue. I should be more focused on how to be able to choose one out of the 5 proposed full fledged state machines without having more than one run at a time.where the sequences definitely could not be allowed to run concurrently with each other.

My beginner Automaton brain is visualizing ... for example purposes: trafficlight1, trafficlight2, trafficlight3, & trafficlight4 & trafficlight5 & having some within an initial State Machine some kind of a conditional .automatic statement that would only allow one of the trafficlight sequences to run at one time. I visited with one of our local (medium sized city) traffic light maintenance people & it appears that based on sensors there actually is more than one unique sequence of traffic lights potentially run from the same program. So hopefully, I am not too far fetched on the possibility of a need for different triggered 5-8 stepped sequences within the same trafficlight system.

Another observation: With the trafficlight example both run alone & concurrently with the previous acceptor machine ... it is displaying only 2 out of the 3 active low relays on (ext relay leds light) at any one time ... that tells me using that specific trafficlight code I might be able to get around the Active LOW issue more easily in my overall Automaton project by just using the normally closed contacts instead of the normally open contacts of the SPDT dry contact relays.

tinkerspy commented 8 years ago

Hi Mike,

Don't put the acceptor/traffilclight state machine files in the Automaton/src folder. Either put them in your sketch folder or put them in their own library folder 'Atm_acceptor' or 'Atm_trafficlight'. Imported libraries should preferably be left untouched.

The traffic light tutorial focuses on building a stand alone light to keep things simple. If I wanted to build a complete system with multiple lights I would build a controller machine that handles the actual sequences each light should perform by sending light.trigger( light.EVT_RED )events to each attached light machine. The 'to be continued' line means that I want to add some examples later of how to run multiple traffic lights and link them together with the onChange and trigger methods.

I wouldn't worry about memory issues unless you're actually running out of memory. Dynamic memory allocation is possible on Arduino but I wouldn't recommend it. Having the acceptor machine check for incoming data in the background won't give you any performance issues either, and if it does there's always the sleep() method.

I've still not understood what your washing machine 'programs' are meant to do. Should they just turn relays on and off at specific intervals (the relays activating motors, pumps or valves)? Are there any other inputs or sensors needed? Could you describe the programs/sequences in a table like this?

Time Relay A (pump) Relay B (motor) Relay C (valve 1) Relay D (valve 2)
00:00 off off off off
00:01 on off on off
00:05 on on on off
00:08 off off off on

Because if that's the case you won't need a custom state machine at all. Do you know the old TV show the Knight Rider?

Hint: Begin with one program/sequence and don't try to solve everything at once.

Rgdz, Tinkerspy

Mike58501 commented 8 years ago

Hi TinkerSpy,

It looks like the directly below image file can be properly seen by you based on the preview here in github. Hopefully it along with our previous ATM_Acceptor gets to the crux of my project so you can visualize properly & provide a pattern for the sequences that could follow. The CR1 through CR4 only have minor differences such as less duration of the fastFwd or fewer FastFwds & even no FastFwds on the final full 5 water bath fill CR4 sequence. From your future pattern hopefully I will be able to do at least 2/3rds of the code writing & all of CR2 thru CR4. At that point I can include some improved comments after I can confidently say that the project became successful because of your Automaton Framework. I would definitely look at the image before going to the much lower paragraphs underneath the image because that could be more verbose than you would prefer. Hopefully the image will give enough information & structured enough to be useful & the better fit & closer to what you asked for. I am thinking that I am not the only beginner who has to relearn some of the norms where "Arduino Setup run only once" "Void Loop run more than once" generalities that tend to be taught at the beginner & even the intermediate Arduino enthusiasts level.

image

This is important to note: The re-written for the lcd.print below code you put in the ino file ... I am thinking it will have to be restructured within 5 additional cpp & h files of the CR 1 thru 4 & the Com because of the changing nature of the repeat variable. The following is my re-written code put in <> with consideration for putting "repeat" with a variable calculation. I am struggling with how to make this work within the above event - action table. Note the TCalc & pP (2 minutes less when customer makes pin #7 go LOW based on the customer's Perma Press selection. I left your comment for now even though the 70 seconds no longer applies.

Atm_timer countdown;
Atm_led relay;

void setup() {
  Serial.begin( 9600 );
   lcd.begin (20, 4);
  lcd.setBacklight(HIGH);
   relay.begin( 4, true ); // Led (relay) on pin 4, active low
  int TCalc = 1021; //this is different depending on the specific CR sequence
  int pP = 122;  // this will hopefully change just once or twice by customer turning dial to perma press
  countdown.begin( 1000 ) // Each step takes 1 second
  .repeat( TCalc - pP ) // Set to 70 seconds
  .onTimer( [] ( int idx, int v, int up ) {
    char buffer[50];
    sprintf( buffer, "Time left: %02d:%02d", v / 60, v % 60 );
    lcd.setCursor(0, 3);
    lcd.print( buffer );
  })
  .onFinish( [] ( int idx, int v, int up ) {
    relay.on();
  })
  .start();
}

Possibly too verbose below but just in case it is helpful:

Just to clarify the innerworkings of what the washing program needs to do based on one of the 4 credit levels + the momentary button push input generated from ATM_ACCEPTOR:

On my prototype & on the spare washing machine in my office-garage area there are five hi voltage (115 or 230 VAC) wires that are waiting hi voltage (230VAC) ACTIONS based on the context of five high voltage (115 or 230VAC) EVENTS. By using 115 or 230 VAC coiled external relays ... I am able to switch on the spdt contacts the needed 0 VDC that UNO pins can work with as inputs. Also by using neg 5 VDC outputs from UNO's pins to the previously linked 8 relay (10 amp dry contact switching) Arduino external module ... I can do the needed power overrides for the existing mechanical timer. By overrides ... I am referring to the 2 second duration start of machine & the 3 & 6 second duration various fast forwarding of the existing mechanical timer motor.

Each program/sequence needs to be a bit more intricate than if it was for a really old washing machine that sequenced based only on just time passing. That is because there are going to be variations depending on the current water pressure & drain times etc. On my table I needed to show the ons & offs of actions ... more based on the presence of voltage to coils. The relay or valve distinction should not matter to the distinct Automaton full fledged State Machine because the custom Machine is only looking for inputs or outputs of neg or pos 5 VDC. The duration controlled outputs are based on the context of the inputs. On the table chart I try will put footnotes for the corresponding lcd cursor set & print commands needed also based on the context of inputs.

Since your table request has the conditional (time) on #1 column & 4 actions in the following 4 columns ... I am trying to follow the same pattern of your request but with the 4 columns & possibly only columns for the ATM_COM. I could have put just on or off in the Start & FastFwd columns but I thought the pin descriptor could make it clearer that Active LOW for the external relay is necessary.

Your specific table seems like a better fit for a really old style complete washer control total replacement ... where the timer does not stop during the cycle if the machines water fill or drain malfunctions. We actually replaced over 30 washers that had other problems such as transmissions & also wiring & hoses that became brittle because of poor quality rubber etc. Since the timers on my existing washers are made of some kind of "trouble free" space age lasts "forever" plastic ... I am seeing a better fit to just set up a modification of the controls in terms of the added lcd & start & for fast forwarding of the existing mechanical timer motor for the needed choices of allowing for quicker (fewer fills & spins) to satisfy those customers who only need a "freshening up" of their clothes ... therefore saving millions of gallons of unnecessary water usage. The external relays are used to make sure the pins of the Arduino only see 0 VDC or no continuity to the negative ground at all.

Thanks again ... Mike

Reason for editing last sentence & an instance before: I replaced the words neg 5V with 0V ... I read that neg voltage can actually fry a pin ... something to be avoided along with >5V on a pin.

tinkerspy commented 8 years ago

The image works fine, but for some reason you code formatting is still a mess. I fixed it for you, but it would be helpful if you could get it right yourself, I mean, you see the difference right?

This explains it (the language specifier needed for Arduino code is c++): https://help.github.com/articles/creating-and-highlighting-code-blocks/

I see you also need inputs in your process, well that makes what you need a true state machine. If it was just a time-based you could have used the Player machine. If he COM thing is common to the 4 sequences I'd just duplicate that part 4 times and create 4 complete sequences including COM. That's simpler than splitting it - even though code duplication is something normally preferably avoided in this case it isn't IMHO.

I figure you should probably just run your sequence(s) in parallel with the timer, the timer just for display purposes.

Have you checked all the inputs and relays for proper working using the 'led' and 'digital' machines? If they can detect and control the inputs and outputs then you can start writing your state machine. The active LOW thing is really no issue, just use digitalWrite( LOW ) instead of digitalWrite( HIGH ).

From you diagram I'd say you need 5 events that check digital pins (7, 9, 10, 11, 12), probably a timer event, and EVT_STARTpublic event and two actions and then the display changes of course. Names are important, give your events and actions good meaningful names, for the states you can just use STEP01-STEP14 if you want. Concentrate on the first sequence machine and forget about the timer. Make a test setup on a breadboard where you simulate the relays with leds and the inputs with buttons or switches.

Final tip: Develop your sequence machines stand-alone. Forget about the acceptor & timer machines for now. Leave the lcd out of it and use the Serial terminal and the trace() command for debugging. Keep it as clean as possible. Once you have everything running satisfactorily add the lcd code then try to integrate with the other code you have already. The beauty of this way of working is that it's a separate module that can function and be tested stand-alone.

Rgdz, Tinkerspy

Mike58501 commented 8 years ago

MikeAcceptorTimeLeftCreditBasedSequence.zip

Hi TinkerSpy & possibly another proficient Automaton Framework person,

Above is the zip file that hopefully will help facilitate someone who is far more proficient at the needed reference & pointer & other subtle needed skills for my specific project.

As far as shortcomings within the zip folder ... I keep getting "flashbacks" of the time many years ago I needed significant assistance efforts from a friend (an experienced mechanical design engineer) after some certified contractor installer people made it so within a few months (at the time) our facility's brand new grandoise 92+ efficient modular boiler system was not supported nor warranty honored by the OEM. Like then ... I am thinking that I am delusional to think that I don't need significant help with the more technical challenges of getting this also new "what appears to be really great" Automaton Framework.

It is very promising that the standalone Atm_acceptor & the timeLeft sketch work perfectly well by themselves within their own cozy INO files. How it can weaved into a better more wisely put together few digitalRead Events matching a few digitalWrites sequenced machines seems to be a challenge. Ideally, that more wisely & more potentially compatible with the other modules even ... based on Credit sequences could be done bu Mike ... but Mike needs to admit he does not have enough general software engineering skills.

By looking within the Zip folder at the notes & comments within the incomplete sketches with automaton functions in the proper folder ... hopefully Tinkerspy & further hopefully along with another Good Samaritan can see that Mike did make "good faith efforts" to make a reasonably compatible ... one of the four needed sequences. My thoughts were that leaving out the transitions to the lcd.prints including the timeLeft would just make it that much harder later on with more unnecessary corrections needed.

Thanks ... I still think that the "work in progress" Automaton will be a good fit for many ... especially after a few more actual "real life" workable examples ... like my project & even beyond get put out there & more collaboration "building on previous knowledge gained" etc.

Mike

tinkerspy commented 8 years ago

Hi Mike,

As far as I can see your problem is still that you're trying to do everything at once. You have the countdown and coin acceptor stuff running? Fine, now put them away and start something new (like the CR1 thing) in isolation. Do not attemp to put in lcd stuff, just concentrate on the timers and the reading and writing of the pins and the process. You know about the trace() command? It's invaluable for figuring out the flow of things. Use it together with Serial.println()'s in your code to help you build.

My thoughts were that leaving out the transitions to the lcd.prints including the timeLeft would just make it that much harder later on with more unnecessary corrections needed.

No, that's a big mistake, and one you keep making. That way you'll never finish your project. It's trivial to add these things to a working project, but it makes getting to a working project much harder .

A quick glance at your code tells me:

You need to work from the bottom up now.

Rgdz, Tinkerspy

Mike58501 commented 8 years ago

CR1.zip

Tinkerspy,

I have on my screen my CR! open along side of your Trafficlight. I have tried as hard as I can looking for any pattern that I did not follow with your Trafficlight tutorial example folder. Take a look at the new CR1 zip file where I tried to isolate just the CR1 for now. Hopefully, you can uncomment some of my attempts to include my digitalReads & digitalWrites. On the first door lock event "digitalRead" ... I really would have liked to have included also ~digitalRead (12, LOW);~ but I am pretty sure it will give me a "too many arguments error" based on some tinkering of my own last week.

Can you try to compile what I have done so far? I can't. It looks like an easy fix based on the "error". For some reason it seems like it must be just different enough from your Trafficlight to affect it. I am going to feel real bad if it is a typo ... but like I said I kept going over & over line by line trying to find that possibility.

If you think it would be better or do any good to delete all possible potential actions relating to idle & lcd leaving just the events & pin changes & pin actions at your Machine Template Editor level ... I will do it. I noticed your fan & knight rider examples ... they show some use of multiple inputs & outputs but I am having trouble seeing how that can work inside of this specific CR1.cpp file portion of the Arduino Uno folder.

Thanks ... Mike

tinkerspy commented 8 years ago

I have on my screen my CR! open along side of your Trafficlight. I have tried as hard as I can looking for any pattern that I did not follow with your Trafficlight tutorial example folder.

That would be this fairly crucial part:

https://github.com/tinkerspy/Automaton/wiki/Machine-building-tutorial-2#adapting-the-begin-method

digitalRead (12, LOW); but I am pretty sure it will give me a "too many arguments error" based on some tinkering of my own last week.

I'm sure of it! It will give the same error next week, next year and would have done the same last year had you tried it. That's because you skipped the most basic tutorials and don't bother to read the manual even when you get an error. Instead you prefer to dive straight into advanced topics, throw some ingredients together which you hope will create the desired reaction and stir.

You got the ingredients right, but unfortunately, you forgot that you need the magic incantation and the problem with the kind of magic called coding is that the incantation is different every time. You only stand a chance of getting it right if you take the course. The beginners course:

http://www.ladyada.net/learn/arduino/

We all took it, now it's your turn.

Rgdz, Tinkerspy