万圣节遥控LED发光兜帽


澜不吃蓝
转载
发布时间: 2025-11-03 11:46:53 | 阅读数 0收藏数 0评论数 0
封面
这款服装兜帽可以是您选择的任何 LED 眼睛生物,只需改变颜色即可。我在 2015年首次使用非常简单的电路和代码制作了这个项目,但今年我想创建一个升级版本,同时控制两种服装的动画。该电路使用一个简单的近距离射频遥控器来控制同一频率上的两个接收器,并且基于 Bill Earl 的教程代码 ,Arduino 代码采用中断来实现响应式动画变化。

准备工作:

材料:

  1. 2 个 NeoPixel Jewel LED 模块
  2. GEMMA M0 微控制器
  3. 315MHz 无线接收器(自锁型)
  4. 315MHz 无线射频遥控器(可选单键、双键或四键版本)
  5. 硅胶包覆多股导线(推荐 30 AWG)
  6. 厚实布料用于制作兜帽/披风
  7. 本版本使用:
  8. 白色烟草布 2 层(共 1 码)
  9. 白色细棉布(cheesecloth)1 层(1 码)
  10. 兜帽内衬:不透光黑色布料(用于遮挡内部光线)
  11. 半透明黑色面料(用于面部面板,1 码)
  12. 19 号镀锌钢丝(用于支撑结构,如眼眶或帽檐定型)



工具:

  1. 电烙铁和焊锡
  2. 剥线钳
  3. 斜口钳(剪线钳)
  4. 镊子
  5. 辅助夹持工具(“第三只手”,可选)
  6. 缝纫机
  7. 剪刀
  8. 手缝针和线
  9. 缝纫珠针
  10. 裁缝划粉(可选,用于在布料上做标记)
1

电路图和代码

电路连接如下:

  1. Gemma D2 到无线接收器 D0
  2. Gemma D0 到无线接收器 D1
  3. Gemma 3V 转无线接收器 +5V
  4. Gemma GND 到无线接收器 GND 和 NeoPixel 宝石 GND
  5. Gemma D1 到 NeoPixel 宝石数据 IN
  6. Gemma Vout 到 NeoPixel jewels PWR
  7. NeoPixel 宝石数据输出到其他 NeoPixel 宝石数据输入

有关装配说明,请参阅下一步。

代码基于 Bill Earl 的 Arduino 草图的多任务处理 ,并进行了修改以控制两个具有两个数字输入的 NeoPixel 宝石。因此,您不必使用无线接收器——您可以使用电路本身的按钮。从此步骤的附件中下载此 Arduino 代码文件,或从此处复制并粘贴到空的 Arduino 草图中:

#include "Adafruit_NeoPixel.h"

// Pattern types supported:
enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE };
// Patern directions supported:
enum direction { FORWARD, REVERSE };

// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPatterns : public Adafruit_NeoPixel
{
public:

// Member Variables:
pattern ActivePattern; // which pattern is running
direction Direction; // direction to run the pattern

unsigned long Interval; // milliseconds between updates
unsigned long lastUpdate; // last update of position

uint32_t Color1, Color2; // What colors are in use
uint16_t TotalSteps; // total number of steps in the pattern
uint16_t Index; // current step within the pattern

void (*OnComplete)(); // Callback on completion of pattern

// Constructor - calls base-class constructor to initialize strip
NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())
:Adafruit_NeoPixel(pixels, pin, type)
{
OnComplete = callback;
}

// Update the pattern
void Update()
{
if((millis() - lastUpdate) > Interval) // time to update
{
lastUpdate = millis();
switch(ActivePattern)
{
case RAINBOW_CYCLE:
RainbowCycleUpdate();
break;
case THEATER_CHASE:
TheaterChaseUpdate();
break;
case COLOR_WIPE:
ColorWipeUpdate();
break;
case SCANNER:
ScannerUpdate();
break;
case FADE:
FadeUpdate();
break;
default:
break;
}
}
}

