M5Stack x 도전 천으로 말하는 봉제인형(옷)을 만든다
소개
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];
라는 부분이 있습니다만, 여기서 외부 텍스트 파일화한 음성 데이터를 읽고 있습니다.
이쪽은 아래의 페이지를 참고로 했습니다
대략적인 흐름으로
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];
라는 부분이 있습니다만, 여기서 외부 텍스트 파일화한 음성 데이터를 읽고 있습니다.
이쪽은 아래의 페이지를 참고로 했습니다
대략적인 흐름으로
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];
라는 부분이 있습니다만, 여기서 외부 텍스트 파일화한 음성 데이터를 읽고 있습니다.
이쪽은 아래의 페이지를 참고로 했습니다
대략적인 흐름으로
extern const unsigned char kusuguttai[28406];
extern const unsigned char konnichiwa[14922];
extern const unsigned char doushitano[15824];
라는 형태로 읽을 수 있도록 했습니다.
할 수있는 것
이런 느낌으로 만지면 말해줍니다.
피 c. 라고 r. 코 m/미 4lYMhGlS — elevendots (@elevendots1) December 15, 2020
향후 조금 더 정확도를 높이고 싶습니다!
Reference
이 문제에 관하여(M5Stack x 도전 천으로 말하는 봉제인형(옷)을 만든다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/tendots/items/9cbde5e701e1865f98ec텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)