Skip to content

Final Project: Indispensable Pill Case

Week 1

While I have considered a couple different options for my final project, I feel that the project that I keep coming back to is my pill case. I live with epilepsy, and my condition is under control as long as I take my medication on time. This can lead to some anxiety, as forgetting to take pills on time can have a major impact on my life. Even when I’m 99% sure I have taken them, I need to carry my pills with me at all times so I can double check, and take them as soon as possible if I realize that I’ve forgotten. Pill cases that are currently on the market aren’t ergonomic, and require two hands to use, so I designed a pill case to fit into my hand, my pocket, and my life.

This 3D printed pill case has served me well, but I feel like it could be much more useful to me, and eventually to others, if it offered some increased functionality. Most importantly, receiving medication reminders and tracking the timing that the medication is taken would help the user adhere to their treatment and gain a better understanding of their behavior over time. In the case of someone like me who also wears a device that tracks the occurrence of seizures, this medication data would provide a valuable insight in determining the risk that missing doses could incur on a user.

Another benefit of the device having Bluetooth connectivity would be that when the device is out of range of the user’s phone, an alert could appear, letting the user know that their medication is no longer on their person. This could be very important for people who have to take their medication throughout the day, as in the most benign scenario, returning home just to pick up forgotten medication is an inconvenient and frustrating situation.

For my final project in Fab Academy, I propose to develop a Bluetooth-connect pill case that can remind the user to take their medication blinking an LED, activating a piezo buzzer, and sending push notifications to the user’s phone. The device will also be able to track when the medication has been taken by using a gyroscope to detect movement of the case, and send a push notification to the user’s phone. The device will be powered by a LiPo battery, and charged through an induction coil. The device will also send a push notification to the user’s phone when Bluetooth connection is lost, to let them know that their medication is no longer on their person. I predict that the most complicated aspect will be the Bluetooth functionality. The first iteration of this project will have the light and buzzer turn on when the pills are scheduled to be taken, and they will turn off once the the user takes their medication.

There are smart pill cases out in the world, such as Pillieve, Hero, and Pillo. Pillieve is a locking pill case designed to limit the consumption of opiods, and Pillo and Hero are counter-top, friendly pill dispenser that essentially serve as a smart medicine cabinet. While these are well designed, useful tools for their target markets, their intended use case is different from the case I have described above.

In 2016, Arsheena E.P. at Fab Lab Kochi built a pill case to remind her grandmother with Alzheimer’s to take her medication on time. In 2017, Corey Rice built a countertop pill dispenser to help his elderly grandmother take her pills on time. Finally, Jasim Bouresli at Fablab Kuwait initially planned to build a Bluetooth-connected pill box, but ended up building a Bluetooth-connected, locking jewelry box. Loes Schakenbos from Waag is currently working on an at-home pill case to sense when her pills have been taken. These FabLab projects give me confidence that my proposed project is not only technically possible, but it is achievable within the timeframe of the course.

How It Works

  1. Medication schedule is set on mobile app

  2. Mobile app sends medication reminder notification on phone, and sends information over Bluetooth to ESP32 in pill case

  3. The Bluetooth update triggers response from OLED, RGB LED, vibration motor, and/or piezo buzzer.

  4. User slides opens the door to the pill case, which contains a magnet. The magnet slides on top of the hall effect sensor, which registers that the pill case is open.

  5. Once the state of the hall effect sensor changes, the gyroscope begins taking readings

  6. The device senses that the pills have been removed once the gyroscope reads that the device has been flipped over with the door open

  7. The ESP32 sends a notification that the pills have been taken back to the mobile apply

  8. The mobile app stores the medication data in a calendar that the user can reference, or export to other health apps.

Spirals

Spiral 1:

  • Medication schedule is stored on ESP32
  • RGB LED and piezo buzzer indicate when it’s time to take pills
  • Hall effect sensor detects when pill case is opened
  • Gyroscope detects when pills are removed from case
  • LED and piezo indicate when pills have been taken

Spiral 2:

  • Medication schedule is stored in mobile app
  • Mobile device connected to pill case over Bluetooth
  • Mobile notification, RGB LED, and piezo buzzer indicate when it’s time to take pills
  • Hall effect sensor detects when pill case is opened
  • Gyroscope detects when pills are removed from case
  • Status update sent from pill case to mobile app
  • Mobile notification sent when connection between mobile device and pill case is lost

Schedule for remaining class:

Apr 28: networking and communications -get ESP32 talking over bluetooth/wifi -revise week 4&6 documentation

May 05: interface and application programming -develop basic interface to set medication schedule on phone

May 12: wildcard week -redesign enclosure to house electronics

May 19: applications and implications -user testing

May 26: invention, intellectual property, and income -incorporate user feedback -design packaging

Jun 02: project development -create presentation video

Jun 09- project presentations

Requirements

http://fabacademy.org/2021/nueval/project_requirements.html

Document a final project masterpiece that integrates the range of units covered, answering:

What does it do? Who’s done what beforehand? What did you design? What materials and components were used? Where did they come from? How much did they cost? What parts and systems were made? What processes were used? What questions were answered? What worked? What didn’t? How was it evaluated? What are the implications? Prepare a summary slide and a one minute video showing its conception, construction, and operation. Your project should incorporate 2D and 3D design, additive and subtractive fabrication processes, electronics design and production, embedded microcontroller interfacing and programming, system integration and packaging.

Where possible, you should make rather than buy the parts of your project. Projects can be separate or joint, but need to show individual mastery of the skills, and be independently operable. Present your final project, weekly and group assignments, and documentation.

Week 2

As mentioned above, I wanted to take some time to further my skills with vector based design software. I did this by recreating the sketch I made of my final project in Adobe Illustrator. I added an additional tool to my tool belt by incorporating gradients into the design to give a sense of depth. The gradient was not very difficult to get the hang of once I started experimenting with it. I added a circular gradient to the circle representing the well that holds the pills for one day. This gradient on the sides of the container gives the appearance that the well has depth, and the pill is not simply resting on the surface of the pill case. I also used the linear gradient tool to shade the pill itself.

To give the suggestion of light emanating from the LED, I used the line tool to create one “ray of light”, then used the rotate tool to duplicate that line by selecting the circle representing to LED as the center point to rotate around.

To demonstrate that the button on the front face of the pill case would be a fingerprint sensor, I wanted to add a little finger print icon to the schematic. Rather than create the icon from scratch, I downloaded a free vector from Vecteezy.com

I then imported this vector into my schematic file, ungrouped the lines so I could select them individually, and used the circle representing the button as a guide to crop the lines of the fingerprint vector.

Overall, I’m very proud of how it turned out!

Week 3

For the vinyl cutting portion of the assignment, I designed a logo for my final project, and cut it our on my Silhouette Cameo vinyl cutter. I have pasted it on the back of my phone and on the case of my calipers so I see it every day, and can figure out if I get sick of it. Once I had designed the general shape of the logo in Adobe Illustrator, I had to modify it to be compatible with the vinyl cutter.

First, I had to join the overlapping lines to make them one cohesive shape.

Second, I needed to outline the strokes. Even though the design appears to have thickness, if I exported the file without outlining the strokes, the vinyl cutter would cut straight down the center of each line in the design, rather than cutting the inside and outside perimeters.

