Introduction: Quality of Life Meter

[Note: The Mk.2 is live!]
Harsh new rules at work getting you down? Overtime sucking the life out of you? Or maybe things are great, either way now you can show your co-workers and management exactly how you feel about your job without a single meeting, memo, or team bonding exercise. This is the Quality of Life Meter. Boss take credit for your hard work? Turn it down. Get a bigger bonus than expected? Turn it up.

There is no exact formula for the Quality of Life Meter, the whole idea is that it's a personal thing. That being said on my project we use it as a measure of the groups level. Things like taking a day off, long weekends, cancelled meetings, and getting critical data on time make the meter go up while overtime, useless meetings, server crashes, and management trying to dictate our quality of life make it go down. It's kind of a gut thing and you'll have to decide for your self exactly what factors into moving your meter.

I won't bore you with the story of how this came about but I will be clear that in my work place this is clearly a joke and everyone knows it. If you just show up with this one day and set it low feelings may be hurt and people may take it personally. I'm not saying I'm against using this as a tool to vent your frustrations but just make sure your intentions are clear, joke or otherwise.

Of course Quality of Life isn't the only thing you can use this for, that's the biggest reason there isn't a label directly on the box (at work there is a sign over it but there's a strict no photo rule so I can't show it). It could jazz up a fundraiser, track your exercise, or help you save up for a trip. The Arduino that powers my design is far from working at capacity so there is the possibility for expanding the meter by adding sensors that can directly control the output value or adding WiFi or Bluetooth connectivity allowing your phone or computer to influence the output.

As always, feel free to ask any questions in the comments or via PM and if you make one, or a variation, I love to see pictures.

Step 1: Materials & Tools

Materials
  • Small Glass/Plastic Pane - Any material that is clear and stiff will work. Glass or plexiglass are the most obvious solutions.
  • Sheet Wood - The type of wood is mostly irrelevant as is the thickness, although I wouldn't go much thinner than 3/8" or 1/4". I used some 3/4" strips that were packed with some toe kicks from IKEA.
  • Cardboard/Plastic Sheet - Any thin, presentable looking material will work, even sheet metals.
  • Small Knob - This needs to fit your pot and be long enough to make it through the wall of your enclosure. In my build I improvised and used an internally threaded spacer as a knob.
  • Screws - Small screws to attach the back sheet to the wood enclosure.
  • Frosting Spray Paint; ($4, Lowes) - If you can find a pre-frosted pane then this is unnecessary.
  • Regular Spray Paint - I used the same color for the enclosure as well as for the blackout on the pane.
  • Wood Filler - When working with particle board (of all varieties) or ply woods using wood filler on the cut edges helps give a uniform texture and look after painting.
  • Wood Glue - Holds it all together.
Circuit Kit
  • 2x Small Perfboards
  • 1x Arduino Uno
  • 1x 6xAA Battery Holder
  • 12x 220 Ohm Resistors
  • 1x Red Blinking LED
  • 3x Red LEDs
  • 4x Yellow LEDs
  • 3x Green LEDs
  • 1x Green Blinking LED
  • 2x 74HC595 Shift Registers
  • 2x 16 pin IC Sockets
  • 1x SPST Switch
  • 1x Potentiometer - I honestly don't know the size I used as mine was salvaged. It just needs to have even output across a range of 0-3V.
  • Wires
  • Batteries
Tools
  • Table or Circular Saw - A table saw is best but you can make due with a circular or even a hand saw if one isn't readily available.
  • Sandpaper
  • Clamps
  • Masking Tape
  • Soldering Equipment
  • Drill & Bits
  • Utility Knife / Scissors

Step 2: Circuit Design

The circuit is relatively straight forward even though the circuit diagram looks pretty messy, there are a lot of connections. Initially I was trying for a 2x6 multiplexed array using a single 595 chip. This turned out to be very hard to program and it may be impossible as I tried several things that I really felt should have worked, at least partially, but got zero results. It worked fine on LEDS 2-11 but the issues start cropping up when you try and integrate flashing LEDs into the circuit. Physical flashing LEDs, like I utilize in the current circuit, don't work because the current is cycling on/off and the LED never has time to get to the off phase, making them stay on constantly. Software solutions designed to make a standard LED flash resulted in similar abject failures. If anyone can whip together a working proof of concept I'd be very interested to see it. After several frustrating weeks spent bug hunting, troubleshooting, and reconfiguring I realized I had a second 595 so I moved to a new circuit with the two 595's daisy chained to get the required number of outputs.

