Tinkercad: Arduino Uno R3 auto-restart/reboot abruptly

Hello guys! I am currenly programming a vending carwash prototype in Tinkercad. I've attached the circuit's link below.

https://www.tinkercad.com/things/1wUKktESdSW-vending-carwash-arduino-uno

I've replaced the universal coin slot temporarily with buttons with pull-down resistors;
Orange wire button = Add 1 to the balance,
Yellow wire button = Add 5 to the balance,
Green wire button = Add 10 to the balance,
Cyan wire button = Pump water with play/pause feature,
Blue wire button = null;

The problem is while the program is running and executing the PumpWater() countdown method which means that the relay in the circuit is ON and the motor is running, after a few seconds ranging from 4-60 second, the Arduino abruptly restart/reboot which ends the program and start over from the setup(). Every time the Arduino restart/reboot, the symbol "À" appears in the serial monitor. I haven't received error messages from Tinkercad when this occur aside from the symbol "À" in the serial monitor. Do you guys know what this symbol means? What do you guys think is the cause of the problem? Does the motor and relay connected to the 5V and ground of the Arduino respectively causes this abrupt restart/reboot when the relay is in closed state?

This is my code:

// C++ code

#include <Adafruit_LiquidCrystal.h>

int balance = 0;
int waterCost = 5;
int foamCost = 5;

// Pin and Button for coins, replacement for the coin slot
int coinPin_1 = 2;
int coinPin_5 = 3;
int coinPin_10 = 4;

// Pin and Button for water and foam function
int waterPin = 5;
int foamPin = 6;

// Pin for relay
int relayPin = 9;

// Event flag for water and foam feature
bool isWatering = false;
bool isFoaming = false;
bool hasWaterTime = false;
bool hasFoamTime = false;

// Variables for toggle
int waterButtonState = 0;
int prevWaterButtonState = 0;
unsigned long toggleTime = 0;
unsigned long debounce = 200UL;

// Millis() variables
unsigned long currentWaterMillis;
unsigned long currentFoamMillis;
unsigned long startWaterMillis;
unsigned long startFoamMillis;

const unsigned long second = 1000UL;
const unsigned long minute = second * 60;
const unsigned long waterTime = minute * 2;
const unsigned long foamTime = minute;
unsigned long waterTimeLeft = waterTime;
unsigned long foamTimeLeft = foamTime;

Adafruit_LiquidCrystal lcd(0);

void setup()
{
  // Serial
  Serial.begin(115200);
  //Intialize the LCD
  lcd.begin(16, 2);
  
  //Set the pin of coinButtons
  pinMode(coinPin_1, INPUT);
  pinMode(coinPin_5, INPUT);
  pinMode(coinPin_10, INPUT);
  // Set the pin of water and foam button
  pinMode(waterPin, INPUT);
  pinMode(foamPin, INPUT);
  
  // Set the pin of relay
  pinMode(relayPin, OUTPUT);
}

void loop()
{
  // Read and add inserted coin
  balance = AddCoinTo(balance);
  
  // Balance constraint
  if(balance < 5)
  {
    if(!hasWaterTime)
    {
      DisplayInsert();
      DisplayBalance(balance);
    }
    if(digitalRead(waterPin) == 1 || digitalRead(foamPin) == 1)
    {
      // clear the display
      lcd.clear();
      lcd.home();
      lcd.print(" INSUFF BALANCE ");
    }
  }
  else if(balance >= 5)
  {
    if(digitalRead(waterPin) == 1 && !hasWaterTime)
    {
      // clear the display
      lcd.clear();
      balance -= waterCost;
      startWaterMillis = millis();
      isWatering = true;
      hasWaterTime = true;
      
      Serial.println(F("WATER IS RUNNING"));
      Serial.print(F("BALANCE: P"));
      Serial.println(balance);
    }
    
    if(!hasWaterTime)
    {
      DisplayPress();
      DisplayBalance(balance);
    }
  }
  
  PumpWater();
  if(digitalRead(waterPin) == 1 && hasWaterTime)
  {
    TogglePumpWater();
  }
}

