Project Overview:

This project creates a simple game on an Arduino using an LCD screen. The player controls a car driving down a road, attempting to avoid oncoming trucks. The car’s position is controlled by a potentiometer, and the game gets progressively faster. If the car crashes into a truck, the game ends with a crash sound and displays the time the player survived.

How It Works:

  • Display: A 16x2 LCD screen shows the road with the car and trucks.
  • Controls: A potentiometer acts as a steering wheel to move the car left or right.
  • Crash Detection: If the car’s position coincides with a truck, the game registers a crash, plays a sound, and displays the survival time.

Components List:

Circuit Connection:

Arduino LCD-Based Car Crash Avoidance Game


  1. LCD Setup:
  • Connect the LCD pins to the Arduino as follows:
  • RS → Pin 2
  • EN → Pin 3
  • D4 → Pin 4
  • D5 → Pin 5
  • D6 → Pin 6
  • D7 → Pin 7
  • VSS → GND
  • VDD → 5V
  • V0 → Potentiometer center pin (other two pins to GND and 5V for contrast adjustment)
  • A (LED+) → 5V (with a 220Ω resistor)
  • K (LED-) → GND
  1. Potentiometer Setup:
  • Connect the middle pin of the potentiometer to A1 on the Arduino.
  • Connect the other two pins to GND and 5V.
  1. Speaker Setup:
  • Connect one end of the speaker to digital pin 9.
  • Connect the other end to GND (through a 220Ω resistor).

Project Code:

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);

const int POTPIN = 1; // Pin for the potentiometer
const int MAXPOT = 800;
const int SPEAKERPIN = 9; // Pin for the speaker
const int RANDSEEDPIN = 0;
const int MAXSTEPDURATION = 300;
const int MINSTEPDURATION = 150;
const int NGLYPHS = 6; // Number of custom glyphs

byte glyphs[NGLYPHS][8] = {
{ B00000,
B01110,
B11111,
B01010,
B00000,
B00000,
B00000,
B00000},

{ B00000,
B00000,
B00000,
B00000,
B01110,
B11111,
B01010,
B00000},

{ B00000,
B11110,
B11111,
B01010,
B00000,
B00000,
B00000,
B00000},

{ B00000,
B00000,
B00000,
B00000,
B11110,
B11111,
B01010,
B00000},

{ B10101,
B01110,
B01110,
B10101,
B00000,
B00000,
B00000,
B00000},

{ B00000,
B00000,
B00000,
B10101,
B01110,
B01110,
B10101,
B00000}
};

const int NCARPOSITIONS = 4; // Number of positions on the road
const char BLANK = 32; // Blank character

char car2glyphs[NCARPOSITIONS][2] = {
{1, BLANK}, {2, BLANK}, {BLANK, 1}, {BLANK, 2}
};
char truck2glyphs[NCARPOSITIONS][2] = {
{3, BLANK}, {4, BLANK}, {BLANK, 3}, {BLANK, 4}
};
char crash2glyphs[NCARPOSITIONS][2] = {
{5, BLANK}, {6, BLANK}, {BLANK, 5}, {BLANK, 6}
};

const int ROADLEN = 15; // Length of the road displayed
int road[ROADLEN];
char road_buff[2 + ROADLEN];
int road_index;
int car_pos;
const int MAXROADPOS = 3 * NCARPOSITIONS;
int step_duration;

int crash;
unsigned int crashtime;
const int CRASHSOUNDDURATION = 250;

const char *INTRO1 = "Trucks ahead,";
const char *INTRO2 = "Drive carefully";
const int INTRODELAY = 2500;

void setup() {
crash = crashtime = road_index = 0;
step_duration = MAXSTEPDURATION;
road_buff[1 + ROADLEN] = '\0';
randomSeed(analogRead(RANDSEEDPIN));
for (int i = 0; i < NGLYPHS; i++) {
lcd.createChar(i + 1, glyphs[i]);
}
for (int i = 0; i < ROADLEN; i++) {
road[i] = -1;
}

pinMode(SPEAKERPIN, OUTPUT);
analogWrite(SPEAKERPIN, 0);
lcd.begin(16, 2);
getSteeringWheel();
drawRoad();

lcd.setCursor(1, 0);
lcd.print(INTRO1);
lcd.setCursor(1, 1);
lcd.print(INTRO2);
delay(INTRODELAY);
}

void loop() {
unsigned long now = millis() - INTRODELAY;

if (!crash) {
getSteeringWheel();
crash = (car_pos == road[road_index]);
}
if (crash) {
if (!crashtime) {
crashtime = now;
drawRoad();

lcd.setCursor(2, 0);
lcd.print("Crashed after");
lcd.setCursor(2, 1);
lcd.print(now / 1000);
lcd.print(" seconds.");
}

if ((now - crashtime) < CRASHSOUNDDURATION) {
analogWrite(SPEAKERPIN, random(255));
} else {
analogWrite(SPEAKERPIN, 0); // Silence after crash
}
delay(20);

} else {
int prev_pos = road[(road_index - 1) % ROADLEN];
int this_pos = random(MAXROADPOS);
while (abs(this_pos - prev_pos) < 2) {
this_pos = random(MAXROADPOS);
}

road[road_index] = this_pos;
road_index = (road_index + 1) % ROADLEN;
drawRoad();
delay(step_duration);
if (step_duration > MINSTEPDURATION) {
step_duration--;
}
}
}

void getSteeringWheel() {
car_pos = map(analogRead(POTPIN), 0, 1024, 0, NCARPOSITIONS);
}

void drawRoad() {
for (int i = 0; i < 2; i++) {
if (crash) {
road_buff[0] = crash2glyphs[car_pos][i];
} else {
road_buff[0] = car2glyphs[car_pos][i];
}

for (int j = 0; j < ROADLEN; j++) {
int pos = road[(j + road_index) % ROADLEN];
road_buff[j + 1] = pos >= 0 && pos < NCARPOSITIONS ? truck2glyphs[pos][i] : BLANK;
}

lcd.setCursor(0, i);
lcd.print(road_buff);
}
}

Explanation of the Code:

  1. Custom Glyphs:
  • Custom characters are created to represent parts of the car, trucks, and crash symbols using the lcd.createChar() function.
  1. Road Buffer:
  • The road is represented as a buffer of characters that scroll across the screen. The buffer updates based on the car’s position and the presence of trucks.
  1. Steering Control:
  • The car’s position on the road is controlled by reading the analog value from the potentiometer, mapped to a discrete range of positions.
  1. Crash Detection:
  • The game checks if the car’s position coincides with a truck’s position on the road. If so, it registers a crash, plays a sound, and displays the time survived.
  1. Game Speed:
  • The game starts at a moderate speed and gradually becomes faster, reducing the delay between steps.

Summary:

This project combines various elements such as custom LCD characters, potentiometer input, and random generation to create a simple yet engaging game. It’s a fun way to explore the capabilities of an Arduino while learning how to manage inputs, outputs, and timing in a dynamic environment.

No comments

Theme images by Dizzo. Powered by Blogger.