Introduction: 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:

  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.

Step 1: Modeling

I used Rhino to design the 3D model of the cat's outline, ensuring the grooves fit perfectly for the LED neon strip.

Step 2: 3D Printing

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

Step 3: 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.

Step 4: 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 ModeCode

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

}

Step 5: Code2

Night Mode: The light switches to a soft white glow that flickers gently, serving as a cozy night light.

Night ModeCode

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

}

}

Step 6: Thanks for Watching!