M5Stack x 도전 천으로 말하는 봉제인형(옷)을 만든다

이 기사는 2020년 11월 17일에 개최된 【온라인】IoT 결박 공부회! IoTLT vol.69 @Youtube 에서 발표한 내용을 베이스로 하고 있습니다.

소개



UX 디자이너의 따뜻한입니다.

UX 디자이너의 따뜻한입니다.

평상시는 UI 설계나 UX 개발등의 일의 옆, 취미로 프로토 타입등을 만들거나 하고 있습니다.
요전날, E텍스타일을 사용한 인풋 모듈 「 nüno 」를 nanbwrks씨와 만들었습니다.
nüno의 최신 버전은 ver.2이지만,
이번에는 이 nüno ver.2를 사용하여 말하는 박제 옷을 만들어 보았습니다.

샤베구루미



GR 디자인 콘테스트 2017 에 응모했다
샤베구루미 」라는 작품을 과거에 작성했지만,
이 때는 음성 재생을 위해 스피커를 박제 배낭에 탑재하고있었습니다.

M5Stack Core2를 사용하면 스피커를 내장하고 있기 때문에 nüno ver.2와 연결하는 것만으로 연결할 수 있기 때문에,
다시 만들어 보기로 했습니다.

하드웨어 구성





간단합니다.



nüno는 GROVE 단자에 대응하고 있으므로 GROVE 케이블로 접속하는 것만으로 작성할 수 있습니다.

Arduino



Arduino의 프로그램은 다음과 같습니다.
또한, nüno에서는 MTCH6102라는 정전 터치 센서를 사용하고 있기 때문에,
프로그램과 같은 계층에 여기 에서 빌려왔다
- MTCH6102.h
- MTCH6102.cpp
사용
#include <M5Core2.h>
#include <Arduino.h>
#include <Wire.h>
#include "MTCH6102.h"
#include <driver/i2s.h>


#define ADDR 0x25
#define ScreenWidth 320
#define ScreenHeight 240

//Voice
#define CONFIG_I2S_BCK_PIN 12
#define CONFIG_I2S_LRCK_PIN 0
#define CONFIG_I2S_DATA_PIN 2
#define CONFIG_I2S_DATA_IN_PIN 34

#define Speak_I2S_NUMBER I2S_NUM_0

#define MODE_MIC 0
#define MODE_SPK 1
#define DATA_SIZE 1024

extern const unsigned char nani[13890];
extern const unsigned char kusuguttai[28406];
extern const unsigned char konnichiwa[14922];
extern const unsigned char doushitano[15824];

//Voide end

MTCH6102 mtch = MTCH6102();

const int len = 8;//感知ポイント数
int nuno_mode = 1;

void setup() {

  // Initialize the M5Stack object
  M5.begin();
  M5.Lcd.fillScreen(TFT_BLACK);
  Serial.begin(115200);

  //Wire.begin();
  mtch.begin(ADDR);
  delay(100);
  mtch.writeRegister(MTCH6102_NUMBEROFXCHANNELS, 0x07);
  mtch.writeRegister(MTCH6102_NUMBEROFYCHANNELS, 0x03);//最低3点必要なため
  mtch.writeRegister(MTCH6102_MODE, MTCH6102_MODE_FULL);
  mtch.writeRegister(MTCH6102_HORIZONTALSWIPEDISTANCE, 0x04);
  mtch.writeRegister(MTCH6102_MINSWIPEVELOCITY, 0x02);
  mtch.writeRegister(MTCH6102_TAPDISTANCE, 0x02);
  mtch.writeRegister(MTCH6102_BASEPOSFILTER, 0x00);
  mtch.writeRegister(MTCH6102_BASENEGAFILTER, 0x00);

  mtch.writeRegister(MTCH6102_CMD, 0x20);
  delay(500);

  //------Voice
  SpeakInit();
  delay(100);
}