[Adobe Illustrator File](../images/final_project/Indispensable_Logo.ai

[DXF File](../images/final_project/Indispensable_Logo.dxf

From there, I exported the file as a .dxf, and opened it in Silhouette Studio.

I cut out the design on my Silhouettte Cameo.

Once cut, I weeded the vinyl, and prepared a strip of transfer sheet to stick to the front of the decals.

Once I attached the transfer sheet to the decals, I split the strip into five separate designs.

I’ve attached these decals to several objects that I interact with every day. This will help me figure out if I learn to love the design or get sick of it, so I iterate as quickly as possible.

Week 6

During the Global MCU, I asked for the group’s opinions and past experiences working with the ESP32. Adrian pointed me to the documentation for the Barduino, which is a fab-able ESP32 breakout board. Both this board, and the ESP32 “hello world” board in the Fab Academy Embedded Programming page use the ESP32 WROOM32D, so I ordered a 5-pack of these chips from Amazon.

I was also directed to this tutorial for working with the ESP32.

The ESP32s arrived incredibly quickly.

I downloaded Eagle so I could begin to design the “hello world” board. I also downloaded the Eagle fab library that includes Eagle-compatible part files for all components in the fab kits. This download was a .lbr file that I had to drag and drop into my “EAGLE” folder in Documents for it to appear as a library in Eagle.

Following the Barduino documentation, I also downloaded the ESP32 library and added it to the EAGLE folder following the same steps. I created a new project file and a new schematic file to go inside it. Once in the schematic workspace, I could begin populating the schematic. First, I needed to include the fab library into the schematic…

Then I could simply click the “add part” button and select the “fab” dropdown to access all files in the library.

Once all necessary components were in the schematic, I could could use the “net” tool to create wires to the pins that will need to be routed, and use the “name” tool to identify where the pin will be connected.

Rather than connecting the two pins directly by a “net,” I could simply just create small nets on the pins and label them with the same name, and they will still be connected by “airwires” when I enter the “board” workspace. This workflow simplified the process of getting a design ready quickly, but I can see how it would be helpful to build a functional schematic with all nets directly connected before entering the board workspace. Once all of the nets were labeled, I entered the board workspace and positioned the components in the center of the frame.

The thin yellow lines in the design are “airwires,” which indicate that the pins they connect were given the same label in the schematic. The goal in the board workspace is to lay out the components and the “route airwire” tool to connect any pins with airwires between them with traces in order to get the most efficient design possible. There are several tricks that can be used to make designs simpler and create shorter traces, including using components such as resistors and capacitors to “jump” over other traces, acting as a bridge.

Once all airwires were routed, it was time to run my design rules check to ensure that there were no glaring errors with my design. In this case, the board was going to be milled on the 3018, so I downloaded the fab design rules and ran a check to ensure that the design was compatible with the manufacturing techniques. Unfortunately, the check revealed that the pads of the ESP32 were too close together for a 1/64” endmill to fit between them, so if the file were exported to Mods, no tool paths would be generated to separate the pads.

Interestingly, the “traces” .png file in the Barduino documentation appears to show wider gaps between the pads, but there is no mention of this issue with the ESP32 footprint listed in their documentation, or of any modifications made to the file to make it compatible with the manufacturing techniques we are using. While I did find an article on how to customize the component’s footprint in Eagle, this issue was a bit more than I could overcome in the given timeframe, and I unfortunately had to shelf the ESP32 hello world board in favor of something a bit simpler.

Week 10

I took another shot at using the ESP32, and figured out how to modify the footprint of the device so it was compatible with the design rules. In the control panel, you click “File,” “Open,” and “Library,” then select the .lbr file of the desired library.

This will bring you into the library editor environment, where you can choose the device footprint you wish to edit by right clicking, then choosing “Edit.”

This will bring you into the footprint editing environment, where you can select a pad, and adjust the dimensions. This was much simpler than I imagined it would be, as the pads’ positions are defined relative to their “centroid,” rather than one of their corners, so the relative spacing between an array of pads remains consistent.

By reducing the size of the pads on the ESP32 footprint, the device passed the “FAB” design rules check, indicating that I will be able to mill it on my 3018 PCB mill!

I adapted code from examples other students had referenced to create a sketch that would cause the state of the LED to change when a magnet was passed over the Hall effect sensor.

int hallEffectPin = 3;
int ledPinRed = 0;
int ledPinGreen = 1;
int state = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(ledPinRed, OUTPUT);
  pinMode(ledPinGreen, OUTPUT);
  pinMode(hallEffectPin, INPUT_PULLUP);

}

void loop() {
  // put your main code here, to run repeatedly:
  state = digitalRead(hallEffectPin);
  if (state == LOW) {
    digitalWrite(ledPinGreen,LOW);
    digitalWrite(ledPinRed,HIGH);
    delay(100);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinRed,HIGH);
    delay(900);
  }
  else {
    digitalWrite(ledPinRed, LOW);
    digitalWrite(ledPinGreen, HIGH);
    delay(200);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinRed,HIGH);
    delay(200);
  }

}

It worked!

Week 12

In our local node review, we discussed the lecture and how we can apply those devices to our projects. I discussed my specific application, and how the output devices will make this possible. Other students discussed using an OLED display, and I was inspired by how small a 32x128 OLED is, so I decided to include one on my board as well.

After the lecture, I ordered the necessary output devices.

Vibration motor:

10mm x 2.7mm DC Motor (3V 85mA 12000RPM)

Piezo buzzer:

CMT-8530S-SMT-TR Datasheet

OLED display:

SSD1306 Datasheet

https://gitlab.fabcloud.org/barcelonaworkshops/barduino-2.0/

http://fablabkamakura.fabcloud.io/FabAcademy/support-documents/microcontrollers/barduino2.0/

https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection

https://randomnerdtutorials.com/esp32-pinout-reference-gpios/

Incorrect pinout

PNG Files

https://dl.espressif.com/dl/package_esp32_index.json

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int motor = 14;

void setup() {
  Serial.begin(115200);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println("INDISPENSABLE");
  display.display();

pinMode(motor, OUTPUT);

}

void loop() {

  digitalWrite(motor, HIGH);  
  delay(500);               
  digitalWrite(motor, LOW);    
  delay(1500);            

}

Video

Week 13

At our local node meeting, I discussed my plans for the interface week with Greg. I decided to focus my efforts on getting the data from the MPU-6050 inertial measurement unit (IMU) transmitting to the Arduino IDE serial monitor, then getting that serial data to print on the OLED display. Once I got those up and running, I would attempt to transmit serial data over Bluetooth.

Once I had finished my experiments with the board I had created for week 12, I set out to make a couple modifications to it. This included running 5 volts to the RGB LED, putting the motor and buzzer on a breakout board, and adding mounting holes.

Once I had made these modifications, I uploaded the .png files to Mods to create the g-code toolpaths. I used a large number of offsets in order to clear the entirety of the disconnected copper from the front face of the board.

I then uploaded this file to UGS and milled out the board using my 3018 CNC mill.

Unfortunately, I accidentally damaged the pads for the OLED display during the soldering process, which limited the usefulness of this board for this week’s assignment.

The show must go on, and I continued my tests with the board I milled for Week 12.

