Little Free STEM Library

0 511 Medium

A smart STEM powered library that advocates for inclusivity for all kids and adolescents!

 

Little Free STEM Library
HARDWARE LIST
1 DFRobot FireBeetle ESP32 IOT Microcontroller (Supports Wi-Fi & Bluetooth)
1 DFRobot 3.5” 480x320 TFT LCD
1 DFRobot DFPlayer - A Mini MP3 Player
1 DFRobot Gravity: Digital 5A Relay Module
1 DFRobot Ultrasonic Distance Sensor
1 Mini Shed Little Free Library
1 Adafruit 3x4 Phone-style Matrix Keypad
1 120W Portable Power Station
1 Solar Panel Kit 20W 12V
1 FFC 18 Pin 0.5mm Pitch 200mm Long (B Type)
1 3 Watt 8 Ohm Single Cavity Mini Speaker
1 I2C IO Expander Module

Software apps and online services

· Arduino IDE

 

INTRODUCTION

Nowadays, children are distracted by and attached to electronics and current technology. With the development of new technologies, it is inevitable for children to not become dependent on short-lived doses of digital entertainment. A short visit to the library is becoming less enjoyable and interesting for even younger children. On the other hand, sometimes community libraries can be far away, causing a short trip to the library to be a hassle and reducing the access children have to their local libraries. Hopefully, with the implementation of our easy-access, community library, we can give children a better access to a library, making it convenient for every age. Additionally, by incorporating smart technology, this will appeal to children more and demonstrate that reading books can be rewarding. This will help children develop their literacy and overarching education efficiently, while making it suitable for parents who are busy.

 

The main purpose of this project is to incorporate STEM technology and support into the build of a Little Free Library. Readers will interact with the library by answering historical questions that eventually unlocks the library when you respond with the correct answer. To support the operation and functionality of the library, a solar panel is attached to the roof of it. With anticipation, we hope that through the immersive, interactive experience, an increase of readers will be compelled to visit the library more often.

 

The materials used to build the library are all purchased from Little Free Library, a non-profit organization. The add-on electronics are mainly purchased from DFRobot, while the software is based from Arduino IDE.

 

FEATURES

1. A 3.5" LCD to display welcome messages, questions, and respond to readers' answers.

2. A speaker to announce welcome messages, questions, and respond to readers' answers.

3. An interactable keypad for the reader to type in their responses.

4. An electronic lock that unlocks the library when the reader answers the question correctly.

5. A distance sensor to detect empty shelves that later notifies the library manager.

6. A solar panel and battery to power the library.

7. A light with a sensor to indicate when to turn on.

8. A light strip to light up the library during night time.

HOW IT WORKS

The LCD and speaker plays the welcome message and waits for the reader's input. Once an input is detected, a question asking what the U.S. President's inauguration year was appears. If the reader responds with the correct answer, the library will be unlocked. If not, the reader will continuously receive new questions until they answer correctly. The questions are completely randomized. However, if the reader cannot input an answer within the time frame, the screen will return to its welcome message and the whole process restarts again.

 

FRONT

 

FRONT

                                                                                                     FRONT               

 

HUMAN INTERFACE

 

DISPLAY, KEYPAD, and SPEAKER

                                                                              DISPLAY, KEYPAD, and SPEAKER

 

CONTROL PANEL

 

DFROBOT ESP32-E

                                                                                              DFROBOT ESP32-E

 

DECORE

 

D1 CODERS

                                                                                                D1 CODERS

 

POWER SUPPLY

 

SOLAR

                                                                                                    SOLAR

 

SOLAR and BATTERY

                                                                                        SOLAR and BATTERY

 

DISPLAY HIGHLIGHT

 

DISPLAY

                                                                                                  DISPLAY

 

NIGHT LIGHT

 

LIGHT WITH SENSORS

                                                                                     LIGHT WITH SENSORS

 

EMPTY SENSOR

 

EMPTY SENSOR

                                                                                             EMPTY SENSOR

Schematics

LFL

 

CODE
#include "DFRobot_GDL.h"
#include "Wire.h"
#include "I2CKeyPad.h"
#include "DFRobotDFPlayerMini.h"
#include "DFRobot_EnvironmentalSensor.h"


const int p_rows = 45;
const int p_columns = 30;
const int y_columns = 5;

