Big Arduino Project/Game Need Help

Hello and how are you all?

So i got my first LED to blink on an arduino, big wow.

Well, I have been a Taekwondo athlete for 11-12 years approx, and my instructor has given me this idea. I want to build a game that there will be 4-5 different LED's on top of sacks. When an LED turns on, people will kick the sack and an input will be closed. I want my arduino to measure the time it took for the input to be closed from the time the LED turned on. Also, i'd like it to randomly turn on the LED's, and once the correct input closes (there will be 4 inputs, 1 under each LED) to turn on another LED. This will be a session of X seconds, in which ill chose the amount of seconds with 4 different inputs (15s, 30s, 60s, 120s) How can I do this?

Thanks, and please bear with me

Useful first place to look

Are the LEDs devices that will sit on top of the sacks (and go flying when the sacks are kicked) or something that could be mounted/suspended separately near the sacks somehow?

Does each bag only get to be kicked once in each session (perhaps you could detect when the bags get kicked off a pressure switch), or is this more of a 'wackamole' type of thing (you'd need to find some other way to detect individual kicks, then)?

There will be several kicks in each session, yes. I have the hardware, I only have trouble writing the software, I don’t know where to start from. I would’ve written on a PLC, but then the sessions wouldn’t be random and everyone would just learn out by hard the sequence. Its gonna be more of a whack-a-mole but a mole would stay up until whacked, and the time needed for him to be whacked has to be stored somewhere. I am looking forward to make a database of the results, so I can make a score board

michalis95: I have the hardware, I only have trouble writing the software

That's great, it sounds as if you have already sorted out most of the conceptual problems. How is the solution going to work, in electrical/electronic terms?

You're probably going to need a form of confirmation of correct AND incorrect contact as well (someone might hit the wrong bag). In the case of correct contact, the same LED might light up after being previously activated if using random selection, so you'd need to know if you hit it first time or not

You might also be looking at a round-robin of led's or known sequence for physically teaching a whole kata, yes I know this would require additional programming and some form of input device (screen/kepyad etc) to define the sequence needed but... I'm throwing ideas out here!

I could see this being extended into a highly useful training tool, reliability of your switches might be an issue though especially if they get hit really hard at times

My initial thoughts are that it could well be extended over using basic switches into some form of contact sensor that would measure actual force of impact as well

I have a couple of questions... If you're measuring the time taken to actualy hit the switch, how are you going to display/save this? Have you thought about only having the led turn on for a certain amount of time before it switches to the next random value (this could be used for both Kata or Reflex training)?

Hajime

abrookfield: You're probably going to need a form of confirmation of correct AND incorrect contact as well (someone might hit the wrong bag). In the case of correct contact, the same LED might light up after being previously activated if using random selection, so you'd need to know if you hit it first time or not

You might also be looking at a round-robin of led's or known sequence for physically teaching a whole kata, yes I know this would require additional programming and some form of input device (screen/kepyad etc) to define the sequence needed but... I'm throwing ideas out here!

I could see this being extended into a highly useful training tool, reliability of your switches might be an issue though especially if they get hit really hard at times

My initial thoughts are that it could well be extended over using basic switches into some form of contact sensor that would measure actual force of impact as well

I have a couple of questions... If you're measuring the time taken to actualy hit the switch, how are you going to display/save this? Have you thought about only having the led turn on for a certain amount of time before it switches to the next random value (this could be used for both Kata or Reflex training)?

Hajime

Measuring force of impact will be VERY nice, but I don't know how to do it yet. On the other hand, I don't mind if the same LED is lit up twice, since we get double kicks as well. There will be 4 different inputs, and I would like one to bind with a single output, so the program would know to continue only if , for ex : O:2 is on, then I:2 will need to be struck.

I don't know how to save the time it takes. My problem is that I cannot do this in software, I am a very new user with the arduino and I am at ground 0, that's why I need help.

I'll code it as using an UNO R3 and I'll look into impact measurement, We'll worry about speed storage later... keep your eyes open for it

try this as a first attempt

/*
========== 
KICKMASTER
==========
switches should be tied to gnd

DO NOT FORGET LED'S NEED CURRENT LIMIT RESISTOR

0, 1, 2, 3   = kick bag switches
4, 5, 6, 7   = led's for kick switches
8, 9, 10, 11 = time select switches
12           = go switch (send low -> high to activate) - LED13 lights when running

Start switch must be cycled for sequence to start again

MISSING THINGS:  
storage/display of time taken to kick
confirmation of good kick
confirmation of WRONG kick

portions ripped from adafruit samples
*/

#define DEBOUNCE 5  // kick input button debouncer

byte buttons[] = {0, 1, 2, 3, 12}; // 0-4 = kick buttons, 12=start button
byte kickMe[] = {4, 5, 6, 7}; // LEDs to light on kick enabled
byte whichTime[] = {8, 9, 10, 11}; // pins to use for time select
int KickSwitchTime[] = {900, 1800, 3600, 7200}; // allow kick switch input time selector (multiples of 16ms)
int kicked, sw_enabled, tryInput, nextKick, currentTime, kickTimer, j, timeInput;

// This handy macro lets us determine how big the array up above is, by checking the size
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or 'currently pressed' 
volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

void setup() {
  byte i;
  
  // set up serial port
  Serial.begin(9600);
  Serial.print("Button checker with ");
  Serial.print(NUMBUTTONS, DEC);
  Serial.println(" buttons");

  // pin13 LED
  pinMode(13, OUTPUT);
 
  // Make input & enable pull-up resistors on switch pins
  for (i=0; i< NUMBUTTONS; i++) {
    pinMode(buttons[i], INPUT);
    digitalWrite(buttons[i], HIGH);
    pinMode(KickSwitchTime[i], INPUT);
    digitalWrite(KickSwitchTime[i], HIGH);
    pinMode(kickMe[i], OUTPUT);
    digitalWrite(kickMe[i], LOW);
  }

  // Run timer2 interrupt every 15 ms 
  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;

  //Timer2 Overflow Interrupt Enable
  TIMSK2 |= 1<<TOIE2;

}

SIGNAL(TIMER2_OVF_vect) {
  check_switches();
}

void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  static long lasttime;
  byte index;

  kickTimer++;
  currentTime++;
  if (millis() < lasttime) {
     // we wrapped around, lets just try again
     lasttime = millis();
  }
  
  if ((lasttime + DEBOUNCE) > millis()) {
    // not enough time has passed to debounce
    return; 
  }
  // ok we have waited DEBOUNCE milliseconds, lets reset the timer
  lasttime = millis();
  
  for (index = 0; index < NUMBUTTONS; index++) {
     
    currentstate[index] = digitalRead(buttons[index]);   // read the button
/*
    Serial.print(index, DEC);
    Serial.print(": cstate=");
    Serial.print(currentstate[index], DEC);
    Serial.print(", pstate=");
    Serial.print(previousstate[index], DEC);
    Serial.print(", press=");
*/    
    if (currentstate[index] == previousstate[index]) {
      if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
          // just pressed
          justpressed[index] = 1;
      }
      else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
          // just released
          justreleased[index] = 1;
      }
      pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}


