Vending Machine Help

Hey all,

I've gotten pretty far, but I can't seem to get the last part right. What I've got done:

  1. Integration of bill validator to Arduino
  2. Toggle Switch state detection (either way can trigger vend, for when a switch is left)
  3. dollars to "pulse" math

What I think I have right:

Pin defs and numbers. I am using platformio and an nodemcu 1.0

Main Code

#include "def.h"
#include "Vend.h"
#include "Arduino.h"

void setup()
{
  // Pin setups for bill validator and button
  pinMode(billValidator, INPUT);
  pinMode(handToggleSwitch, INPUT_PULLUP);
  pinMode(augerPulse, INPUT);
  pinMode(augerEnable, OUTPUT);
  pinMode(Output_PIN, OUTPUT);

  // Initialize serial ports for communication.
  Serial.begin(74880);
  Serial.println("Waiting for dollar...");
}

void loop()
{
  // get the duration of the pulse

  duration = pulseIn(billValidator, LOW);
  int toggleState = digitalRead(handToggleSwitch);
  //Serial.println(toggleState); //DEBUG
  Serial.println(augerPulseCounter);

  // Receiving a dollar bill will create a pulse
  // with a duration of 150000 - 160000.

  if(duration > 12000)
    {
    // Count dollar
    dollarCounter++;
    // Checking for understanding
    Serial.print("Credits: ");
    // Display new dollar count
    Serial.println(dollarCounter);
    augerPulseCounter = dollarCounter*cornPrice;
    augerPulseCounter = augerPulseCounter/.75;
    Serial.println(round(augerPulseCounter));
    }
  if (toggleState != lastToggleState)
    {
      vend();
    }
    lastToggleState = toggleState;

    loop();
}

helper code (def.h and vend.h)

//Defined Pins

#define billValidator 2
#define handToggleSwitch 4
#define augerPulse 14
#define augerEnable 5
#define Output_PIN 0

//Defined Variables

int dollarCounter = 0;
int toggleState = 1;
int lastToggleState = 1;
float augerPulseCounter = 0;
unsigned long duration;
float cornPrice = (100/9.5);

//Defined Constants



void vend()
{
  if (augerPulseCounter > 0)
    {
    Serial.println("Vending");
    while (augerPulseCounter > 0)
      {
      digitalWrite(augerEnable, HIGH);
      augerPulseCounter = augerPulseCounter - digitalRead(augerPulse);

      if (augerPulseCounter != 0)
        {
          vend();
        }
      }
    dollarCounter = 0;
    }
  else if (augerPulseCounter == 0)
    {
      digitalWrite(augerEnable, LOW);
      Serial.println("Please insert Cash");
      loop();
    }
}

I feel like I've been staring at it so long nothing makes sense anymore.

I need the augerPulse pin to subtract from augerPulseCounter, but keep vending until it is at 0.

Any help is appreciated!

Your recursive calls to loop() will eventually cause your processor to run out of memory. DON'T have loop() call loop(). Because loop() calls vend(), DON'T have vend() call loop().

It is a little strange to use float for "augerPulseCounter" since pulses usually either exist or don't and don't come in fractions. If that count ever is a fraction, subtracting an integer is not going to get you 0. It will get you a negative number but that negative number won't ever be == 0.

It is very unclear why the price of corn is 100 auger pulses per 9.5 dollars and you then divide the auger pulse count by 0.75.

Using 'pulseIn()' is usually not the best way to detect pulses. You should use state change detection and count the rising or falling edges with debouncing for mechanical contacts. Similar for the auger pulse input. Subtracting 1 from the auger pulse count whenever the input is HIGH may decrement more than once per switch activation (assuming you are counting a pulse that indicates motion).

