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.