Project showcase
Formula LED

Formula LED © MIT

Race through your office at the speed of light! A project inspired by the OpenLEDRace project by @gbarbarov, made at Xing in Barcelona.

  • 6,475 views
  • 2 comments
  • 17 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)
09507 01
Soldering iron (generic)

Apps and online services

About this project

This project was made during Hackweek 12 at XING Barcelona as an adaptation of this. It's basically the LED version of popular racing games like Scalextric with acceleration, friction and players going off track when they are too fast.

Rules

  • There are two players: red and blue
  • The race begins with a random countdown
  • Keep pressing the button on the controller to accelerate
  • When a player goes too fast it changes color to green or yellow
  • Keep going too fast to be "thrown off the track". When this happens the player's speed is reset to 0 and the player blinks until it accelerates back to speed 1
  • There are 4 laps in a race
  • The first player to cross the line at the end of the 4th lap wins
  • Press the reset button to start again

    https://github.com/jesuslg123/formula-led

Code

LED_Race.inoC/C++
You will need the FastLED library
#include "FastLED.h"
#define NUM_LEDS 300
#define LED_PIN 6

#define PLAYER1_PIN 7
#define PLAYER2_PIN 8

#define ACCELERATION 0.4
#define FRICTION 0.03
#define HIGHSPEED 3
#define MAX_SPEED 3.6
#define MAX_LOOPS 5

CRGBArray<NUM_LEDS> leds;

struct Player {
  int buttonPin;
  int buttonState;
  int prevPosition;
  int position;
  int loop;
  float speed;
  bool isWinner;
  bool isOffTrack;
  bool blinking;
  CRGB::HTMLColorCode color;
  CRGB::HTMLColorCode highSpeedColor;
};

struct Player player1;
struct Player player2;

int raceCountdown = 3;
bool raceFinished = false;

void setup() {
  initPlayer(&player1, PLAYER1_PIN, CRGB::Red, CRGB::Green);
  initPlayer(&player2, PLAYER2_PIN, CRGB::Blue, CRGB::Yellow);

  FastLED.addLeds < NEOPIXEL, LED_PIN > (leds, NUM_LEDS);

  clearTrack();

  Serial.begin(9600);
}

void loop() {
  if (raceCountdown >= 0) {
    delay(random(500, 1001));
    drawCountdown(raceCountdown);
    raceCountdown--;
    return;
  }
  
  if (raceFinished) {
    delay(1000);
    return;
  }

  movePlayer(&player1);
  movePlayer(&player2);
  drawPlayer(&player1);
  drawPlayer(&player2);

  if (isRaceFinished()) {
    struct Player winner = findWinner(player1, player2);
    drawWinner(winner);
    raceFinished = true;
  }

  delay(15);
}

void initPlayer(struct Player *player, int pin, CRGB::HTMLColorCode color, CRGB::HTMLColorCode highSpeedColor) {
  player->buttonPin = pin;
  player->buttonState = LOW;
  player->prevPosition = 0;
  player->position = 0;
  player->loop = 0;
  player->speed = 0.0;
  player->isWinner = false;
  player->isOffTrack = false;
  player->blinking = false;
  player->color = color;
  player->highSpeedColor = highSpeedColor;
}

bool buttonReleased(struct Player *player) {
  int previousState = player->buttonState;
  player->buttonState = digitalRead(player->buttonPin);

  if (previousState == HIGH && player->buttonState == LOW) {
    return true;
  }

  return false;
}

void movePlayer(struct Player *player) {
  if (buttonReleased(player)) {
    player->speed += ACCELERATION; // acceleration

//    Serial.println("P speed: " + (String)player->speed + " offTrack: " + (String)player->isOffTrack + " blink: " + (String)player->blinking);

    if (player->isOffTrack) {
      player->blinking = !(player->blinking);
    }
  }

  player->speed -= player->speed * FRICTION;

  if (player->speed < 0) {
    player->speed = 0;
  } else if (player->speed >= MAX_SPEED) {
    player->speed = 0;
    player->isOffTrack = true;
  }

  player->prevPosition = player->position;
  player->position = (int)(player->position + player->speed) % NUM_LEDS;

  if (player->position < player->prevPosition) {
    player->loop += 1;
  }

  if (player->loop == MAX_LOOPS) {
    player->isWinner = true;
  }
  //  Serial.println("Speed: " + (String)player->speed + " Position: " + (String)player->position + " P1: " + (String)player1.loop + " P2: " + (String)player2.loop);
}