void loop() {
  digitalWrite(13,HIGH); delay(1000);
  digitalWrite(13,LOW); delay(1000);
  digitalWrite(13,HIGH); delay(1000);
  digitalWrite(13,LOW); delay(1000);
  kicked = 1;
  nextKick=0;
  kickTimer=0;
  //if start button already low, wait for it to go high
  while(pressed[4]==LOW);
  // wait for start button to go low 
  while (pressed[4]==HIGH);

  // lets see whick time scenario to use
  for (j=0; j < 4; j++){
    digitalWrite(whichTime[j],HIGH);
    if (digitalRead(whichTime[j])==LOW) timeInput=j;
  }

  currentTime=0;
  // main timer loop
  while(currentTime < KickSwitchTime[timeInput]){
    digitalWrite(13,HIGH);
    if (kicked==1){
      // choose a new position to kick
      nextKick=random(1,4);
      kickTimer=0;
      digitalWrite(kickMe[nextKick], HIGH);
    }
    for (byte i = 0; i < NUMBUTTONS; i++){
      if ( (pressed[i]) && (i==nextKick) ){
        // we got a good kick, lets move on
        kicked=1;
        // kickTimer = multiples of 16mS
        // save kickTimer somewhere
        
        // turn off current led
        digitalWrite(kickMe[nextKick], LOW);
      }
    }
  }

}

abrookfield:
try this as a first attempt

/*

==========
KICKMASTER

switches should be tied to gnd

DO NOT FORGET LED’S NEED CURRENT LIMIT RESISTOR

0, 1, 2, 3   = kick bag switches
4, 5, 6, 7   = led’s for kick switches
8, 9, 10, 11 = time select switches
12           = go switch (send low → high to activate) - LED13 lights when running

Start switch must be cycled for sequence to start again

MISSING THINGS:  
storage/display of time taken to kick
confirmation of good kick
confirmation of WRONG kick

portions ripped from adafruit samples
*/

#define DEBOUNCE 5  // kick input button debouncer

byte buttons = {0, 1, 2, 3, 12}; // 0-4 = kick buttons, 12=start button
byte kickMe = {4, 5, 6, 7}; // LEDs to light on kick enabled
byte whichTime = {8, 9, 10, 11}; // pins to use for time select
int KickSwitchTime = {900, 1800, 3600, 7200}; // allow kick switch input time selector (multiples of 16ms)
int kicked, sw_enabled, tryInput, nextKick, currentTime, kickTimer, j, timeInput;

