D20 RGB Lamp Writeup

I recently created a D20 RGB Lamp using my 3D printer, and Arduino, and RGB LED lights.  Demonstration below

 

Menu Flow Diagram:

 

Parts List:

Parts:
Arduino – https://www.sparkfun.com/products/11113
LEDs (x5) – https://www.sparkfun.com/products/13282
Power Supply – https://www.sparkfun.com/products/12889
Barrel Jack – https://www.sparkfun.com/products/10785
Push buttons (similar, x2) – https://www.sparkfun.com/products/9190
D20 Translucent – http://amzn.to/2hLp1iy

3D Files – https://www.thingiverse.com/thing:2010875

 

Code:

Requires Neopixel libraries, move from the zipped libraries folder to your Arduino Libraries folder.  Code was created for 5 LED’s and the following hookup-

Data Out (from Arduino) – Pin 3

SW1 (internal pullup used, connect one side to ground) – Pin 4

SW2 (internal pullup used, connect one side to ground) – Pin 5

D20 Lamp Code

/* SparkFun WS2812 Breakout Board Example
SparkFun Electronics
date: July 25, 2013
license: GNU GENERAL PUBLIC LICENSE
Requires the Adafruit NeoPixel library. It’s awesome, go get it.
https://github.com/adafruit/Adafruit_NeoPixel
This simple example code runs three sets of animations on a group of WS2812
breakout boards. The more boards you link up, the better these animations
will look.
For help linking WS2812 breakouts, checkout our hookup guide:
https://learn.sparkfun.com/tutorials/ws2812-breakout-hookup-guide
Before uploading the code, make sure you adjust the two defines at the
top of this sketch: PIN and LED_COUNT. Pin should be the Arduino pin
you’ve got connected to the first pixel’s DIN pin. By default it’s
set to Arduino pin 4. LED_COUNT should be the number of breakout boards
you have linked up.
*/
#include <Adafruit_NeoPixel.h>
#include “WS2812_Definitions.h”
#define LED_DATA 3
#define LED_COUNT 5
#define POT1 A0
#define POT2 A1
#define SW1 4
#define SW2 5
#define MENURUN 0
#define MENUBRIGHTNESS 1
#define MENUANIMATION 2
#define MENUANIMATIONCOLOR 3
#define MENUSTOP 4
#define RAINBOW 0
#define RACE 1
#define FULLFADE 2
#define FADE 3
#define RAINBOWFADE 4
#define LIGHT 1
#define DARK 0
#define MAXBRIGHTNESS 250
#define DEBOUNCEMAX 150
#define delaySpeedMax 750
unsigned char menuState = MENURUN;
unsigned char brightness = 125;
unsigned int menuButtonDebounceTime = DEBOUNCEMAX;
unsigned char menuButtonPressed = 0;
unsigned char menuButton = 0;
unsigned int menuSelectDebounceTime = DEBOUNCEMAX;
unsigned char menuSelectPressed = 0;
unsigned char menuSelect = 0;
unsigned char rainbowCounter = 0;
unsigned int delaySpeed = 150;
unsigned int delaySpeedCounter = delaySpeed;
unsigned char animationMode = RAINBOW;
unsigned long animationColor = RED;
unsigned char fadeBrightness = 0;
unsigned char fadeDirection = LIGHT;
unsigned char rainbowMode = 0;
unsigned long internalColor = RED;
unsigned int theaterJ = 0;
unsigned int theaterQ = 0;
unsigned char theaterON = 0;
// Create an instance of the Adafruit_NeoPixel class called “leds”.
// That’ll be what we refer to from here on…
Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_COUNT, LED_DATA, NEO_GRB + NEO_KHZ800);
void setup()
{
//pinMode(POT1, INPUT);
//pinMode(POT2, INPUT);
pinMode(SW1, INPUT);
digitalWrite(SW1, HIGH);
pinMode(SW2, INPUT);
digitalWrite(SW2, HIGH);
leds.begin(); // Call this to start up the LED strip.
clearLEDs(); // This function, defined below, turns all LEDs off…
leds.show(); // …but the LEDs don’t actually update until you call this.
randomSeed(analogRead(0));
animationColor = getRandomColor(0);
}
void loop()
{
unsigned int addedDelay = 0;
//unsigned int brightness = analogRead(POT1);
//unsigned int delaySpeed = analogRead(POT2);
if (!digitalRead(SW1)) {
if (menuButtonDebounceTime)
menuButtonDebounceTime–;
else {
if (!menuButtonPressed) {
menuButtonPressed = 1;
menuButton = 1;
}
else
menuButton = 0;
}
}
else {
if (menuButtonDebounceTime < DEBOUNCEMAX)
menuButtonDebounceTime++;
else
menuButtonPressed = 0;
}
if (!digitalRead(SW2)) {
if (menuSelectDebounceTime)
menuSelectDebounceTime–;
else {
if (!menuSelectPressed) {
menuSelectPressed = 1;
menuSelect = 1;
}
else
menuSelect = 0;
}
}
else {
if (menuSelectDebounceTime < DEBOUNCEMAX)
menuSelectDebounceTime++;
else
menuSelectPressed = 0;
}
if (menuButton) {
if (menuState < 4)
menuState++;
else
menuState = 0;
clearLEDs(); // This function, defined below, turns all LEDs off…
rainbowCounter = 0;
internalColor = animationColor;
rainbowMode = 0;
fadeBrightness = 0;
fadeDirection = LIGHT;
theaterJ = 0;
theaterQ = 0;
theaterON = 0;
}
switch (menuState) {
case MENURUN:
// Ride the Rainbow Road
if (menuSelect) {
if (delaySpeed < delaySpeedMax)
delaySpeed += 50;
else
delaySpeed = 50;
}
if ((animationMode == RAINBOW) || (animationMode == RACE))
addedDelay = 100;
else
addedDelay = 0;
if (delaySpeedCounter)
delaySpeedCounter–;
else {
delaySpeedCounter = delaySpeed + addedDelay;
switch (animationMode) {
case RAINBOW:
doRainbow();
break;
case RACE:
rainbowMode = 1;
doRace();
break;
case FULLFADE:
//rainbowMode = 1;
theaterChaseRainbow();
break;
case FADE:
doFade();
break;
case RAINBOWFADE:
rainbowMode = 1;
doFade();
break;
default:
break;
}
}
//delay(100); // Delay between rainbow slides
break;
case MENUBRIGHTNESS:
if (menuSelect) {
if (brightness < MAXBRIGHTNESS)
brightness += 25;
else
brightness = 25;
}
leds.setBrightness(brightness);
leds.setPixelColor(0, BLUE);
leds.setPixelColor(1, RED);
leds.setPixelColor(2, GREEN);
leds.setPixelColor(3, PURPLE);
leds.setPixelColor(4, WHITE);
break;
case MENUANIMATION:
if (menuSelect) {
if (animationMode < 4)
animationMode++;
else
animationMode = 0;
if (animationMode == 2 || animationMode == 4)
rainbowMode = 1;
else
rainbowMode = 0;
}
clearLEDs();
leds.setPixelColor(animationMode, RED);
break;
case MENUANIMATIONCOLOR:
if (menuSelect) {
animationColor = getRandomColor(animationColor);
}
leds.setPixelColor(0, GREEN);
leds.setPixelColor(1, animationColor);
break;
case MENUSTOP:
//leds.setPixelColor(0, PURPLE);
break;
default:
menuState = MENUSTOP;
break;
}
leds.show(); // …but the LEDs don’t actually update until you call this.
/*
// Indigo cylon
// Do a cylon (larson scanner) cycle 10 times
for (int i=0; i<10; i++)
{
// cylon function: first param is color, second is time (in ms) between cycles
cylon(INDIGO, 500); // Indigo cylon eye!
}
*/
/*
// A light shower of spring green rain
// This will run the cascade from top->bottom 20 times
for (int i=0; i<20; i++)
{
// First parameter is the color, second is direction, third is ms between falls
cascade(MEDIUMSPRINGGREEN, TOP_DOWN, 100);
}
*/
}
void doRainbow() {
if (rainbowCounter < 10 * 5)
rainbowCounter++;
else
rainbowCounter = 0;
rainbow(rainbowCounter);
}
void doRace() {
if (rainbowCounter < 4)
rainbowCounter++;
else {
if (rainbowMode)
internalColor = getRandomColor(internalColor);
else
internalColor = animationColor;
rainbowCounter = 0;
}
race(internalColor, rainbowCounter);
}
void doFade() {
unsigned char brightStep = brightness / 25;
if (fadeDirection == LIGHT) {
if (fadeBrightness < brightness – brightStep)
fadeBrightness += brightStep;
else {
fadeBrightness = brightness;
fadeDirection = DARK;
}
}
else {
if (fadeBrightness > brightStep)
fadeBrightness -= brightStep;
else {
fadeBrightness = 0;
fadeDirection = LIGHT;
if (rainbowMode)
internalColor = getRandomColor(internalColor);
else
internalColor = animationColor;
}
}
leds.setPixelColor(0, internalColor);
leds.setPixelColor(1, internalColor);
leds.setPixelColor(2, internalColor);
leds.setPixelColor(3, internalColor);
leds.setPixelColor(4, internalColor);
leds.setBrightness(fadeBrightness);
}
void race (unsigned long color, unsigned char pixel) {
byte red = (color & 0xFF0000) >> 16;
byte green = (color & 0x00FF00) >> 8;
byte blue = (color & 0x0000FF);
clearLEDs();
leds.setPixelColor(pixel, red, green, blue);
}
// Sets all LEDs to off, but DOES NOT update the display;
// call leds.show() to actually turn them off after this.
void clearLEDs()
{
for (int i = 0; i < LED_COUNT; i++)
{
leds.setPixelColor(i, 0);
}
}
// Prints a rainbow on the ENTIRE LED strip.
// The rainbow begins at a specified position.
// ROY G BIV!
void rainbow(byte startPosition)
{
// Need to scale our rainbow. We want a variety of colors, even if there
// are just 10 or so pixels.
int rainbowScale = 192 / LED_COUNT;
// Next we setup each pixel with the right color
for (int i = 0; i < LED_COUNT; i++)
{
// There are 192 total colors we can get out of the rainbowOrder function.
// It’ll return a color between red->orange->green->…->violet for 0-191.
leds.setPixelColor(i, rainbowOrder((rainbowScale * (i + startPosition)) % 192));
}
// Finally, actually turn the LEDs on:
//leds.show();
}
// Input a value 0 to 191 to get a color value.
// The colors are a transition red->yellow->green->aqua->blue->fuchsia->red…
// Adapted from Wheel function in the Adafruit_NeoPixel library example sketch
uint32_t rainbowOrder(byte position)
{
// 6 total zones of color change:
if (position < 31) // Red -> Yellow (Red = FF, blue = 0, green goes 00-FF)
{
return leds.Color(0xFF, position * 8, 0);
}
else if (position < 63) // Yellow -> Green (Green = FF, blue = 0, red goes FF->00)
{
position -= 31;
return leds.Color(0xFF – position * 8, 0xFF, 0);
}
else if (position < 95) // Green->Aqua (Green = FF, red = 0, blue goes 00->FF)
{
position -= 63;
return leds.Color(0, 0xFF, position * 8);
}
else if (position < 127) // Aqua->Blue (Blue = FF, red = 0, green goes FF->00)
{
position -= 95;
return leds.Color(0, 0xFF – position * 8, 0xFF);
}
else if (position < 159) // Blue->Fuchsia (Blue = FF, green = 0, red goes 00->FF)
{
position -= 127;
return leds.Color(position * 8, 0, 0xFF);
}
else //160 <position< 191 Fuchsia->Red (Red = FF, green = 0, blue goes FF->00)
{
position -= 159;
return leds.Color(0xFF, 0x00, 0xFF – position * 8);
}
}
uint32_t getRandomColor(uint32_t oldColor) {
uint32_t tempColor = oldColor;
tempColor = Wheel(random(255));
while (tempColor == oldColor) {
tempColor = Wheel(random(255));
}
return tempColor;
}
//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow() {
if (theaterON) {
//leds.setPixelColor(0, 0); //turn every third pixel off
//leds.setPixelColor(2, 0); //turn every third pixel off
//leds.setPixelColor(4, 0); //turn every third pixel off
leds.setPixelColor(1, Wheel( (1 + theaterJ) % 255)); //turn every third pixel on
leds.setPixelColor(3, Wheel( (3 + theaterJ) % 255)); //turn every third pixel on
theaterON = 0;
}
else {
//leds.setPixelColor(1, 0); //turn every third pixel off
//leds.setPixelColor(3, 0); //turn every third pixel off
leds.setPixelColor(0, Wheel( (0 + theaterJ) % 255)); //turn every third pixel on
leds.setPixelColor(2, Wheel( (2 + theaterJ) % 255)); //turn every third pixel on
leds.setPixelColor(4, Wheel( (4 + theaterJ) % 255)); //turn every third pixel on
theaterON = 1;
}
if (theaterJ < 255)
theaterJ++;
else
theaterJ = 0;
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r – g – b – back to r.
uint32_t Wheel(byte WheelPos)
{
WheelPos = 255 – WheelPos;
if (WheelPos < 85)
{
return leds.Color(255 – WheelPos * 3, 0, WheelPos * 3);
}
else if (WheelPos < 170)
{
WheelPos -= 85;
return leds.Color(0, WheelPos * 3, 255 – WheelPos * 3);
}
else
{
WheelPos -= 170;
return leds.Color(WheelPos * 3, 255 – WheelPos * 3, 0);
}
}

