Neon Meow Cat Light
This is my cat🐱.Ever since I moved here, I can only see he through FaceTime.So, I decided to create this neon cat light to keep his presence close.I designed the outline based on his chubby figure and placed it on my bedside table. It’s both a decorative piece and a functional light.
Links I referenced👇
https://learn.adafruit.com/led-neon-signs-with-neopixels
Supplies
Materials Used:
- Acrylic board: For the base.
- LED neon strip: For the lighting.
- Arduino Gemma board: For programming the light modes.
- Buttons: To switch between modes.
- Wires: For connections.
- Power adapter: To power the light.
Modeling
I used Rhino to design the 3D model of the cat's outline, ensuring the grooves fit perfectly for the LED neon strip.
3D Printing
I printed the outline using a 3D printer, creating a sturdy frame to hold the components and the neon light securely.
Assembly
After printing the frame, I placed the LED strip into the grooves, connected the Arduino board and wires, and programmed the buttons to control the light modes.
Code1
Day Mode: The light flashes like a comet, with each "comet" in a different color. After the comet effect, a rainbow light flows smoothly through the strip.
Day Mode Code
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define BUTTON_PIN 2 // 按钮引脚(接地)
#define PIXEL_PIN 1 // NeoPixel数据引脚
#define PIXEL_COUNT 140 // LED数量
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
boolean oldState = HIGH;
int mode = 0; // 0: off, 1: animations
// 动画序列:0:RainbowComet(往返一次), 1:RainbowChase
int currentAnim = 0;
// 彗星动画参数
int cometPos = 0;
bool cometForward = true;
bool cometDone = false;
uint8_t cometTailLength = 20;
// 彗星颜色循环索引
uint8_t cometColorIndex = 0;
// 定义5种颜色的Hue和Saturation
// 黄色、绿色、蓝色、紫色、白色
uint16_t cometHues[5] = {10920, 21840, 43680, 54600, 0};
uint8_t cometSats[5] = {255, 255, 255, 255, 0};
// 白色通过S=0实现,无需关心Hue
uint16_t cometBaseHue = 0;
uint8_t cometBaseSat = 255;
// RainbowChase动画参数
uint16_t chaseBaseHue = 0;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
strip.begin();
strip.show(); // 初始化后关灯
}
void loop() {
boolean newState = digitalRead(BUTTON_PIN);
// 检测按钮按下从高到低的变化
if ((newState == LOW) && (oldState == HIGH)) {
delay(20);
newState = digitalRead(BUTTON_PIN);
if(newState == LOW) {
mode = 1; // 切换到动画模式
currentAnim = 0; // 从彗星动画开始
cometPos = 0;
cometForward = true;
cometDone = false;
// 切换到下一个颜色
cometColorIndex = (cometColorIndex + 1) % 5;
cometBaseHue = cometHues[cometColorIndex];
cometBaseSat = cometSats[cometColorIndex];
}
}
oldState = newState;
if (mode == 1) {
switch (currentAnim) {
case 0: // RainbowComet动画:往返一次
if (!cometDone) {
rainbowCometAnimation();
} else {
currentAnim = 1; // 往返完成,进入RainbowChase
}
break;
case 1: // RainbowChase快速流动
rainbowChaseAnimation();
break;
}
} else {
// off模式:关灯
strip.clear();
strip.show();
}
}
// RainbowComet动画函数:从头到尾再从尾到头往返一次
void rainbowCometAnimation() {
strip.clear();
// 彗星头部颜色使用cometBaseHue和cometBaseSat
int headHue = cometBaseHue;
uint8_t headSat = cometBaseSat;
strip.setPixelColor(cometPos, strip.gamma32(strip.ColorHSV(headHue, headSat, 255)));
// 设置彗星尾巴(略微改变Hue增加层次感)
for(int t=1; t<=cometTailLength; t++) {
int pos = cometPos - (cometForward ? t : -t);
while (pos < 0) pos += strip.numPixels();
while (pos >= strip.numPixels()) pos -= strip.numPixels();
uint8_t brightness = 255 - (255/cometTailLength)*t;
int tailHue = (headHue + t*300) % 65536;
// 尾巴使用与头部相同的饱和度设置
strip.setPixelColor(pos, strip.gamma32(strip.ColorHSV(tailHue, headSat, brightness)));
}
strip.show();
// 更新彗星位置
if (cometForward) {
cometPos++;
if (cometPos >= strip.numPixels()) {
// 到达末端,开始返回
cometPos = strip.numPixels() - 1;
cometForward = false;
}
} else {
cometPos--;
if (cometPos < 0) {
// 返回到起点,结束彗星动画
cometPos = 0;
cometDone = true;
}
}
delay(20);
}
// RainbowChase动画函数:快速流动的追逐效果
void rainbowChaseAnimation() {
strip.clear();
for(int i=0; i<strip.numPixels(); i++) {
uint16_t pixelHue = chaseBaseHue + (i * 300);
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue % 65536, 255, 255)));
}
strip.show();
chaseBaseHue += 512;
delay(10);
}
Downloads
Code2
Night Mode: The light switches to a soft white glow that flickers gently, serving as a cozy night light.
Night Mode Code
#include <Adafruit_NeoPixel.h>
#define BUTTON_PIN 2
#define PIXEL_PIN 1 // 根据实际连接更改引脚
#define PIXEL_COUNT 140
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
boolean oldState = HIGH;
boolean animationActive = false;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
strip.begin();
strip.setBrightness(50); // 设置亮度,避免太暗
strip.show();
}
void loop() {
boolean newState = digitalRead(BUTTON_PIN);
// 检测按钮是否从高到低
if (newState == LOW && oldState == HIGH) {
delay(20); // 去抖动
if (digitalRead(BUTTON_PIN) == LOW) {
animationActive = !animationActive; // 切换动画状态
if (!animationActive) {
strip.clear();
strip.show(); // 关闭灯效
}
}
}
oldState = newState;
// 如果动画激活,运行闪烁效果
if (animationActive) {
fadeEffect(5, 60); // 调整步长和延迟控制效果
}
}
void fadeEffect(int step, int delayTime) {
for (int brightness = 0; brightness <= 255; brightness += step) {
setAllPixels(strip.Color(brightness, brightness, brightness));
strip.show();
delay(delayTime);
}
for (int brightness = 255; brightness >= 0; brightness -= step) {
setAllPixels(strip.Color(brightness, brightness, brightness));
strip.show();
delay(delayTime);
}
}
void setAllPixels(uint32_t color) {
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, color);
}
}