// This handy macro lets us determine how big the array up above is, by checking the size
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or ‘currently pressed’
volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

void setup() {
 byte i;
 
 // set up serial port
 Serial.begin(9600);
 Serial.print(“Button checker with “);
 Serial.print(NUMBUTTONS, DEC);
 Serial.println(” buttons”);

// pin13 LED
 pinMode(13, OUTPUT);

// Make input & enable pull-up resistors on switch pins
 for (i=0; i< NUMBUTTONS; i++) {
   pinMode(buttons[i], INPUT);
   digitalWrite(buttons[i], HIGH);
   pinMode(KickSwitchTime[i], INPUT);
   digitalWrite(KickSwitchTime[i], HIGH);
   pinMode(kickMe[i], OUTPUT);
   digitalWrite(kickMe[i], LOW);
 }

// Run timer2 interrupt every 15 ms
 TCCR2A = 0;
 TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;

//Timer2 Overflow Interrupt Enable
 TIMSK2 |= 1<<TOIE2;

}

SIGNAL(TIMER2_OVF_vect) {
 check_switches();
}

void check_switches()
{
 static byte previousstate[NUMBUTTONS];
 static byte currentstate[NUMBUTTONS];
 static long lasttime;
 byte index;

kickTimer++;
 currentTime++;
 if (millis() < lasttime) {
    // we wrapped around, lets just try again
    lasttime = millis();
 }
 
 if ((lasttime + DEBOUNCE) > millis()) {
   // not enough time has passed to debounce
   return;
 }
 // ok we have waited DEBOUNCE milliseconds, lets reset the timer
 lasttime = millis();
 
 for (index = 0; index < NUMBUTTONS; index++) {
   
   currentstate[index] = digitalRead(buttons[index]);   // read the button
/*
   Serial.print(index, DEC);
   Serial.print(": cstate=");
   Serial.print(currentstate[index], DEC);
   Serial.print(", pstate=");
   Serial.print(previousstate[index], DEC);
   Serial.print(", press=");
*/    
   if (currentstate[index] == previousstate[index]) {
     if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
         // just pressed
         justpressed[index] = 1;
     }
     else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
         // just released
         justreleased[index] = 1;
     }
     pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
   }
   //Serial.println(pressed[index], DEC);
   previousstate[index] = currentstate[index];   // keep a running tally of the buttons
 }
}

void loop() {
 digitalWrite(13,HIGH); delay(1000);
 digitalWrite(13,LOW); delay(1000);
 digitalWrite(13,HIGH); delay(1000);
 digitalWrite(13,LOW); delay(1000);
 kicked = 1;
 nextKick=0;
 kickTimer=0;
 //if start button already low, wait for it to go high
 while(pressed[4]==LOW);
 // wait for start button to go low
 while (pressed[4]==HIGH);

// lets see whick time scenario to use
 for (j=0; j < 4; j++){
   digitalWrite(whichTime[j],HIGH);
   if (digitalRead(whichTime[j])==LOW) timeInput=j;
 }

currentTime=0;
 // main timer loop
 while(currentTime < KickSwitchTime[timeInput]){
   digitalWrite(13,HIGH);
   if (kicked==1){
     // choose a new position to kick
     nextKick=random(1,4);
     kickTimer=0;
     digitalWrite(kickMe[nextKick], HIGH);
   }
   for (byte i = 0; i < NUMBUTTONS; i++){
     if ( (pressed[i]) && (i==nextKick) ){
       // we got a good kick, lets move on
       kicked=1;
       // kickTimer = multiples of 16mS
       // save kickTimer somewhere
       
       // turn off current led
       digitalWrite(kickMe[nextKick], LOW);
     }
   }
 }

}

Dude, you are the best! Thats extremely utterly helpful, I’m very grateful i would never be able to code such thing on my own. That is a great help, a huge kick-start although I’ll need to sit my ass down and try to understand what everything does. Even so, just a confirmation of a good kick will be super enough for me. If there is a possible way my team can donate to you please tell me

Think about what I said in my first reply, I see lots of room for improvement and expansion!

Lets see how long it takes you to add a confirmation led with say a 0.5 second on time and then move on to next kick hint: Analog ports can also be output ports 8)

Payment..? pfffft....... glad to help get you started!

is there a like button here? i would like to give a like to this person above me ^_^

more powers to your project.. Im also a taekwondo player and it is nice to have this project to help train new players. how about also a timer? to time whether those kicks can also reach the maximum time of one round?

kawoonoon: is there a like button here? i would like to give a like to this person above me ^_^

On the person's posting there is an entry under the person's name for 'Karma'. Click on the green square, and the person's Karma goes up by 1. Evidently in the past, they had the option to lower a person's Karma, but that is not allowed with the current web software. I recall reading there is a timeout where you can only bump Karma once an hour (or perhaps of the same individual).