Great Glue Gun Recap!

I recently helped out behind the scenes of the two part Ben Heck Great Glue episode. I did the electronics design, assembly, and firmware for Ben. He put that with the mechanical part of the extruder, changed out the trigger, and packaged it up real nice for the episode. As he rarely does write ups I thought I’d post the code (pre hall effect) and the parts I remember using for others to follow in the great glue gun foot steps.

Here is a partial working demo early in the process

 

Here are the two episodes-

 

Original Parts – Sparkfun

H-Bridge $2.35 https://www.sparkfun.com/products/315

Trigger Pot (retired) https://www.sparkfun.com/products/retired/10314

SSR $4.95 https://www.sparkfun.com/products/10636

Proto board $2.95 https://www.sparkfun.com/products/8811

Wall Wart 9V $5.95 https://www.sparkfun.com/products/298

Thermistor 10k $1.95 https://www.sparkfun.com/products/250 (I think I ruined one and ended up using a 100k though)

RGB LED $.95 https://www.sparkfun.com/products/11120

 

By request I cross referenced what I could for Newark http://www.newark.com , they should be available at http://canada.newark.com/ as well

BenDuino (Ben’s custom Arduino Uno, link is similar but larger) – http://www.newark.com/arduino/a000066/dev-brd-atmega328-arduino-uno/dp/78T1601