int AddCoinTo(int bal)
{
  if(digitalRead(coinPin_1) == 1)
  {
    bal += 1;
    Serial.print(F("BALANCE: P"));
    Serial.println(bal);
  }
  if(digitalRead(coinPin_5) == 1)
  {
    bal += 5;
    Serial.print(F("BALANCE: P"));
    Serial.println(bal);
  }
  if(digitalRead(coinPin_10) == 1)
  {
    bal += 10;
    Serial.print(F("BALANCE: P"));
    Serial.println(bal);
  }
  return bal;
}

void DisplayBalance(int bal)
{
  lcd.setCursor(0, 1);
  lcd.print("  BALANCE: P");
  lcd.print(bal);
}

void DisplayInsert()
{
  lcd.home();
  lcd.print("INSERT:P1,P5,P10");
}

void DisplayPress()
{
  lcd.home();
  lcd.print(" PRESS A BUTTON ");
}

void PumpWater()
{
  currentWaterMillis = millis();
  long displayWaterTime;
  if(isWatering)
  {
    unsigned long elapsedWaterTime = currentWaterMillis - startWaterMillis;
    if(elapsedWaterTime > waterTimeLeft)
    { 
      if(digitalRead(relayPin) == 1)
      {
        digitalWrite(relayPin, 0);
      }
      displayWaterTime = 0;
      
      isWatering = false;
      hasWaterTime = false;
    }
    else if(elapsedWaterTime <= waterTimeLeft)
    {
      if(digitalRead(relayPin) == 0)
      {
        digitalWrite(relayPin, 1);
      }
      displayWaterTime = waterTimeLeft - elapsedWaterTime;      
    }
  }
  else if(!isWatering)
  {
    if(digitalRead(relayPin) == 1)
    {
      digitalWrite(relayPin, 0);
    }
    if(hasWaterTime)
    {
      displayWaterTime = waterTimeLeft;
    }
  }
  
  // Display Time
  if(hasWaterTime)
  {
    int countdown_minute = ((displayWaterTime / 1000) / 60) % 60;
    int countdown_sec = (displayWaterTime / 1000) % 60;
    
    lcd.home();
    lcd.print("WTR");
    if(countdown_minute < 10)
    {
      lcd.print(" ");
    }
    lcd.print(countdown_minute);
    lcd.print(":");
    if(countdown_sec < 10)
    {
      lcd.print("0");
    }
    lcd.print(countdown_sec);
  }
  // Reset the waterTimeLeft after the countdown is finished
  if(displayWaterTime == 0)
  {
    waterTimeLeft = waterTime;
  }
}

// Play/Pause toggle of the water time countdown:
void TogglePumpWater()
{
  isWatering = !isWatering;
  if(isWatering)
  {
    startWaterMillis = millis();
    Serial.println(F("WATER IS RUNNING"));
  }
  else if(!isWatering)
  {
    waterTimeLeft -= (millis() - startWaterMillis);
    Serial.println(F("WATER HAS STOPPED"));
  }
}

This is the output of the serial monitor:

This is the circuit:


Any help and insights are appreciated. Thank you in advance.

I think you can probably read well enough to post properly usurping the ‘guide’ at the top of each category.
Show us your code and schematic

What are the colours you notred? the resistor bands ?

Think more, write less, and be informative in your post.

I apologize for the lack of information. I've edited the post and added the code as well as the circuit of the vending carwash prototype.

I don’t like being the nag, ut I’m guessing you still haven’t read the tips to posting…

There is almost no information in the circuit diagram - without annotations,…

Please repost your code- start a new post in this existing thread using CODE TAGS to properly display your code.

Thank you for your guidance, I'll be working on it.

The problem still occurs after I've added the dedicated power source to the motor. I was wrong in assuming that the issue occurred because I powered the motor through the Arduino's 5V pin instead of providing it with its own dedicated power source.

Wait - tinkercod did this? I'm impressed. Many simulators don't do such a good job with pesky real problems with the circuitry and power.

It seems like if it is so smart it might just have come out and said what the problem is. Had you presented here a real project with this symptom, the immindiant responses would point you at a lower or wiring issue.

a7

