DCモータのPWM制御により曲を演奏する(matlab+mbed)


DCモーターのPWM制御を行うと、PWM周波数に従ってモーターから音が発生します。
これを利用して、モーターで音楽を演奏します。
mp3ファイルから読み込んだ音声を、FFTして周波数(時間変化する)に変換します。
得た周波数データを逐次マイコンに送信し、マイコンは受信したPWM周波数でモーターをPWM制御します。

以下のような感じです。

環境

  • matlab
  • マイコン:mbedLPC1768
  • モータドライバ:自作(Hブリッジ式)
  • モーター:マブチ rz-735

モータドライバは高い周波数に耐えられればなんでもいいんじゃないかな。
20 kHzくらいまで出せればオッケーなので、Pololuのやつなら何でもいいと思う。

matlabコード

matalab 2020以上でないとserialportが使えないので注意

読み込んだ音声ファイルを、区間NでFFTし、そのときの最大スペクトルを持つ周波数をモーターへの出力周波数としています。

port_name = 'COM26'; %COMポート
filename = 'hogehoge.mp3'; %音声ファイル名

[audio,Fs] = audioread(filename);
T = 1/Fs;
L = length(audio);
start_sec = 0.1;
start = round(start_sec / T);
step = 1000;
N = 1000;
input_list = zeros(1, start+L);

for i = start : step : start+L-N
    % stepずつ走査し,区間NでaudioをFFT
    y = audio(i : i+N);
    Y = fft(y(1:1+N));
    P2 = abs(Y/N);
    P1 = P2(1:N/2+1);
    P1(2:end-1) = 2*P1(2:end-1);
    f = Fs*(0:(N/2))/N;
    [~,I]=max(P1);
    Ma=f(I);
    input_list(i) = round(Ma);

    % テスト用に音声を再現
    t = [T*1 : T : T*N];
    Ma = round(Ma);
    output(i-start+1 : i-start+N) = sin(2*pi*Ma*t);
end

% スピーカーに音声を出力
% sound(output(start:L-N), Fs);

% mbedに送信
s = serialport(port_name, 9600);

for i = start : step : start+L-N
    h = bitshift(input_list(i), -16); %上位ビット
    m = bitshift(input_list(i), -8);  %中位ビット
    l = bitand(input_list(i), 255);   %下位ビット
    %送信
    write(s,h,"uint8");
    write(s,m,"uint8");
    write(s,l,"uint8");
    % 待機
    pause(T*step);
end
write(s,0,"uint8");
write(s,0,"uint8");
write(s,0,"uint8");
clear s;

mbedコード

以下のコードはコンパイル通らないので注意です。
MotorControlerクラスのところだけうまいこと書き換えてください。
シリアル通信のところはそのままで大丈夫です。
通信ずれると止まりますが、まあいいでしょう

#include "mbed.h"
#include "MotorControler.h"

int main()
{
    Serial matlab(USBTX, USBRX);
    MotorControler MOTOR(p21,p22,p23);
    MOTOR.setPwmFrequency(20000);
    MOTOR.enableDriver();
    MOTOR = 0.7;

    while(1)
    {
        if(matlab.readable() > 0)
        {
            int h = (int)matlab.getc();
            int m = (int)matlab.getc();
            int l = (int)matlab.getc();
            MOTOR.setPwmFrequency(h<<16 | m<<8 | l);
        }
    }
}

結果

ボッカデラベリタ
https://twitter.com/newlvAlPr/status/1363865660887998467

夜に駆ける
https://twitter.com/newlvAlPr/status/1364057845604343809