H-Bridge – http://www.newark.com/texas-instruments/sn754410ne/ic-peripheral-drivers-half-h-36v/dp/08F8145

Trigger Pot – Sorry no cross reference for this sweet product 🙁

SSR – http://www.newark.com/sharp/s202s02f/ssr-pc-board-8a-80vrms-to-240vrms/dp/14N9588

Proto board with ground plane – No cross reference

Wall Wart 9V – http://www.newark.com/triad-magnetics/wsu090-0800-r/ac-dc-conv-external-plug-in-1/dp/83T4327

Thermistor 10k – http://www.newark.com/epcos/b57891m0103k000/thermistor-ntc-radial-leaded/dp/63W2796

Make sure to change the code to use the 10k, I ruined my 10k’s after a few prototypes, jbweld is too strong.  Anyways I used 100k’s, it’s an easy code change and 10k is more often used

RGB LED we used 10mm not a 5mm – http://www.newark.com/kingbright/l-154a4sureqbfzgew/led-multicol-rgb-5mm-x-bright/dp/66W1972

Code

#include <math.h>
#define MotorENPIN  3
#define Motor1APIN  2
#define Motor2APIN  4
#define Light1PIN  5
#define Light2PIN  6
#define minSpeed 50
#define maxSpeedLow   90
#define maxSpeedHigh  160
#define meltTemp 235
#define speedTempOffset 25
//#define SSRPIN    7
#define ThermistorPIN A0                 // Analog Pin 0
#define TriggerPIN  A1
//#define TempSetPIN  A2
boolean extruding = false;
boolean atTemp = false;
int maxSpeed = maxSpeedLow;
int updateCount = 0;
int setTemp = 0;
int reqSpeed = 0;
int setSpeed = 0;
int temp;
int count = 0;
float pad = 100000;                       // balance/pad resistor value, set this to
                                        // the measured resistance of your pad resistor