I began to work with the GY-521, the breakout board that houses the MPU-6050 6-DoF inertial measurement unit (IMU). I referenced this page from RandomNerdTutorials to help me get started.

I added the “Adafruit MPU6050” library to the Arduino IDE, and loaded the “basic_readings” example sketch.

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");

  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  Serial.print("Accelerometer range set to: ");
  switch (mpu.getAccelerometerRange()) {
  case MPU6050_RANGE_2_G:
    Serial.println("+-2G");
    break;
  case MPU6050_RANGE_4_G:
    Serial.println("+-4G");
    break;
  case MPU6050_RANGE_8_G:
    Serial.println("+-8G");
    break;
  case MPU6050_RANGE_16_G:
    Serial.println("+-16G");
    break;
  }
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  Serial.print("Gyro range set to: ");
  switch (mpu.getGyroRange()) {
  case MPU6050_RANGE_250_DEG:
    Serial.println("+- 250 deg/s");
    break;
  case MPU6050_RANGE_500_DEG:
    Serial.println("+- 500 deg/s");
    break;
  case MPU6050_RANGE_1000_DEG:
    Serial.println("+- 1000 deg/s");
    break;
  case MPU6050_RANGE_2000_DEG:
    Serial.println("+- 2000 deg/s");
    break;
  }

  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  Serial.print("Filter bandwidth set to: ");
  switch (mpu.getFilterBandwidth()) {
  case MPU6050_BAND_260_HZ:
    Serial.println("260 Hz");
    break;
  case MPU6050_BAND_184_HZ:
    Serial.println("184 Hz");
    break;
  case MPU6050_BAND_94_HZ:
    Serial.println("94 Hz");
    break;
  case MPU6050_BAND_44_HZ:
    Serial.println("44 Hz");
    break;
  case MPU6050_BAND_21_HZ:
    Serial.println("21 Hz");
    break;
  case MPU6050_BAND_10_HZ:
    Serial.println("10 Hz");
    break;
  case MPU6050_BAND_5_HZ:
    Serial.println("5 Hz");
    break;
  }

  Serial.println("");
  delay(100);
}

void loop() {

  /* Get new sensor events with the readings */
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  /* Print out the values */
  Serial.print("Acceleration X: ");
  Serial.print(a.acceleration.x);
  Serial.print(", Y: ");
  Serial.print(a.acceleration.y);
  Serial.print(", Z: ");
  Serial.print(a.acceleration.z);
  Serial.println(" m/s^2");

  Serial.print("Rotation X: ");
  Serial.print(g.gyro.x);
  Serial.print(", Y: ");
  Serial.print(g.gyro.y);
  Serial.print(", Z: ");
  Serial.print(g.gyro.z);
  Serial.println(" rad/s");

  Serial.print("Temperature: ");
  Serial.print(temp.temperature);
  Serial.println(" degC");

  Serial.println("");
  delay(500);
}

Ensuring that the baud rate in the terminal was the same as the one set in the sketch, I could then get a live readout of the data coming from the MPU-6050!

Once this was up and running, I made some tweaks to this sketch to simplify the data coming through to the terminal, as I am only interested in the gyroscope data.

I then moved on to incorporate the OLED display. I referenced this page from RandomNerdTutorials, and loaded the “MPU6050_oled” sketch from the Adafruit MPU6050 library.

Again, I modified this sketch to minimize the data that is output to the OLED, and make it more readable.

#include <Adafruit_MPU6050.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>

Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);

void setup() {
  Serial.begin(115200);
  // while (!Serial);
  Serial.println("Indispensable Pill Case - MPU6050 & OLED Test");

  if (!mpu.begin()) {
    Serial.println("Sensor init failed");
    while (1)
      yield();
  }
  Serial.println("Found a MPU-6050 sensor");

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }
  display.display();
  delay(500); // Pause for 2 seconds
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setRotation(0);

  display.clearDisplay();
  display.setCursor(0, 0);
  display.print(" ");
  display.println("*** INDISPENSABLE ***");
  display.println("******PILL CASE******");
  delay(1000);

}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  display.clearDisplay();
  display.setCursor(0, 0);

  Serial.print("Gyroscope ");
  Serial.print("X: ");
  Serial.print(g.gyro.x, 1);
  Serial.print(" rps, ");
  Serial.print("Y: ");
  Serial.print(g.gyro.y, 1);
  Serial.print(" rps, ");
  Serial.print("Z: ");
  Serial.print(g.gyro.z, 1);
  Serial.println(" rps");

  display.println("*** INDISPENSABLE ***");
  display.print("       X: ");
  display.print(g.gyro.x, 1);
  display.println("");
  display.print("       Y: ");
  display.print(g.gyro.y, 1);
  display.println("");
  display.print("       Z: ");
  display.print(g.gyro.z, 1);

  display.display();
  delay(100);
}

Having accomplished the MPU6050 and OLED components of my week’s goals, I turned my attention to the Bluetooth aspect. With the ESP32 Dev Module selected as the board in the Tools tab, I opened SerialToSerialBT from the BluetoothSerial tab in the Examples tab.

Once compiled, I uploaded this sketch to the board through the FTDI port.

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32test"); //Bluetooth device name
  Serial.println("The device started, now you can pair it with bluetooth!");
}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }
  delay(20);
}

I downloaded a Bluetooth serial monitor app to my iPhone, but I was unable to detect the ESP32’s Bluetooth signal. I borrowed my sister’s Android phone and downloaded the Serial Bluetooth Terminal app from the Google Play Store.

The ESP32 appeared on the list of Bluetooth devices, and I selected it to established a connection to the phone.

Once the two devices were connected, I opened the serial monitor in the Arduino IDE on the laptop that the ESP32 was connected to. I then typed “Hello, world.” into the Serial Bluetooth Terminal on the Android phone, and the message appeared in the serial monitor on the laptop!

I then typed the same message into the laptop’s serial monitor, and it appeared in the monitor on the phone!

Week 14

I have heard of a number of the topics Neil discussed in lecture, but much of it went over my head. There are obviously many powerful tools that can be used to make professional mobile applications to interface with electronics, but I unfortunately don’t have have the time to learn these tools.

I shared a link to Espressif Rainmaker, which is a service offered by Espressif, the company that develops the ESP32 modules. It provides an SDK, cloud hosting, and drag-and-drop app templates to simplify the IoT development process. Unfortunately, the code needs to be compiled in Espressif’s ESP IDF for it to be compatible with Rainmaker. From what I can gather, migrating the code to this new platform would require some time and effort. While I don’t intend to do this during the course, Rainmaker could be an interesting option moving forward.

Another option discussed was MIT App Inventor. This is a web-based, coding-block-based service that allows the user to build drag-and-drop apps within the web platform, then send them to the mobile companion app by scanning a QR code. A big benefit of this platform is that there is a large user community that post tutorials, so there is a good chance that I could find some useful resources when I run into issues. Also, apps created on this platform can also interface with sketches in the Arduino IDE, which is a big positive considering the time limitations. While the example apps look pretty clunky, this seems like my best option to get something up and running within a week.

