Neon Meow Cat Light

by Qianyue Zhou in Circuits > Arduino

615 Views, 14 Favorites, 0 Comments

Neon Meow Cat Light

IMG_1683.JPG
IMG_3027.JPG
IMG_1688.JPG
IMG_1712.jpg
WechatIMG34922.jpg
IMG_1714.jpg

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:

  1. Acrylic board: For the base.
  2. LED neon strip: For the lighting.
  3. Arduino Gemma board: For programming the light modes.
  4. Buttons: To switch between modes.
  5. Wires: For connections.
  6. Power adapter: To power the light.

Modeling

截屏2024-12-10 12.55.11.png
截屏2024-12-10 12.55.42.png

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

IMG_1715.jpg
IMG_1623.JPG

I printed the outline using a 3D printer, creating a sturdy frame to hold the components and the neon light securely.

Assembly

IMG_1631.JPG
IMG_1630.JPG

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

gif6.gif
gif5.gif
gif4.gif
gif2.gif
gif3.gif
gif1.gif

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

gif7.gif

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);

}

}

Thanks for Watching!