AKBONE2022 で LED パネルを使ったオープンソーストレーニングキットを考える

秋葉原ロボット部で(ほぼ)毎年作っているトレーニングキット AKBONE 。

今年版の AKBONE2022 はLEDパネルを扱うものにしようかなと試作しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/5b0838e6-9378-5e52-c14c-cdde7816d8a0.png)

現在アルファ版を作成して諸々検討中。

この記事は現在検討中の技術課題をオープンソースの流れで共有します。

# アルファ版インフォメーション

## 基板シェイプ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/74426772-6860-d9ac-601b-b8b0a4c0e31e.png)

## 回路図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/3ae059d1-35fd-aa6f-6107-d0633e7af695.png)

## 搭載可能モジュール

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/a2a9a3d6-ba03-ef49-bc1e-65cd1561b646.png)

## 機能

- ESP32 で HUB75 仕様の LED パネルを駆動できる
- 各種センサーモジュール、ブザー、SDカードスロット、ロータリーエンコーダー、押しボタンスイッチを搭載でき、ESP32で扱える
- ESP32 と 通信できる Linux ボードを搭載できる
- ESP32 と Linux ボードは シリアルまたはSPIで通信できる
- Liux ボードからのオーディオ出力はアンプを経由してスピーカーに接続できる

## 教育的効果

- かんたんなはんだづけでサイネージが実現できる
- サイネージのサンプルプログラムはいくつか用意し、プログラムレスでも楽しめる使える
- ESP32 をプログラムすることでサイネージの表示を自分で制御できる
- ブロックプログラミング環境、Arduino IDE、Python 、シェルスクリプトなどレベルに応じたプログラムトレーニングができる
- LED 点灯数と電源の選定から電圧と電流の概念を掴むことができる
- 加速度センサを用い、力学の教材として用いることができる
- ラスターグラフィック表示を通してXY座標系の理解を進めることができる
- VT-100 化することで Linux ボードのコンソールとして使うことができる
- バックスクロール可能なスタンドアロンコンソールを用い、一人一台のLinux ブートプロセスの教材とすることができる

などなど


## 接続確認できたLEDパネル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/412aa858-de08-c6c7-0cbd-5418a2004496.png)

P4 64dotx32dot 256mmx128mm

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f2b565bc-faff-faa5-9200-90523fa662c3.png)

安くてデカイ 55元ぐらいで調達しています

P3 64dotx32dot 192mmx96mm

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/36b13fd0-312a-dabe-11ac-aceeaed71aca.png)

P2 128dotx64dot 256mmx128mm

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ee0e6daf-577e-393b-ff15-a22ffed08621.png)

128x64 は ちょっとファームを直さないといけないですね。

# 基本的な動作確認

まずはLEDパネルが光るだけの動作確認をします。

AKBONE2022 は ESP32ボードとして NodeMCU や DevKitC、DevKitv1 などを装着できるようにしています。
利用するESPボードに合わせてソケットを立て、はんだづけします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c6017f73-d4bd-09a1-9282-d765fda05610.png)

LEDパネル電源コネクタをはんだづけ。」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/5dcf45a8-3a52-a072-7b4d-e6ea78000020.png)

HUB75コネクタをはんだづけ。今回はピッタリ合うのがなかったので適当なコネクタを加工しました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1aa33732-f273-774a-19e3-404c6771e71e.png)

電源とHUB75を接続します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/0770f0dc-69ac-af1b-ba6c-b450356c9fdd.png)
LEDパネルに接続

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/521a8bd3-54a0-1354-2e69-7990312dc5ab.png)

ファームウェアを書き込みます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/11d2f2d1-4a81-955b-6c79-30b0c3a2870b.png)

動作したらOK.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/067b1bef-edaa-a864-48f1-be220bc57aaf.png)

書き込み時に不安定になるので外部電源コネクタを立てて、ここから電源供給するようにしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/2c368d69-e798-91bb-e7b6-f0dbe4861e8b.png)

# テスト用ファームウェア

