Introduction: Valentines Box

We share Valentine's at my office for team building. Everyone decorates a bag or box to collect the Valentines. Mine was a bit over the top. Shows blue eyes at baseline. Uses IR LED and sensor (http://www.radioshack.com/product/index.jsp?productId=2049723) to determine when a card is put through the slot. When that occurs the motor comes on and the card is pulled into the slot by the wheels.


Step 1: Red Eyes

Eyes turn red when card is inserted into slot and motor turns on. The LCD display increments the count of valentines received. 

The bag is the one given to each employee to decorate. I used an Android robot toy from Google. The head comes off. I drilled out the eyes and inserted tri-color LEDs from Radio Shack (http://www.radioshack.com/product/index.jsp?productId=3020765). 

There is a ribbon cable  with  going through a hole in the bag and a hole in the lid to connect to the prototype board connected to the Arduino (see next step). The cable as made using a ribbon cable (https://www.adafruit.com/products/793), and then the LEDs soldered in after stripping one end of the ribbon cables and attaching bare female connectors (http://www.pololu.com/catalog/product/1930), with some shrink tubing used to keep the wires from shorting.

Code is below:

 /*************************************************************
Motor shield
https://www.instructables.com/id/Arduino-Motor-Shield-Tutorial/


Function pins per Ch. A pins per Ch. B
Direction                D12             D13
PWM                       D3               D11
Brake                      D9               D8
Current Sensing   A0               A1

lcd code from http://www.arduino.cc/playground/Learning/SparkFunSerLCD
LCD is 20x4

for Leonardo need to use Serial1 class

*************************************************************/
const int IRthreshold = 180;
const int IRPin = 3;    // Read IR value on analog 3
const int SignalPin = A2; // send signal to sound Arduino
const int RedPin = A4;
const int BluePin = A5;
boolean cardsensed = false;
boolean LEDflag = false;
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long timestamp = 0;  // used to keep track of how long IR sensor blocked
const long MotorDelay = 500;    // keep motor going for half a second after IR sensor clears
const long LEDdelay = 4000;
int val = 0;
int count = 0;



void setup()
{
  //Setup Channel A
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin
  pinMode(SignalPin, OUTPUT);
  digitalWrite(SignalPin, LOW);
  pinMode(RedPin, OUTPUT);
  pinMode(BluePin, OUTPUT);

  Serial1.begin(9600);

  delay(1000); // time to settle in, just in case
  clearLCD();
  backlightOn();
  selectLineOne();
  delay(10);
  Serial1.print("Happy Valentines Day");
  delay(10);
  selectLineTwo();
  Serial1.print("        CCE!");
  delay(10);
  selectLineThree();
  Serial1.print("I now have:");
  delay(10);

  blueLED(); // blue at baseline
}

void loop()
{
  val = analogRead(IRPin);
  if (val > IRthreshold)  // path blocked
  {
    cardsensed = true;
    LEDflag = true;
    timestamp = millis();
    //forward @ full speed
    digitalWrite(12, HIGH); //Establishes forward direction of Channel A
    digitalWrite(9, LOW);   //Disengage the Brake for Channel A
    analogWrite(3, 255);   //Spins the motor on Channel A at full speed
    redLED(); // red when it's gotten a card
  }

  if(val < IRthreshold)
  {
    if(cardsensed)
    {
      if ((millis()-timestamp) >= MotorDelay)
      {
        cardsensed = false;
        analogWrite(3,0); // turn off motor, but let it coast so no brake
        count++;
        selectLineFour();
        Serial1.print(count);
        Serial1.print(" Valentines");
        digitalWrite(SignalPin, HIGH);
        delay(20);
        digitalWrite(SignalPin, LOW);
      }  
    }
    if(LEDflag)
    {
      if ((millis()-timestamp) >= LEDdelay)
      {
        LEDflag = false;
        blueLED(); // back to being sad and blue
      }
    }
  } 
}

///////////////////////////// FUNCTIONS ////////////////////////////////

void selectLineOne(){  //puts the cursor at line 0 char 0.
   Serial1.write(0xFE);   //command flag
   Serial1.write(128);    //position
}
void selectLineTwo(){  //puts the cursor at line 2 char 0.
   Serial1.write(0xFE);   //command flag
   Serial1.write(192);    //position
}
void selectLineThree(){  //puts the cursor at line 3 char 0.
   Serial1.write(0xFE);   //command flag
   Serial1.write(148);    //position
}
void selectLineFour(){  //puts the cursor at line 4 char 0.
   Serial1.write(0xFE);   //command flag
   Serial1.write(212);    //position
}
void goTo(int position) { //position = line 1: 0-19, line 2: 20-39, etc, 79+ defaults back to 0
if (position<20){ Serial1.write(0xFE);   //command flag
              Serial1.write((position+128));    //position
}else if (position<40){Serial1.write(0xFE);   //command flag
              Serial1.write((position+128+64-20));    //position
}else if (position<60){Serial1.write(0xFE);   //command flag
              Serial1.write((position+128+20-40));    //position
}else if (position<80){Serial1.write(0xFE);   //command flag
              Serial1.write((position+128+84-60));    //position             
} else { goTo(0); }
}
void clearLCD(){
   Serial1.write(0xFE);   //command flag
   Serial1.write(0x01);   //clear command.
}
void backlightOn(){  //turns on the backlight
    Serial1.write(0x7C);   //command flag for backlight stuff
    Serial1.write(157);    //light level.
}
void backlightOff(){  //turns off the backlight
    Serial1.write(0x7C);   //command flag for backlight stuff
    Serial1.write(128);     //light level for off.
}
void backlight50(){  //sets the backlight at 50% brightness
    Serial1.write(0x7C);   //command flag for backlight stuff
    Serial1.write(143);     //light level for off.
}
void serCommand(){   //a general function to call the command flag for issuing all other commands  
  Serial1.write(0xFE);
}

void blueLED(){
  digitalWrite(BluePin, LOW); // reverse of usual since common
  digitalWrite(RedPin, HIGH); // anode
}

void redLED(){
  digitalWrite(BluePin, HIGH);
  digitalWrite(RedPin, LOW);
}

Step 2: Electronics

Most of circuit (motor, LED, LCD display) is run off of an Arduino Leonardo with an Arduino motor shield. See previous step for code.

The box says "Thank you very much" - it uses an Arduino Duemilanove with a  Sparkfun VoiceBox shield (https://www.sparkfun.com/products/10661O).

Uses a simple signal (raises a pin high on the primary Arduino - senses the signal on the ViceBox Arduino)

has 3 random beeps before and after thank you - sounds a bit like R2D2

code is below

/*================================================================
Valentines thank you

     Voice Box part based on code written by Ryan Owens, SparkFun Electronics

*/

//Soft serial library used to send serial commands on pin 2 instead of regular serial pin.
#include <SoftwareSerial.h>

const int UnusedPin = 4; // unused analog pin used to get random input for seed
const int SignalPin = A0; // to get signal from main Arduino
int signal;


//Define the Pin Numbers for the Voice Box part
#define E0  5
#define E1  6
#define E2  7
#define E3  8
#define E4  9
#define E5  10
#define E6  11
#define E7  12
#define RDY  13
#define RES  3
#define SPK  4
#define txPin  2



//Create a SoftSerial Objet
SoftwareSerial speakjet = SoftwareSerial(0, txPin);

char speakjetsetup[] = {20, 96, 21, 114, 22, 88, 23, 5, 0}; // for whatever reason Voice Box only seems to
                                                            // work correctly if lines end in 0

                                  //thank                                you            very                             much
char thankyou[] = {169, 8, 130, 142, 196, 6, 8, 160, 6, 166, 150, 7, 128, 6, 140, 134, 15, 8, 182, 0};

char pause[] = {5, 0}; // 5 = 60ms pause; 0 to end line

////////////////////////// SET UP ////////////////////////////////////////////
void setup() {

  pinMode(SignalPin, INPUT);


  //Configure the pins for the SpeakJet module
  pinMode(txPin, OUTPUT);
  pinMode(SPK, INPUT);

  //Set up a serial port to talk from Arduino to the SpeakJet module on pin 3.
  speakjet.begin(9600);   

  //Configure the Ready pin as an input
  pinMode(RDY, INPUT);

  //Configure Reset line as an output
  pinMode(RES, OUTPUT);

  //Configure all of the Event pins as outputs from Arduino, and set them Low.
  for(int i=E0; i<=E7; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }

  //All I/O pins are configured. Reset the SpeakJet module
  digitalWrite(RES, LOW);
  delay(100);
  digitalWrite(RES, HIGH);

  //send setup commands to SpeakJet
  speakjet.println(speakjetsetup);

  randomSeed(analogRead(UnusedPin));

  delay(5000); // allow things to settle down
}

////////////////////////// LOOP ////////////////////////////////////////////
void loop()
{
  signal = digitalRead(SignalPin);
  if (signal == HIGH)
  {
    // redLED();
    randombeeps(3);
    delay(1000);
    speakjet.print(thankyou);
    delay(800);
    randombeeps(3);
    // delay(3000);
    // blueLED();
  }
} // end of loop

///////////////////////////// FUNCTIONS ////////////////////////////////

void randombeeps(int beeps)
{
  for (int k=0; k<beeps; k++) // generate number of beeps
  {
    int rndnum = random(220, 230); // maps to  beep sounds on voicebox, 220-229
    char rndchar = char(rndnum);
    speakjet.print(rndchar);
    speakjet.print(pause);
  }
}

void blueLED(){
  digitalWrite(BluePin, HIGH);
  digitalWrite(RedPin, LOW);
}

void redLED(){
  digitalWrite(BluePin, LOW);
  digitalWrite(RedPin, HIGH);
}

Step 3: Gearing

Tricky part was the gears. I used Vex parts that I had on hand. in order to get both top and bottom wheels to spin I had to angle the gears. Note that the large gears are on a beam that is angles to engage the gears on the wheel axles. 

The Vex motor works fine with the Arduino motor shield.

Step 4:

For power I used a 9V regulated power supply. Even though the Vex motor is nominally 7V it worked OK (it was only on for brief periods). I used an Adafruit jack (https://www.adafruit.com/products/368) and some wire to bring the power to the Vin and ground terminal blocks (center positive). 

The whole thing is contained in a plastic storage box I got on sale at Office Depot. 

Valentine's Day Contest

Participated in the
Valentine's Day Contest