In lecture, I shared a link to my Week 13 documentation to demonstrate an IMU and OLED talking over I2C when a student who was presenting said that they were having difficulty with this process. They were using an ATTiny processor which has much less flash memory than the ESP, and Neil mentioned that the OLED library takes up a large amount of storage. Henk shared a link to this library which is considerably smaller. As the firmware for my device becomes more complicated, I may want to look into moving away from the Adafruit OLED and GFX libraries that I currently need to include for my sketch to run.

After class, I continued to build off the sketch I had created for Week 13, and I merged it with the sketch from Week 10 where the hall effect sensor triggered the RGB LED. The code is as follows:

#include <Adafruit_MPU6050.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>

Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);

int hallEffectPin = 25;
const int ledPinGreen = 26;
const int ledPinBlue = 27;
int state = 0;
int motor = 14;

void setup() {

  pinMode(ledPinGreen, OUTPUT);
  pinMode(ledPinBlue, OUTPUT);
  pinMode(hallEffectPin, INPUT_PULLUP);
  pinMode(motor, OUTPUT);

  Serial.begin(115200);
  // while (!Serial);
  Serial.println("Indispensable Pill Case - MPU6050 & OLED Test");

  if (!mpu.begin()) {
    Serial.println("Sensor init failed");
    while (1)
      yield();
  }
  Serial.println("Found a MPU-6050 sensor");

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }
  display.display();
  delay(500); // Pause for 2 seconds
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setRotation(0);

}

void loop() {
  // put your main code here, to run repeatedly:

  state = digitalRead(hallEffectPin);
  if (state == HIGH) {
    digitalWrite(ledPinGreen,LOW);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(100);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(900);
  }
  else {
    digitalWrite(ledPinGreen, HIGH);
    digitalWrite(ledPinBlue, LOW);
    digitalWrite(motor, HIGH);

    delay(200);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);

    delay(200);
  }

  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  display.clearDisplay();
  display.setCursor(0, 0);

  Serial.print("Gyroscope ");
  Serial.print("X: ");
  Serial.print(g.gyro.x, 1);
  Serial.print(" rps, ");
  Serial.print("Y: ");
  Serial.print(g.gyro.y, 1);
  Serial.print(" rps, ");
  Serial.print("Z: ");
  Serial.print(g.gyro.z, 1);
  Serial.println(" rps");

  display.println("*** INDISPENSABLE ***");
  display.print("       X: ");
  display.print(g.gyro.x, 1);
  display.println("");
  display.print("       Y: ");
  display.print(g.gyro.y, 1);
  display.println("");
  display.print("       Z: ");
  display.print(g.gyro.z, 1);

  display.display();
  delay(100);
}

May 6

During the local node lecture, we discussed our plans for the week, and it was revealed that other students also plan to use ESP32s and MIT App Inventor, so we will hopefully be able to more effective solve problems as they arise.

One of the goals of the project is portability, so I’d like to make the pill case battery-powered. The lightest-weight and most space-efficient way to do this is to use a Li-Po battery. These 1S batteries are stated to run at 3.7V, but in practice, they range from 4.2V at a full charge down to 3.0V. This means that I should be able to use these batteries with the 3.3V regulator I currently have on my board to be powered by the 5V from the mini-USB. These 3.7V Li-Pos use a JST-PH connector, so to incorporate them into my board, I purchased these SMD JST-PH ports, and downloaded this Eagle library also provided by Adafruit.

May 7

Now that I had selected an app development tool, it was time to get started building the app. I went to the MIT App Inventor website and followed the instructions to download the Android emulator. Now that I was set up to start using App Inventor, I needed to decide roughly what the framework of the app would look like.

At its core, the app should allow a user to set the time for their medication reminder, and trigger the “alarm state” of the pill case at that time. When the case registers that the pills have been taken, the app should be notified in order to update a medication history that the user can reference. The medication history seems like it would be a bit complex, but the medication reminder alarm and Bluetooth controlled LED seem fairly straightforward.

I decided to focus on building a standalone alarm clock app first, as this wouldn’t require interfacing with the ESP32, and would let me get up to speed with App Inventor. Once I got the hang of it, I would be able to tackle controlling the LED over Bluetooth, then attempt to merge the two to have the alarm clock control the LED over Bluetooth. I found this YouTube tutorial for making an alarm clock app with MIT App Inventor, and downloaded this alarm plugin for MIT App Inventor. Following the tutorial, I built an app that allows users to set an alarm with a message that will appear as a notification at the specified time.

When I tried to run this app using the MIT App Inventor Companion App in the Android Emulator, I got a message stating that the app did not have the proper permissions. I searched the error message, and found a post pointing back to the plugin’s documentation, which stated: “Note: You will have to build the app to be able to test it, because the companion app does not offer the required permission.” Based on this message, it looks like I won’t be able to test this alarm app until I can borrow a friend’s Android phone. Despite this setback, this was still a good intro to MIT App Inventor, and I feel much more confident about the rest of the week.

Through looking into this error code, I also found some helpful resources. Namely, I found a collection of App Inventor extensions, including a Bluetooth Low Energy extension and documentation to support it. I also found a couple posts on useful topics on the App Inventor forums, including two-way Bluetooth communication with Arduino, sending and receiving data to an ESP32 over BLE, and sending and receiving data from FirebaseDB with the ESP32. This last post will be useful when creating a medication history that can be referenced by the user.

May 8

During Global Open Time, I shared the current state of my project, and my plans for this week. I asked about others’ experience with MIT App Inventor, and Adrian pointed me to his Week 12 documentation.

Adrian also shared a link to the six-pack CNC, which was developed by Fab Lab Barcelona.

We discussed the ESP32 and the square “e-pad” in the center of the footprint. Rico shared the ESP32 Hardware Design Guidelines as well as this video which shows soldering through plated vias on the back of the board.

We also discussed milling double-sided boards. Important to note are the need for registration marks when milling them, then need to mirror the bottom layer before converting it to g-code, and the use of PCB rivets.

After Global Open Time, I followed this YouTube tutorial to build an MIT App Inventor app to turn on an LED over Bluetooth. There was also a link in the description to a GitHub repository that included the Arduino sketch created in the tutorial. Following this tutorial, I build an identical App Inventor project, and replicated the Arduino sketch.

char Incoming_value = 0;

void setup()
{
  Serial.begin(9600);         
  pinMode(13, OUTPUT);       
}

void loop()
{
  if(Serial.available() > 0)  
  {
    Incoming_value = Serial.read();      
    Serial.print(Incoming_value);        
    Serial.print("\n");        
    if(Incoming_value == '1')             
      digitalWrite(13, HIGH);  
    else if(Incoming_value == '0')       
      digitalWrite(13, LOW);   
  }                            
}

I uploaded the sketch to the ESP32, and scanned the App Inventor project’s QR code using the App Inventor Companion app, but was unable to find the ESP32 listed when I scanned for Bluetooth devices. Taking a step back, I realized that the tutorial was using the HC-05 Bluetooth module, and I would need to open the Bluetooth serial connection for the ESP32 to be discoverable. I followed this tutorial to be able to turn on and off a LED over Bluetooth using the same serial monitor app I used in week 13. I uploaded the following code to my ESP32 and was able to control the LED over Bluetooth!

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;
int received;// received value will be stored in this variable
char receivedChar;// received value will be stored as CHAR in this variable