I've celebrated to early after completing a 1 countdown cycle. The problem still occurs apparently after I've provided the motor its own dedicated power source.

Say more. When ezzctly does the problem occur, same as when you powered on the relay? Is it consistent?

Also, please confirm you are working in simulation only.

a7

I am only doing this project in Tinkercad simulation. The abrupt restart/reboot of Arduino only occurs after 4-60 seconds when the relay is ON and the motor is running. I've noticed that the digitalWrite(relayPin, n) is being executed every loop, I've put a constraint into it to prevent this from happening. I'll be monitoring if the problem still occurs after putting the digitalWrite(relayPin, n) constraint. Thanks for your input.

I often surpress this activity as well, but there should be absolutely no problem writing HIGH to an output that is already, or LOW.

I am working with your code, but it is also a day for the beach so don't hold your breath.

Your sketch seems to be without any of the several standard first issues.

a7

OK, she who must not be kept waiting has texted, but I did manage to build your circuit and execute your code.

  • I changed the switches to be pulled up, see PRESSED in the code.
  • I swapped in the available LCD I2C, only the object and initialisation are different.

I am pretty good at this kind of hacking, so my belief is that your logic is unchanged.

I note that if you keep a finger on the buttons, they continue to do what you might only want to happen when the buttons become pressed, as opposed to being held pressed.

This is called "state change detection" or "edge detection", and along with switch debouncing will be essential to have in you sketch. See an example in the IDE and follow links to a competent article that goes into some detail.

But neither issue should cause the problem you observe, so.

Here's a link to the so far:

Try this alternate simulation!

L8R

a7

We struggled heroically with your code, and we are done. Fixing it will change your code into our code.

The button handling can't be easily fixed. The logic of starting the water running is confused by the logic for pausing/restarting the water. Quite a tnagle.

Recommendation: start over using a finite state machine approach coded hewing to the IPO model for control programs.

google

arduino two things at once
arduino finite state machine

and learn about the IPO model in the abstarct here:

The IPO Model.

In all our hacking, there was never any sign of the exact issue you came here for. The conclusion we reach is that something in tinkercod is messing with you.

The wokwi simulation should function like you would think just reading the code, that is to say without either the "Arduino restart/reboot" or "À".

Are you 100 percent sure you posted the sketch that has this issue?

I am out. I got nothing on the problem you presented.

a7

1 Like

Thank you very much for your insights in further improving my code. I'll be studying those topics and be working on it. The only change I've done in the sketch is putting the digitalWrite(relayPin, n) constraint. After multiple simulation in Tinkercad, I've manage to complete the 2 minutes countdown without the Arduino restarting/rebooting so far.

A good place to start is the completely separable issue of the coin deposit.

Your real coin acceptor may be producing short clean pulses that the code deals with properly.

As an exercise and for good measure, bullet proof the coin code by

  • debouncing the pushbuttons
  • adding value to balance once per press

This will mean the balance won't go up rapidly while you are pressing the button.

In our experiments we did this by using a button library. ezButton (case counts, not EZButton) gets my highest praise for such libraries "it doesn't suck" and woukd be one way to go.

But I always militate for doing debouncing and state change detection "by hand" at least once in your life; it's a nice pair of problems that you can learn from by coming to an understanding of a few of the many ways to solve those problems.

a7

Thank you very much for giving me a direction where to start, I'll be starting with the fundamentals of button debouncing, both the hardware and code solutions. After fully understanding button debouncing, I'll try to incorporate the ezButton library that you've recommended. I am currently studying the FSM of vending machine to have a better understanding on how to properly program its software design and functionalities.

1 Like

That's a good plan.

I may have said there are literally dozens of explainers, be it articles or videos or in the context of an organized course on these matters.

A trick can be used to (temporarily) set the problem of debouncing off to the side whilst the matter of state change detection is being studied.

This thread is worth the time

and this one goes a bit into doing things in a more explicit manner

It does help to read a few ppl's attempt to get this idea across. In the end, it is all the same, but reading code and truly understanding it helps develop valuable skills - like being able to "see" the balance shoot up on a wild ride while a button is being pressed...

Good luck and we here always. No life.

a7

1 Like

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