static char p_2d [p_rows][p_columns] = {
{"George Washington"},		
{"John Adams"}, 			
{"Thomas Jefferson"}, 		
{"James Madison"},		
{"James Monroe"}, 		
{"John Quincy Adams"},		
{"Andrew Jackson"}, 		
{"Martin Van Buren"}, 		
{"William Henry Harrison"},	
{"John Tyler"}, 			
{"James Knox Polk"},		
{"Zachary Taylor"},		
{"Millard Fillmore"},		
{"Franklin Pierce"},		
{"James Buchanan"},		
{"Abraham Lincoln"},		
{"Andrew Johnson"},		
{"Ulysses S. Grant"}, 		
{"Rutherford B. Hayes"},		
{"James A. Garfield"},		
{"Chester Arthur"},		
{"Grover Cleveland"}, 		
{"Benjamin Harrison"},				
{"William McKinley"}, 		
{"Theodore Roosevelt"}, 		
{"William Howard Taft"},		
{"Woodrow Wilson"}, 		
{"Warren G. Harding"},		
{"Calvin Coolidge"},		
{"Herbert Hoover"},		
{"Franklin D. Roosevelt"},	
{"Harry S. Truman"},		
{"Dwight D. Eisenhower"}, 	
{"John F. Kennedy"},		
{"Lyndon B. Johnson"},		
{"Richard M. Nixon"}, 		
{"Gerald R. Ford"},		
{"Jimmy Carter"},		
{"Ronald Reagan"},		
{"George Bush"},			
{"William J. Clinton"}, 		
{"George W. Bush"}, 		
{"Barack Obama"}, 		
{"Donald J. Trump"},		
{"Joe Biden"}};

static char p_year [p_rows][y_columns] = {
"1789",  //{"George Washington"},		1 	
"1797",  //{"John Adams"}, 		 			2
"1801",  //{"Thomas Jefferson"}, 		3	
"1809",  //{"James Madison"},		 4
"1817",  //{"James Monroe"}, 			5
"1825",  //{"John Quincy Adams"},	6				
"1829",  //{"Andrew Jackson"}, 		7	
"1837",  //{"Martin Van Buren"}, 	8				
"1841",  //{"William Henry Harrison"}, 9				
"1841",  //{"John Tyler"}, 		 			10
"1845",  //{"James Knox Polk"},				11	
"1849",  //{"Zachary Taylor"},					12
"1850",  //{"Millard Fillmore"},					13
"1853",  //{"Franklin Pierce"},					14
"1857",  //{"James Buchanan"},					15
"1861",  //{"Abraham Lincoln"},			16
"1865",  //{"Andrew Johnson"},			17		
"1869",  //{"Ulysses S. Grant"}, 		 
"1877",  //{"Rutherford B. Hayes"},	 			
"1881",  //{"James A. Garfield"},					
"1881",  //{"Chester Arthur"},					
"1885",  //{"Grover Cleveland"}, 					
"1889",  //{"Benjamin Harrison"},								
"1897",  //{"William McKinley"}, 			
"1901",  //{"Theodore Roosevelt"}, 	 	
"1909",  //{"William Howard Taft"},	 			
"1913",  //{"Woodrow Wilson"}, 			
"1921",  //{"Warren G. Harding"},					
"1923",  //{"Calvin Coolidge"},		 
"1929",  //{"Herbert Hoover"},					
"1933",  //{"Franklin D. Roosevelt"},	 
"1945",  //{"Harry S. Truman"},			
"1953",  //{"Dwight D. Eisenhower"}, 		
"1961",  //{"John F. Kennedy"},					
"1963",  //{"Lyndon B. Johnson"},		 
"1969",  //{"Richard M. Nixon"}, 			
"1974",  //{"Gerald R. Ford"},					
"1977",  //{"Jimmy Carter"},					
"1981",  //{"Ronald Reagan"},			
"1989",  //{"George H. W. Bush"},		 			
"1993",  //{"William J. Clinton"}, 	 	
"2001",  //{"George W. Bush"}, 			
"2009",  //{"Barack Obama"}, 			
"2017",  //{"Donald J. Trump"},					
"2021"   //{"Joe Biden"}
};

//folder 01
//001 - welcome
//002 - unlock
//003 - what year_did
//004 - become_pre
//005 - example
//006 - press any key to start
//folder 02
//001 to 009
//folder 03
//001gw ... 0045jb


#define ESP32

 //LCD SCREEN   
