ちゃんと走らないと怒られるウォークマン
はじめに
ランニングしているとどうしても自分に負けて途中でやめてしまいがちな自分に向けて、ちゃんと走らないと怒ってくれるウォークマンを作りました。
Spresense は、小型で簡単に音楽生成ができ、かつ、AIを取り込めるので、自分のランニング状況に合わせて再生音声を変更するということが可能です。それを利用しました。
用意したもの
SPRESENSEメインボード[CXD5602PWBMAIN1]
B-stem PDA01 SPRESENSE用機能拡張ボード
PDA01は、小型でオーディオ出力を持っているだけでなく、充電機能、加速度センサもついているので、今回のケースにはピッタリ。
後は、SDカード。SDカードは何でもよいのですが、キオクシアのモノが安定動作しています。
KIOXIA(キオクシア) 旧東芝メモリ microSDHCカード 32GB
準備したものはこれだけ。
元ネタ
元ネタはこれです。
http://spresense.livedoor.blog/archives/24443523.html
プログラム
Spresenseには、Step Countorのサンプルプログラムがあり、そこには行動認識のAIも入っています。
ただ、対応センサが BMI160 になのですが、PDA01 に載っているのは、KX122 なのでそちらへの変更を行います。
変更の仕方は、以下にあります。
4.1.2. Step Counter の物理センサを変更してみる
これによって、走ってる、歩いてる、止まってるの行動認識ができるようになります。
これを利用して走っていないことを認識したら怒るようにします。
次に、音声再生を行います。せっかくなのでちゃんと聞きたい音楽を聴こうということで、
プレイリストでの音声再生を行うスケッチを利用します。
これを StepCounter のスケッチにマージします。
ただ、再生する音声は、ちゃんと走っている時と、歩いてしまっている時で切り替えたいので、Playlistを切り替えて再生するようにしてみます。
実際には、Playlist の インスタンスを3つ生成し、実際に使うリストへのポイントをきりかえることで実現します。
Playlist thePlaylist0("TRACK_DB0.CSV");
Playlist thePlaylist1("TRACK_DB1.CSV");
Playlist thePlaylist2("TRACK_DB2.CSV");
Playlist* thePlaylist = &thePlaylist0;
static uint8_t ChangeList = 0xff;
とし、それぞれの関数
static void list()
static bool next()
static bool prev()
の中の
thePlaylist.
を
thePlaylist->
に変更。
void setup()
の中の
thePlaylist.
を
thePlaylist0.
thePlaylist1.
thePlaylist2.
に変更し、行動の変化点を検出したら切り替えるように、行動認識からの結果を判定する
bool step_counter_result(sensor_command_data_mh_t &data)
の中に、
static uint current_type = STEP_COUNTER_MOVEMENT_TYPE_STILL;
を定義し、
if(current_type != steps->movement_type){
switch (steps->movement_type)
{
case STEP_COUNTER_MOVEMENT_TYPE_WALK:
ChangeList = 1;
break;
case STEP_COUNTER_MOVEMENT_TYPE_RUN:
ChangeList = 2;
break;
case STEP_COUNTER_MOVEMENT_TYPE_STILL:
ChangeList = 0;
break;
default:
ChangeList = 0xff;
break;
}
current_type = steps->movement_type;
}
と言った感じで、状態が変わった場合、 ChangeList を変更して再生すべきリストが変わったことを伝えます。
音楽生成部分では、文字をscanfで入力する部分を削除し、
if (Serial.available() > 0) {
switch (Serial.read()) {
case 'a': // autoplay
if (preset.autoplay) {
preset.autoplay = 0;
} else {
preset.autoplay = 1;
}
printf("Auto=%s\n", (preset.autoplay) ? "On" : "Off");
EEPROM.put(eeprom_idx, preset);
break;
case 'p': // play
if (s_state == Stopped) {
s_state = Ready;
show(¤tTrack);
}
break;
case 's': // stop
if (s_state == Active) {
stop();
}
s_state = Stopped;
break;
case '+': // volume up
preset.volume += 10;
if (preset.volume > 120) {
/* set max volume */
preset.volume = 120;
}
printf("Volume=%d\n", preset.volume);
theAudio->setVolume(preset.volume);
EEPROM.put(eeprom_idx, preset);
break;
case '-': // volume down
preset.volume -= 10;
if (preset.volume < -1020) {
/* set min volume */
preset.volume = -1020;
}
printf("Volume=%d\n", preset.volume);
theAudio->setVolume(preset.volume);
EEPROM.put(eeprom_idx, preset);
break;
case 'l': // list
if (preset.repeat) {
thePlaylist.setRepeatMode(Playlist::RepeatModeOff);
list();
thePlaylist.setRepeatMode(Playlist::RepeatModeOn);
} else {
list();
}
break;
case 'n': // next
if (s_state == Ready) {
// do nothing
} else { // s_state == Active or Stopped
if (s_state == Active) {
stop();
s_state = Ready;
}
if (!next()) {
s_state = Stopped;
}
}
break;
case 'b': // back
if (s_state == Active) {
stop();
s_state = Ready;
}
prev();
break;
case 'r': // repeat
if (preset.repeat) {
preset.repeat = 0;
thePlaylist.setRepeatMode(Playlist::RepeatModeOff);
} else {
preset.repeat = 1;
thePlaylist.setRepeatMode(Playlist::RepeatModeOn);
}
printf("Repeat=%s\n", (preset.repeat) ? "On" : "Off");
EEPROM.put(eeprom_idx, preset);
break;
case 'R': // random
if (preset.random) {
preset.random = 0;
thePlaylist.setPlayMode(Playlist::PlayModeNormal);
} else {
preset.random = 1;
thePlaylist.setPlayMode(Playlist::PlayModeShuffle);
}
printf("Random=%s\n", (preset.random) ? "On" : "Off");
EEPROM.put(eeprom_idx, preset);
break;
case 'm':
case 'h':
case '?':
menu();
break;
default:
break;
}
}
その代わりに、リストの変更要求が来たら、変更するコードに変えます。
switch (ChangeList) {
case 1: // change list
if (s_state == Active) {
stop();
s_state = Ready;
}
thePlaylist = &thePlaylist1;
puts("Chaneg to 1");
next();
ChangeList=0xff;
break;
case 2: // change list
if (s_state == Active) {
stop();
s_state = Ready;
}
thePlaylist = &thePlaylist2;
next();
puts("Chaneg to 2");
ChangeList=0xff;
break;
case 0: // change list
if (s_state == Active) {
stop();
s_state = Ready;
}
thePlaylist = &thePlaylist0;
next();
puts("Chaneg to 0");
ChangeList=0xff;
break;
default:
break;
}
これによって、動作すると再生リストが変わるコードができます。
※作成したコードは整理した上、どこかにUPします。
ここまでで、プログラムの準備ができました。
音声ファイル
各音声ファイルとそのプレイリストは、適宜、準備をします。
聴きたい曲だけでなく、子供たちから、歩いてしまった、止まってしまったときのお怒りの声を頂きました!
ケーシングと動作
実際に、良いケースがなかったので、子供が食べていたチョコボールの箱に入れてみました。
動かしている動画は、取れなかったので、今度追記します。
終わりに
もうちょっと丁寧にやっていこうと思ったのですが、締め切りに迫られざっくりになってしまいました。
今後、もうちょっと整理していきます。
投稿者の人気記事
-
Interested_Spresense
さんが
2022/09/26
に
編集
をしました。
(メッセージ: 初版)
-
Interested_Spresense
さんが
2022/09/26
に
編集
をしました。
ログインしてコメントを投稿する