const char turnON ='a';
const char turnOFF ='b';
const int LEDpin = 26;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32_Indispensable"); //Bluetooth device name
  Serial.println("The device started, now you can pair it with bluetooth!");
  Serial.println("To turn ON send: a");//print on serial monitor  
  Serial.println("To turn OFF send: b"); //print on serial monitor
  pinMode(LEDpin, OUTPUT);

}

void loop() {
    receivedChar =(char)SerialBT.read();

  if (Serial.available()) {
    SerialBT.write(Serial.read());

  }
  if (SerialBT.available()) {

    SerialBT.print("Received:");// write on BT app
    SerialBT.println(receivedChar);// write on BT app      
    Serial.print ("Received:");//print on serial monitor
    Serial.println(receivedChar);//print on serial monitor    
    //SerialBT.println(receivedChar);//print on the app    
    //SerialBT.write(receivedChar); //print on serial monitor
    if(receivedChar == turnON)
    {
     SerialBT.println("LED ON:");// write on BT app
     Serial.println("LED ON:");//write on serial monitor
     digitalWrite(LEDpin, HIGH);// turn the LED ON

    }
    if(receivedChar == turnOFF)
    {
     SerialBT.println("LED OFF:");// write on BT app
     Serial.println("LED OFF:");//write on serial monitor
      digitalWrite(LEDpin, LOW);// turn the LED off
    }    



  }
  delay(20);
}

Knowing that this sketch functioned properly, I merged sections of it with sections of the sketch I had attempted to use the day before, to create the following:

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

char Incoming_value = 0;

BluetoothSerial SerialBT;

void setup()
{
  pinMode(27, OUTPUT);  
  Serial.begin(115200);
  SerialBT.begin("ESP32test"); //Bluetooth device name
  Serial.println("The device started, now you can pair it with bluetooth!");        

}

void loop()
{
  if(Serial.available() > 0)  
  {
    Incoming_value = Serial.read();      
    Serial.print(Incoming_value);        
    Serial.print("\n");        
    if(Incoming_value == '0')             
      digitalWrite(27, HIGH);  
    else if(Incoming_value == '1')       
      digitalWrite(27, LOW);  
  }               

}

Unfortunately, I still had the same issue, but I was unsure of what was causing it. I had other things to get done, so I decided to direct my attention elsewhere and come back to this later.

May 9

One potential issue with powering the pill case through a LiPo is that the battery would need to be recharged through an external charger when it’s depleted. In order to overcome this issue, I need to have the LiPo and a mini USB port connected to the board, along with components that will allow the LiPo to power the board under normal circumstances, but will allow the USB power supply to recharge the battery when it is plugged in. While this is a bit over my head, Adafruit’s Huzzah32 ESP32 Feather incorporates these components and provides a lot of documentation for the board, including details on power management and downloads, including the Eagle PCB files.

One major issue I noticed with the hall effect / gyro / OLED / RGB sketch was that the delays in the blinking function of the LEDs caused the gyroscope data to read out much more slowly. I followed this tutorial on the millis function, which can be used in place of the delay function, in order to allow the sketch to multitask. The tutorial was also provided in a written format, which was helpful. I instituted the millis function to blink the LED without using the delay function when the hall effect sensor is triggered.

When attempting to load the Fade example sketch, I kept getting the error: “‘analogWrite’ was not declared in this scope.” Upon further research, I found out that the ESP32 doesn’t use analogWrite, but instead uses “ledcAttachPin.” This isn’t a simple cut and paste solution, as pins need to be assigned to channels for ledc to work properly. I was pointed to this page about PWM with the ESP32 from, you guessed it, Random Nerd Tutorials, which explained things fairly well.

May 10

During Spencer’s office hours, the other students and I shared our experiences during the past week. This proved to be very helpful, as the others were also using the ESP32 and MIT App Inventor. Xiaolin shared a link to the documentation of a student who controlled an RGB LED connected to an ESP32 over Bluetooth Low Energy (BLE) using the Blynk app.

I shared the issue I was having with Bluetooth sketch with the group, and Nick offered a solution. Because I was initializing two separate serial connections, I needed to make sure that I was referencing the proper one. The way my sketch was set up, I was having the ESP serial read itself, rather than reading the Bluetooth serial. Making these changes was very simple, and it solved the problems I was experiencing!

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

char Incoming_value = 0;

BluetoothSerial SerialBT;

void setup()
{
  pinMode(27, OUTPUT);  
  Serial.begin(115200);
  SerialBT.begin("ESP32test"); //Bluetooth device name
  Serial.println("The device started, now you can pair it with bluetooth!");        

}

void loop()
{
  if(SerialBT.available() > 0)  
  {
    Incoming_value = SerialBT.read();      
    Serial.print(Incoming_value);        
    Serial.print("\n");        
    if(Incoming_value == '0')             
      digitalWrite(27, HIGH);  
    else if(Incoming_value == '1')       
      digitalWrite(27, LOW);  
  }               

}

May 14

I researched using the bool function in the Arduino sketch to have the app be able to switch the ESP between an idle state and an active state. In the idle state, the ESP doesn’t read inputs, but in the active state, the ESP will begin reading data from the hall effect sensor, and when the hall effect sensor is triggered, it will display the gyroscope values on the OLED.

#include "BluetoothSerial.h"
#include <Adafruit_MPU6050.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>

Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);

const int hallEffectPin = 25;
const int ledPinGreen = 26;
const int ledPinBlue = 27;
const int motor = 14;
int hallEffectState = 0;
int ledState = LOW;
int motorState = HIGH;

unsigned long previousMillis = 0;
const long interval = 500;

char Incoming_value = 0;
bool idleState = true;

BluetoothSerial SerialBT;

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

void setup() {
  // put your setup code here, to run once:

  pinMode(ledPinGreen, OUTPUT);
  pinMode(ledPinBlue, OUTPUT);
  pinMode(hallEffectPin, INPUT_PULLUP);
  pinMode(motor, OUTPUT);

  Serial.begin(115200);
  SerialBT.begin("Indispensable"); //Bluetooth device name
  Serial.println("Indispensable Pill Case");
  Serial.println("Remember What Empowers You");
  Serial.println("The device started, now you can pair it with bluetooth!");

  if (!mpu.begin()) {
    Serial.println("Sensor init failed");
    while (1)
      yield();
  }
  Serial.println("Found a MPU-6050 sensor");

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever

}
}