64x32用のLED点灯テスト。
ライブラリも何もなく単にGPIO制御で光らせています。
動作確認は Arduino IDE 1.8.13 上で行っています。
128x64でもとりあえず曲りなりに表示します。

```

/*
 * 
 * for 64dot x 32 dot RGB LED panel with ICN2037 and ICN2012 using HUB75

 (HUB75 pin layout)
   +-+-+
 R1|o|o|G1
 B1|o|o|GND
 R2|o|o|G2
 B2 o|o|GND/A4
 A0 o|o|A1
 A2|o|o|A3
CLK|o|o|LAT
 OE|o|o|GND
   +-+-+
*/

#include <stdio.h>
#include <string.h>

#define R1PIN     33
#define G1PIN     32
#define B1PIN     25
#define R2PIN     18
#define G2PIN     19
#define B2PIN     5
#define A0PIN     12
#define A1PIN     14
#define A2PIN     27
#define A3PIN     26
// #define A4PIN       4 // GND
#define CLKPIN    4
#define LATPIN    17
#define OEPIN     16
#define LEDPANEL_X      64
#define LEDPANEL_Y      32
unsigned long imagedata[ 512 ] = {
  0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
  0x10000000,0x00222000,0x70000070,0x50000000,0x33333330,0x20000020,0x44444440,0x10000000,
  0x10000000,0x02000200,0x70000070,0x50000000,0x30000000,0x20000020,0x40000000,0x10000000,
  0x10000000,0x20000020,0x70000070,0x50000000,0x30000000,0x20000020,0x40000000,0x10000000,
  0x10000000,0x20000020,0x70000070,0x50000000,0x30000000,0x20000200,0x40000000,0x10000000,
  0x10000000,0x20000020,0x70000700,0x50000000,0x30000000,0x20000200,0x40000000,0x10000000,
  0x10000000,0x20000020,0x07070700,0x50000000,0x33333330,0x20000200,0x40000000,0x10000000,
  0x10000000,0x20000020,0x07070700,0x50000000,0x30000000,0x02002000,0x44444440,0x10000000,
  0x10000000,0x20000020,0x07070700,0x50000000,0x30000000,0x02002000,0x40000000,0x10000000,
  0x10000000,0x20000020,0x07070700,0x50000000,0x30000000,0x02002000,0x40000000,0x10000000,
  0x10000000,0x20000020,0x07777000,0x50000000,0x30000000,0x02020000,0x40000000,0x10000000,
  0x10000000,0x20000020,0x00707000,0x50000000,0x30000000,0x02020000,0x40000000,0x10000000,
  0x10000000,0x02000200,0x00707000,0x50000000,0x30000000,0x00220000,0x40000000,0x10000000,
  0x11111110,0x00222000,0x00707000,0x55555550,0x33333330,0x00200000,0x44444440,0x11111110,

  0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
  0x00030000,0x60000060,0x55555500,0x77777700,0x04444400,0x22222200,0x00111000,0x55555555,
  0x00303000,0x66000600,0x50000050,0x70000070,0x40000040,0x20000020,0x01000100,0x00050000,
  0x00303000,0x66006000,0x50000050,0x70000070,0x40000040,0x20000020,0x10000010,0x00050000,
  0x00303000,0x60660000,0x50000050,0x70000070,0x40000040,0x20000020,0x10000010,0x00050000,
  0x03000300,0x60600000,0x50000050,0x70000070,0x40000040,0x20000020,0x10000010,0x00050000,
  0x03000300,0x60060000,0x55555500,0x70000070,0x40000040,0x20000200,0x10000010,0x00050000,
  0x03000300,0x60060000,0x50000050,0x77777700,0x40000040,0x22222200,0x10000010,0x00050000,
  0x30000030,0x60006000,0x50000050,0x77000000,0x40000040,0x20000200,0x10000010,0x00050000,
  0x30000030,0x60006000,0x50000050,0x70700000,0x40000040,0x20000020,0x10000010,0x00050000,
  0x33333030,0x60000600,0x50000050,0x70070000,0x40000040,0x20000020,0x10000010,0x00050000,
  0x30000030,0x60000600,0x50000050,0x70007000,0x40000040,0x20000020,0x10000010,0x00050000,
  0x30000030,0x60000060,0x50000050,0x70000700,0x40000040,0x20000200,0x01000100,0x00050000,
  0x30000030,0x60000060,0x55555500,0x70000070,0x04444400,0x22222000,0x00111000,0x00050000,
  0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
  0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
  0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};
unsigned long fundata[ 16] = {
  0x12345671,0x23456712,0x34567123,0x45671234,0x56712345,0x67123456,0x71234567,0x00000000,
  0x12345671,0x23456712,0x34567123,0x45671234,0x56712345,0x67123456,0x71234567,0x00000000,
};

void rowselect( int rowaddress )
{
int a,b,c,d,e;
  digitalWrite( OEPIN, HIGH );
  usleep(3);
  digitalWrite( A0PIN, rowaddress & 0x01 );
  digitalWrite( A1PIN, (rowaddress >> 1 ) & 0x01  );
  digitalWrite( A2PIN, (rowaddress >> 2 ) & 0x01 );
  digitalWrite( A3PIN, (rowaddress >> 3 ) & 0x01  );
 // digitalWrite( A4PIN, (rowaddress >> 4 ) & 0x01  );
  usleep(3);
  digitalWrite( LATPIN, HIGH );
  digitalWrite( LATPIN, LOW );
  digitalWrite( OEPIN, LOW );
}
int getcolor( int x, int rowaddress, int bank ){
    int color;
    int imagedataaddress = ((rowaddress+bank*16)*LEDPANEL_X+x)/8;
    if ( 0 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 28)& 0x07;
    } else if ( 1 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 24)& 0x07;
    } else if ( 2 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 20)& 0x07;
    } else if ( 3 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 16)& 0x07;
    } else if ( 4 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 12)& 0x07;
    } else if ( 5 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 8)& 0x07;
    } else if ( 6 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 4)& 0x07;
    } else if ( 7 == x % 8 ){
        color= (imagedata[ imagedataaddress ] >> 0)& 0x07;
    }
    return(color);
}
void setup( void )
{
    Serial.begin(115200);
    delay(100);
    pinMode( R1PIN,  OUTPUT );
    pinMode( G1PIN,  OUTPUT );
    pinMode( B1PIN,  OUTPUT );
    pinMode( R2PIN,  OUTPUT );
    pinMode( G2PIN,  OUTPUT );
    pinMode( B2PIN,  OUTPUT );
    pinMode( A0PIN,   OUTPUT );
    pinMode( A1PIN,   OUTPUT );
    pinMode( A2PIN,   OUTPUT );
    pinMode( A3PIN,   OUTPUT );
   // pinMode( A4PIN,   OUTPUT );
    pinMode( CLKPIN, OUTPUT );
    pinMode( LATPIN, OUTPUT );
    pinMode( OEPIN,  OUTPUT );
    digitalWrite( CLKPIN, LOW );
    digitalWrite( LATPIN, LOW );
    digitalWrite( OEPIN, LOW );
}
void loop( void )
{
    int color;
    int x;
    int rowaddress;
    int test1;
    int test2;
    static int counter;
    for( rowaddress=0 ; rowaddress<LEDPANEL_Y/2; rowselect( rowaddress++ ) ) {
        for( x=0 ; x<LEDPANEL_X ; x++ ) {
            color = getcolor( x, rowaddress, 0 );
            digitalWrite( R1PIN,  color        & 0x01  );
            digitalWrite( G1PIN, ((color >> 1 ) & 0x01  ) );
            digitalWrite( B1PIN, ((color >> 2 ) & 0x01  ) );
            color = getcolor( x, rowaddress, 1 );
            digitalWrite( R2PIN,  color       & 0x01  );
            digitalWrite( G2PIN, ((color >> 1 ) & 0x01  ));
            digitalWrite( B2PIN, ((color >> 2 ) & 0x01  ));
            digitalWrite( CLKPIN, HIGH );
            usleep(3);
            digitalWrite( CLKPIN, LOW );    
        }
    }
    counter++;
    for ( int i=0; i<8 ;i++){
      imagedata[255-i] =fundata[counter/100%8+i];
    }
}
    
```

