24浏览
查看: 24|回复: 2

[项目] 【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球

[复制链接]
Flexball 基于柔性 PCB,配备 100 个 WS2812 2020 可寻址 LED。它由 ESP8285-01f 控制,这是乐鑫最小的基于 ESP 的模块。此外,它还配备了一个 ADXL345 加速度计传感器。
最初的想法是在那个圆形矩阵 (10x10) 上显示文本消息,但不幸的是,手臂的距离太大,不容易阅读(您可以在视频末尾观看)。尽管如此,它是我迄今为止建造的最漂亮的 LED 雕塑。

这是我的第一个柔性 PCB 设计,所以你肯定会发现一些可能不是最好在这里使用的东西。作为 DIY 制造商,对我来说最重要的部分是它最终会起作用 - 嘿,它确实有效!:)
对于柔性电路,我读过一些特殊的设计规则:
不要在设计的柔性部分使用带有拐角或边缘的走线。走线可能会破裂,信号可能会损坏。弯曲的痕迹在这里是更好的。
GND 平面也是如此,它可能会因 PCB 的弯曲而断裂。更好的选择是使用上图所示的哈希网络。
焊盘和过孔应该用这些泪滴连接到走线上......在我最喜欢的设计软件 Eagle 中找不到此选项。如果你能帮忙,请在评论中告诉我:)
设计这种 PCB 时最难的部分是 LED、盖子和臂末端焊盘的圆形排列。我创建了一个简单的 Excel 表格,根据相应手臂的半径和角度计算 XY 位置。如果您需要这样的循环安排,这肯定是一个巨大的帮助。

我已将 BOM 附加到此步骤。有关每个组件的详细信息,请参见此处。
可以在以下列表中找到一些主要组件的想法:
PCB 系列
ESP8285-01F
ADXL345
WS2812 2020 LED 指示灯
MCP73831 Lipo 充电器 IC
电池保护套件

除了一百个 LED 之外,没有任何特别的细节需要记住。我用过我的 DIY 热板烙铁,但这根本不是最好的主意。首先,它太小了,无法加热所有 PCB。其次是我降低了温度,以保护损坏 PCB。它有点太低了,因此我也不得不使用我的回流焊枪。
剩下的就是一点点的跟踪和错误。:D一百个 LED 乍一试不想工作。我花了大约两个小时才把它全部点亮。但最令人满意的时刻是所有 LED 都完美亮起时。
另一个棘手的部分是将底部圆圈的臂焊接到顶部的圆圈上。我绝对推荐在这里使用第三只手,否则可能会变得非常困难!

该代码基于 FastLED 库,该库可以驱动多个可寻址 LED,如 APA102、SK9822 或 WS2812。
代码中唯一必须的附加组件是锁存部分。只要锁存引脚保持高位,ESP 就可以保持自己的电源。一旦它被拉到 GND,球就会禁用自己的功率。附件中显示了一个基本示例。

该项目仍在进行中。尽管如此,这是我的一个秘密项目,我迫不及待地想向你们展示这些很棒的东西。如果您有其他想法,球可以做什么,请在下面的评论中告诉我。

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图1

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图2

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图3

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图4

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图6

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图5

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图8

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图7

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图9

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球图10

驴友花雕  中级技神
 楼主|

发表于 17 小时前

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球