void drawCountdown(int countdownStage) {
  switch (countdownStage) {
    case 3:
      setTrackColor(CRGB::Blue);
      break;
    case 2:
      setTrackColor(CRGB::Red);
      break;
    case 1:
      setTrackColor(CRGB::Green);
      break;
    default:
      clearTrack();
  }
}

void drawPlayer(struct Player *player) {
  if (player->isOffTrack) {    
    // draw an explosion
    CRGB::HTMLColorCode offTrackColor = player->blinking ? player->color : CRGB::Black;

    drawOnTrack(player->position + 1, 1, offTrackColor);
    drawOnTrack(player->position - player->loop - 1, 1, offTrackColor);

    if (player->speed >= 1 && !player->blinking) {
      player->isOffTrack = false;
      // clear the back of the explosion
      drawOnTrack(player->prevPosition - player->loop - 1, 1, CRGB::Black);
    }

    FastLED.show();
  }
    
  if (player->position != player->prevPosition || (player->position == 0 && player->loop == 0) || ledsAreBlack(player->position, player->loop)) {
    // draw the player
    drawOnTrack(player->prevPosition, player->loop + 1, CRGB::Black);
    drawOnTrack(player->position, player->loop + 1, playerColor(player));

    FastLED.show();
  }
}

void drawOnTrack(int position, int length, CRGB::HTMLColorCode color) {
  for (int j = 0; j < length; j++) {
    int index = modulo(position - j, NUM_LEDS);
    leds[index] = color;
  }
}

CRGB::HTMLColorCode playerColor(struct Player *player) {
   if (player->speed > HIGHSPEED) {
    return player->highSpeedColor;
  } else {
    return player->color;
  }
}

bool isRaceFinished() {
  return player1.isWinner || player2.isWinner;
}

struct Player findWinner(struct Player player1, struct Player player2) {
  if (player1.isWinner) {
    return player1;
  } else if (player2.isWinner) {
    return player2;
  }
}

void drawWinner(struct Player winner) {
  setTrackColor(winner.color);
}

void clearTrack() {
  setTrackColor(CRGB::Black);
}

void setTrackColor(CRGB::HTMLColorCode color) {
  leds = color;
  FastLED.show();
}

// utilities
int modulo(int x, int n) {
  return (x % n + n) % n;
}

bool ledsAreBlack(int index, int length) {
  bool res = true;

  for (int i = 0; i < length; i++) {
    int idx = modulo(index - i, NUM_LEDS);
    res |= (leds[idx].r == 0 && leds[idx].g == 0 && leds[idx].b == 0);
  }
  
  return res;
}

Custom parts and enclosures

Player 2 controller
Player 1 controller

Schematics

Schematics
Ledrace bb pgrsqbtnyu

Comments

Similar projects you might like

Open LED Race

Project in progress by Gerardo Barbarov Rostan

  • 45,479 views
  • 33 comments
  • 120 respects

Arduino tutorial: LED Matrix red 32x8 256 Led

Project showcase by DIY Electronics Projects

  • 9,951 views
  • 0 comments
  • 8 respects

DIY Led Racing Game (Open Led Race)

Project tutorial by Mirko Pavleski

  • 2,229 views
  • 1 comment
  • 3 respects

Bluetooth control led with lcd led status display real time.

Project tutorial by Youssef Sabaa

  • 45,176 views
  • 10 comments
  • 62 respects

Hot Glue LED Matrix Lamp

Project tutorial by John Bradnam

  • 20,722 views
  • 6 comments
  • 54 respects

Astralis LED Sign

Project showcase by Uberibsen

  • 1,118 views
  • 1 comment
  • 1 respect
Add projectSign up / Login