Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 4 | ||||
| × | 1 |
When you first see the IKEA PS 2014 Pendant lamp, It's hard not to think of Star Wars Death Star.
I wanted to create a IoT (Internet Of Things) connected Wifi Death Lamp. I searched the net for projects and found one project that inspired me the most http://davidbliss.com/2014/11/18/transforming-sphere-lamp/ I also added a Ultrasonic Sensor from this project https://youtu.be/95-dtNbKG6Q/
I aquired the parts and started the assembling.
- This project is work in progress. Currently I am finalizing and testing the software.
Testing the stepper motor (Arduino Uno + Arduino Stepper Motor Shield r3)
Particle photon test code (works with Particle Core aswell)
C/C++Test code for controlling the NeoPixels + Stepper with your hand (gestures).
// This #include statement was automatically added by the Spark IDE.
#include "neopixel/neopixel.h"
// This #include statement was automatically added by the Spark IDE.
#include "application.h"
// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN D2
#define PIXEL_COUNT 114
#define PIXEL_TYPE WS2812B
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
int led0 = D7; // This one is the built-in tiny one to the right of the USB jack
int motortrigg = D6; // Stepper-trigger to ARDUINO -> PIN2 INPUT trigg Arduino/MotorShield
int trigger = D3; // TRIGG
int echo = D4; //ECHO
int ping = 0; //loop couter
int showType = 0; //led show start
unsigned long triggerTarget;
uint8_t value = 1;
void setup() {
pinMode(motortrigg, OUTPUT);
pinMode(trigger, OUTPUT);
pinMode(echo, INPUT);
pinMode(led0, OUTPUT);
digitalWrite(trigger, LOW);
digitalWrite(motortrigg, LOW);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
showType = value;
startShow(showType); // Set last shownumber from EEPROM
}
void loop() {
digitalWrite(led0, LOW); // Turn OFF the LED pin
// Pull the trigger pin high for roughly 10uS then pull it low and wait another 10uS.
triggerTarget = micros();
while (micros() < triggerTarget + 10) {
digitalWrite(trigger, HIGH);
}
while (micros() < triggerTarget + 20) {
digitalWrite(trigger, LOW);
}
// Read the return echo then convert it to in and cm.
unsigned long sonar = pulseIn(echo, HIGH);
//float in = sonar / 148;
int cm = sonar / 58;
if (cm >= 8 && cm <= 10){ digitalWrite(led0, HIGH); // // Internal led
digitalWrite(motortrigg, HIGH); // Trigger stepper on PARTICLE CORE PIN D6 -> PIN D2 ARDUINO + MOTOR SHIELD
delay(50);
digitalWrite(motortrigg, LOW);
digitalWrite(led0, LOW);
}
//if (cm < 35){ digitalWrite(led2, HIGH); // LED on object closer than x cm
if (cm >= 15 && cm <=30 ){ digitalWrite(led0, HIGH); // Internal led on
// NEOPIXELS light em up!
//colorAll(strip.Color(255, 20, 0), 5); // Orangeish!!
showType++;
if (showType > 9) //Number of SHOWS
showType=0;
startShow(showType);
}
// Bump the ping counter.
ping++;
}
//--- functions
unsigned long pulseIn(uint8_t pin, uint8_t state) {
GPIO_TypeDef* portMask = (PIN_MAP[pin].gpio_peripheral); // Cache the target's peripheral mask to speed up the loops.
uint16_t pinMask = (PIN_MAP[pin].gpio_pin); // Cache the target's GPIO pin mask to speed up the loops.
unsigned long pulseCount = 0; // Initialize the pulseCount variable now to save time.
unsigned long loopCount = 0; // Initialize the loopCount variable now to save time.
unsigned long loopMax = 20000000; // Roughly just under 10 seconds timeout to maintain the Spark Cloud connection.
// Wait for the pin to enter target state while keeping track of the timeout.
while (GPIO_ReadInputDataBit(portMask, pinMask) != state) {
if (loopCount++ == loopMax) {
return 0;
}
}
// Iterate the pulseCount variable each time through the loop to measure the pulse length; we also still keep track of the timeout.
while (GPIO_ReadInputDataBit(portMask, pinMask) == state) {
if (loopCount++ == loopMax) {
return 0;
}
pulseCount++;
}
// Return the pulse time in microseconds by multiplying the pulseCount variable with the time it takes to run once through the loop.
return pulseCount * 0.405; // Calculated the pulseCount++ loop to be about 0.405uS in length.
}
//---- NEOPIXEL functions
void colorAll(uint32_t c, uint8_t wait) {
uint16_t i;
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
}
strip.show();
delay(wait);
}
void startShow(int i) {
switch(i){
case 0: value = 0;
colorWipe(strip.Color(0, 0, 0), 2); // Black/off
break;
case 1: value = 1;
colorWipe(strip.Color(255, 45, 0), 2); // Orange
break;
case 2: value = 2;
colorWipe(strip.Color(0, 255, 0), 2); // Green
break;
case 3: value = 3;
colorWipe(strip.Color(255, 255, 255), 2); // White
break;
case 4: value = 4;
theaterChase(strip.Color(0, 255, 0), 5); // Green
break;
case 5: value = 5;
theaterChase(strip.Color(255, 0, 0), 5); // Red
break;
case 6: value = 6;
theaterChase(strip.Color( 0, 0, 255), 5); // Blue
break;
case 7: value = 7;
lightTop(0,255,255,5);
break;
case 8: value = 8;
lightBottom(0,255,255,5);
break;
case 9: value = 9;
wave(255,0,128);
break;
}
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
// 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 strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
//------------------- cut in functions
void wave(int r,int g,int b){
for(uint8_t i=0; i<99; i++) {
setThreePixels(i, r, g, b);
strip.show();
delay(10);
}
for(uint8_t i=0; i<45; i++){
setThreePixels(strip.numPixels()-i, r, g, b);
strip.show();
delay(10);
}
}
void lightTop(int r,int g,int b, uint8_t wait){
for(uint8_t i=0; i<45; i++) {
strip.setPixelColor(i/1.875, r, g, b);
strip.setPixelColor(24+i, r, g, b);
strip.setPixelColor(114-i, 0, 0, 0);
strip.show();
delay(wait);
}
}
void lightBottom(int r,int g,int b, uint8_t wait){
for(uint8_t i=0; i<45; i++) {
strip.setPixelColor(i/1.875, 0, 0, 0);
strip.setPixelColor(24+i, 0, 0, 0);
strip.setPixelColor(114-i, r, g, b);
strip.show();
delay(wait);
}
}
void setThreePixels(int LED,int r,int g,int b) {
strip.setPixelColor(LED, r, g, b);
if (LED>0) strip.setPixelColor(LED-1, r, g, b);
if (LED<strip.numPixels()-1)strip.setPixelColor(LED+1, r, g, b);
}
Arduino stepper motor code
C/C++Stepper motor code for Arduino + Motor shield. Stepper has three states/positions (fully open/semi-open/fully closed). The current position is also stored in the EEPROM (to know postiion when power off/on).
#include <EEPROM.h> // position 0-220 stored in position 0
#include <Stepper.h>
const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 12,13);
// give the motor control pins names:
const uint8_t pwmA = 3;
const uint8_t pwmB = 11;
const uint8_t brakeA = 9;
const uint8_t brakeB = 8;
const uint8_t dirA = 12;
const uint8_t dirB = 13;
uint16_t currentPosition = 0; // 0 - 2200; set by position from smartthings; 0 is closed/furthest from motor
//button toggle switch
int button = 2; //button pin, connect to +3.3V as button, otherwise ground through resistor
int press = 0;
int toggle = 0; // 0-3; Switch case loop
void setup() {
//Serial.begin(9600); //debug
// read values out of memory
//EEPROM.write(1, toggle);
currentPosition = EEPROM.read(0)*10;// Read current position
//toggle = EEPROM.read(1);// 0-3; Switch case loop stored in EEPROM (when power off)
//Serial.print("EEPROM Position: ");
//Serial.print(EEPROM.read(0)*10);
//Serial.print(" Toggle: ");
//Serial.print(toggle);
// set the PWM and brake pins so that the direction pins // can be used to control the motor:
pinMode(pwmA, OUTPUT);
pinMode(pwmB, OUTPUT);
pinMode(brakeA, OUTPUT);
pinMode(brakeB, OUTPUT);
// turn on POWER (turn to low to release the motor and avoid heating)
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
// turn off BRAKES
digitalWrite(brakeA, LOW);
digitalWrite(brakeB, LOW);
// 150 is max speed unloaded
// at 150, there is not enough torque to open the lamp, lowering speed overcomes this.
myStepper.setSpeed(110);
// turn off POWER (to release the motor and avoid heating)
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
//button toggle switch stuff
// pinMode(10, OUTPUT); //LED on pin 10 "Debug led"
pinMode(button, INPUT); //arduino monitor pin state
digitalWrite(2, LOW); //enable pullups to make pin 5 high --- PULL DOWN!!! earth natural state
}
void loop() {
press = digitalRead(button);
if (press == HIGH)
{
switch(toggle){
case 0: //digitalWrite(10, LOW); // set the LED on
//Stepper
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
digitalWrite(brakeA, LOW);
digitalWrite(brakeB, LOW);
digitalWrite(dirA, HIGH);
digitalWrite(dirB, HIGH);
setPosition("0"); //MAX step 0-106
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
digitalWrite(dirA, LOW);
digitalWrite(dirB, LOW);
//stepper slut
toggle++;
//EEPROM.write(1, toggle);// Store current switch-case in EEPROM
break;
case 1: //digitalWrite(10, HIGH); // set the LED on
//Stepper
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
digitalWrite(brakeA, LOW);
digitalWrite(brakeB, LOW);
digitalWrite(dirA, HIGH);
digitalWrite(dirB, HIGH);
setPosition("50"); //MAX step 0-106
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
digitalWrite(dirA, LOW);
digitalWrite(dirB, LOW);
//stepper slut
toggle++;
//EEPROM.write(1, toggle);// Store current switch-case in EEPROM
break;
case 2: //digitalWrite(10, HIGH); // set the LED on
//Stepper
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
digitalWrite(brakeA, LOW);
digitalWrite(brakeB, LOW);
digitalWrite(dirA, HIGH);
digitalWrite(dirB, HIGH);
setPosition("102"); //MAX step 0-106 | Currently 102
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
digitalWrite(dirA, LOW);
digitalWrite(dirB, LOW);
//stepper slut
toggle++;
//EEPROM.write(1, toggle);// Store current switch-case in EEPROM
break;
case 3: //digitalWrite(10, HIGH); // set the LED on
//Stepper
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
digitalWrite(brakeA, LOW);
digitalWrite(brakeB, LOW);
digitalWrite(dirA, HIGH);
digitalWrite(dirB, HIGH);
setPosition("50"); //MAX step 0-106
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
digitalWrite(dirA, LOW);
digitalWrite(dirB, LOW);
//stepper slut
toggle = 0;
//EEPROM.write(1, toggle);// Store current switch-case in EEPROM
break;
}
delay(50); //delay for debounce
} //End of if statement
} //End of main loop
void setPosition (String targetPosition) {
uint16_t targetMapped = map(targetPosition.toInt(), 0, 99, 0, 220);
targetMapped = targetMapped*10; // since we save value 0-220 we want an increment of 10
uint16_t deltaPosition = targetMapped - currentPosition;
// TODO: add a saftey to be sure current position will be 0-2200;
currentPosition += deltaPosition;
EEPROM.write(0, currentPosition/10);
//Serial.print(" New position:");
//Serial.print(EEPROM.read(0)); //DEBUG - print latest position
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
delay(250);
myStepper.step(deltaPosition);
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
}
Thanks to David Bliss and Chase Hinshaw.
Comments