void loop() {
  // put your main code here, to run repeatedly:
  if(SerialBT.available() > 0)  
  {
    Incoming_value = SerialBT.read();      
    Serial.print(Incoming_value);        
    Serial.print("\n");        
    if(Incoming_value == '0')             
      idleState = true;  
    else if(Incoming_value == '1')       
      idleState = false;  
  }               

  unsigned long currentMillis = millis();

  if(idleState == false)
  {
    hallEffectState = digitalRead(hallEffectPin);

    if (hallEffectState == HIGH) {

    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    // Display static text
    display.println("*** INDISPENSABLE ***");
    display.println("---------------------");
    display.println("    TIME TO TAKE     ");
    display.println("     YOUR PILLS      ");
    display.display();


    digitalWrite(ledPinGreen,LOW);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(100);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(900);
  }

  else {

    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);

    display.clearDisplay();
    display.setCursor(0, 0);

    Serial.print("Gyroscope ");
    Serial.print("X: ");
    Serial.print(g.gyro.x, 1);
    Serial.print(" rps, ");
    Serial.print("Y: ");
    Serial.print(g.gyro.y, 1);
    Serial.print(" rps, ");
    Serial.print("Z: ");
    Serial.print(g.gyro.z, 1);
    Serial.println(" rps");

    display.println("*** INDISPENSABLE ***");
    display.print("       X: ");
    display.print(g.gyro.x, 1);
    display.println("");
    display.print("       Y: ");
    display.print(g.gyro.y, 1);
    display.println("");
    display.print("       Z: ");
    display.print(g.gyro.z, 1);

    display.display();
    delay(100);

    if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
      motorState = HIGH;
    } else {
      ledState = LOW;
      motorState = LOW;
    }

  }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPinBlue, ledState);
    digitalWrite(motor, motorState);
  }
  }

  else if (idleState == true) {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    // Display static text
    display.println("*** INDISPENSABLE ***");
    display.println("---------------------");
    display.println("    REMEMBER WHAT    ");
    display.println("    EMPOWERS YOU     ");
    display.display();

    digitalWrite(ledPinGreen,LOW);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(100);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(900);
  }

}

This sketch worked! Unfortunately, I loaded a fade sketch onto the board shortly afterward, then quickly proceeded to tear the programming pins off the board, so I was unable to record a video of the sketch and app working together.

May 16

I began modeling the pill case in Fusion 360. Rather than using the spur gear plug-in, I modeled the involute gears using this tutorial.

May 19

Neil gave an interesting lecture about exciting projects that have grown out of CBA and Fab Academy. Of particular interest to me was the cube-sat he briefly mentioned, as I am a big aerospace nerd.

May 20

While getting work done at Starbucks, my laptop battery failed. I tried a number of troubleshooting steps, but the computer would crash about five minutes after being turned on, no matter how much the battery was charged, or even if the laptop was plugged in.

May 21

Accepting defeat, I brought my laptop into a repair shop, and began searching for an alternative workstation. Luckily, my generous mother let me use her desktop PC until my laptop was repaired, so I downloaded Fusion 360 onto her desktop and was off to the races. I began by laying out the pill compartment, the drive gear / thumb wheel, the battery, and the OLED display. These are the most prominant components, and my thinking was that once I determined their position, I could fit everything else around them.

Having designed similar pill cases before (minus the electronics), I had a good understanding of the limits of how compact the pill compartments could be while maintaining their usefulness, and how large the case could be without it being too cumbersome. With these parameters in mind, I modeled the components in Fusion 360, and an enclosure that encapsulated them.

May 22

During the Global Open Time, I discussed the current state of my project, and Rico shared a great resource describing supply-side time management.

Now that the enclosure was modeled around the large components, I needed to solve the 3D puzzle of getting everything else to fit inside it. In order to do this, the first step was to create a list of all the components. Luckily, this was part of this week’s assignment, so it was time to do my homework.

What will it do?

  • Indespensable is a portable pill case to hold vital medications, remind users to take those pills, and track when the pills are taken. It is designed to replace a standard pill case, so it is assumed that the user can operate a traditional pill case independently, without assistance or intervention.

Who’s done what beforehand?

There are smart pill cases out in the world, such as Pillieve, Hero, and Pillo. Pillieve is a locking pill case designed to limit the consumption of opiods, and Pillo and Hero are counter-top, friendly pill dispenser that essentially serve as a smart medicine cabinet. While these are well designed, useful tools for their target markets, their intended use case is different from the case I have described above.

In 2016, Arsheena E.P. at Fab Lab Kochi built a pill case to remind her grandmother with Alzheimer’s to take her medication on time. In 2017, Corey Rice built a countertop pill dispenser to help his elderly grandmother take her pills on time. Finally, Jasim Bouresli at Fablab Kuwait initially planned to build a Bluetooth-connected pill box, but ended up building a Bluetooth-connected, locking jewelry box. Loes Schakenbos from Waag is currently working on an at-home pill case to sense when her pills have been taken. These FabLab projects give me confidence that my proposed project is not only technically possible, but it is achievable within the timeframe of the course.

What will you design?

  • The case itself, the circuit board inside of the case, the code that runs on the board, and the app that connects the case to a phone.

What materials and components will be used? Where will it come from? How much will they cost?

-PLA/PHA filament - $29.99 / kg

-Bearings - $0.62 / bearing

-Neodymium magnets - $0.18 magnet

-1000 mAh LiPo battery - $9.79

-Qi wireless charging receiver - $14.95

-FR1 PCB blank

-ESP32 - $5.40

-JST connectors - $12.99 / kit

-GY-521 - $5.39

-SSD1306 0.96” OLED - $6.99

-Piezo buzzer - $2.62 / buzzer

-Vibration motor - $1.17 / motor

-Hall-effect sensor

-Nylon fasteners - $11.88 / kit

What parts and systems will be made?

-Pill case enclosure

-Pill case PCBs

-Mobile app

What processes will be used?

-3D printing

-CNC milling

What questions need to be answered?

-LiPo / Qi Charging circuitry

-Triggering state change with gyroscope value

-Sending data from ESP32 to database in app

How will it be evaluated?

-Can the app change the state of the ESP32 to indicate it’s time to take pills?

-Can the sensors detect that the pills have been taken?

-Can the ESP32 send that data back to the app to let it know the pills have been taken?

-The functional component will be fairly straightforward to evaluate, but the most important, and difficult component to evaluate will be the emotional design component. I hope to consult with mentors in the emotional design and affective computing communities to better evaluate this aspect.

May 23

Now that I had all of my components itemized, I could begin fitting them inside the enclosure. I knew that this would take a long time, and I was right. I’m still not finished.

May 25

My SD card reader and M2 fasteners arrived in the mail, so I begin some test prints. The first one was to see if I could use the M2 holes in the OLED display to mount the OLED directly to the enclosure, or if I wouldn’t be able to print functional threads of that size. If the test failed, I would need to use a bracket to hold the OLED in place, and attach the bracket to the enclosure with M3 fasteners. This would be significantly more bulky, which would be sub-optimal.

The first test was a failure, but I used Fusion’s “Offset Face” feature to increase the size of the threaded hole to account for the over-extrusion of the printer. This second test was a huge success, meaning I don’t need to use a bracket to mount the OLED.

The next test print was to confirm that the gears interact properly. Each gear has two bearings attached to it, and sits on a shaft with a threaded hole through its center.

I printed out both gears, and noticed a few issues. One issue that was easy to fix was that the void to house the lower bearing was slightly too shallow, most probably due to the bridging filament sagging on top of its supports. I measured that the lower bearing is 0.4mm proud of the lower face of gear on both the small and large gear. The other issue was that the teeth don’t fully interlock. I suspect that this also has to do with the lower edge of the teeth on the large gear being printed on top of supports, which don’t do their job 100% perfectly, so the lower edge of the teeth doop, making them wider, and not fitting into the teeth of the small gear. This is also a simple fix of adjusting the width of the teeth to account for the dimensional innacuracy.

May 26