The 74HC595's are serial-in-parallel-out shift registers. This means you can use three pins on your microcontroller to send the bytes of data serially (one bit after another) to the 595 which then applies each bit to different output pins and then outputs those bits in parallel (all at once). When you daisy chain 595's you can now send two bytes of data and the first 595 then passes the first byte onto the second 595 and they both execute all 16 bits at once.

*Enough faffing about though, lets break down this circuit. Starting with the Arduino, we are using 3 digital pins to control the 595's. Pin 8 is the latch pin which holds the outputs steady while you write new data and is attached to pin 5 on both 595's. Pin 11 is used to transmit the serial data and is attached to pin 3 on the FIRST 595 ONLY. Pin 12 is the clock which pulses to send each bit and it's attached to pin 6 on both 595's.
The 5V output pin is attached to pins 1 and 7 on both 595's. The GND pin grounds all five "chunks" of the circuit.

*The potentiometer takes 3.3V from the Arduino and runs back to the Arduino ground. The sweep, or output, is connected to the first analog pin on the Arduino, A0. I don't know the value of the pot as it's a salvage but it is pretty small in size and made out of plastic so it can't be anything crazy.

*The power source is 6 AA batteries, providing ~9V, in a holder that uses a 9V battery clip as leads. The positive terminals pass through a push button SPST to the Vin pin on the Arduino. The plan is to use rechargeable batteries to cut running costs.

*On the 595's the pins I haven't addressed are 3, 4, 8, and the outputs. Pin 3 on #1 connects to the Arduino, as discussed above, but on #2 it ties to pin 8 on the first 595. Pin 8 is left unconnected on #2. On both 595's pin 4 connects to GND. The outputs, labeled as Q's, are pretty straight forward. starting with Q0 on #1 and the red flashing LED and ending with the green flashing LED attached to Q3 on #2.

*The LED array is simply a parallel array, one LED and resistor per row. All the resistors tie to the common ground. The size of the resistor needed depends on the specs of your specific LEDs. Use R = V / I, where R is the size of resistor needed, V is the voltage passing through the LED (5V if you use Arduino), and I is the acceptable current for the LEDs. 220 Ohm resistors will work well for most standard 5mm LEDs.

Step 3: Enclosure Design

The enclosure is a simple wooden "picture frame" with a glass/plastic face and a cardboard back. The size of the enclosure was determined by the glass pane I found and the depth was set by the width of the scrap wood  was making it with. The window is held in place by a groove cut into the frame and the backing is simply screwed into place.

To create the thermometer outline I simply scaled free a clip art picture to fit on the window. Before you start finalizing your circuit and soldering it into place you need to know the final size of the image so that you can get the spacing of the LEDs correct.

Step 4: Firmware

The code executes in three general steps: 1) Read in and divide up the pot position, 2) Decide what to display, 3) Output the proper command to the 595's.

Step 1 is contained in it's own user defined function. First you read in the analog pin attached to the potentiometer. This will result in a reading between 0-682 (remember we're on 3.3V, not 5). Next we want to return a value 0-11, representing the 11 segments on our thermometer, to the main program. To do this you perform an integer on the input using the size of one segment, 62 (682/11 = 62). The use of integer division, which uses only whole numbers, is not a mistake, it allows the function to return a whole number without taking the extra step of rounding the result with another line of code.

Once you output the segment that the pot is indicating the code needs to correlate that number to the binary sequence that will light up the appropriate LEDs. The decimal values that convert to the proper binary strings to control the 595's are stored in an array where their position in the array conveniently is the same as the output from the pot.