/*M0*/
#if defined ARDUINO_SAM_ZERO
#define TFT_DC  7
#define TFT_CS  5
#define TFT_RST 6
/*ESP32 and ESP8266*/
#elif defined(ESP32) || defined(ESP8266)
#define TFT_DC  D2
#define TFT_CS  D6
#define TFT_RST D3
/*AVR series mainboard*/
#else
#define TFT_DC  2
#define TFT_CS  3
#define TFT_RST 4
#endif

/**
* @brief Constructor Constructor of hardware SPI communication
* @param dc Command/data line pin for SPI communication
* @param cs Chip select pin for SPI communication
* @param rst reset pin of the screen
*/

//DFRobot_ST7789_240x240_HW_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
//DFRobot_ST7789_240x320_HW_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
//DFRobot_ILI9341_240x320_HW_SPI  screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
DFRobot_ILI9488_320x480_HW_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);

/* M0 mainboard DMA transfer */
//DFRobot_ST7789_240x240_DMA_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
//DFRobot_ST7789_240x320_DMA_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
//DFRobot_ILI9341_240x320_DMA_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
//DFRobot_ILI9488_320x480_DMA_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);

/*
*User-selectable macro definition color
*COLOR_RGB565_BLACK   COLOR_RGB565_NAVY    COLOR_RGB565_DGREEN   COLOR_RGB565_DCYAN 
*COLOR_RGB565_MAROON  COLOR_RGB565_PURPLE  COLOR_RGB565_OLIVE    COLOR_RGB565_LGRAY     
*COLOR_RGB565_DGRAY   COLOR_RGB565_BLUE    COLOR_RGB565_GREEN    COLOR_RGB565_CYAN  
*COLOR_RGB565_RED     COLOR_RGB565_MAGENTA COLOR_RGB565_YELLOW   COLOR_RGB565_ORANGE           
*COLOR_RGB565_WHITE   
*/

//MP3 UART
#if (defined(ARDUINO_AVR_UNO) || defined(ESP8266))   // Using a soft serial port
  #include <SoftwareSerial.h>
  SoftwareSerial softSerial(/*rx =*/4, /*tx =*/5);
  #define FPSerial softSerial
#else
  #define FPSerial Serial2 //TX - Pin17 D10; RX - Pin16 D11
#endif

DFRobotDFPlayerMini myDFPlayer;

//I2C
#define I2C_KEYPAD_4x3            43
const uint8_t KEYPAD_ADDRESS = 0x20;

I2CKeyPad keyPad(KEYPAD_ADDRESS);

uint32_t start, stop;
uint32_t lastKeyPressed = 0;

bool no_print1 = true;
bool no_print2 = true;
bool no_print3 = true;
bool no_print4 = true;

DFRobot_EnvironmentalSensor environment(/*addr = */SEN050X_DEFAULT_DEVICE_ADDRESS, /*pWire = */&Wire);

// defines variables
long duration;
int distance;

//#define bluePin D7
//#define redPin  D2
//#define trigPin D5
//#define echoPin D12
#define mp3txPin D10 //17
#define mp3rxPin D11 //16
#define lockPin D7

#define  MAX_RANG      (520)//the max measurement vaule of the module is 520cm(a little bit longer than  effective max range)
#define  ADC_SOLUTION      (1023.0)//ADC accuracy of Arduino UNO is 10bit
#define  sensityPin A0    // select the input pin 
float dist_t, sensity_t;

void setup() {       
  //Serial.begin(115200);
  Serial.begin(9600);
  Serial.println("start");
  screen.begin();

  //Set font size to 4, font range 1-4
  screen.setTextSize(2.5);
        
  //Set screen color 
  screen.fillScreen(COLOR_RGB565_BLACK);
  screen.setFont(&FreeSansBold9pt7b);//Set font to FreeMono12pt7b
  screen.setRotation(3);
  screen.setCursor(/*x=*/0,/*y=*/30);
        
  //Set text color 
  screen.setTextColor(COLOR_RGB565_YELLOW);
        
  //Set to text auto-wrap mode, true=Auto-wrap, false=No auto-wrap
  screen.setTextWrap(true);
  Serial.println("start done");
        
  #if (defined ESP32)
    FPSerial.begin(9600, SERIAL_8N1, /*rx =*/mp3rxPin, /*tx =*/mp3txPin);
  #else
    FPSerial.begin(9600);
  #endif

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(FPSerial, /*isACK = */false, /*doReset = */true)) {  //Use serial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
  }
  else {
    Serial.println(F("DFPlayer Mini online."));
  }

  myDFPlayer.volume(20);  //Set volume value. From 0 to 30
  //myDFPlayer.loop(1);  //Play the first mp3Wire.begin();

  //I2C keypad
  Wire.setClock(400000);
  if (keyPad.begin() == false)
  {
    Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n");
    while(1);
  }

  keyPad.setKeyPadMode(I2C_KEYPAD_4x3);

  //pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  //pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  pinMode(sensityPin, INPUT);
  pinMode(lockPin, OUTPUT); //set Lock
 
}