// Increment the Index and reset at the end
void Increment()
{
if (Direction == FORWARD)
{
Index++;
if (Index >= TotalSteps)
{
Index = 0;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
else // Direction == REVERSE
{
--Index;
if (Index <= 0)
{
Index = TotalSteps-1;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
}

// Reverse pattern direction
void Reverse()
{
if (Direction == FORWARD)
{
Direction = REVERSE;
Index = TotalSteps-1;
}
else
{
Direction = FORWARD;
Index = 0;
}
}

// Initialize for a RainbowCycle
void RainbowCycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = RAINBOW_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}

// Update the Rainbow Cycle Pattern
void RainbowCycleUpdate()
{
for(int i=0; i< numPixels(); i++)
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
}
show();
Increment();
}

// Initialize for a Theater Chase
void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = THEATER_CHASE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Theater Chase Pattern
void TheaterChaseUpdate()
{
for(int i=0; i< numPixels(); i++)
{
if ((i + Index) % 3 == 0)
{
setPixelColor(i, Color1);
}
else
{
setPixelColor(i, Color2);
}
}
show();
Increment();
}

// Initialize for a ColorWipe
void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = COLOR_WIPE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color;
Index = 0;
Direction = dir;
}

// Update the Color Wipe Pattern
void ColorWipeUpdate()
{
setPixelColor(Index, Color1);
show();
Increment();
}

// Initialize for a SCANNNER
void Scanner(uint32_t color1, uint8_t interval)
{
ActivePattern = SCANNER;
Interval = interval;
TotalSteps = (numPixels() - 1) * 2;
Color1 = color1;
Index = 0;
}

// Update the Scanner Pattern
void ScannerUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
if (i == Index) // Scan Pixel to the right
{
setPixelColor(i, Color1);
}
else if (i == TotalSteps - Index) // Scan Pixel to the left
{
setPixelColor(i, Color1);
}
else // Fading tail
{
setPixelColor(i, DimColor(getPixelColor(i)));
}
}
show();
Increment();
}

// Initialize for a Fade
void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = FADE;
Interval = interval;
TotalSteps = steps;
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Fade Pattern
void FadeUpdate()
{
// Calculate linear interpolation between Color1 and Color2
// Optimise order of operations to minimize truncation error
uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
ColorSet(Color(red, green, blue));
show();
Increment();
}

// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t DimColor(uint32_t color)
{
// Shift R, G and B components one bit to the right
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}

// Set all pixels to a color (synchronously)
void ColorSet(uint32_t color)
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}

// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}

// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}

// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}