The final step is to push the commands to 595's. The order of operations is to deactivate the latch pin, preventing the LEDs from changing while the new commands are written, use the shift out command to send the binary strings through the data pin, which uses the clock pin to differentiate bits, and finally reactivate the latch pin to output the new data across all the pins simultaneously.

//LED TEST 2 w/ 74HC595
//by Bwrussell 2013
//https://www.instructables.com/id/Quality-of-Life-Meter/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

//74HC595-Arduino Interface Pin Definitions
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
//Pin connected to DS of 74HC595
int dataPin = 11;
//Pin connected to the sweep pin of the pot
#define potPin A5

//arrays that hold the LED states for each pot position, one for each 595
int ledStatesA[] = {1,2,6,14,30,62,126,254,254,254,254,254};
int ledStatesB[] = {0,0,0,0,0,0,0,0,1,3,7,15};

//Variable Defs
int knobPosition;

void setup() {
  //Start Serial for debuging purposes	
  Serial.begin(9600);
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

}

void loop(){
  knobPosition = potRead();
  
  digitalWrite(latchPin, 0);
  //send data to the second 595 (8-11)
  shiftOut(dataPin, clockPin, ledStatesB[knobPosition]); 
  //cosend data to the first 595 (0-7)
  shiftOut(dataPin, clockPin, ledStatesA[knobPosition]);
  //return the latch pin high to signal chip that it 
  //no longer needs to listen for information
  digitalWrite(latchPin, 1);
}

void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first, 
  //on the rising edge of the clock,
  //clock idles low

//internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

 //clear everything out just in case to
 //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);


  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);


    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {	
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

// Function for reading and segmanting the pot input
int potRead () {
  int potRaw = 0;
  //read in the raw pot position, averaging over 5 samples
  for (int i=0; i<5; i++){
    potRaw = potRaw + analogRead(potPin);
  }
  potRaw = potRaw/5;
  //segment the raw data into 12 equal segmants, returns a value 0-11
  int potPosition = potRaw / 60; //Use 60 for 3.3V, 93 for 5V across the pot
  //send the current segment to the main loop
  return potPosition ;
}


The source code is available in the .zip file (the .ino wouldn't upload) and a plain text file.

Just a quick plug: In some of the initial testing I used the fairly new ArduinoDroid app for Android. It's pretty awesome for what it is. It allows you to write Arduino code, with color coding and compiling, anywhere, like on lunch break at work. With a proper USB cable you can also power and upload to an Arduino board. There are some other features I haven't used yet like Bluetooth control and such but for a maker on the go or field work this app is phenomenal. I would highly recommend it especially since it is completely free (ad supported) and unrestricted. If you like it then you can pay a nominal fee to remove the ads and support development. I don't know who the developer is but they rock.

Step 5: Build the LED Array

If you're a little unsure about how the circuit goes together or are thinking about making modifications I would strongly suggest mocking the circuit up with breadboards before you make anything semi-permanent. This goes for testing and changing the program a well. There is a bit of soldering and it's easy to get lost when you're flipping the perfboard back and forth and accidentally go to the wrong pin so knowing your way around the circuit is helpful.

I started by placing the resistors since they are on the edge and it sets the spacing for the LEDs. The ground legs of the resistors are all tied to gather. Then solder the LEDs next to the resistors. The sockets for the 595's are placed near the LEDs that they will control. I haven't worked much with PC board and I didn't leave myself very much room. If you have some ribbon cable that would work here I would recommend it. If I were to start over that's what I would use. Before connecting everything together I added long flexible leads, with Arduino header compatible pins,  to the board as tie in nodes for GND and +5V. With everything in place follow the circuit diagram and wire up all the 595 connections. Take care when flipping between the back and the front of the PCB. I'd made a couple of connections when I started before I noticed that I'd shifted the pins and had to desolder and start over. The leads for the data, clock, and latch pins should be long and have Arduino header compatible ends.

With the LED circuit complete, decide if the pot and switch can be wired now. If they need to be fit into the enclosure from the outside then you'll probably have to wait until they can be secured in the enclosure to wire them in. If not, attach Arduino leads to the pot and wire the switch to the battery pack. You may need to attach different leads to the switch and power pack to make them Arduino compatible. I was able to add leads to the pot but had to wait to add the switch.

When you're done make sure to test again before moving on.

Step 6: Enclosure Build

Measure and cut the walls for your enclosure. Remember you'll need overlap on the edges and the inside dimensions of the assembled enclosure needs to be smaller than the size of the window you're using.

I used a table saw to create the groove that holds the window. Simply lower the blade until it's ~.125" above the table. Set the fence ~.25" from the blade and run each piece through. If you don't have a table saw with a little setup you should be able to cut the groove with a handheld circular saw or even a hand saw.

At this point you need to have a switch, pot and knob picked out so you can prep the enclosure for them. Taking into account where the walls will overlap when assembled, something that nearly bit me, drill holes appropriate for your components. If your walls are thicker than the threads on any panel mounted components then you will need to counterbore the back side of the hole to allow room for either the body or the nut, depending on which way the component mounts to the panel.

Before painting any type of particle board I like to cover the cut faces that will see paint with a wood filler. If you don't do this then those faces will absorb the paint better than the uncut faces and you will struggle to get a uniform. look. Just cover each surface with the filler, let it dry, then sand it smooth. I also used the filler to block the ends of the window groove that were exposed on the two side walls. When the edges are prepped, prime and paint.

Step 7: Window Painting

The idea here is to have the LEDs shine through individual segments in a thermometer shape painted on the window. I didn't want the bare LEDs visible so I started with a layer of frosting to diffuse the light and then covered everything but the segments with a dark, solid color.

Start by cleaning the glass thoroughly and then spray on a couple coats of the glass frosting paint and allow it to dry.
You should already have a template of the thermometer shape that you used to space the LEDs on your circuit board. Using this template cut out a matching template in cardboard. This will act as your mask for painting the outline. Place the mask in the middle of the window and use a couple of small clamps to hold it in place. Lay down a few coats of the dark paint, over the frosting. When the paint is dry carefully remove the mask.

Using masking tape block out the areas you want the light to shine through, leaving strips between each segment. These segments should align with the LEDs on your circuit board. When all the segments are masked apply a couple more coats of the dark paint. This will give you lines between your segments and a place to attach the dividers.

Step 8: Light Dividers

To keep the light from adjacent LEDs from spilling into the wrong segments we are going to need some sort of divider between the LEDs. I used some stiff, thin cardboard which I bent and cut into shape around the circuit board and hot glued into place, to the glass. I painted them but that probably isn't necessary if they are a solid white/grey/beige/black color. You will need to surround the entire thermometer shape and have dividers for each segment.

In addition I made a back plate out of the same cardboard. I put a crease in the middle, horizontally, so that you only have to remove half of the screws to access the battery pack.

Step 9: Assembly

Time to our components into a contraption.

First, put together three of the enclosures sides. The top, bottom, and edge with the switch and pot are probably your best bet. The walls are simply wood glued together. The easiest way to get everything lined up is to put glue on the two edges you're glueing and then clamp everything together, all four walls and the glass pane. When the glue dries you can remove the unglued edge and start loading components.

The Arduino is screwed to the wall with the switch, near the top. I used velcro to patches to attach the battery box to the back side of the glass pane. A little super glue holds the patches in place nicely. The final major component is the all important circuit board. In a bit of a jury rig I used some Gorilla Tape to secure the circuit in place. It looks a little shoddy but it isn't going anywhere and it allows for easy access if you need to take the circuit off for any reason.

With everything in place make the final connections in the circuit, probably: battery to switch and ground, switch to Arduino, the pot to 3.3V, GND, and A5, and the five circuit board leads (5V, GND, 8, 11, & 12) to the Arduino. With everything connected make sure to test the circuit before buttoning everything up.

If it's all in working order then glue the final wall in place and screw the back plate in place.

Step 10: Display

Put it somewhere the concerned parties can see it and make sure you label it properly. Just be warned, something you start as just a joke may take on more life than you ever imagined, management has a way of doing that.


I've completed the Mk.2 Quality of Life Meter which now features multiple users, wireless capabilities, and data logging. Check it out!