void loop(){
  char keys[] = "123A456B789C*0#DNF";  // N = NoKey, F = Fail   
  char keyin[5];
  char *pos;
  uint8_t cnt;
  unsigned long timer = millis();
  int term = random(p_rows);
  int color = COLOR_RGB565_LGRAY;
  int song = 0;
  bool empty = false;

  screen.fillScreen(COLOR_RGB565_BLACK);
  //screen.drawLine(screen.width, 30, 0, 30, color);

  //1. Print welcome message
  while (!keyPad.isPressed()) {
    //screen.fillScreen(COLOR_RGB565_BLACK);
    //if(millis() - timer > 20000) {
    //  timer = millis();
      //myDFPlayer.next();
      //myDFPlayer.play(1);
      //myDFPlayer.play(56);
      //delay(10);
    //}
    //myDFPlayer.playLargeFolder(2, 999);
    //myDFPlayer.playFolder(1, 1);

    //for (int cnt = 1; cnt <= 10; cnt++) {
      //screen.setCursor(/*x=*/0,/*y=*/35);
      //screen.setTextColor(COLOR_RGB565_YELLOW);
      //screen.println(cnt);
      //screen.println();
    //  myDFPlayer.playFolder(2, cnt);
    //  Serial.print(cnt);
    //  delay(3000);
    //}
    //myDFPlayer.play(1);
    screen.setCursor(/*x=*/0,/*y=*/50);
    screen.setTextColor(COLOR_RGB565_YELLOW);
    screen.println("WELCOME TO THE LITTLE FREE STEM LIBRARY");
    //myDFPlayer.playFolder(1, 1);
    if(millis() - timer > 3000) {
      timer = millis();
      if (song == 0) {
        myDFPlayer.playFolder(1, 1);
        song = 1;
      } else {
        myDFPlayer.playFolder(1, 6);
        song = 0;
      }
    }
    //delay(3000);
    screen.println();
    screen.setTextColor(color);
    //screen.setTextWrap(true);
    //screen.setTextSize(1);
    screen.println("Press any key to start");
    //myDFPlayer.playFolder(1, 6);
    //delay(3000);
  } 
  
  //screen.fillScreen(COLOR_RGB565_BLACK);
  //screen.setCursor(/*x=*/0,/*y=*/25);
  //screen.println("Let's start");
  //myDFPlayer.next();  //Play next mp3 every 3 second.
  
  screen.fillScreen(COLOR_RGB565_BLACK);
  screen.setCursor(/*x=*/0,/*y=*/50);
  screen.setTextColor(COLOR_RGB565_LGRAY);
  screen.println("please answer the following question to unlock");
  myDFPlayer.playFolder(1, 2);
  delay(3000);
  //myDFPlayer.next();  //Play next mp3 every 3 second.
  //myDFPlayer.play(57);

  screen.fillScreen(COLOR_RGB565_BLACK);
  screen.setTextColor(COLOR_RGB565_GREEN);
  screen.setCursor(/*x=*/0,/*y=*/30);
  //screen.println(term);
  screen.println("In which year did ");
  myDFPlayer.playFolder(1, 3);
  delay(2000);
  screen.setTextColor(COLOR_RGB565_LGRAY);
  screen.println(p_2d[term]);
  //for (int i = 1; i <=46; i++){
  //  screen.println(i);
  //  myDFPlayer.playFolder(3, i);
  //  delay(3000);
  //}
  myDFPlayer.playFolder(3, (term+1));
  delay(2000);
  screen.setTextColor(COLOR_RGB565_GREEN);
  screen.print("become President?");
  myDFPlayer.playFolder(1, 4);
  delay(2000);
  Serial.println(p_year[term]);
  screen.println();
  screen.println();
  screen.setTextColor(COLOR_RGB565_CYAN);
  screen.println("Please enter the year and the '#' sign at the end, ex: 1948#");
  myDFPlayer.playFolder(1, 5);
  
  //delay(6000);
  char buf[5];
  int result = readKeyPadUntil('#', buf, 5, 100000);
  if (result == 0)
  {
    Serial.println(buf);
    //screen.fillScreen(COLOR_RGB565_BLACK);
    screen.fillScreen(COLOR_RGB565_BLACK);
    screen.setCursor(/*x=*/0,/*y=*/50);
    screen.println(buf);
    //if(strcmp(buf, "1234") == 0) {
    if(strcmp(buf, p_year[term]) == 0) {
      //while (Serial.available ()==0){}
      screen.setTextColor(COLOR_RGB565_GREEN);
      myDFPlayer.playFolder(1, 7);
      screen.println("YEAH!!! CORRECT!!!");
      screen.println("UNLOCKED!!");
      //unlock
      digitalWrite(lockPin, HIGH);
      delay(20000);
      digitalWrite(lockPin, LOW);
      //myDFPlayer.playFolder(1, 6); //please close the door once you are done
      delay(30000);
    } else {
      screen.setTextColor(COLOR_RGB565_RED);
      myDFPlayer.playFolder(1, 8);
      screen.print("Wrong!! Please try again!!");
      delay(2000);
    }

    //adhoc codes
    //check Ambient light range: 0~120 klx
    //Print the data obtained from sensor
    Serial.println("-------------------------------");
    Serial.print("Temp: ");
    Serial.print(environment.getTemperature(TEMP_F));
    Serial.println(" ℉");
    Serial.print("LuminousIntensity: ");
    Serial.println(environment.getLuminousIntensity());
    Serial.println("-------------------------------");

    //check if library is empty
    // read the value from the sensor:
    sensity_t = analogRead(sensityPin);
    dist_t = sensity_t * MAX_RANG  / ADC_SOLUTION;//
    Serial.print(dist_t,0);
    Serial.println("cm");
    if (dist_t > 24) {
      empty = true;
      myDFPlayer.playFolder(1, 9);
      screen.fillScreen(COLOR_RGB565_BLACK);
      screen.setCursor(/*x=*/0,/*y=*/50);
      screen.setTextColor(COLOR_RGB565_YELLOW);  
      screen.println("Refill!! Library is empty!!");
      Serial.println("Library is empty");
      delay(5000);
    }
    else {
      empty = false;
    }
  }
  if (result == -1)
  {
    Serial.print("FAILURE: ");
    Serial.println(buf);
  }
  if (result == -2)
  {
    Serial.print("TIMEOUT: ");
    Serial.println(buf);
  }
  if (result == -3)
  {
    Serial.print("OVERFLW: ");
    Serial.println(buf);
  }
  //delay(1000);
}