float thermr = 100000;                   // thermistor nominal resistance
float Thermistor(int RawADC) {          //converts thermistor reading into a resistance and then temperature in C
  long Resistance;
  float logVal;
  float tempTemp;  // Dual-Purpose variable to save space.
  Resistance=((1024 * pad / RawADC) – pad);
  logVal = 3950/log((float)100000/Resistance);
  //T2= T1*B/ln(R1/R2)  /  ( B/ln(R1/R2) – T1 )
  tempTemp = (25+273.15)*logVal;
  tempTemp = tempTemp / (logVal-(25+273.15));
  tempTemp = tempTemp – 273.15;  // Convert Kelvin to Celsius
  tempTemp = (tempTemp * 9.0)/ 5.0 + 32.0;                  // converts to  Fahrenheit
  return tempTemp;              // Return the Temperature
}
void setup() {
  Serial.begin(115200);
  pinMode(MotorENPIN, OUTPUT);
  analogWrite(MotorENPIN, 0);
  pinMode(Motor1APIN, OUTPUT);
  digitalWrite(Motor1APIN, LOW);
  pinMode(Motor2APIN, OUTPUT);
  digitalWrite(Motor2APIN, LOW);
  pinMode(Light1PIN, OUTPUT);
  digitalWrite(Light1PIN, HIGH);
  pinMode(Light2PIN, OUTPUT);
  digitalWrite(Light2PIN, LOW);
  //pinMode(SSRPIN, OUTPUT);
  //digitalWrite(SSRPIN, LOW);
  analogRead(ThermistorPIN);
  analogRead(TriggerPIN);
  //analogRead(TempSetPIN);
}
void loop() {
  int readTemp = Thermistor(analogRead(ThermistorPIN)); // read ADC and  convert it to F
  if ((readTemp > 0) && (readTemp < 500))
    temp = readTemp;
  //setTemp = analogRead(TempSetPIN);
  //setTemp = map(setTemp,0,1023,50,350);            //analog reading 0-1023, temperature range 50 to 350F
  if (temp <= meltTemp){                            //if less than set temp, turn on SSR, set lights
    //digitalWrite(SSRPIN, HIGH);
    digitalWrite(Light1PIN, LOW);
    digitalWrite(Light2PIN, HIGH);
    maxSpeed = maxSpeedLow;
    atTemp = false;
  }
  if ((temp > (meltTemp + 5)) && (temp <= meltTemp + speedTempOffset)){  //if greater than set temp but less than set temp + 10, set lights
    digitalWrite(Light1PIN, HIGH);
    digitalWrite(Light2PIN, HIGH);
    maxSpeed = maxSpeedLow;
    atTemp = true;
  }
  if (temp > (meltTemp + speedTempOffset + 5)){                        //if greater than set temp + 10, turn off SSR, set lights
    //digitalWrite(SSRPIN, LOW);
    digitalWrite(Light2PIN, LOW);
    digitalWrite(Light1PIN, HIGH);
    maxSpeed = maxSpeedHigh;
    atTemp = true;
  }
  reqSpeed = 1023 – analogRead(TriggerPIN);
  if (reqSpeed < 3){                                 //if less than 3 (deadzone) and was extruding, reverse the motor to suck in the gluestick
    if (extruding == true && count >= 450){
      analogWrite(MotorENPIN, 0);
      delay(50);
      digitalWrite(Motor1APIN, LOW);
      digitalWrite(Motor2APIN, HIGH);
      analogWrite(MotorENPIN, 125);
      setSpeed = 0;
      delay(150);
      analogWrite(MotorENPIN, 0);
      delay(50);
      extruding = false;
      count = 0;
    }
    else{                                              //if less than 3 (deadzone) and was not extruding or reverse timed out, turn off motor
      count = 0;
      analogWrite(MotorENPIN, 0);
      setSpeed = 0;
    }
  }
  else if (reqSpeed > 5 && atTemp == true){                              //if greater than 5 (deadzone), turn on motor mapped to stick, 5-1023 reading 50-150 motor, set extruding
    if (count < 450)
      count++;
    setSpeed = map(reqSpeed,5,1023,minSpeed,maxSpeed);
    digitalWrite(Motor1APIN, HIGH);
    digitalWrite(Motor2APIN, LOW);
    analogWrite(MotorENPIN, setSpeed);
    extruding = true;
  }
  if (updateCount <= 250)
    updateCount++;
  else{
    writeUpdates();
    updateCount = 0;
  }
  //writeUpdates();                                      //for debugging
}
void writeUpdates(){
  Serial.print(“Temp: “);
  Serial.print(temp,1);
  Serial.println(“”);
  //Serial.print(“Req Speed: “);
  //Serial.print(reqSpeed,1);
  //Serial.println(“”);
  //Serial.print(“Set Speed: “);
  //Serial.print(setSpeed,1);
  //Serial.println(“”);
}
As always code and parts list offered without warranty and very little support but you can always shoot me an email and I’ll see what I can do 🙂

 

