Skip to content

Instantly share code, notes, and snippets.

@mongonta0716
Last active January 13, 2022 06:30
Show Gist options
  • Save mongonta0716/9ee8aa756ea4b74d4ea2498d4df012fa to your computer and use it in GitHub Desktop.
Save mongonta0716/9ee8aa756ea4b74d4ea2498d4df012fa to your computer and use it in GitHub Desktop.
スタックチャン + Aquestalk LSIで初めまして( https://twitter.com/mongonta555/status/1479484496764637184 )
#include <Arduino.h>
#include "BF_AquesTalkPicoWire.h" // https://github.com/botanicfields/PCB-MBUS-AquesTalk-pico-LSI/tree/main/BF-034_Wire
#include "esp_adc_cal.h" // for esp_adc_cal_characteristics_t
#if defined(ARDUINO_M5STACK_Core2)
#include <M5Core2.h>
#define SERVO_PIN_X 13
#define SERVO_PIN_Y 14
#elif defined( ARDUINO_M5STACK_FIRE )
#include <M5Stack.h>
#define SERVO_PIN_X 22
#define SERVO_PIN_Y 21
#elif defined( ARDUINO_M5Stack_Core_ESP32 )
#include <M5Stack.h>
#define SERVO_PIN_X 16
#define SERVO_PIN_Y 17
#endif
#include <Avatar.h> // https://github.com/meganetaaan/m5stack-avatar
#include <ServoEasing.hpp> // https://github.com/ArminJo/ServoEasing
using namespace m5avatar;
Avatar avatar;
AquesTalkPicoWire aqtp;
const int fir_size(20);
const double fir_coef[] =
{ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, }; // moving average
int ring_buf[fir_size];
int ring_buf_head(0);
const int fir_out_size(30);
int fir_out[fir_out_size];
esp_adc_cal_characteristics_t adc_chars;
#define START_DEGREE_VALUE_X 90
#define START_DEGREE_VALUE_Y 90
ServoEasing servo_x;
ServoEasing servo_y;
bool random_move = false;
const char* lyrics[] = { "BtnA:MoveTo90 ", "BtnB:ServoTest ", "BtnC:RandomMode "};
const int lyrics_size = sizeof(lyrics) / sizeof(char*);
int lyrics_idx = 0;
void testMode() {
random_move = false;
servo_y.easeToD(50, 500);
servo_y.easeToD(90, 1000);
servo_y.easeToD(75, 1000);
servo_x.easeToD(70, 500);
servo_x.easeToD(110, 500);
servo_x.easeToD(90, 1000);
servo_y.easeToD(50, 500);
servo_y.easeToD(90, 500);
servo_y.easeToD(75, 1000);
}
void initADC() {
adc_power_on();
adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_7); // ADC1 Channel 7 = GPIO35
adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11); // attenuation 11dB
adc1_config_width(ADC_WIDTH_BIT_12); // width 12bit
//Characterize ADC at particular ATTEN
const int default_vref(1100);
esp_adc_cal_value_t cal_value = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, default_vref, &adc_chars);
//Check type of calibration value used to characterize ADC
String msg = "[AdcWaveInit] cal_value = ";
switch (cal_value) {
case ESP_ADC_CAL_VAL_EFUSE_VREF: msg += "eFuse Vref"; break;
case ESP_ADC_CAL_VAL_EFUSE_TP: msg += "Two Point"; break;
default: msg += "Default"; break;
}
Serial.println(msg);
// ring buffer and FIR
ring_buf_head = 0;
}
void lipsync(void *args) {
unsigned int start_ms = millis();
for(;;) {
// read ADC for one frame of LCD
for (int i = -30; i < fir_out_size; ++i) {
// read ADC into ring buffer
if(++ring_buf_head >= fir_size)
ring_buf_head = 0;
ring_buf[ring_buf_head] = esp_adc_cal_raw_to_voltage(adc1_get_raw(ADC1_CHANNEL_7), &adc_chars);
// FIR filter on the ring buffer
double fir_sum = 0.0;
for (int j = 0; j < fir_size; ++j) {
int k = ring_buf_head - j;
if (k < 0)
k += fir_size;
fir_sum += fir_coef[j] * (double)ring_buf[k];
}
// output of FIR filter
if (i >= 0)
fir_out[i] = (int)fir_sum;
vTaskDelay(1/portTICK_RATE_MS);
}
// statistics
int sum = fir_out[0];
int min = fir_out[0];
int max = fir_out[0];
for (int i = 1; i < fir_out_size; ++i) {
sum += fir_out[i];
min = min > fir_out[i] ? fir_out[i] : min;
max = max < fir_out[i] ? fir_out[i] : max;
}
int ave = sum / fir_out_size;
int pp = max - min;
int elapsed_ms = millis() - start_ms;
Serial.printf("[AdcWave] %dms, min %d, ave %d, max %d, pp %d\n", elapsed_ms, min, ave, max, pp);
float ratio = pp / 600.0f;
avatar.setMouthOpenRatio(ratio);
vTaskDelay(1/portTICK_RATE_MS);
}
}
void startThreads() {
xTaskCreateUniversal(lipsync,
"lipsync",
1024,
NULL,
6,
NULL,
tskNO_AFFINITY);
}
void setup() {
#if defined(ARDUINO_M5STACK_Core2)
M5.begin(true, true, true, false, kMBusModeOutput);
// M5.begin(true, true, true, false, kMBusModeInput);
#elif defined( ARDUINO_M5STACK_FIRE ) || defined( ARDUINO_M5Stack_Core_ESP32 )
M5.begin(true, true, true, true); // Grove.Aを使う場合は第四引数(I2C)はfalse
#endif
aqtp.Begin(Wire);
if (servo_x.attach(SERVO_PIN_X, START_DEGREE_VALUE_X, DEFAULT_MICROSECONDS_FOR_0_DEGREE, DEFAULT_MICROSECONDS_FOR_180_DEGREE)) {
Serial.print("Error attaching servo x");
}
if (servo_y.attach(SERVO_PIN_Y, START_DEGREE_VALUE_Y, DEFAULT_MICROSECONDS_FOR_0_DEGREE, DEFAULT_MICROSECONDS_FOR_180_DEGREE)) {
Serial.print("Error attaching servo y");
}
servo_x.setEasingType(EASE_QUADRATIC_IN_OUT);
servo_y.setEasingType(EASE_QUADRATIC_IN_OUT);
setSpeedForAllServos(60);
avatar.init();
initADC();
aqtp.Send("#V\r"); // read version
for (int i = 0; i < 10; ++i) {
aqtp.ShowRes();
delay(200);
}
aqtp.Send("#J\r"); // chime sound J
for (int i = 0; i < 10; ++i) {
aqtp.ShowRes();
delay(200);
}
aqtp.Send("#K\r"); // chime sound K
for (int i = 0; i < 10; ++i) {
aqtp.ShowRes();
delay(200);
}
startThreads();
//aqtp.Send("sutakkuchan,bu-to,o-ke-,shisutemu,no-maru,taipuzero,sutanbai\r");
aqtp.Send("hajimema'_shite watashiwa su'-pa-/kawai'i/robotto suta'xtu_ku/chan'nto/iima'_su.yoroshikune?\r");
testMode();
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) {
random_move = false;
servo_x.setEaseTo(90);
servo_y.setEaseTo(90);
synchronizeAllServosStartAndWaitForAllServosToStop();
}
if (M5.BtnB.wasPressed()) {
for (int i=0; i<2; i++) {
testMode();
}
}
if (M5.BtnC.wasPressed()) {
random_move = !random_move;
}
if (random_move) {
int x = random(45);
int y = random(40);
M5.update();
if (M5.BtnC.wasPressed()) {
random_move = false;
}
servo_x.setEaseTo(x + 45);
servo_y.setEaseTo(y + 40);
synchronizeAllServosStartAndWaitForAllServosToStop();
int delay_time = random(10);
delay(2000 + 100*delay_time);
avatar.setSpeechText("Stop BtnC");
}
// if (!random_move) {
// const char* l = lyrics[lyrics_idx++ % lyrics_size];
// avatar.setSpeechText(l);
// avatar.setMouthOpenRatio(0.7);
// delay(200);
// avatar.setMouthOpenRatio(0.0);
// delay(2000);
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment