Pill Bottle Fill Level: IoT and LCD Device
Summary
This project uses the mbed with additional sensors in order to measure and display the fill level of a container such as a bottle of pills or milk jug. It then outputs the percentage left to the LCD as well as a web page, so that someone could check the amount of milk left while at the grocery store.

Hardware
The components involved are listed with links to data sheets or wiki pages.
Sharp IR Sensor: http://sharp-world.com/products/device/lineup/data/pdf/datasheet/gp2y0a21yk_e.pdf
ESP8266 Wi-Fi Huzzah: https://developer.mbed.org/teams/Ece-4180-team-who/wiki/Using-Adafruit-ESP8266-Huzzah
uLCD-144-G2: https://developer.mbed.org/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
Proper Pin assignments for each device are below
uLCD
| Device | mbed |
|---|---|
| 5V | VU |
| TX | p27 |
| RX | p28 |
| GND | GND |
| RES | p30 |
IR Sensor
| Device | =mbed |
|---|---|
| Analog In | p20 |
| Power | VU |
| Ground | GND |
Huzzah Wifi Chip
| Huzzah | mbed LPC1768 | External 5V DC supply >=500MA |
|---|---|---|
| gnd | gnd | gnd |
| TX | RX(p27) | |
| RX | TX(p28) | |
| V+ | 5VDC | |
| RST | p26 (optional) |
Quote:
Don't forget to use an external supply for 5V. The mbed does not supply enough current by itself.
Setup and Use
Wifi
In order to setup the Wifi correctly for the first time, you must change the SSID and Password settings in the code.
RFID
It is a good idea to secure the IR sensor with glue or tape in order to maintain consistently accurate readings.
Calibration
Depending on bottle size- pill bottle or milk jug, the IR sensor needs to be calibrated the first time. Run the code, place the IR sensor over an empty bottle, and make note of the second number on the LCD screen (labeled "Sensor Value"). Now fill up the bottle and repeat the process. Note this number as well. In order to get the most accurate reading, replace the variables lowlimit and uplimit (located at top of code) with these variables, respectively.
Usage
There are two options when reading the fill percentage. Option 1 is using the LCD Screen, updating about every two seconds. The video shown below demonstrates that option.
Option two involves reading the fill percentage off of a hosted webpage. In order to find the IP for that, run the virtual USB serial terminal. It will give you the IP address that it can be accessed through. Usually it is 10.0.1.127. The video below denmonstrates option two.
Software
Can be downloaded at:
main.cpp
#include "mbed.h"
#include "uLCD_4DGL.h"
//IR value ranges
float uplimit = .655;
float lowlimit = .467;
Serial pc(USBTX, USBRX);
AnalogIn ainpin(p20); // ir sensor
DigitalOut led1(LED1);
DigitalOut led4(LED4);
Timer t;
//LCD system setup
float sensorval = 0.0;
int count,ended,timeout;
char buf[2024];
char snd[1024];
char cPercent[8];
float percent;
char ssid[32] = "SSID"; // enter WiFi router ssid inside the quotes
char pwd [32] = "password"; // enter WiFi router password inside the quotes
//LCD screen
uLCD_4DGL mylcd(p28,p27,p30);
//Wifi Networking
//wifi chip var
Serial esp(p9, p10); // tx, rx
DigitalOut reset(p11);
//custom functions for calculating pill bottle
int CalcPixValue(float, float, float);
void DrawProgressBar(int, int, int);
void SendCMD(),getreply(),ESPconfig(),ESPsetbaudrate();
void dev_recv()
{
led1 = !led1;
while(esp.readable()) {
pc.putc(esp.getc());
}
}
void pc_recv()
{
led4 = !led4;
while(pc.readable()) {
esp.putc(pc.getc());
}
}
int main()
{
//IR setup
//IR value ranges
float uplimit = .655;
float lowlimit = .647;
//LCD system setup
mylcd.baudrate(3000000);
float sensorval = 0.0;
reset=0; //hardware reset for 8266
pc.baud(9600); // set what you want here depending on your terminal program speed
pc.printf("\f\n\r-------------ESP8266 Hardware Reset-------------\n\r");
wait(0.1);
reset=1;
timeout=2;
getreply();
esp.baud(9600); // change this to the new ESP8266 baudrate if it is changed at any time.
ESPconfig(); //****************** include Config to set the ESP8266 configuration ***********************
pc.attach(&pc_recv, Serial::RxIrq);
esp.attach(&dev_recv, Serial::RxIrq);
// continuosly get AP list and IP
while(1) {
sleep();
//IR sensor
//sensorval = ainpin.read(); //read in voltage and set it to sensor val (between 0-1)
int pix = CalcPixValue(sensorval, uplimit, lowlimit);
//Print progress bar to LCD
//DrawProgressBar(pix, 2, 6);
}
}
//IR sensor commands
//given analog value 0-1 num, returns pixel value at which the fill bar should be drawn
int CalcPixValue(float num, float up, float low)
{
float range = up-low;
float height, sensornorm1, sensornorm;
sensornorm1 = (num - low)/(range);
sensornorm =-1* sensornorm1 + 1;
//correct for small error
if (sensornorm1<0)
sensornorm1 = 0;
else if (sensornorm1 >1.00)
sensornorm1 = 1;
//convert to percent
sensornorm1 = sensornorm1*100.0;
mylcd.cls();
// print out the values
mylcd.printf("\n Percent Full =\n %f2\n\n\n SensorValue=\n %3f", sensornorm1,num);
//restrict the value a scaled value of 127 pixels
height = (sensornorm)*127;
//if outside of range, post to 0% or 100% of bar
if (num > up) {
height = 0;}
else if (num < low) {
height = 127;}
return floor(height);
}
void DrawProgressBar(int pixVal, int startX, int endX)
{
//clears value
int count = 0;
while ( (startX + count) <= endX )
{
mylcd.line(startX + count, 127, startX + count, pixVal, WHITE);
count = count + 1;
}
}
//Wifi Commands
// Sets new ESP8266 baurate, change the esp.baud(xxxxx) to match your new setting once this has been executed
void ESPsetbaudrate()
{
strcpy(snd, "AT+CIOBAUD=9600\r\n"); // change the numeric value to the required baudrate
SendCMD();
}
// +++++++++++++++++++++++++++++++++ This is for ESP8266 config only, run this once to set up the ESP8266 +++++++++++++++
void ESPconfig()
{
wait(1);
pc.printf("\f---------- Starting ESP Config ----------\r\n\n");
strcpy(snd,".\r\n.\r\n");
SendCMD();
wait(1);
pc.printf("---------- Reset & get Firmware ----------\r\n");
strcpy(snd,"node.restart()\r\n");
SendCMD();
timeout=5;
getreply();
pc.printf(buf);
wait(.2);
pc.printf("\n---------- Get Version ----------\r\n");
strcpy(snd,"print(node.info())\r\n");
SendCMD();
timeout=4;
getreply();
pc.printf(buf);
wait(.3);
// set CWMODE to 1=Station,2=AP,3=BOTH, default mode 1 (Station)
pc.printf("\n---------- Setting Mode ----------\r\n");
strcpy(snd, "wifi.setmode(wifi.STATION)\r\n");
SendCMD();
timeout=4;
getreply();
pc.printf(buf);
wait(.2);
pc.printf("\n---------- Listing Access Points ----------\r\n");
strcpy(snd, "function listap(t)\r\n");
SendCMD();
wait(1);
strcpy(snd, "for k,v in pairs(t) do\r\n");
SendCMD();
wait(1);
strcpy(snd, "print(k..\" : \"..v)\r\n");
SendCMD();
wait(1);
strcpy(snd, "end\r\n");
SendCMD();
wait(1);
strcpy(snd, "end\r\n");
SendCMD();
wait(1);
strcpy(snd, "wifi.sta.getap(listap)\r\n");
SendCMD();
wait(1);
timeout=15;
getreply();
pc.printf(buf);
wait(.2);
pc.printf("\n---------- Connecting to AP ----------\r\n");
pc.printf("ssid = %s pwd = %s\r\n",ssid,pwd);
strcpy(snd, "wifi.sta.config(\"");
strcat(snd, ssid);
strcat(snd, "\",\"");
strcat(snd, pwd);
strcat(snd, "\")\r\n");
SendCMD();
timeout=10;
getreply();
pc.printf(buf);
wait(.5);
pc.printf("\n---------- Get IP's ----------\r\n");
strcpy(snd, "print(wifi.sta.getip())\r\n");
SendCMD();
timeout=3;
getreply();
pc.printf(buf);
wait(1);
pc.printf("\n---------- Get Connection Status ----------\r\n");
strcpy(snd, "print(wifi.sta.status())\r\n");
SendCMD();
timeout=5;
getreply();
pc.printf(buf);
pc.printf("\n\n\n If you get a valid (non zero) IP, ESP8266 has been set up.\r\n");
pc.printf(" Run this if you want to reconfig the ESP8266 at any time.\r\n");
pc.printf(" It saves the SSID and password settings internally\r\n");
wait(.10);
pc.printf("\n---------- Setting up http server ----------\r\n");
strcpy(snd, "srv=net.createServer(net.TCP)\r\n");
SendCMD();
wait(1);
strcpy(snd, "srv:listen(80,function(conn)\r\n");
SendCMD();
wait(1);
strcpy(snd, "conn:on(\"receive\",function(conn,payload)\r\n");
SendCMD();
wait(1);
strcpy(snd, "print(payload)\r\n");
SendCMD();
wait(1);
strcpy(snd, "conn:send(\"<!DOCTYPE html>\")\r\n");
SendCMD();
wait(1);
strcpy(snd, "conn:send(\"<html>\")\r\n");
SendCMD();
wait(1);
strcpy(snd, "conn:send(\"<h1> Welcome to the bottle monitoring system.</h1>\")\r\n");
SendCMD();
wait(1);
strcpy(snd, "conn:send(\"<h2> Last time your bottle was checked for a fill level it contained </h2>\")\r\n");
SendCMD();
wait(1);
//Send most recent IR sensor data to site
//sensorval = ainpin.read(); //read in voltage and set it to sensor val (between 0-1)
int pix = CalcPixValue(sensorval, uplimit, lowlimit);
//reset it
strcpy(snd,"");
sprintf(cPercent, "%f",percent);
strcat(snd,cPercent);
strcat(snd, "conn:send(\"<h2> percent of the pill's original level ");
strcat(snd," </h2>\")\r\n");
//strcat(snd, cPercent + "</h2>\")\r\n" );
SendCMD();
wait(1);
strcpy(snd, "conn:send(\"</html>\")\r\n");
SendCMD();
wait(1);
strcpy(snd, "end)\r\n");
SendCMD();
wait(1);
strcpy(snd, "conn:on(\"sent\",function(conn) conn:close() end)\r\n");
SendCMD();
wait(1);
strcpy(snd, "end)\r\n");
SendCMD();
wait(1);
timeout=17;
getreply();
pc.printf(buf);
pc.printf("\r\nDONE");
}
void SendCMD()
{
esp.printf("%s", snd);
}
void getreply()
{
memset(buf, '\0', sizeof(buf));
t.start();
ended=0;
count=0;
while(!ended) {
if(esp.readable()) {
buf[count] = esp.getc();
count++;
}
if(t.read() > timeout) {
ended = 1;
t.stop();
t.reset();
}
}
}
Please log in to post comments.