Neil’s lecture highlighted different systems for protecting intillectual property. Already disenchanted by the patent system, I was glad to hear that Neil discouraged seeking them. After the lecture, I reviewed the different types of creative commons licences. Regarding my project specifically, I would like to like to keep open the option to commericalize it, so I was interested in the Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0) license. That being said, my journey as a maker has been made possible through open-source software and hardware, and I would love to contribute to the collective knowledge base, especially with something that I feel is as essential as the product I’m developing. I can see a scenario where I continue to refine the design and manufacturing of a “flagship” model that could be commercialized, but maintain an open-source “dev kit” that could be manufactured in a home fab lab.

For Traintrackr, I have researchered trademarks to some extent, but have become nervous that I would waste money and / or essentially shoot myself in the foot by improperly discribing, or mis-charecterizing the mark. Should I commercialize the pill case, I would like to trademark the name, logo, and slogan, but I would seek professional help to do so.

May 27

During our local node check-in, I asked for some help decoding the schematic of the Adafruit Huzzah32 ESP32 development board, so I integrate its power management components into my board. We went over the datasheet, power management page, and schematic of the board. We looked at datasheets of the components, and when I had a good idea of which components did what, and which I would need to incorporate into my board, I searched for them on DigiKey. They were in stock, and I added them to my cart, but by the time I went to chack out later in the class, all of the components were out of stock.

I needed to adapt or die at this point, so I decided to move the power management circuitry to a second spiral, and focus on getting the board up and running with ana external USB power bank connected to a mini USB port in the enclosure. I would also order a Huzzah32 board so if I had time, I could desolder the power management components and solder them on to a future version of the pill case circuit board.

May 28

It was now game time. Two weeks until I would be presenting my final project. The clock was ticking. While the CAD looked relatively complete, there were still many small details missing in the enclosure, such as mounting holes, threadings, and clearances. More importantly, I had to model the screw heads and the connector terminals to make sure that components on the front and the back of the enclosure wouldn’t interfere with eachother. While there were components that had to be on the front face of the enclosure, my job was now to get as much as possible on to the main board. Not only did this cut down on the overall number of breakout boards I would need, but more importantly it would reduce the number of connectors, which are very bulky given the tight space. I moved the vibration motor and hall effect sensor to the main board, which went a long way. Unfortunately, I couldn’t mill the footprint of the MPU6050 accelerometer on the 1308, so I had to use the breakout board, but I was able to get clever and mount it behind the “feedback board” using the same mounting holes. Essentially, by overlapping in the XY plane where I had Z axis space to spare, I was able to free up some z-axis real estate where I needed it the most. This process was long, but necessary, and made it possible to move into the 2D world of PCB design without fear of creating a board with components that couldn’t fit in the enclosure.

May 30

I printed out the enclosure on Printcess, and everything almost went perfectly. As you can see in the picture below, one of the threaded holes in the posts that connect the two halves on the enclosure was too short, and inserting the screw all the way caused the post to snap in half. This was a quick fix in CAD, and the second version of the part worked perfectly.

Enclosure Files:

F3D

STL: Enclosure - Front

STL: Enclosure - Back

STL: Gear - Large

STL: Gear - Small

STL: Door

May 31

I exported a .dxf of the circuit board perimeter from Fusion, and attempted to load it into Eagle. interestingly, Eagle can only handle very rudimentary .dxf shapes for some reason, and no matter how I joined, unjoined, or chopped up the curvy shape, only bits and pieces of the board perimeter would load into Eagle. Fortunately, one of these permutations gave me enough of the shape to work with that I could accurately place all of the components, then I could just export the traces into Illustrator, where I could properly edit the perimeter vector file. Later on, I did find this tool to convert SVG files to Eagle scripts. In the future, I’ll give this a shot.

For the JST connectors linking the daughter boards to the mother board, I used JST-PH SMD connectors I purchased from Adafruit. I downloaded [this Eagle library] that contained THT and SMT footprints for vertical and horizontal connectors of a variety of sizes.

Jun 1

I created the schematic and board files, routed the airwires, exported the .dxf file into Illustrator, edited the files, and created the .png files that I will import into Mods.

I then generated a test slide and video file to serve as placeholders for my final project documentation.

Jun 2

Neil gave a great lecture, and I wish he had given it sooner. All the concepts he touched upon were familiar, but it was still goog to hear him reiterate them. The most important three were Murphy’s Law, supply-side time management, and triaging. Murphy’s Law has been all too real in the past few weeks, and I’m only in a position to finish my project because of how proactive I’ve been with my final project. Nonetheless, I’m still preparing for another problem to rear it’s ugly head, so I’m pushing along to make sure I have time to spare. To account for the other two, I’ll make a list of things I have left to do and a schedule to make sure I have time to get everything done, and cut out what I don’t have time for.

To Do:

Enclosure

  • reduce tolerances on bearing mating surfaces and pill door

  • OLED screen cover

    • design screen cover
    • design mold
    • mill mold
    • injection mold part
    • adjust enclosure design to accomodate screen cover
  • reprint enclosure in Goo PLA/PHA

PCB

  • power management circuit
    • redesign main board with power management components and connectors
    • mill main board

Code

  • incorporate buzzer

  • remove delays from LED fade

  • adjust hall effect sensor threshold

  • improve OLED code

  • incorporate gyroscope

    • read data
    • pass threshold
    • return to idle state
    • send data to app

App

  • incorporate alarm clock

  • include logo and color scheme

Schedule:

Wednesday 6/2

  • ~~Process board files in Illustrator~~

  • ~~Generate g-code files in Mods~~

  • ~~Mill boards on 3018~~

Thursday 6/3

  • ~~Solder boards~~

Friday 6/4

  • ~~Attach JST connectors to boards~~

Saturday 6/5

  • Load code on to board

  • Incorporate alarm clock in to app

Sunday 6/6

  • Incorporate gyroscope data

    • film process
  • Design screen cover

    • film process
  • Program tool paths

    • film process

Monday 6/7

  • Mill OLED screen cover mold

    • film process
  • Injection mold screen cover

    • film process
  • Begin editing footage

    • identify gaps

Tuesday 6/8

  • Integrate power management circuitry

    • re-design circuit board

    • post-process in Illustrator

    • generate g-code in Mods

    • mill board on 3018

    • solder components

    • reprint enclosure

    • film full process

Wednesday 6/9

  • Finish integrating power management circuitry

  • Assemble enclosure

    • film process
  • Continue editing project video

  • Make project slide

Thursday 6/10

  • Film project functioning

  • Finish editing project video

  • Deep breaths

Friday 6/11

  • Present project video

  • Drink champagne

I designed the “feedback” breakout board in Eagle, and generated the “traces” and “perimeter” files in Illustrator.

Eagle Schematic File

Eagle Board File

I sent these to Mods and generated the .nc files to send to the 3018. I downloaded Universal G-Code Sender onto my Raspberry Pi 3B+. It ran as I would expect, except for the fact that it didn’t display the g-code visualizer window. It appears as though something changed in Mods, becasue the units were now in mm/s rather than mm/min, which caused me to break two 0.8 mm bits before I realized what was going on. Once I figured this out, I was able to mill out my main board without issue.

Jun 3

Our local node meeting went well, but I was unable to go in person. We talked about triaging and supply-side time management. Greg suggested that of the spirals I could follow once I get everything integrated, I should focus on the power management circuitry and triage the injection-molded screen protector.