//
// until   = end character
// buffer  = buffer to fill
// length  = length of buffer (including '\0'
// timeout = timeout in milliseconds
// returns 0 = success
//        -1 = keyPad fail
//        -2 = timeout
//        -3 = buffer overflow
int readKeyPadUntil(char until, char * buffer, uint8_t length, uint16_t timeout)
{
  char keymap[19] = "123A456B789C*0#DNF";  // ... NoKey  Fail }  
  uint8_t bufferIndex = 0;
  uint32_t start = millis();

  // empty buffer
  buffer[bufferIndex] = 0;

  while (true)
  {
    // while no key is pressed wait
    while (keymap[keyPad.getKey()] == 'N')
    {
      delay(1);
      yield();
      if (millis() - start > timeout) return -2;
    }

    // get the key pressed
    uint8_t raw = keyPad.getLastKey();

    // process key pressed
    uint8_t key = keymap[raw];

    // handle end conditions
    if ( key == until) return 0;
    if ( key == 'F') return -1;    // failed to read;
    if (bufferIndex == length) return -3;

    // add key to buffer
    buffer[bufferIndex++] = key;
    buffer[bufferIndex] = 0;

    // while key is pressed wait
    while (keymap[keyPad.getKey()] == key)
    {
      yield();
      if (millis() - start > timeout) return -2;
    }
  }
}

The article was first published in hackster, November 20, 2023

cr: https://www.hackster.io/d1-coders/little-free-stem-library-e5345e

author: Darren Shen&Evelyn Shen

License
All Rights
Reserved
licensBg
0