ソフト基板LEDを筒にするケース -2-

 とりあえず筒の改訂版できたので組んでみる。ケーブルも内側にきちんとはまる。

 両面テープでの固定はあとでやるとして、とりあえずリングだけで固定はされている。リングは設計ミスのプリントをそのまま使ったので、ちょっとブカブカ感はあるので、上下のリングのほうも内径に合わせてプリントやりなおししないとだな。

 隙間はこのくらい。たぶん両面テープで貼るとジャストくらいになる感じ。でも、ジャストだとLED配置と少し間隔が異なるので、内側に一部重ねるようなスリットを作る工夫がいるかも。とりあえず放置。

 プログラムで表示パターンも変えてみた。あとスピードもアップしといた。

早くしてみた - YouTube
https://www.youtube.com/watch?v=sdXiKx7Bcck

 だいぶまぶしいな。

 普通に乳白の梱包材をかぶせてみたけど、それだけだとLEDの点光源が目立つので、なんかレンチキュラー的な分散できるシートないかしらん。

 Aliexpressにはいろいろあるけど、送料が高い。

 ガンプラのモノアイ用に使われるらしい。これでいいかな。

BitTradeOne MMDFSF 光拡散 ディフューザー・フィルム 模型のライティングクオリティアップ LED | ホビー用素材 通販
https://www.amazon.co.jp//dp/B0D5PS6FTH

 点光源を順次点灯消灯していると、点が目立つのは仕方がない。

 いまのところ、Groveから給電しているので、引けるのは最大で300mAくらいかな...

 最大輝度で1色:最大約20mA/個として、白にするとRGB同時点灯なので最大約60mA/個くらいか。なかなか厳しいね。安全なのは単色で10個くらいか。

 輝度をいまの20だと想定すると、最大値は255なので、8%弱。これだと結構点灯してもだいじょうぶそう。白点灯でも48個ぜんぶつけても226mAくらいなので大丈夫かな。

 とりあえず、1灯だとつらいので、前後含めて3灯で、中央1灯を明るさ20、前後2灯を明るさ10にしてみる。少しは流れている感じが出るかな?