# ピン配置

```
#define R1PIN     33
#define G1PIN     32
#define B1PIN     25
#define R2PIN     18
#define G2PIN     19
#define B2PIN     5
#define A0PIN     12
#define A1PIN     14
#define A2PIN     27
#define A3PIN     26
// #define A4PIN       4 // GND
#define CLKPIN    4
#define LATPIN    17
#define OEPIN     16
#define LEDPANEL_X      64
#define LEDPANEL_Y      32
```
その他


|ESP32|Linuxボード|信号名|説明| 
|:----:|:----:|:----:|:----:|
|VP(GPIO36)||SW_B|ロータリーエンコーダーB相|
|VN(GPIO39)||SW_ANALOG|ロータリーエンコーダーSWとESCスイッチのマルチプレックス|
|GPIO34||SW_A|ロータリーエンコーダーA相|
|GPIO35|MOSI/RX|SDMISO_SMOSI_RX2|microSDソケットMISO/LinuxボードSPI0_MOSI/ジャンパー選択でLinuxボードRX|
|GPIO23|MISO/TX|SDMOSI_SMISO_TX2|microSDソケットMOSI/LinuxボードSPI0_MISO/ジャンパー選択でLinuxボードTX|
|GPIO13|SCLK|SCLK|microSDソケットCLK/LinuxボードSPI0_CLK|
|GPIO22||I2C_SDA|センサやGrove端子のSDA|
|GPIO21||I2C_SCL|センサやGrove端子のSCL|
|GPIO2||BUZZER|圧電ブザー|
|GPIO15|CS|CS|microSDソケットCS/LinuxボードSPI0_CS|
|TX|RX|TX|ESP32ボード上でUSBシリアルとして接続/ジャンパー選択でLinuxボードRX|
|RX|TX|RX|ESP32ボード上でUSBシリアルとして接続/ジャンパー選択でLinuxボードTX|




SW_ANALOGは、10kでプルアップされていて、ロータリーエンコーダーSWを押すとGND,ESCを押すと電圧が中点となります。両方押すとGND。



# 拡張モジュール詳細


中華製の市場で安く購入できるものをつなげられるようにしています。

ジャイロ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/cc217339-efc9-09ab-7f8c-0c27e9a2bbd6.png)

RTC
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d14b0ed1-8dd6-12c3-c201-a3ce8bf8fb1f.png)


温湿度気圧センサ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9688b2a9-6818-3198-4b26-5e0db2384f0e.png)


オーディオアンプ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/52ebe158-2b23-1af3-901b-3e34ed20a632.png)


スピーカー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/6b57c341-8371-0618-3230-a743993bec12.png)
https://detail.tmall.com/item.htm?id=42529253508&spm=a1z09.2.0.0.47fa2e8doTeVkT&_u=n1ieqpng4ede&skuId=4261755627790

# 技術的検討事項

- 開発環境
  - ワークショップで使うとなるとポータブル環境が必要
  - Arduino 1.8系?
- ブロックプログラミング
  - Ardublock?
- LED ドライバ
  - DMA利用
  - 描画ドライバとしてフォントや簡単な幾何描画を行いたい
  - GFX / g8lib あたり?
  - Laviyan GFX を使うようにできないか?
- サンプルプログラム
  - 温湿度気圧計
  - RTCを使った時計
  - SDカード連携
- Linux との連携
  - VT-100互換のESP32のファームウェア
  - 以下が実現できないか?
  - ロータリーエンコーダーでバックスクロール
  - ESCボタンで表示ポーズ

P2LEDは破損しやすい・・・カバーが必要?

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/98b60e4a-1dc5-da6c-4bf1-9ce4bdb0529a.png)