LEGO MINDSTORMS EV3 API の DirectCommand で音楽を奏でてみる

LEGO MINDSTORMS EV3 API を使うと、Windows デスクトップ、ストアアプリ、Windows Phone 8 から Mindstorms EV3 をコントロールできます。

まずはモーターを制御してトレーニングロボットを走らせるんでしょうね。

2014-01-18 12-09-19

が、せっかく音の出るオモチャです。チューリップくらい演奏してみたくなります。
ということで、やってみました。
技術的に難しいところはない上にこのままだと実用度はほぼゼロですが、EV3 操作の一つとして紹介します。別スレッドを使ってモデルを走らせながら音楽を鳴らすのも楽しそうです。

まずはソースコードを。EV3 の操作自体は簡単です。
音階の周波数の定数値定義と楽譜がソースコードの大半なのでそれらは本稿の末尾に。
プログラミングとは別のところで苦労(?)しましたが、たまにはこういうことにエネルギーを注ぐのもいいでしょう。もうちょっと楽譜作りをがんばればドレミの歌なんかもできます。


MainWindow.xaml.cs

using System.Windows;
using Lego.Ev3.Core;
using Lego.Ev3.Desktop;

namespace Ev3Music01
{
    public partial class MainWindow : Window
    {
        private Brick _brick;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _brick = new Brick(new BluetoothCommunication("COM6"));
            await _brick.ConnectAsync();
        }

        private async void PlayMusic_Click(object sender, RoutedEventArgs e)
        {
            await Score.PlayTulip(_brick);
        }
    }
}

PC と EV3 とは Bluetooth 接続するので、あらかじめペアリングしておいてください。
私の環境では COM6 ですが、BluetoothCommunication のコンストラクターにはそれぞれの環境に応じた引数を渡してください。

_brick = new Brick(new BluetoothCommunication("COM6"));
await _brick.ConnectAsync();

念のために画面(WPF) はこんな感じ。今回はこれ以上の説明は不要ですね。

2014-01-18 12-15-01


MusicPlayer.cs

using System;
using System.Threading.Tasks;
using Lego.Ev3.Core;

namespace Ev3Music01
{
    public class MusicPlayer
    {
        public static async Task PlayToneAsync(Brick brick, int volume, ushort frequency, ushort duration)
        {
            await brick.DirectCommand.PlayToneAsync(volume, frequency, duration);
            await Task.Delay(new TimeSpan(0, 0, 0, 0, duration));
        }

        public static async Task PlayToneAsync(Brick brick, int volume, Scale scale, ushort duration)
        {
            await brick.DirectCommand.PlayToneAsync(volume, (ushort)scale, duration);
            await Task.Delay(new TimeSpan(0, 0, 0, 0, duration));
        }

        public static async Task PlayRestAsync(Brick brick, ushort duration)
        {
            await Task.Delay(new TimeSpan(0, 0, 0, 0, duration));
        }
    }
}

EV3 にコマンド (DirectCommand) を送信する処理です。PlayToneAsync メソッドで非同期に音を鳴らします。
volume (音量) は 0~100、frequency (周波数) は300~10000 が指定できるようです。duration (長さ) は ミリ秒単位の指定です。ただし実際には 300 Hz より若干低い音でも出せるようです。

await brick.DirectCommand.PlayToneAsync(volume, frequency, duration);
await Task.Delay(new TimeSpan(0, 0, 0, 0, duration));

非同期なので PlayToneAsync を連続して実行すると最後の音しか鳴りません。Task.Delay で音が鳴り終わるのを待ちます。


Scale.cs

ここで音階ごとに周波数を指定します。これで PlayToneAsync の引数で毎回周波数を指定する代わりに Scale.C4 のような指定が出来ます。
frequency は ushort なので残念ながら小数値は指定できません。正しい周波数ではありませんが、ここは制限事項ですね。

namespace Ev3Music01
{
    public enum Scale : ushort
    {
        C4 = 262,
        Cs4 = 277,
        D4 = 294,
        Ds4 = 311,
        E4 = 330,
        F4 = 349,
        Fs4 = 370,
        G4 = 392,
        Gs4 = 415,
        A4 = 440,
        As4 = 466,
        B4 = 494,
        C5 = 523,
        Cs5 = 554,
        D5 = 587,
        Ds5 = 622,
        E5 = 659,
        F5 = 698,
        Fs5 = 740,
        G5 = 784,
        Gs5 = 831,
        A5 = 880,
        As5 = 932,
        B5 = 988,
        C6 = 1047,
        Cs6 = 1109,
        D6 = 1175,
        Ds6 = 1245,
        E6 = 1319,
        F6 = 1397,
        Fs6 = 1480,
        G6 = 1568,
        Gs6 = 1661,
        A6 = 1760,
        As6 = 1865,
        B6 = 1976,
    }
}

Score.cs

楽譜はこんな感じで記述してみました。

using System.Threading.Tasks;
using Lego.Ev3.Core;

namespace Ev3Music01
{
    public class Score
    {
        private const int Volume = 10;
        private const int BeatLength = 500;

        public static async Task PlayTulip(Brick brick)
        {
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);

            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.G4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);

            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);

            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.G4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);

            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.G4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.G4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.G4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.A4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.A4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.G4, BeatLength);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);

            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.E4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.D4, BeatLength);
            await MusicPlayer.PlayToneAsync(brick, Volume, Scale.C4, BeatLength * 3);
            await MusicPlayer.PlayRestAsync(brick, BeatLength);
        }
    }
}
広告
カテゴリー: Mindstorms, Visual Studio タグ: , パーマリンク

LEGO MINDSTORMS EV3 API の DirectCommand で音楽を奏でてみる への2件のフィードバック

  1. elbruno より:

    I Just see your amazing video of Win8 app and Lego Mindstorms >> https://www.youtube.com/watch?v=pqz2r7MMRBI&list=UU8Kp1QCiiKk_v5WuxC31ASA are you planning to share the code? thanks :D

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中