3灯輝度違い - YouTube
https://www.youtube.com/watch?v=POftp2X3jIo

 #include <stdbool.h>

 #include <stdint.h>

 #include "freertos/FreeRTOS.h"

 #include "freertos/task.h"

 #include "esp_err.h"

 #include "esp_log.h"

 #include "led_strip.h"

 #include "led_strip_rmt.h"

 /*

 * ATOMS3 Lite Grove

 *

 * 赤:5V

 * 黒:GND

 * 黄:GPIO2

 */

 #define LED_STRIP_GPIO 2

 /*

 * 4×12 LEDマトリックスを筒状に配置

 *

 * 周方向:12列

 * 高さ方向:4段

 */

 #define CYLINDER_AROUND 12U

 #define CYLINDER_LEVELS 4U

 #define LED_STRIP_LED_NUM (CYLINDER_AROUND * CYLINDER_LEVELS)

 /*

 * 中央のLEDと前後のLEDの明るさ。

 * 設定範囲は0~255。

 */

 #define LED_BRIGHTNESS 20U

 #define ADJACENT_BRIGHTNESS 10U

 /*

 * アニメーション速度。

 *

 * ROTATION_INTERVAL_MS:

 * 周方向へ1ステップ移動する間隔。

 *

 * LEVEL_INTERVAL_MS:

 * 1周後に次の段へ移るまでの間隔。

 *

 * REPEAT_INTERVAL_MS:

 * 最上段終了後に最下段へ戻るまでの間隔。

 */

 #define ROTATION_INTERVAL_MS 20U

 #define LEVEL_INTERVAL_MS 20U

 #define REPEAT_INTERVAL_MS 50U

 /*

 * 上下が逆の場合は0に変更する。

 */

 #define LED_INPUT_SIDE_IS_BOTTOM 1

 /*

 * 回転方向が逆の場合は0に変更する。

 */

 #define INCREASING_IS_CLOCKWISE 1

 static const char *TAG = "cylinder_led";

 typedef struct {

 bool red;

 bool green;

 bool blue;

 } color_components_t;

 /*

 * 下から順番に使用する色。

 *

 * 0段目:赤

 * 1段目:緑

 * 2段目:黄

 * 3段目:青

 */

 static const color_components_t level_colors[CYLINDER_LEVELS] = {

 {

 .red = true,

 .green = false,

 .blue = false,

 },

 {

 .red = false,

 .green = true,

 .blue = false,

 },

 {

 .red = true,

 .green = true,

 .blue = false,

 },

 {

 .red = false,

 .green = false,

 .blue = true,

 },

 };

 /*

 * 筒状の座標を実際のLED番号へ変換する。

 *

 * around:

 * 周方向。0~11。

 *

 * level:

 * 高さ方向。0~3。

 * 0が最下段。

 *

 * マトリックスは4灯ごとのS字配線を想定。

 *

 * 列0: 0 1 2 3

 * 列1: 7 6 5 4

 * 列2: 8 9 10 11

 * 列3:15 14 13 12

 *

 * 最下段を一周するLED番号:

 *

 * 0, 7, 8, 15, 16, 23,

 * 24, 31, 32, 39, 40, 47

 */

 static uint32_t cylinder_to_led_index(

 uint32_t around,

 uint32_t level)

 {

 uint32_t physical_around;

 uint32_t physical_level;

 if (INCREASING_IS_CLOCKWISE) {

 physical_around = around;

 } else {

 physical_around =

 CYLINDER_AROUND - 1U - around;

 }

 if (LED_INPUT_SIDE_IS_BOTTOM) {

 physical_level = level;

 } else {

 physical_level =

 CYLINDER_LEVELS - 1U - level;

 }

 /*

 * 偶数列は正方向。

 */

 if ((physical_around & 1U) == 0U) {

 return physical_around * CYLINDER_LEVELS

 + physical_level;

 }

 /*

 * 奇数列は逆方向。

 */

 return physical_around * CYLINDER_LEVELS

 + (CYLINDER_LEVELS - 1U - physical_level);

 }

 /*

 * LEDドライバ内部の全ピクセルを消灯状態にする。

 *

 * この関数ではrefreshしない。

 */

 static void clear_led_buffer(led_strip_handle_t strip)

 {

 for (uint32_t index = 0;

 index < LED_STRIP_LED_NUM;

 ++index) {

 ESP_ERROR_CHECK(

 led_strip_set_pixel(

 strip,

 index,

 0,

 0,

 0

 )

 );

 }

 }

 /*

 * 指定された段・周方向位置のLEDを点灯する。

 *

 * level_colorsで有効な色成分にbrightnessを設定する。

 */

 static void set_level_pixel(

 led_strip_handle_t strip,

 uint32_t level,

 uint32_t around,

 uint8_t brightness)

 {

 const color_components_t color =

 level_colors[level];

 const uint32_t led_index =

 cylinder_to_led_index(around, level);

 const uint8_t red =

 color.red ? brightness : 0U;

 const uint8_t green =

 color.green ? brightness : 0U;

 const uint8_t blue =

 color.blue ? brightness : 0U;

 ESP_ERROR_CHECK(

 led_strip_set_pixel(

 strip,

 led_index,

 red,

 green,

 blue

 )

 );

 }

 /*

 * 中央1灯と前後2灯を表示する。

 *

 * 前方:明るさ10

 * 中央:明るさ20

 * 後方:明るさ10

 *

 * 周方向の端では剰余計算によりつながる。

 */

 static void show_rotating_pixels(

 led_strip_handle_t strip,

 uint32_t level,

 uint32_t around)

 {

 const uint32_t previous =

 (around + CYLINDER_AROUND - 1U)

 % CYLINDER_AROUND;

 const uint32_t next =

 (around + 1U)

 % CYLINDER_AROUND;

 clear_led_buffer(strip);

 /*

 * 前方の暗いLED。

 */

 set_level_pixel(

 strip,

 level,

 previous,

 ADJACENT_BRIGHTNESS

 );

 /*

 * 中央の明るいLED。

 */

 set_level_pixel(

 strip,

 level,

 around,

 LED_BRIGHTNESS

 );

 /*

 * 後方の暗いLED。

 */

 set_level_pixel(

 strip,

 level,

 next,

 ADJACENT_BRIGHTNESS

 );

 ESP_ERROR_CHECK(

 led_strip_refresh(strip)

 );

 }

 /*

 * espressif/led_strip 3.x用の初期化。

 */

 static led_strip_handle_t create_led_strip(void)

 {

 led_strip_handle_t strip = NULL;

 const led_strip_config_t strip_config = {

 .strip_gpio_num = LED_STRIP_GPIO,

 .max_leds = LED_STRIP_LED_NUM,

 .led_model = LED_MODEL_WS2812,

 /*

 * WS2812Bの一般的な色成分順。

 */

 .color_component_format =

 LED_STRIP_COLOR_COMPONENT_FMT_GRB,

 .flags = {

 .invert_out = false,

 },

 };

 const led_strip_rmt_config_t rmt_config = {

 .clk_src = RMT_CLK_SRC_DEFAULT,

 /*

 * 10MHz、1カウント100ns。

 */

 .resolution_hz = 10U * 1000U * 1000U,

 /*

 * 自動設定。

 */

 .mem_block_symbols = 0,

 .flags = {

 .with_dma = false,

 },

 };

 ESP_ERROR_CHECK(

 led_strip_new_rmt_device(

 &strip_config,

 &rmt_config,

 &strip

 )

 );

 ESP_ERROR_CHECK(

 led_strip_clear(strip)

 );

 return strip;

 }

 void app_main(void)

 {

 led_strip_handle_t strip =

 create_led_strip();

 ESP_LOGI(

 TAG,

 "Cylinder animation start: around=%u levels=%u leds=%u",

 (unsigned int)CYLINDER_AROUND,

 (unsigned int)CYLINDER_LEVELS,

 (unsigned int)LED_STRIP_LED_NUM

 );

 while (true) {

 /*

 * 下から上へ段を移動する。

 *

 * 0段目:赤

 * 1段目:緑

 * 2段目:黄

 * 3段目:青

 */

 for (uint32_t level = 0;

 level < CYLINDER_LEVELS;

 ++level) {

 ESP_LOGI(

 TAG,

 "level=%lu",

 (unsigned long)level

 );

 /*

 * 現在の段を12ステップで一周する。

 */

 for (uint32_t around = 0;

 around < CYLINDER_AROUND;

 ++around) {

 show_rotating_pixels(

 strip,

 level,

 around

 );

 vTaskDelay(

 pdMS_TO_TICKS(

 ROTATION_INTERVAL_MS

 )

 );

 }

 /*

 * 1周終了後に消灯して次の段へ進む。

 */

 clear_led_buffer(strip);

 ESP_ERROR_CHECK(

 led_strip_refresh(strip)

 );

 vTaskDelay(

 pdMS_TO_TICKS(

 LEVEL_INTERVAL_MS

 )

 );

 }

 /*

 * 最上段終了後に消灯し、

 * 最下段から繰り返す。

 */

 clear_led_buffer(strip);

 ESP_ERROR_CHECK(

 led_strip_refresh(strip)

 );

 vTaskDelay(

 pdMS_TO_TICKS(

 REPEAT_INTERVAL_MS

 )

 );

 }

 }

 最初のものより、流れている感じは出ていると思う。


オリジナル投稿:
ソフト基板LEDを筒にするケース -2-|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/12245527