bool sound = 0;
void loop() {
  M5.update();
  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Lcd.setCursor(0, 70);
  byte data;
  int sensVals[len];
  for (int i = 0; i < len; i++) {
    data = mtch.readRegister(MTCH6102_SENSORVALUE_RX0 + i);
    sensVals[i] = data;
    M5.Lcd.fillRect(30 + (i * 35), ScreenHeight - 20, 30, 10, TFT_BLACK);
    M5.Lcd.setCursor(30 + (i * 35), ScreenHeight - 20);
    M5.Lcd.print(data);
  }

  if (nuno_mode == 1) {
    data = mtch.readRegister(MTCH6102_GESTURESTATE);
    if (data != 0) {
      //Serial.println(data, HEX);
      if (data == 0x41) {
        Serial.println("swipeLeft");
        if(sound) {DingDong("kusuguttai");}
      }
      if (data == 0x61) {
        Serial.println("swipeRight");
        if(sound) {DingDong("doushitano");}
      }
      if (data == 0x10) {
        Serial.println("click");
        if(sound) {DingDong("nani");}
      }
      if (data == 0x20) {
        Serial.println("double click");
        if(sound) {DingDong("konnichiwa");}
      }
    }
  }

  M5.Lcd.setCursor(0, 70);

  //背景ライン
  for (int i = 0; i < len; i++) {
    M5.Lcd.drawLine((i + 1) * 35, ScreenHeight - 40, (i + 1) * 35, 0, 0x0000cc);
  }
  for (int i = 1; i < 11; i++) {
    M5.Lcd.drawLine(0, i * 20, ScreenWidth, i * 20, 0x0000cc);
  }
  //グラフ線の描画
  for (int i = 0; i < len + 1; i++) {
    float prev = 0;
    float current = 0;
    if (i == 0) {
      prev = 0;
    } else {
      prev = sensVals[i - 1];
    }
    if (i == len) {
      current = 0;
    } else {
      current = sensVals[i];
    }
    M5.Lcd.drawLine(i * 35, 200 - (prev / 255) * 200, ((i + 1) * 35), 200 - (current / 255) * 200, TFT_WHITE);
  }

  delay(100);
}


//-------Voice

bool InitI2SSpeakOrMic(int mode)
{
  esp_err_t err = ESP_OK;

  i2s_driver_uninstall(Speak_I2S_NUMBER);
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER),
    .sample_rate = 8000,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 2,
    .dma_buf_len = 128,
  };
  i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
  i2s_config.use_apll = false;
  i2s_config.tx_desc_auto_clear = true;

  err += i2s_driver_install(Speak_I2S_NUMBER, &i2s_config, 0, NULL);
  i2s_pin_config_t tx_pin_config;

  tx_pin_config.bck_io_num = CONFIG_I2S_BCK_PIN;
  tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN;
  tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN;
  tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN;
  err += i2s_set_pin(Speak_I2S_NUMBER, &tx_pin_config);
  err += i2s_set_clk(Speak_I2S_NUMBER, 8000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);

  return true;
}

void SpeakInit(void) {
  M5.Axp.SetSpkEnable(true);
  InitI2SSpeakOrMic(MODE_SPK);
}

void DingDong(String str)
{
  size_t bytes_written = 0;
  if(str == "nani"){
    i2s_write(Speak_I2S_NUMBER, nani, 13890, &bytes_written, portMAX_DELAY);
  }
  if(str == "kusuguttai"){
    i2s_write(Speak_I2S_NUMBER, kusuguttai, 28406, &bytes_written, portMAX_DELAY);
  }
  if(str == "konnichiwa"){
     i2s_write(Speak_I2S_NUMBER, konnichiwa, 14922, &bytes_written, portMAX_DELAY);
  }
  if(str == "doushitano"){
    i2s_write(Speak_I2S_NUMBER, doushitano, 15824, &bytes_written, portMAX_DELAY);
  }
}

//--------Voice end

음성 변환



「말하는 인형」이므로 당연히 음성 데이터가 필요합니다.
이번에는 Arduino 프로그램 전반에
extern const unsigned char kusuguttai[28406];
extern const unsigned char konnichiwa[14922];
extern const unsigned char doushitano[15824];

라는 부분이 있습니다만, 여기서 외부 텍스트 파일화한 음성 데이터를 읽고 있습니다.
이쪽은 아래의 페이지를 참고로 했습니다

대략적인 흐름으로
  • Audacity 설치
  • Audacity에서 모노 데이터에
  • Audacity에서 8000Hz로 변환
  • 오디오 내보내기에서 원시 형식의 데이터로 변환
  • 명령 줄에서 텍스트 데이터로 변환 및 클립 보드에 복사
  • Arduino 프로그램 파일 같은 디렉토리에 배치

  • 라는 형태로 읽을 수 있도록 했습니다.

    할 수있는 것



    이런 느낌으로 만지면 말해줍니다.

    피 c. 라고 r. 코 m/미 4lYMhGlS — elevendots (@elevendots1) December 15, 2020


    향후 조금 더 정확도를 높이고 싶습니다!


    좋은 웹페이지 즐겨찾기