// 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 Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else if(WheelPos < 170)
{
WheelPos -= 85;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
else
{
WheelPos -= 170;
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
};

void JewelsComplete();


// Define some NeoPatterns for the two rings and the stick
// as well as some completion routines
NeoPatterns Jewels(14, 1, NEO_GRBW + NEO_KHZ800, &JewelsComplete);


const int BRIGHTNESS = 50;

// Initialize everything and prepare to start
void setup()
{
Serial.begin(115200);

pinMode(2, INPUT);
pinMode(0, INPUT);

// Initialize all the pixels
Jewels.setBrightness(BRIGHTNESS);
Jewels.begin();

// Kick off a pattern
Jewels.TheaterChase(Jewels.Color(255,50,0), Jewels.Color(0,0,0,50), 100);
}

// Main loop
void loop()
{
// Update the jewels.
Jewels.Update();

// Switch patterns on a button press:
if (digitalRead(2) == HIGH) // Button #1 pressed
{
Jewels.Color1 = Jewels.Color(255, 50, 0);
Jewels.ActivePattern = FADE;
Jewels.TotalSteps = 100;
Jewels.Interval = 1;
}
else if (digitalRead(0) == HIGH) // Button #2 pressed
{
Jewels.Color1 = Jewels.Color(255, 0, 0);
Jewels.ActivePattern = SCANNER;
Jewels.TotalSteps = Jewels.numPixels();
Jewels.Interval = 100;
}
else // Back to normal operation
{
// Restore all pattern parameters to normal values
Jewels.Color1 = Jewels.Color(255, 50, 0);
Jewels.ActivePattern = THEATER_CHASE;
Jewels.TotalSteps = Jewels.numPixels();
Jewels.Interval = 100;
}
}

//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------


// Jewels Completion Callback
void JewelsComplete()
{
// Random color change for next scan
//Jewels.Color1 = Jewels.Wheel(random(255));
Jewels.Reverse();
}
INO
wireless_halloween_hood_multitask_arduino.ino
9.64KB
2

组装电路

一套帮助的第三手夹具可以使将电线焊接到组件上的过程变得非常简单和有趣。但如果您没有套装,请不要担心;您始终可以在焊接时使用一些胶带或海报腻子来保持电路板稳定。

使用细绞线(约 6 英寸/15 厘米长)连接两个 NeoPixel 宝石(上一步中的图表)。如果您使用的电线太短,您将无法将 LED 眼睛相距足够远,如果使用过多的电线,当您穿着服装时,松弛会沾到您的脸上。

主电路将位于翻领区域(胸部与肩膀的交汇处),因此对于链条中第一个 NeoPixel 珠宝和 Gemma 之间的连接,电线会更长。您可以将电线举到眼部区域并将其拉出以测量电线应传播的距离,然后再添加一点以进行松弛和保险。

为了连接 Gemma 和无线接收器,我选择使用带有母头的原型线,因为无线接收器已经连接了接头引脚。

3

电池电量

为了为电路供电,我使用了 500mAh 锂聚合物电池 。如果使用锂聚合物电池,明智的做法是保护其免受划痕、刺穿、磨损、弯曲和其他滥用。您可以用一些坚固的织物胶带包裹它,或者为它制作一个 3D 打印支架

您可以轻松地使用 3xAAA 支架代替(将其放在口袋中而不是翻领内)。

4

缝制图片和裁剪织物

我使用了自己为这套服装初版所制作的纸样,这是一个多页PDF文件,拼接后可组成完整的纸样片。

将布料对折,使布边(布料的织边)对齐以确保布纹方向正确,然后按照纸样上标注的位置,将纸样片沿折边放置并用珠针固定。接着,用划粉或铅笔在纸样片外围(折边处除外)画出约5/8英寸(约3厘米)的缝份。由于我的布料较薄,我希望将其加厚;又因为我做了两个兜帽,最终在主面料上每片纸样都裁剪了四层。此外,我还额外裁剪了一层薄纱般的细棉布(cheesecloth),覆盖在外部以增加质感,并最终加了一层黑色面料作为内衬,以阻挡透入的光线。现在回想起来,如果事先规划好这一点,其实可以省去最初的一层白色面料,这样每个兜帽就只需三层布料,而不是四层了。

5

组织织物

在每个图案上别针并缝制省道/肩缝,然后将兜帽和斗篷沿颈缝与右侧并拢对齐。缝合接缝,以及直接穿过引擎盖顶部的接缝。

试戴引擎盖。折叠并固定引擎盖的原始前边缘,然后将其缝合起来,形成整齐的边缘以及电线穿过的通道。

接下来,剪下一块圆形的透明黑色织物以覆盖引擎盖的前部。这将支撑电路并隐藏您的脸。佩戴兜帽时将其固定到位以获得最佳贴合度,然后手工或机器将其缝在兜帽开口处。

6

在帽子中安装电路

我戴上帽子,打开电路,然后用镜子找出 LED 的最佳位置。然后我用别针标记位置,并用黑线小心地缝合,将 NeoPixel 珠宝上的安装孔连接到透明的黑色前面板上。我的眼睛就在我的真实眼睛下方,这使得我很容易看到它们。

7

开始佩戴

穿起来非常有趣。很容易看到外面,别人不容易看到你的脸。整个东西也非常舒适,这要归功于超大的兜帽和金属丝框架,它可以防止正面面料垂在脸上。

阅读记录0
点赞0
收藏0
禁止 本文未经作者允许授权,禁止转载
猜你喜欢
评论/提问(已发布 0 条)
评论 评论
收藏 收藏
分享 分享
pdf下载 下载
pdf下载 举报