Miho Yamada
Published © LGPL

Alligato-R

The alligator that said “ありがとうございます(Thank you very much)”

BeginnerFull instructions provided2 hours58
Alligato-R

Things used in this project

Hardware components

M5Stack Core2 ESP32 IoT Development Kit
M5Stack Core2 ESP32 IoT Development Kit
×1

Software apps and online services

Fusion
Autodesk Fusion
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Alligato-r

Alligato-r 3Dmodel pdf

Alligato-R v7.f3d

fuion file

Schematics

Alligato-r

Only core2 and USB

Alligato-R v7.f3d

Fusion file

Code

alligato-r.ino

Arduino
Pressing the green button will load the audio files stored on the SD card. The button will turn red while loading.
#include <M5Core2.h>
#include <driver/i2s.h>

void setup() {
    M5.begin();
    
    // 画面を左に90度回転(横向き)
    M5.Lcd.setRotation(1);
    
    M5.Lcd.setTextSize(3);
    M5.Lcd.fillScreen(BLACK);
    
    // スピーカー有効化
    M5.Axp.SetSpkEnable(true);
    
    // SDカード初期化
    if (!SD.begin()) {
        M5.Lcd.setTextColor(RED);
        M5.Lcd.println("SD Card Error!");
        delay(2000);
    }
    
    // I2S設定(スピーカー用)
    initSpeaker();
    
    // ボタン表示
    drawButtons();
}

void initSpeaker() {
    i2s_driver_uninstall(I2S_NUM_0);
    
    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
        .sample_rate = 44100,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
        .communication_format = I2S_COMM_FORMAT_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 8,
        .dma_buf_len = 64,
        .use_apll = false,
        .tx_desc_auto_clear = true,
        .fixed_mclk = 0
    };
    
    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
    
    i2s_pin_config_t pin_config = {
        .bck_io_num = 12,
        .ws_io_num = 0,
        .data_out_num = 2,
        .data_in_num = I2S_PIN_NO_CHANGE
    };
    
    #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
        pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
    #endif
    
    i2s_set_pin(I2S_NUM_0, &pin_config);
}

void drawButtons() {
    M5.Lcd.fillScreen(BLACK);
    
    // 大きなありがとうボタン(画面中央に配置)
    M5.Lcd.fillRoundRect(60, 60, 200, 120, 15, GREEN);

}

void playThanksAudio() {
    // 画面にフィードバック表示(シンプルに)
    M5.Lcd.fillRoundRect(60, 60, 200, 120, 15, RED);

    
    if (SD.exists("/arigato_ja.wav")) {
        File audioFile = SD.open("/arigato_ja.wav");
        if (audioFile) {
            // WAVヘッダーをスキップ
            audioFile.seek(44);
            
            uint8_t buffer[512];
            size_t bytes_written;
            
            while (audioFile.available()) {
                size_t bytesRead = audioFile.read(buffer, sizeof(buffer));
                if (bytesRead > 0) {
                    i2s_write(I2S_NUM_0, buffer, bytesRead, &bytes_written, portMAX_DELAY);
                }
            }
            audioFile.close();
        }
    } else {
        // WAVファイルがない場合はビープ音
        playBeep();
    }
    
    // 1秒後にボタンを元に戻す
    delay(1000);
    drawButtons();
}

void playBeep() {
    // シンプルなビープ音
    int16_t high = 8000;
    int16_t low = -8000;
    size_t bytes_written;
    
    for (int i = 0; i < 22050; i++) { // 0.5秒
        int16_t sample = (i % 44) < 22 ? high : low; // ~1000Hz
        i2s_write(I2S_NUM_0, &sample, sizeof(sample), &bytes_written, portMAX_DELAY);
    }
}

void showInfo() {
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(CYAN);
    M5.Lcd.setCursor(50, 30);
    M5.Lcd.println("System Info");
    
    M5.Lcd.setTextSize(1);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.setCursor(10, 70);
    M5.Lcd.println("Audio File: /arigato_ja.wav");
    
    M5.Lcd.setCursor(10, 90);
    if (SD.exists("/arigato_ja.wav")) {
        File f = SD.open("/arigato_ja.wav");
        M5.Lcd.println("Status: Found (" + String(f.size()) + " bytes)");
        f.close();
    } else {
        M5.Lcd.setTextColor(RED);
        M5.Lcd.println("Status: Not Found");
        M5.Lcd.setTextColor(WHITE);
    }
    
    M5.Lcd.setCursor(10, 110);
    M5.Lcd.println("Sample Rate: 44.1kHz");
    M5.Lcd.setCursor(10, 130);
    M5.Lcd.println("Channels: Mono");
    M5.Lcd.setCursor(10, 150);
    M5.Lcd.println("Bits: 16-bit");
    
    M5.Lcd.setTextColor(YELLOW);
    M5.Lcd.setCursor(10, 190);
    M5.Lcd.println("Touch anywhere to return");
    
    // タッチ待ち
    while (true) {
        M5.update();
        if (M5.Touch.ispressed() || M5.BtnA.wasPressed() || M5.BtnB.wasPressed() || M5.BtnC.wasPressed()) {
            drawButtons();
            break;
        }
        delay(50);
    }
}

void loop() {
    M5.update();
    
    // タッチ検出(ありがとうボタンエリア: x:60-260, y:60-180)
    if (M5.Touch.ispressed()) {
        TouchPoint_t pos = M5.Touch.getPressPoint();
        if (pos.x >= 60 && pos.x <= 260 && pos.y >= 60 && pos.y <= 180) {
            playThanksAudio();
            delay(200); // デバウンス
        }
    }
    
    // 物理ボタン
    if (M5.BtnA.wasPressed()) {
        // テスト再生
        playThanksAudio();
    }
    
    if (M5.BtnB.wasPressed()) {
        // 画面リロード
        drawButtons();
    }
    
    if (M5.BtnC.wasPressed()) {
        // 情報表示
        showInfo();
    }
    
    delay(50);
}

Credits

Miho Yamada
1 project • 1 follower

Comments