植物排布:音频反应式LED显示
我一直对通过代码理解自然中出现的模式感到着迷。与宇宙中存在的内在涌现模式交流。植物排布就是这样一种模式,它出现在向日葵、肉质植物及其他植物中心的扩展双螺旋形状。代码意外地简单:// 内部和外部是临时的,// 只是为了让细胞之间的间距 float [][] points = new float [ numCells + numOuter + numInner ][ 2 ] ; float outerRadius = width / 2 ; final int total = numCells + numInner + numOuter ; for ( int i = 0 ; i < total ; i ++ ) { float f = i / float ( total ); float a = i * 1 . 6180339887 ; float distance = f * outerRadius ; float x = - cos ( a * TWO_PI ) * distance ; float y = sin ( a * TWO_PI ) * distance ; points [ i ][ 0 ] = x ; points [ i ][ 1 ] = y ; } 在圆的径向线上的几个线性点,逐个按黄金比例的增加倍数旋转。你会得到一个整齐的点云,已经看起来非常像向日葵。用Voronoi镶嵌它看起来很有趣,像种子荚: 当绘制点的Voronoi镶嵌结果时形状显现出来 在尝试这个一段时间后,我有了一个想法:如果我把它变成一个物理对象,把RGB地址可控LED放在每个单元中呢?一种细胞LED矩阵。我在高中时建立了一个矩形的neopixel矩阵,但我一直在等待找到下一个更有趣的形状。从数字到物理 我从我的处理草图中导出了单元边缘数据,并将其导入到使用CadQuery库的python草图中。编写了一些代码以从数据中构建物理几何体:# 创建单个单元的负空间 # 通过负偏移缩小 cell_shape = ( cq . Workplane ( "XY" ) . polyline ( vertices ) . close () . offset2D ( - wall_thickness / 2 , kind = 'intersection' ) . extrude ( total_height ) . translate (( 0 , 0 , base_height ))) # 从总形状中切割出它以创建一个有墙壁的壳 total_shape = total_shape . cut ( cell_shape ) # 切割出形状的孔以适应单元中心的LED total_shape = total_shape . cut ( led_hole . rotate (( 0 , 0 , 0 ), ( 0 , 0 , 1 ), math . degrees ( angle )) . translate (( centerX , centerY , 0 ))) 这个片段在构造所有合并的voronoi细胞的总体积后,从总量中减去每个单独单元的缩小体积,然后在每个单元中雕刻一个LED大小的洞。对所有单元执行此操作得到了下面的黄色形状。我还在此时将几何体分成四个大致相等的象限,每个象限的尺寸可以放入我的3D打印机床。我导出了STEP文件,并在FreeCAD中做了一些后处理,添加了螺孔,建立了一个薄版本,作为“面板”,其下有纸张。我在薄版本的底部切割并粘贴了纸,并利用螺孔将其固定在单元壁上。每个象限的CadQuery模型 面板模型,在FreeCAD中从CadQuery输出转换 我3D打印了这些形状,并找到了些透光纸,这种纸能够很好地扩散光,看起来有机而有趣,光线透过它。 我喜欢这一种桑树纸的样子,它有着如此美丽的有机纤维。 焊接89个LED有点乏味。但我找到了进入流动状态的方法,它变得放松。我将其连接到了我随便找的STM32黑色小板子,并编写了一个小的neopixel驱动程序,使用SPI。它在一些基本测试模式下已经很酷了。我构建了一个简单的草图框架,让我能够为LED编写处理风格的“着色器”代码。使用查找表为每个LED提供浮点位置,就像在单位圆上一样,我可以轻松编写这样的代码,它感觉像个片段着色器: void radial_spirals ( LEDBuffer leds ) { for ( int i = 0 ; i < NUM_LEDS ; i ++ ) { // 遍历每个单元 // 从LUT获取LED位置 float x = led_positions [ i ][ 0 ]; float y = led_positions [ i ][ 1 ]; // 极坐标 float r = sqrtf ( x * x + y * y ); float theta = atan2f ( y , x ); // 弧度角 [-π, π] // 螺旋模式:结合角度和半径 float spiral = sinf ( theta * 2.0f + r * 5.0f - seconds * 2.0f ); float brightness = ( spiral + 1.0f ) * 0.5f ; uint8_t level = ( uint8_t )( brightness * 255.0f ); leds [ i ] = rgb ( level , 0 , 0 ); } } 相当不错。我很快发现了这种我最喜欢的径向模式,一种从中心向外调制亮度的脉动正弦波。这最终成为我稍后进行的音频响应草图的主要特征。 添加音频 如果它能动态地对房间里的声音做出反应,而不是只显示预定义的模式,那会多酷啊?我希望它能感觉到生动而动态。驱动它的STM32板支持浮点和ARM DSP指令,所以我可以运行傅里叶变换并进行音频分析。我在我的面包板上添加了一枚数字I2S麦克风,INMP441。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