项目代码

  1. #include <Arduino.h>
  2. #include <FastLED.h>
  3. const int button = 13;
  4. const int latch = 12;
  5. bool state = false;
  6. boolean battery_empty = false;
  7. boolean battery_charging = false;
  8. boolean stay_on = false;
  9. int hue = 0;
  10. double pi = 3.141;
  11. double chg_bright = 100;
  12. #define LED_PIN     14
  13. #define BRIGHTNESS  120
  14. #define LED_TYPE    WS2812
  15. #define COLOR_ORDER GRB
  16. const uint8_t kMatrixWidth  = 10;
  17. const uint8_t kMatrixHeight = 10;
  18. const bool    kMatrixSerpentineLayout = false;
  19. // This example combines two features of FastLED to produce a remarkable range of
  20. // effects from a relatively small amount of code.  This example combines FastLED's
  21. // color palette lookup functions with FastLED's Perlin/simplex noise generator, and
  22. // the combination is extremely powerful.
  23. //
  24. // You might want to look at the "ColorPalette" and "Noise" examples separately
  25. // if this example code seems daunting.
  26. //
  27. //
  28. // The basic setup here is that for each frame, we generate a new array of
  29. // 'noise' data, and then map it onto the LED matrix through a color palette.
  30. //
  31. // Periodically, the color palette is changed, and new noise-generation parameters
  32. // are chosen at the same time.  In this example, specific noise-generation
  33. // values have been selected to match the given color palettes; some are faster,
  34. // or slower, or larger, or smaller than others, but there's no reason these
  35. // parameters can't be freely mixed-and-matched.
  36. //
  37. // In addition, this example includes some fast automatic 'data smoothing' at
  38. // lower noise speeds to help produce smoother animations in those cases.
  39. //
  40. // The FastLED built-in color palettes (Forest, Clouds, Lava, Ocean, Party) are
  41. // used, as well as some 'hand-defined' ones, and some proceedurally generated
  42. // palettes.
  43. #define NUM_LEDS (kMatrixWidth * kMatrixHeight)
  44. #define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)
  45. // The leds
  46. CRGB leds[kMatrixWidth * kMatrixHeight];
  47. // The 16 bit version of our coordinates
  48. static uint16_t x;
  49. static uint16_t y;
  50. static uint16_t z;
  51. // We're using the x/y dimensions to map to the x/y pixels on the matrix.  We'll
  52. // use the z-axis for "time".  speed determines how fast time moves forward.  Try
  53. // 1 for a very slow moving effect, or 60 for something that ends up looking like
  54. // water.
  55. uint16_t speed = 20; // speed is set dynamically once we've started up
  56. // Scale determines how far apart the pixels in our noise matrix are.  Try
  57. // changing these values around to see how it affects the motion of the display.  The
  58. // higher the value of scale, the more "zoomed out" the noise iwll be.  A value
  59. // of 1 will be so zoomed in, you'll mostly see solid colors.
  60. uint16_t scale = 30; // scale is set dynamically once we've started up
  61. // This is the array that we keep our computed noise values in
  62. uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
  63. CRGBPalette16 currentPalette( PartyColors_p );
  64. uint8_t       colorLoop = 1;
  65. void SetupRandomPalette()
  66. {
  67.   currentPalette = CRGBPalette16(
  68.                       CHSV( random8(), 255, 32),
  69.                       CHSV( random8(), 255, 255),
  70.                       CHSV( random8(), 128, 255),
  71.                       CHSV( random8(), 255, 255));
  72. }
  73. // This function sets up a palette of black and white stripes,
  74. // using code.  Since the palette is effectively an array of
  75. // sixteen CRGB colors, the various fill_* functions can be used
  76. // to set them up.
  77. void SetupBlackAndWhiteStripedPalette()
  78. {
  79.   // 'black out' all 16 palette entries...
  80.   fill_solid( currentPalette, 16, CRGB::Black);
  81.   // and set every fourth one to white.
  82.   currentPalette[0] = CRGB::White;
  83.   currentPalette[4] = CRGB::White;
  84.   currentPalette[8] = CRGB::White;
  85.   currentPalette[12] = CRGB::White;
  86. }
  87. // This function sets up a palette of purple and green stripes.
  88. void SetupPurpleAndGreenPalette()
  89. {
  90.   CRGB purple = CHSV( HUE_PURPLE, 255, 255);
  91.   CRGB green  = CHSV( HUE_GREEN, 255, 255);
  92.   CRGB black  = CRGB::Black;
  93.   
  94.   currentPalette = CRGBPalette16(
  95.     green,  green,  black,  black,
  96.     purple, purple, black,  black,
  97.     green,  green,  black,  black,
  98.     purple, purple, black,  black );
  99. }
  100. //
  101. // Mark's xy coordinate mapping code.  See the XYMatrix for more information on it.
  102. //
  103. uint16_t XY( uint8_t x, uint8_t y)
  104. {
  105.   uint16_t i;
  106.   if( kMatrixSerpentineLayout == false) {
  107.     i = (y * kMatrixWidth) + x;
  108.   }
  109.   if( kMatrixSerpentineLayout == true) {
  110.     if( y & 0x01) {
  111.       // Odd rows run backwards
  112.       uint8_t reverseX = (kMatrixWidth - 1) - x;
  113.       i = (y * kMatrixWidth) + reverseX;
  114.     } else {
  115.       // Even rows run forwards
  116.       i = (y * kMatrixWidth) + x;
  117.     }
  118.   }
  119.   return i;
  120. }
  121. // Fill the x/y array of 8-bit noise values using the inoise8 function.
  122. void fillnoise8() {
  123.   // If we're runing at a low "speed", some 8-bit artifacts become visible
  124.   // from frame-to-frame.  In order to reduce this, we can do some fast data-smoothing.
  125.   // The amount of data smoothing we're doing depends on "speed".
  126.   uint8_t dataSmoothing = 0;
  127.   if( speed < 50) {
  128.     dataSmoothing = 200 - (speed * 4);
  129.   }
  130.   
  131.   for(int i = 0; i < MAX_DIMENSION; i++) {
  132.     int ioffset = scale * i;
  133.     for(int j = 0; j < MAX_DIMENSION; j++) {
  134.       int joffset = scale * j;
  135.       
  136.       uint8_t data = inoise8(x + ioffset,y + joffset,z);
  137.       // The range of the inoise8 function is roughly 16-238.
  138.       // These two operations expand those values out to roughly 0..255
  139.       // You can comment them out if you want the raw noise data.
  140.       data = qsub8(data,16);
  141.       data = qadd8(data,scale8(data,39));
  142.       if( dataSmoothing ) {
  143.         uint8_t olddata = noise[i][j];
  144.         uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing);
  145.         data = newdata;
  146.       }
  147.       
  148.       noise[i][j] = data;
  149.     }
  150.   }
  151.   
  152.   z += speed;
  153.   
  154.   // apply slow drift to X and Y, just for visual variation.
  155.   x += speed / 8;
  156.   y -= speed / 16;
  157. }
  158. void mapNoiseToLEDsUsingPalette()
  159. {
  160.   static uint8_t ihue=0;
  161.   
  162.   for(int i = 0; i < kMatrixWidth; i++) {
  163.     for(int j = 0; j < kMatrixHeight; j++) {
  164.       // We use the value at the (i,j) coordinate in the noise
  165.       // array for our brightness, and the flipped value from (j,i)
  166.       // for our pixel's index into the color palette.
  167.       uint8_t index = noise[j][i];
  168.       uint8_t bri =   noise[i][j];
  169.       // if this palette is a 'loop', add a slowly-changing base value
  170.       if( colorLoop) {
  171.         index += ihue;
  172.       }
  173.       // brighten up, as the color palette itself often contains the
  174.       // light/dark dynamic range desired
  175.       if( bri > 127 ) {
  176.         bri = 255;
  177.       } else {
  178.         bri = dim8_raw( bri * 2);
  179.       }
  180.       CRGB color = ColorFromPalette( currentPalette, index, bri);
  181.       leds[XY(i,j)] = color;
  182.     }
  183.   }
  184.   
  185.   ihue+=1;
  186. }
  187. // There are several different palettes of colors demonstrated here.
  188. //
  189. // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
  190. // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
  191. //
  192. // Additionally, you can manually define your own color palettes, or you can write
  193. // code that creates color palettes on the fly.
  194. // 1 = 5 sec per palette
  195. // 2 = 10 sec per palette
  196. // etc
  197. #define HOLD_PALETTES_X_TIMES_AS_LONG 1
  198. void ChangePaletteAndSettingsPeriodically()
  199. {
  200.   uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
  201.   static uint8_t lastSecond = 99;
  202.   
  203.   if( lastSecond != secondHand) {
  204.     lastSecond = secondHand;
  205.     if( secondHand ==  0)  { currentPalette = RainbowColors_p;         speed = 20; scale = 30; colorLoop = 1; }
  206.     if( secondHand ==  5)  { SetupPurpleAndGreenPalette();             speed = 10; scale = 50; colorLoop = 1; }
  207.     if( secondHand == 10)  { SetupBlackAndWhiteStripedPalette();       speed = 20; scale = 30; colorLoop = 1; }
  208.     if( secondHand == 15)  { currentPalette = ForestColors_p;          speed =  8; scale =120; colorLoop = 0; }
  209.     if( secondHand == 20)  { currentPalette = CloudColors_p;           speed =  4; scale = 30; colorLoop = 0; }
  210.     if( secondHand == 25)  { currentPalette = LavaColors_p;            speed =  8; scale = 50; colorLoop = 0; }
  211.     if( secondHand == 30)  { currentPalette = OceanColors_p;           speed = 20; scale = 90; colorLoop = 0; }
  212.     if( secondHand == 35)  { currentPalette = PartyColors_p;           speed = 20; scale = 30; colorLoop = 1; }
  213.     if( secondHand == 40)  { SetupRandomPalette();                     speed = 20; scale = 20; colorLoop = 1; }
  214.     if( secondHand == 45)  { SetupRandomPalette();                     speed = 50; scale = 50; colorLoop = 1; }
  215.     if( secondHand == 50)  { SetupRandomPalette();                     speed = 90; scale = 90; colorLoop = 1; }
  216.     if( secondHand == 55)  { currentPalette = RainbowStripeColors_p;   speed = 30; scale = 20; colorLoop = 1; }
  217.   }
  218. }
  219. // This function generates a random palette that's a gradient
  220. // between four different colors.  The first is a dim hue, the second is
  221. // a bright hue, the third is a bright pastel, and the last is
  222. // another bright hue.  This gives some visual bright/dark variation
  223. // which is more interesting than just a gradient of different hues.
  224. void setup() {
  225.   pinMode(latch, OUTPUT);
  226.   digitalWrite(latch, HIGH);
  227.   pinMode(button, INPUT);
  228.   state = digitalRead(button);
  229.   // initialize the x/y and time values
  230.   LEDS.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
  231.   LEDS.setBrightness(BRIGHTNESS);
  232.   // Initialize our coordinates to some random values
  233.   x = random16();
  234.   y = random16();
  235.   z = random16();
  236. }
  237. void loop() {
  238.   // Periodically choose a new palette, speed, and scale
  239.   ChangePaletteAndSettingsPeriodically();
  240.   // generate noise data
  241.   fillnoise8();
  242.   
  243.   // convert the noise data to colors in the LED array
  244.   // using the current palette
  245.   mapNoiseToLEDsUsingPalette();
  246.   LEDS.show();
  247.   delay(10);
  248. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 17 小时前

【Arduino 动手做】FLEXBALL - 带 WiFi 的百像素柔性 PCB 球

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail