Claw Machine

Hello, I have a software problem: the code counts from 20 to 0 just fine, however, when it is finished, it will go back to counting from 255 to 0. The joystick works, but not the stepper motors with the joystick. Please help, hardware and software:

file:///C:/Users/austin/Desktop/2019-07-28%2013_25_55-Greenshot.png

Action_Contraption.ino (8.92 KB)

1 Like

Where in your code is the “loosen the grip” function that needs to occur right before the prize gets to the chute?

Without that, your machine will bankrupt.

When you see your count is >20, set it to 20. Or when you see your count is 0, don't just deduct 1 but set the count to 20.

I thought I was clear... in code it looks like this.

Count up:

(count < 20) ? count++ : count = 0;

Count down:

(count > 0) ? count-- : count = 20;

Now your variable count won't go outside the 0-20 range, and nicely roll over.[/code]

UptownKitten:
Is that a for loop or while loop, sorry, I am still a beginner. :frowning:

Neither. It's called a *ternary *operator.

Place it where you're doing the counting in your code. But before you do, make sure you actually know what it's doing.

UptownKitten:
Also, how do I get the LCD to stop blinking? Like, when I get the LCD to show the results of the time, it keeps blinking.

Blinking like a turn signal on a car or very short, almost imperceptible blinks? If the latter it's likely because you're continually writing to the display. It's preferable to update the display only when some data being sent there changes.

UptownKitten:
Thanks everyone, a bunch. So, what about the joystick & stepper motor?

UptownKitten:
Also, what about the blinking of the LCD?

UptownKitten:
I am also having problems with my limit switches, may someone, please, help with that?

This won't work. Stop and think about what the program must do. Did you make up a flowchart/state diagram before you started?

Even small projects like this are not thrown together all at once. Get the most elementary pieces working separately then combine them one at a time working out bugs along the way. Become familiar with the concepts presented in the first five demos in IDE -> file/examples/digital.

Start with something like switches - get one switch reading correctly; then debounce it; then generate state change flags if that's going to be necessary (as it so often is). Prove that these things work by making up a small sketch which increments/decrements a counter value and prints same to the serial monitor only when the value changes. Make a self-resetting timer and substitute it for the counter. When this works add in code to also print the counter to the LCD.

Speaking of the serial monitor: it's a major troubleshooting tool. If you're not getting the results you expect, start putting print statements in suspect areas to show the questionable values as the code progresses.

You could also shorten the code quite a bit by putting together a few functions to handle the repetitive parts of the code - like setting all those outputs LOW and the display update. But, that's for later. Right now, name your I/O. There are a lot of signals referred to by numbers. Even a simple const byte YstepperCoilA = 26; will help others trying to help you as well as your future self.

UptownKitten:
I am also having problems with my limit switches, may someone, please, help with that?

Get working limit switches.

Now if you seriously want useful help, you should start describing in detail what your problems are, exactly.

just a guess, but did you get that code from a site somewhere ?

there are two things you should read

