OUR CONCEPT
The shelf can be calibrated to sense the normal weight of the objects in the shelf. A parent can then turn a dial to set the amount of time the toys can be out. When a toy is removed, a colored LED turns on to indicate that it is missing. After the set amount of time has passed, a voice says, "The (shelf color/s) shelf is empty! Time to put the toys away!", and a cheerful song plays. The music stops when the toys are replaced. A light sensor turns off the shelf when the room is dark, ensuring that children are not woken by the sound or light.
THE PROCESS
We began working with an Arduino Uno. To play a song, we needed a larger amount of memory than the Uno had on board, so we added a Sparkfun Mp3 Shield. To run it, we used the Sparkfun Mp3 Shield Arduino Library by Bill Porter. What we soon realized is that, between the library and the shield itself, most of the pins on the board were being used.
Pins used by the Mp3 shield and Mp3 shield library (black) |
We considered a couple of options to mitigate this problem. The first was to use a shift register to increase the number of outputs from the board (tutorial here). However, the shift register uses pins 8, 11 and 12, which are used by the shield.
Bill Porter wrote a library to make it easier to use serial communication between two Arduino boards. We borrowed a second Arduino Uno and then used the EasyTransfer Arduino Library to send information between them.
We used Force Sensitive Resistors to sense the approximate force of the objects on the shelf. These were not extremely precise, but with some experimenting, we were able to generate results reliable enough for our purposes. We used a layer of felt and a layer of foam core over each sensor to distribute the weight. Two days ago, one of our FSRs failed, so the code below is written for two FSRs, and one button.
There is a button for calibrating the weights on the shelf, a rotary potentiometer for setting the playtime length, and a mini photocell to sense when the lights in the room are turned off. We used a battery-powered Mp3 player speaker to play the sound.
We used the Metro library by Thomas Ouellet Fredericks to handle time-based functions, like triggering sound.
View the code after the break...
CODE FOR BOARD ONE (NO MP3 SHIELD):
/* Smart Shelf Program:
Uses an FSR sensor to sense the presence of an object. When an object is removed
from the shelf, the timeLED lights up to indicate that the object is gone (mostly
for test purposes). After 15 seconds, if the object is still missing, a second light
(weightLED) lights up to indicate that it's time to return the object.
Charissa Lind, May 2012
For a project by Charissa Lind and Erin Murphy
Including Metro library by Thomas Ouellet Fredericks and Easy Transfer Library by Bill Porter*/
#include <Metro.h> //Call Metro (timer) library
#include <EasyTransfer.h> //Call EasyTransfer Library
//create object
EasyTransfer ET;
struct SEND_DATA_STRUCTURE{
//for EasyTransfer
//put your variable definitions here for the data you want to send
//THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
int timeup; //variables used to send signals that a particular song should play
int timeupB;
int timeupAB;
int timeupBC;
int timeupC;
int timeupAC;
int timeupABC;
int stopmusic;
};
//give a name to the group of data (EasyTransfer)
SEND_DATA_STRUCTURE mydata;
//variables for sensor A
const int fsrAnalogPin = A0; //Sensor A goes to analog pin 0.
int fsrReading; //variable that will be used to store values from FSR A.
int aHigh; //will be the highest acceptable reading when the toy is in the shelf.
int aLow; //will be the lowest acceptable reading when the toy is in the shelf.
const int timeLED = 11; //purple LED
//variables for sensor B
const int fsrAnalogPinB = A1; //Sensor B goes to analog pin 2
int fsrReadingB; //variable that will be used to store values from FSR B.
int bHigh;
int bLow;
const int timeLEDB = 10; //blue LED
//variables for sensor C/button C
const int fsrAnalogPinC = 8; //this is a digital pin, since our FSR broke, but I kept the label consistent.
int fsrReadingC;
int pinStateC = 0;
int cHigh; //used for an FSR sensor...it won't show up in this code, because our sensor broke and we used a button instead
int cLow; //ditto.
const int timeLEDC = 7; //green LED
//variables for button
const int buttonPin = 2;
int buttonState= 0;
//variables for light sensor
const int lightSensor=A2;
int light= 0;
int metroPot=A3; //potentiometer on analog pin 3 (will be used to set time)
int metroVal= 15000; //by default, toy can be gone for 15 seconds (for real use, as opposed to demo use, this would be much longer)
int metroInt = 15000; //will change with the potentiometer's position.
//variables for timer
Metro ledMetro = Metro(metroInt, 1); //Sensor A has an interval of 15 seconds.
//this interval will be used when waiting for the object to return.
Metro ledMetroB = Metro(metroInt, 1); //Sensor B has an interval of 15 seconds.
//this interval will be used when waiting for the object to return.
Metro ledMetroC = Metro(metroInt, 1); //Sensor C has an interval of 15 seconds.
//this interval will be used when waiting for the object to return.
void reset(){//Sets up a command that can be called in loop() and will reset Metro's timer.
}
void setup()
{
Serial.begin(9600); //set up a serial output for testing
pinMode(timeLED, OUTPUT); //set up the LED on pin 11
pinMode(timeLEDB, OUTPUT); //set up the LED on pin 10
pinMode(timeLEDC, OUTPUT); //set up the LED on pin 7
pinMode(fsrAnalogPinC, INPUT); //the button on pin 8 is an input
pinMode(buttonPin, INPUT); //the button on pin 2 is an input
//start the EasyTransfer library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc.
ET.begin(details(mydata), &Serial);
randomSeed(analogRead(0));
}
void sensorA(){ //this section will set up actions for sensor A
metroVal = analogRead(metroPot); //get reading from rotary potentiometer on pin A3
metroInt = map(metroVal, 0, 1023, 5000, 30000); //map that value to a time value (in milliseconds)
light= analogRead(lightSensor); //get reading from photocell
if(light<500){ //if the light is off, turn everything off.
Serial.println("off");
digitalWrite(timeLED, LOW); //all lights off
ledMetro.reset();
mydata.stopmusic = 1;
ET.sendData();
}
else{
fsrReading= analogRead(fsrAnalogPin); //get reading from sensor A
if (fsrReading>aLow && fsrReading<aHigh){ //if the object is present
digitalWrite(timeLED, LOW); //all lights off
ledMetro.reset(); //reset the timer
mydata.timeup = 0; //music off
mydata.timeupAB = 0;
ET.sendData(); //send "off" signal to Mp3 shield
}
else{ //if object is not present
digitalWrite(timeLED, HIGH); //turn on time LED to indicate program is waiting for object
mydata.timeup = 0; //music is still off.
mydata.timeupAB = 0;
ET.sendData();
if(ledMetro.check() == 1) //if 15 seconds have passed (and no object is present)
{
if ((fsrReadingB<bLow || fsrReadingB>bHigh) && (fsrReading<aLow || fsrReading>aHigh) && (pinStateC == LOW)){
//if A,B, and C are missing.
digitalWrite(timeLED, HIGH);
mydata.timeupABC= 1; //play "all toys are missing" sound
mydata.timeupAB=0;
mydata.timeupAC=0;
mydata.timeupBC=0;
mydata.timeup=0;
ET.sendData();//send the signal to play "all toys are missing" sound
}
if ((fsrReadingB<bLow || fsrReadingB>bHigh) && (fsrReading<aLow || fsrReading>aHigh) && (pinStateC == HIGH)){
//if A and B are missing.
digitalWrite(timeLED, HIGH);
mydata.timeupAB = 1; //send signal to play "Blue and Purple are missing" sound
mydata.timeup = 0;
mydata.timeupB = 0;
mydata.timeupBC = 0;
mydata.timeupABC = 0;
ET.sendData();
}
if ((fsrReadingB>bLow && fsrReadingB<bHigh) && (fsrReading<aLow || fsrReading>aHigh) && (pinStateC ==LOW)){
//if A and C are missing
digitalWrite(timeLED, HIGH);
mydata.timeupAC = 1;
mydata.timeup = 0;
mydata.timeupC = 0;
mydata.timeupAB = 0;
mydata.timeupABC = 0;
ET.sendData();
}
if ((fsrReading<aLow || fsrReading>aHigh) && (fsrReadingB>bLow && fsrReadingB<bHigh) && (pinStateC ==HIGH)){
digitalWrite(timeLED, HIGH); //keep the timer LED on
//if only A is missing.
mydata.timeup= 1;
mydata.timeupABC= 0;
mydata.timeupAB = 0;
mydata.timeupBC = 0;
mydata.timeupAC=0;
ET.sendData();
}
}
else{ //otherwise, don't tell the Mp3 shield to play anything.
mydata.timeup=0;
mydata.timeupAB = 0;
mydata.timeupABC= 0;
mydata.timeupAC=0;
ET.sendData();
}
}
}
}
void sensorB(){//the same thing, but set up with variables for sensor B
if(light<500){
Serial.println("off");
digitalWrite(timeLEDB, LOW); //all lights off
ledMetroB.reset();
mydata.timeupB = 0;
ET.sendData();
}
else{
//Begin second sensor
fsrReadingB= analogRead(fsrAnalogPinB);
if (fsrReadingB>bLow && fsrReadingB<bHigh){
digitalWrite(timeLEDB, LOW);
ledMetroB.reset();
mydata.timeupB = 0;
mydata.timeupBC = 0;
ET.sendData();
}
else{
digitalWrite(timeLEDB, HIGH);
mydata.timeupB = 0;
mydata.timeupBC =0;
mydata.timeupAB = 0;
ET.sendData();
if(ledMetroB.check() == 1)
{
if ((fsrReadingB<bLow || fsrReadingB>bHigh) && (pinStateC==LOW) && (fsrReading>aLow && fsrReading<aHigh)){
digitalWrite(timeLEDB, HIGH);
mydata.timeupBC = 1;
mydata.timeupB = 0;
mydata.timeupAB = 0;
mydata.timeupABC = 0;
ET.sendData();
}
if((fsrReadingB<bLow || fsrReadingB>bHigh) && (pinStateC == HIGH) && (fsrReading>aLow && fsrReading<aHigh)){
digitalWrite(timeLEDB, HIGH);
mydata.timeupB = 1;
mydata.timeupAB = 0;
mydata.timeupBC = 0;
mydata.timeupABC = 0;
ET.sendData();
}
}
}
}
}
void sensorC(){ //same as above, but for sensor/button C.
metroVal = analogRead(metroPot);
metroInt = map(metroVal, 0, 1023, 5000, 30000);
light= analogRead(lightSensor);
if(light<500){
Serial.println("off");
digitalWrite(timeLEDC, LOW);
ledMetroC.reset();
mydata.timeupC = 0;
ET.sendData();
}
else{
pinStateC = digitalRead(fsrAnalogPinC);
if (pinStateC == HIGH){
digitalWrite(timeLEDC, LOW);
ledMetroC.reset();
mydata.timeupC = 0;
mydata.timeupAC = 0;
mydata.timeupABC = 0;
ET.sendData();
}
else{ //if object is not present
digitalWrite(timeLEDC, HIGH);
mydata.timeupC = 0;
mydata.timeupAC = 0;
mydata.timeupBC = 0;
mydata.timeupABC = 0;
ET.sendData();
if(ledMetroC.check() == 1)
{
if ((pinStateC == LOW) && (fsrReading<aLow || fsrReading>aHigh) && (fsrReadingB>bLow && fsrReadingB<bHigh)){
digitalWrite(timeLEDC, HIGH);
mydata.timeupAC = 1;
mydata.timeupC = 0;
mydata.timeupABC = 0;
mydata.timeupBC = 0;
ET.sendData();
}
if ((pinStateC == LOW) && (fsrReading>aLow && fsrReading<aHigh) && (fsrReadingB>bLow && fsrReadingB<bHigh)){
digitalWrite(timeLEDC, HIGH);
mydata.timeupC= 1;
mydata.timeupAC = 0;
mydata.timeupABC = 0;
mydata.timeupBC = 0;
ET.sendData();
}
}
}
}
}
void interval(); //for Metro library
void button (){ //this section sets up the button to calibrate the shelf on button press.
if(light<500){
Serial.println("off");
}
else{
buttonState = digitalRead(buttonPin); //read push button state
if (buttonState == HIGH) {
fsrReading= analogRead(fsrAnalogPin); //get reading from sensor A
fsrReadingB= analogRead(fsrAnalogPinB); //get reading from sensor B
aHigh= (fsrReading+ 150); //set high end of acceptable weight range for sensor A
aLow= (fsrReading- 150); //set low end of acceptable weight range for sensor A
bHigh= (fsrReadingB+ 150); //set high end of acceptable weight range for sensor B
bLow= (fsrReadingB- 150); //set low end of acceptable weight range for sensor B
}
}
}
void stopmusic(){ //this section sets up the shelf to stop playing music when the objects are all present.
if ((pinStateC == HIGH) && (fsrReading>aLow && fsrReading<aHigh) && (fsrReadingB>bLow && fsrReadingB<bHigh)){
mydata.stopmusic = 1;
ET.sendData();
ledMetro.reset();
ledMetroB.reset();
ledMetroC.reset();
}
else{
mydata.stopmusic = 0;
ET.sendData();
}
}
void loop(){ // this is where Arduino actually runs through the commands above.
button();
ledMetro.interval(metroInt);
ledMetroB.interval(metroInt);
ledMetroC.interval(metroInt);
sensorA();
sensorB();
sensorC();
stopmusic();
//send the data
ET.sendData();
delay(250);
}
CODE FOR BOARD TWO (MP3 SHIELD):
/* Smart Shelf Program Part 2:
Uses an FSR sensor to sense the presence of an object. When an object is removed
from the shelf, the timeLED lights up to indicate that the object is gone (mostly
for test purposes). After 15 seconds, if the object is still missing, a second light
(weightLED) lights up to indicate that it's time to return the object.
Charissa Lind, May 2012
For a project by Charissa Lind and Erin Murphy
Including Metro library by Thomas Ouellet Fredericks and Mp3 Shield Library and Easy Transfer Library by Bill Porter*/
#include <EasyTransfer.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
//call necessary libraries
SFEMP3Shield MP3player; //create object
//create object
EasyTransfer ET;
struct RECEIVE_DATA_STRUCTURE{
//for EasyTransfer
//put your variable definitions here for the data you want to receive
//THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
int timeup; //variables used to send signals that a particular song should play
int timeupB;
int timeupAB;
int timeupBC;
int timeupC;
int timeupAC;
int timeupABC;
int stopmusic;
};
//give a name to the group of data
RECEIVE_DATA_STRUCTURE mydata;
void setup(){
Serial.begin(9600);
MP3player.begin(); //start the shield
//start the EasyTransfer library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc.
ET.begin(details(mydata), &Serial);
}
void musicA(){
ET.receiveData(); //receive data from the other board
if(mydata.timeup ==1 && mydata.timeupB !=1){ //if signal is received to play song for object A. (purple shelf)
MP3player.playTrack(1);
Serial.println (mydata.timeup);
}
}
void musicB(){
ET.receiveData();
if(mydata.timeupB==1 && mydata.timeup !=1){
MP3player.playTrack(2);
}
}
void musicC(){
ET.receiveData();
if(mydata.timeupC ==1 && mydata.timeupB !=1 && mydata.timeup != 1){
MP3player.playTrack(3);
}
}
void musicAB(){
ET.receiveData();
if(mydata.timeupAB ==1 && mydata.timeupABC==0){
MP3player.playTrack(4);
}
}
void musicAC(){
ET.receiveData();
if(mydata.timeupAC ==1 && mydata.timeupABC ==0){
MP3player.playTrack(5);
}
}
void musicBC(){
ET.receiveData();
if(mydata.timeupBC ==1 && mydata.timeupABC==0){
MP3player.playTrack(6);
}
}
void musicABC(){
ET.receiveData();
if(mydata.timeupABC ==1){
MP3player.playTrack(7);
}
}
void stopmusic(){
ET.receiveData();
if(mydata.stopmusic ==1){
MP3player.stopTrack();
}
}
//Voila!
void loop(){ //run the functions above
ET.receiveData();
musicA();
musicB();
musicC();
musicAB();
musicAC();
musicBC();
musicABC();
stopmusic();
//you should make this delay shorter then your transmit delay or else messages could be lost
delay(10);
}
No comments:
Post a Comment