Also, if you have questions regarding this project, I did a little write up on Element14, any Ben Heck questions and suggestions should go there, it’s a helpful community with better knowledge base than just me (though I do contribute a lot there).

 

Oh, and look for a reflow write up in a few weeks.  Ben ended up doing a few episodes on the toaster reflow oven I was working on at his shop.

Another Ben Heck Show Appearance

Well, this will be a quick little post, mostly for a location to drop some files.  I made another Ben Heck Show appearance, this brings me up to 3.  The video can be seen here

 

All the videos can be seen here

http://www.youtube.com/playlist?list=PLty7pvZZzbVi8Ud1Tei8N7pI25UojzUFa

 

 

It was a cool experience as it always is.  Some guys from Engadget were there to film as well and it was cool to talk with them.  Also Ben and I got in an abbreviation contest which was fun. VHDL stands for VHSIC Hardware Description Language, with VHSIC standing for Very High Speed Integrated Circuit.  That is the coolest one I know.

 

Anyways, a few people have asked for the code and such so I will embed it at the bottom.  I have the Android code and the TI Launchpad firmware code, both in separate zips.  The Android code was written for either Jellybean or ICS, don’t remember which, and that was for the rotate command, like the pot stir app.  The APK is in the zip file.  I didn’t take the time to really document as I’ve been a busy guy.  Hopefully I’ll get to do a life update and an update on my ShapeOko CNC machine shortly.

 

Anyways, here you go

Android SANTA Project

TI Arduino Code Files