Hey John, thanks for the reply.

  1. 10-4 on the loop, just curious if it will return to void after the vend()?
  2. I am using a float for auger pulses (don't I need to use it somewhere?) so I can get the round number of auger pulses for how much money was deposited, I was not able to get the float to convert to a int, to the nearest round. It was always just 10 for even a 10.9. I did run into that issue of not getting to 0, and going negative, so I do understand that needs repair.
  3. I was working with the prices my dad gave me haha!! 100lbs of corn for 9.50USD, divided by the 0.75 (how much corn dispensed per pulse on the hall sensors).
  4. Is there any reading material you can suggest for a better way to detect pulses?

This is literally the first coding I've ever done "solo" All projects before this were derivatives of a copy/paste. I'm surprised to have gotten this far, but I have a LOT of learning to do.

Cheers.

Besides what johnwasser pointed out this line doesn't make any sense:

      augerPulseCounter = augerPulseCounter - digitalRead(augerPulse);

You are subtracting the STATE of the input which only tells you the state of the input in that instance. You need to check for transitions (HIGH to LOW or LOW to HIGH) in order to detect a pulse.

Besides, nothing guarantees you that in future IDEs that a HIGH will be 1 and a LOW will be 0.

Ok, thank you. I will try and re-write that part.

theomajigga:

  1. 10-4 on the loop, just curious if it will return to void after the vend()?

Yes, when functions return the next thing to execute is whatever is just after the function call.

theomajigga:
2. I am using a float for auger pulses (don't I need to use it somewhere?) so I can get the round number of auger pulses for how much money was deposited, I was not able to get the float to convert to a int, to the nearest round. It was always just 10 for even a 10.9. I did run into that issue of not getting to 0, and going negative, so I do understand that needs repair.
3. I was working with the prices my dad gave me haha!! 100lbs of corn for 9.50USD, divided by the 0.75 (how much corn dispensed per pulse on the hall sensors).

So it's about 10.526 pounds per dollar (9.5 cents a pound) and you want to vend to the nearest 3/4 pound.

This is one way to name the constants to make it easier to understand and round to the nearest full pulse:

// Up in the header:
const float PoundsPerVendPulse = 0.75;
const float CentsPerPound = 9.5;

    // Down in the code:
    float poundsToVend = (dollars * 100) / CentsPerPound;
    int pulsesToVend = (poundsToVend / PoundsPerVendPulse) + 0.5; // Round to nearest pulse

theomajigga:
4. Is there any reading material you can suggest for a better way to detect pulses?

There is a built-in example File->Examples->02.Digital->StateChangeDetection for clean signals and an example File->Examples->02.Digital->Debounce for glitchy signals from things like mechanical switches

John,

I rewrote the stuff a little bit and it seems to be working as intended. Now my problem is, I believe I am getting a stack overflow, and a rst.

What I implemented from your suggestions:

  1. Removed recursive loops.
  2. simplified the math, moved the full equation over to the float.
  3. added a paidAugerPulse which I compare to the actual augerPulse counter
  4. I used lazy debounce, just snapped some small delays (auger rotates at 54rpm, with 2 magnets on the sensor, and hand switch is a on/off.

What is working:

Everything is, but it's overflowing. The bill counter is giving full credits, and rounding to the nearest int. the toggle switch can be left in either position and will not trigger a vend until it is flipped, and the auger will stop feeding if the toggle state changes in the middle of the vend. Any chance you can find where my error is?

main

#include "def.h"
#include "Vend.h"
#include "Arduino.h"

void setup()
{
  // Pin setups for bill validator and button
  pinMode(billValidator, INPUT);
  pinMode(handToggleSwitch, INPUT);
  pinMode(augerPulse, INPUT);
  pinMode(augerEnable, OUTPUT);
  pinMode(Output_PIN, OUTPUT);
  // Initialize serial ports for communication.
  Serial.begin(74880);
}

void loop()

{
  // get the duration of the pulse
  Serial.println("Please Insert Cash");
  int toggleState = digitalRead(handToggleSwitch);
  if (toggleState != lastToggleState)

    {
      vend();
    }
  delay(100);
  // Receiving a dollar bill will create a pulse
  // with a duration of 150000 - 160000.
  dollarPulse = pulseIn(billValidator, LOW);
  if(dollarPulse > 12000)
    {
    // Count dollar
    dollarCounter++;
    // Checking for understanding
    Serial.println("Credits: ");
    // Display new dollar count
    Serial.println(dollarCounter);
    paidAugerPulse = (dollarCounter*cornPrice)+0.5;
    Serial.println(paidAugerPulse);
    }
}

def and vend.h

//Defined Pins

#define billValidator 2
#define handToggleSwitch 4
#define augerPulse 16
#define augerEnable 5
#define Output_PIN 0

//Defined Variables

int dollarCounter = 0;
int toggleState;
int lastToggleState;
int augerPulseCounter = 0;
int paidAugerPulse;
unsigned long dollarPulse;
float cornPrice = (100/9.5)/.75;

//Defined Constants
void vend()
{
  toggleState = digitalRead(handToggleSwitch);
  if (toggleState != lastToggleState)
  {
    if (paidAugerPulse > augerPulseCounter)
          {
          Serial.println("Vending...");
          Serial.println(paidAugerPulse);
          while (paidAugerPulse > 0)
            {
            digitalWrite(augerEnable, HIGH);

            augerPulseCounter = digitalRead(augerPulse);

            if (toggleState == lastToggleState)
              {
                digitalWrite(augerEnable, LOW);
              }
            if (augerPulseCounter == HIGH)
              {
                paidAugerPulse--;
              }
              delay(500);
            if (paidAugerPulse != 0)
              {
                vend();
              }
            }
          lastToggleState = toggleState;  
          dollarCounter = 0;
          digitalWrite(augerEnable, LOW);
          }
    else if (paidAugerPulse == 0)
      {
        Serial.println("No Credits, Please insert Cash");
        lastToggleState = toggleState;
      }
      digitalWrite(augerEnable, LOW);
  }
}

You are calling vent() recursively from within vend().

oh man, I was doing that for the serial output so I could watch the counter fall :frowning: stupid mistake.