Multiple IR Break Beam Sensors to build a racecourse.

I am a novice, but enthusiastic, arduino user. I use them to build things and make sensors for experiments. I am not a coding expert and rely on open source code to make things work for me.

I am building a cockroach racecourse with a IR Break Beam Sensors at the end to register a winner. I will have 4 lanes (each with a set of sensors) and small LED lights to light up the winning lane. I am using an Adafruit Metro for the controller. Can anyone help me find a code that allows me to use multiple sensors and output a single LED for the winner?

Thanks for your help.

Patrick

When ever I've used a break beam sensor, it works like an active low switch. So the following code is tested with 4 buttons with their pinMode()s as input pullup.

The buttons and the leds are in arrays. State change detection is used to continuously monitor the buttons and as soon as it finds an active one, it declares that one the winner and lights its led. (The weHaveAWinner flag prevents more than one lane being the winner.)

The output in the serial monitor looks thus:

Lane 1 is the winner
Lane 3 also ran
Lane 2 also ran
Lane 0 also ran

... and here's the code:

//  https://forum.arduino.cc/index.php?topic=639153.0
// light up led for winning lane
// 4 october 2019

// the buttons
byte buttonPins[] = {4, 5, 6, 7}; //remember indexed from 0 ;)
//                              the buttons must be wired from pin to ground, pinmodes are input_pullup
const byte howManyButtons(sizeof(buttonPins) / sizeof(byte));
bool buttonStates[howManyButtons];         // current state of the button
bool lastButtonStates[howManyButtons];     // previous state of the button
bool weHaveAWinner = false;

//the lane leds
byte ledPins[] = {14, 15, 16, 17};

//the pulse led
int pulseLedInterval = 500;
unsigned long previousMillisPulse;
bool pulseState = false;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println("which lane is the winner?");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);

  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  for (int i = 0; i < howManyButtons; i++)
  {
    pinMode(buttonPins[i], INPUT_PULLUP);
    //initialize button states
    buttonStates[i] = digitalRead(buttonPins[i]);
    lastButtonStates[i] = buttonStates[i];
  }

  //initialise lane leds
  for (int i = 0; i < howManyButtons; i++)
  {
    pinMode(ledPins[i], OUTPUT);
  }
  
  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pulseState);

  Serial.println("setup() done");
  Serial.println("Waiting for a winner....");
  Serial.println(" ");
}

void loop()
{
  doPulse();
  checkForButtonStateChange();
} //loop

void readButtons()
{
  for (int i = 0; i < howManyButtons; i++)
  {

  }
}//readButtons

void checkForButtonStateChange()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    buttonStates[i] = digitalRead(buttonPins[i]);
    // compare the buttonState to its previous state
    if (buttonStates[i] != lastButtonStates[i]) // means it changed... but which way?
    {
      if (buttonStates[i] == LOW)  // changed to pressed
      {
        Serial.print("Lane ");
        Serial.print(i);
        if (!weHaveAWinner)
        {
          Serial.println(" is the winner");
          digitalWrite(ledPins[i], HIGH);
          weHaveAWinner = true;
        }
        else Serial.println(" also ran");
      }
      // poor man's de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    lastButtonStates[i] = buttonStates[i];
  }
} // checkForButtonStateChange()

void doPulse()
{
  if (millis() - previousMillisPulse >= pulseLedInterval)
  {
    previousMillisPulse = millis();
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
  }
} //doPulse

Is cockroach racing really a thing?

PS: I have no idea what an adafruit Metro is; above tested on an Uno.

1 Like

Just did a quick re-think: the exact details will depend on your actual sensors, but break beams with pullups are more likely to go high when blocked. (The blocking of the beam turns the transistor off, so no short to ground, the 5V pullup wins.).

If that's the case, change this line to ==HIGH:

if (buttonStates[i] == LOW)

Thanks for the great info. I just ran a quick test and got it to work. My arduino only goes up to pin13 so I changed the LED pins to 8-11 and it worked well. Once I get it wired up completely, I will post a picture of it to this site if anyone else needs it.

And yes, after I researched it, I found that many places do cockroach races. I am doing it as a fun activity in my science class. We have the cockroaches for experiments that the students design (using choice chambers). They have been an easy and fun way to give the kids hands on experience.

You have been a great help. Thanks again.

TrinityTeacher:
Thanks for the great info. I just ran a quick test and got it to work.

Great news.

TrinityTeacher:
My arduino only goes up to pin13

According to this page, looks to me like the Metro is quite Uno-like, and it says:

METRO has 20 GPIO pins, 6 of which are Analog in as well

Note the "as well": that sounds to me like it's the same as an Uno, where the analog pins A0-A5 are actually digital, and count on from 14-19.

Is a Metro just an Uno with a smaller USB plug and the leds moved to the edge? (The latter's great if you use a shield, which normally obscures those.)

edit: I jut noticed I left this remnant of a function in the code I posted. I took its actual code out and incorporated it elsewhere, and forgot to delete it. So you can zap this:

void readButtons()
{
  for (int i = 0; i < howManyButtons; i++)
  {

  }
}//readButtons