Smaller screens (1100px<) might have website design issues.
Our group was able to code everything except "Bonus Button to start the flashes".
The code written below works when the light is on persistently, for 1-5 blinks, and when the light was never on or there were more than 5 blinks (a serial message is printed).
The LCD screen is only used to display the number of blinks the user has inputted.
I decided to make the light tracking mode to only rotate towards the light, not move, because that would only require copy-and-pasting our code. The light tracking mode lasts 8 seconds.
//LIBRARIES 90 (import liquid crystal)
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "pitches.h"
//CONSTANTS
#define LEFT_PHOTO_PIN 8
#define RIGHT_PHOTO_PIN 6
#define SPEAKER_PIN 4
const float LIGHT_BLINK_AMOUNT = 4500;
const float DARK_AMOUNT = 18000;
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
Servo servoLeft;
Servo servoRight;
//VARIABLES AND ARRAYS
unsigned long intervalTime;
float tLeft;
float tRight;
float averageLight;
boolean isLightOn;
int blinkAmount;
int melody[] = {
NOTE_C3, NOTE_C4, NOTE_DS4, NOTE_G4, NOTE_DS4, NOTE_C4, NOTE_DS4, NOTE_C4, NOTE_G3, NOTE_C4, NOTE_DS3, NOTE_C4, NOTE_C3
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = { 4, 9, 9, 9, 9, 9, 9, 9, 6, 9, 6, 9, 4 };
void setup() {
intervalTime = millis();
isLightOn = false;
blinkAmount = 0;
lcd.init();
lcd.clear();
lcd.backlight();
Serial.begin(9600);
servoLeft.attach(12);
servoRight.attach(13);
//startup tone play
tone(SPEAKER_PIN, 3000, 1000);
delay(1000);
}
void loop() {
lcd.setCursor(0, 0);
lcd.print(" "); //clear line after switch statement if needed
lcd.setCursor(0, 0);
lcd.print("Blinks=");
lcd.print(blinkAmount);
lcd.setCursor(0, 1);
lcd.print("Timer Start");
//"intialize" (we're in a loop) tLeft, tRight, averageLight
tLeft = float(rcTime(LEFT_PHOTO_PIN));
tRight = float(rcTime(RIGHT_PHOTO_PIN));
averageLight = (tLeft + tRight) / 2;
/*CHECKING BLINKS*/
//is light on and not on before?
if (averageLight <= LIGHT_BLINK_AMOUNT and !isLightOn) {
isLightOn = true;
//Serial.println("Light is on (start of a blink).");
} else if (averageLight >= DARK_AMOUNT and isLightOn) {
// Serial.println("Light is off (end of a blink)");
isLightOn = false;
blinkAmount ++;
}
/*AIMAN PRINT AMOUNT OF BLINKS HERE*/
if (millis() - intervalTime >= 5000) {
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print("Timer End");
lcd.setCursor(0,0);
switch (blinkAmount) {
case 0:
if (isLightOn) {
//light was on persistently
playShortSong();
printOnScreen("Song Mode");
} else {
delay(1000);
}
break;
case 1:
//low note high note go forward 1 foot
printOnScreen("Fwd 1 ft");
tone(SPEAKER_PIN, 261, 1000);
delay(1000);
tone(SPEAKER_PIN, 1046, 1000);
delay(1000);
noTone(SPEAKER_PIN);
maneuver(1700, 1300, 2000);
break;
case 2:
//High note, low note, Turn right full circle
printOnScreen("Circle Mode");
tone(SPEAKER_PIN, 1046, 1000);
delay(1000);
tone(SPEAKER_PIN, 261, 1000);
delay(1000);
noTone(SPEAKER_PIN);
maneuver(1700, 1700, 2576);
break;
case 3:
//Three Fast Beeps then Activate light tracking mode - robot should TURN/ROTATE towards a bright light
for (int i = 0; i < 3; i ++) {
tone(SPEAKER_PIN, 1318, 500);
delay(500);
noTone(SPEAKER_PIN);
}
printOnScreen("Light Track Mode");
lightTrackingMode();
break;
case 4:
//spell a letter by moving: 'N'
printOnScreen("Letter N");
maneuver(1700, 1300, 2000); //forward "|"
maneuver(1700, 1700, 980); //rotate right to move diagonally
maneuver(1700, 1300, 2050); //move diagonally a biut more "\"
maneuver(1300, 1300, 980); //rotate left to face "up"/opposite of starting orientation
maneuver(1700, 1300, 2000); //forward "|" ("up"), complete "N"
break;
case 5:
//draw a big circle
printOnScreen("Big Circle");
maneuver(1523, 1300, 6220);
break;
default:
//too many blinks
printOnScreen("Too many blinks.");
Serial.println("Default/else statement. too many blinks.");
break;
}
/*Reset timer and blink amount*/
intervalTime = millis(); //reset timer
blinkAmount = 0; //reset
}
}
void printOnScreen (String text) {
lcd.print(" ");
lcd.home();
lcd.print(text);
}
void lightTrackingMode () {
intervalTime = millis(); //use interval time to count 8 seconds of light tracking
float ndShade;
while (millis() - intervalTime < 8000) {
tLeft = float(rcTime(LEFT_PHOTO_PIN));
tRight = float(rcTime(RIGHT_PHOTO_PIN));
ndShade = tRight / (tLeft + tRight) - 0.5;
//shade on right?
if (ndShade > 0.0) {
maneuver(1300, 1300, 50); //rotate left
} else {
maneuver(1700, 1700, 50); //shade on left, rotate right
}
}
}
void playShortSong() {
for (int thisNote = 0; thisNote < sizeof(melody) / sizeof(int); thisNote++) {
// to calculate the note duration, take one second divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
tone(SPEAKER_PIN, melody[thisNote], 1000 / (noteDurations[thisNote]));
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = (1000 / (noteDurations[thisNote])) * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(SPEAKER_PIN);
}
}
long rcTime(int pin)
{
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
delay(5);
pinMode(pin, INPUT);
digitalWrite(pin, LOW);
long time = micros();
while (digitalRead(pin));
time = micros() - time;
return time;
}
// maneuver function
void maneuver(int speedLeft, int speedRight, int msTime)
{
servoLeft.writeMicroseconds(speedLeft); // Set left servo speed
servoRight.writeMicroseconds(speedRight); // Set right servo speed
delay(msTime); // Delay for msTime
if (msTime == -1)
{
servoLeft.detach(); // Stop servo signals
servoRight.detach();
}
else
{
// Stop the servos
servoLeft.writeMicroseconds(1500); // Neutral signal (stop)
servoRight.writeMicroseconds(1500);
}
}