After class, I milled the feedback board as well, and began soldering the boards. As I was attempting to film myself soldering, I realized that filming does cause each step of the process to take longer, and I need to adjust my schedule accordingly. I also need to maake a storyboard of my video so I can be sure to get all the footage I need.

Storyboard

-Title slide

  • CAD

  • ECAD

  • Coding

  • 3D Printing

  • PCB milling

  • Soldering

  • Flashing

  • Assembly

Jun 4

Finally seeing the board populated and integrated into the enclosure was truly a sight for sore eyes.

I spent a good portion of the day wrestling with crimping connectors to attach the breakout boards to the main board. I eventually realized that the crimping tool wasn’t the right one for the job, and I was close to giving up and soldering the boards directly by wires, but eventually I realized that I was also initally positioning the connectors incorrectly, and I was able to position them properly and get the tool to do the job well enough that the wires would fit in the connectors.

Jun 5

I talked during the Global Open Time with Neil, who basically recommended that I scrap all new features, and just get what I have in front of me functioning, integrated, and documented. I swallowed my pride, and scrapped the OLED protector and power management circuitry.

This is where seemingly everything went wrong. My beautiful board didn’t program. Continuity and voltage tests with the multimeter indicated that everything should be functioning properly, but the board wouldn’t flash. At one point, I fried the ESP32, and resoldered a new one on to the board, but it still wouldn’t program.

Jun 6

I made slight modifications to the board design, adding back the reset button that I had figured I could remove, because I had been able to program the board with only the flash button in the past. This second board would program, but none of the I2C devices would function properly. I could get the motor to buzz, but that was it. The LED on the IMU module was lit, so I knew it was recieving power, and there was continuity through the JST connectors. Thoroughly frustrated, panic began to sink in.

Jun 7

I finally got the files from my crashed laptop back, and I milled out the last board that I had made that had worked without a hitch (see Week 12 documentation). While I had the .png files to mill this board during the “dark ages,” I didn’t have the Eagle files, so I re-designed the two previous failed boards from scratch. Once I got this Week 12 board up and running, I at least felt like I wasn’t going crazy, and I had a new starting point to get a functional board in the right form-factor.

Jun 8

I tried to slightly modify my Week 12 board, keeping the pinout but re-routing all of the wires and adding the SMD JST connectors. This was a mistake, and I had the exact same issue as my second failed board. I had no idea what was causing these issues, and I still don’t. I don’t think it was an issue with the JST connectors, because there was continuity across them, but I should have stopped, desoldered the connectors, and attempted to just solder the wires straight to the board to test this once and for all.

I now had a nice collection of failed boards.

Jun 9

I took another step backwards, basically altering nothing about my Week 12 board except for replacing the RGB LED and piezo buzzer with a FTDI connector with corresponding pads, moving the location of the Hall effect sensor and the vibration motor, and changing the perimeter of the board to fit the enclosure. I even went as far (not far) to not move the location of the USB port, which meant I would have to cut a hole into the side of the enclosure to plug it in, but at this point, this is what had to be done. I simply didn’t have the time to assume that that change wouldn’t make a difference.

Eagle Schematic File

Eagle Board File

The fourth time was the charm. I loaded the following code onto the board, and all of the components functioned properly.

#include "BluetoothSerial.h"
#include <Adafruit_MPU6050.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>

Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

const int hallEffectPin = 25;
const int ledPinGreen = 26;
const int ledPinBlue = 27;
const int motor = 12;
int hallEffectState = 0;
int ledState = LOW;
int motorState = HIGH;

unsigned long previousMillis = 0;
const long interval = 500;

char Incoming_value = 0;
bool idleState = true;

BluetoothSerial SerialBT;

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

void setup() {
  // put your setup code here, to run once:

  pinMode(ledPinGreen, OUTPUT);
  pinMode(ledPinBlue, OUTPUT);
  pinMode(hallEffectPin, INPUT_PULLUP);
  pinMode(motor, OUTPUT);

  Serial.begin(115200);
  SerialBT.begin("Indispensable"); //Bluetooth device name
  Serial.println("Indispensable Pill Case");
  Serial.println("Remember What Empowers You");
  Serial.println("The device started, now you can pair it with bluetooth!");

  if (!mpu.begin()) {
    Serial.println("Sensor init failed");
    while (1)
      yield();
  }
  Serial.println("Found a MPU-6050 sensor");

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever

}
}

void loop() {
  // put your main code here, to run repeatedly:
  if(SerialBT.available() > 0)  
  {
    Incoming_value = SerialBT.read();      
    Serial.print(Incoming_value);        
    Serial.print("\n");        
    if(Incoming_value == '0')             
      idleState = true;  
    else if(Incoming_value == '1')       
      idleState = false;  
  }               

  unsigned long currentMillis = millis();

  if(idleState == false)
  {
    hallEffectState = digitalRead(hallEffectPin);

    if (hallEffectState == HIGH) {

    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    // Display static text
    display.println("*** INDISPENSABLE ***");
    display.println("---------------------");
    display.println("                     ");
    display.println("    TIME TO TAKE     ");
    display.println("     YOUR PILLS      ");
    display.display();


    digitalWrite(ledPinGreen,LOW);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(100);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(900);
  }

  else {

    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);

    display.clearDisplay();
    display.setCursor(0, 0);

    Serial.print("Gyroscope ");
    Serial.print("X: ");
    Serial.print(g.gyro.x, 1);
    Serial.print(" rps, ");
    Serial.print("Y: ");
    Serial.print(g.gyro.y, 1);
    Serial.print(" rps, ");
    Serial.print("Z: ");
    Serial.print(g.gyro.z, 1);
    Serial.println(" rps");

    display.println("*** INDISPENSABLE ***");
    display.println("---------------------");
    display.print("       X: ");
    display.print(g.gyro.x, 1);
    display.println("");
    display.print("       Y: ");
    display.print(g.gyro.y, 1);
    display.println("");
    display.print("       Z: ");
    display.print(g.gyro.z, 1);

    display.display();
    delay(100);

    if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
      motorState = HIGH;
    } else {
      ledState = LOW;
      motorState = LOW;
    }

  }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPinBlue, ledState);
    digitalWrite(motor, motorState);
  }
  }

  else if (idleState == true) {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    // Display static text
    display.println("*** INDISPENSABLE ***");
    display.println("---------------------");
    display.println("                     ");
    display.println("    REMEMBER WHAT    ");
    display.println("    EMPOWERS YOU     ");
    display.display();

    digitalWrite(ledPinGreen,LOW);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(100);
    digitalWrite(ledPinGreen,HIGH);
    digitalWrite(ledPinBlue,HIGH);
    digitalWrite(motor, LOW);
    delay(900);
  }

}

I felt dirty cutting into the enclosure, but I used a fine-tooth x-acto saw and diamond files, so it was about as precise as I could get it without re-printing the enclosure to account for the new board layout. I integrated all of the components into the enclosure, filming as I went.

As a finishing touch, I applied one of the vinyl decals I created in Week 3 to the back of the enclosure. And with that, all that was left to do was make the slide and edit the video.

Jun 10

I downloaded KdenLive, which I found fairly intuitive to use. I brought all of the clips into the software, chopped them up, and added some slides I made in Adobe Illustrator. And with that, my project was ready to present.


Last update: July 9, 2021