[How To Use This Forum](http://"if you don't want free play, get rid of the forward slashs & the */ * in the code below")

and

If you did get the code from a instructable or some such, in order for us to offer help, please post a link to the original site. If not, then you seem to be pretty organized

there is an Axiom about forums, the better the question, the better the answer.

to quote iRobot, "the answers are limited, you must ask the right questions,"

I would suggest that you make copy of the sketh just for the steppers
Just a follow the joystick simple
IIt Should be live all the time for the test
Once you have that work then add the end switches

In your code.

byte delaytimeforLCD = 500;

Maybe spend a moment and lookup how big of a number a “byte” can hold. Might explain your fast blinking.

You also set variable time1 as a “byte” so anytime it goes 1 less than 0, guess what it’s value is.

So the second time the loop runs void runGame(), time1 = 0 and timelimit = 0 and then this line comes up.

(time1 > timelimit) ? —time1 : time1 = 20;

Honestly I am confused by that line, I certainly know what the —time1 will do to a “0” value time1 though.

Forgot to add in, I am also confused as to how exactly you’re making sure 1 second passes before you decrement time remaining. Seems your just taking away time each loop, but it’s after midnight and I get loopy this time of the night.

UptownKitten:
Someone told me to use a ternary operator in order for the loop to stop going to 255, but it still goes to 255. So, I need help knowing how to fix it. The ternary operator causes the loop to countdown from 20 to 0, and in the loop I double checked to countdown as well.

That’s like saying someone told you to put a bandaid on your cut finger while neglecting to address the fact your whole hand had actually been cut off.

(time1 > timelimit) ? --time1 : time1 = 20;

When “time1” = 1 and since your set “timelimit” = 0 this will run as True and decrement time1 to then = 0.

Now your next code blocks will —time1 again and roll it over to 255 since a byte cannot be -1.

As too all your other issues, If it all works spread out on the table, but not when crammed into your enclosure I would suspect a connection or interference issue. But since the stepper motors likely are drawing way more current when assembled it also may be a power supply issue.

UptownKitten:
How can I fix the timer part? Like, when I need the time on the claw machine to decrease to 0, and, once at zero, can move on to the next part. Do I need to use a for loop, while loop, or ternary operator?

Depends on the rest of your program. Do feel free to post it (the proper way - as described in the sticky; not as attachment).

how do I stop the blinking on the LCD?

You were asked before but never gave a clear description of this "blinking". There can be multiple ways a display blinks, needing different solutions. Seeing your code is also paramount.

5 kB is not too long to post inline (the limit is 9,000 characters), and if it's "way too long" you should instead be posting a minimal sketch demonstrating the problem.

For the LCD: looking at the code it will blink, but not like a car. Not 1/4s on, 1/4 off, but much shorter off. The problem is that you all the time use lcd.clear() instead of simply overwriting the current text.

Counting part: as timelimit = 0, the condition for this loop will ALWAYS be true (as explained already in this thread):

for(byte time1 = 20; time1 >= timelimit; --time1){

This will work a lot better:

for(byte time1 = 20; time1 > timelimit; --time1){
 for (byte time1 = 20; time1 >= timelimit; --time1) {
    lcd.print("Time remaining: ");
    lcd.print(time1);
    delay(delaytimeforLCD);
    lcd.clear();
    time1--;

Maybe I'm just getting loopy. Why is time1 decremented twice? And further down besides.

You could shrink the code by putting the eight instances of

    lcd.print("Time remaining: ");
    lcd.print(time1);
    delay(delaytimeforLCD);
    lcd.clear();
    time1--;

in a function.

Code, autoformatted for better readability:

#include <Time.h>
#include <TimeLib.h>

#include <Bounce2.h>
// Include the Arduino Stepper Library
#include <Stepper.h>
#include <Wire.h>
// Include NewLiquidCrystal Library for I2C
#include <LiquidCrystal_I2C.h>
// Define LCD pinout
const int  en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3;
// Define LCD display connections
const int i2c_addr = 0x27;
LiquidCrystal_I2C lcd(i2c_addr, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);

// Number of steps per output rotation
const byte stepsPerRevolution = 200;

// Create Instance of Stepper library
Stepper Xstepper(stepsPerRevolution, 22, 23, 24, 25);
Stepper Ystepper(stepsPerRevolution, 26, 27, 28, 29);
Stepper Zstepper(stepsPerRevolution, 30, 31, 32, 33);

Bounce debouncer = Bounce();
#define CoinLimitSwitch 34
#define CoinLED 35
#define U 36
#define D 37
#define L 38
#define R 39
#define ClawLED 40
#define Claw 41
#define X 42
#define Y 43
#define X2 44
#define Y2 45
#define Demo 46
#define Test 47
#define Solenoid 48
#define Z 49

const byte timelimit = 0;
const byte delaytimeforLCD = 250;

void setup() {

  pinMode(CoinLimitSwitch, INPUT_PULLUP);
  pinMode(U, INPUT_PULLUP);
  pinMode(D, INPUT_PULLUP);
  pinMode(L, INPUT_PULLUP);
  pinMode(R, INPUT_PULLUP);
  pinMode(Claw, INPUT_PULLUP);
  pinMode(X, INPUT_PULLUP);
  pinMode(X2, INPUT_PULLUP);
  pinMode(Y, INPUT_PULLUP);
  pinMode(Y2, INPUT_PULLUP);
  pinMode(Z, INPUT_PULLUP);
  pinMode(Demo, INPUT_PULLUP);
  pinMode(Test, INPUT_PULLUP);

  pinMode(CoinLED, OUTPUT);
  pinMode(ClawLED, OUTPUT);
  pinMode(Solenoid, OUTPUT);

  debouncer.attach(CoinLimitSwitch);
  debouncer.attach(U);
  debouncer.attach(D);
  debouncer.attach(L);
  debouncer.attach(R);
  debouncer.attach(Claw);
  debouncer.attach(X);
  debouncer.attach(X2);
  debouncer.attach(Y);
  debouncer.attach(Y2);
  debouncer.attach(Z);
  debouncer.attach(Demo);
  debouncer.attach(Test);
  debouncer.interval(5);

  Xstepper.setSpeed(60);
  Ystepper.setSpeed(60);
  Zstepper.setSpeed(100);

  // Start with a presenting message as the pins are being initialized
  // Set display type as 16 char, 2 rows
  lcd.begin(16, 2);
  // Print on first row
  lcd.print("Presenting...");
  // Wait 2 seconds
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print(" The Arduino Action Contraption");
  for (int PositionCount = 0; PositionCount < 25; PositionCount++)
  {
    lcd.scrollDisplayLeft(); //builtin command to scroll right the text
    delay(500);//delay of 250 msec
  }
  delay(3000);
}

void loop() {
  //gameIdle(); //if you don't want free play, get rid of the forward slashs & the */ *\ in the code below
  runGame();

  if (digitalRead(Demo) == LOW) {
    demo();
  }
  if (digitalRead(Test) == LOW) {
    testInputs();
  }
}

//----------------------------- Game Idle -----------------------------------

/*void gameIdle(){

  while(digitalRead(CoinLimitSwitch) == HIGH){
  lcd.clear();
  lcd.print("Please, insert");
  lcd.setCursor(0,1);
  lcd.print("<= $0.25.");
  digitalWrite(CoinLED, HIGH);
  delay(500);
  digitalWrite(CoinLED, LOW);
  delay(500);
  }
  digitalWrite(CoinLED, LOW);
  digitalWrite(CoinLimitSwitch, LOW);
  lcd.clear();
  runGame();
  }
*/
//-------------------start of gameplay ------------------------------
void runGame() {

  for (byte time1 = 20; time1 >= timelimit; --time1) {
    lcd.print("Time remaining: ");
    lcd.print(time1);
    delay(delaytimeforLCD);
    lcd.clear();
    time1--;

    while (digitalRead(U) == LOW) {
      lcd.print("Time remaining: ");
      lcd.print(time1);
      delay(delaytimeforLCD);
      lcd.clear();
      time1--;
    }

    digitalWrite(30, LOW);
    digitalWrite(31, LOW);
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
    lcd.print("Time remaining: ");
    lcd.print(time1);
    delay(delaytimeforLCD);
    lcd.clear();
    time1--;

    while (digitalRead(D) == LOW) {
      Zstepper.step(-stepsPerRevolution);
      lcd.print("Time remaining: ");
      lcd.print(time1);
      delay(delaytimeforLCD);
      lcd.clear();
      time1--;
    }
    digitalWrite(30, LOW);
    digitalWrite(31, LOW);
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);

    while (digitalRead(L) == LOW) {
      Ystepper.step(stepsPerRevolution);
      lcd.print("Time remaining: ");
      lcd.print(time1);
      delay(delaytimeforLCD);
      lcd.clear();
      time1--;
    }
    digitalWrite(26, LOW);
    digitalWrite(27, LOW);
    digitalWrite(28, LOW);
    digitalWrite(29, LOW);

    while (digitalRead(R) == LOW) {
      Ystepper.step(-stepsPerRevolution);
      lcd.print("Time remaining: ");
      lcd.print(time1);
      delay(delaytimeforLCD);
      lcd.clear();
      time1--;
    }

    digitalWrite(26, LOW);
    digitalWrite(27, LOW);
    digitalWrite(28, LOW);
    digitalWrite(29, LOW);

    while (digitalRead(Claw) == HIGH) {
      digitalWrite(ClawLED, HIGH);
      delay(500);
      digitalWrite(ClawLED, LOW);
      delay(500);
      lcd.print("Time remaining: ");
      lcd.setCursor(0, 1);
      lcd.print(time1);
      delay(delaytimeforLCD);
      lcd.clear();
    }
    Zstepper.step(-stepsPerRevolution);
    lcd.print("Time remaining: ");
    lcd.print(time1);
    delay(delaytimeforLCD);
    lcd.clear();
    time1--;

    if (time1 == timelimit) {
      break;
      gameOver();
    }
  }
}
void demo() {
}

void testInputs() {

}

void gameOver() {
  lcd.clear();
  lcd.print("Game Over :(");
  runGame();
}

That code is a mess, and I have no idea what you were possibly thinking while writing it.

So you have time1 as the counter of your for loop, counting down as that loop runs (the name suggests it's time based, but it isn't, it's just a counter).

Then I noticed in that runGame() function you have LOTS of while() loops where you get in if a specific input is LOW, then get stuck waiting for that input to go HIGH again, and in each of those you're decrementing time1 several times a second. Why are you doing this?

There's another point within that for loop where you decrement time1, outside those while loops. Why?

Then you have the block

    if (time1 == timelimit) {
      break;
      gameOver();
    }

That's just plain weird, as the for loop itself is supposed to take care of stopping the loop when the counter reaches a certain value, that's what a for loop is for. Furthermore, that gameOver() is of course never called as you break already.

UptownKitten:
What do you mean by "You could shrink the code by putting the eight instances of
Code: in a function."?

The same way you created the other functions, like rungame() you could put the quoted code in a function called, I dunno, updateLCD. Then, instead of typing out the same stuff over and over just do a call to updateLCD();. It should be pretty easy as there are no values passed and none returned.