🐔

📣RaspberryPi Picoずブラりザで通信する

2023/07/07に公開

RaspberryPi Picoに無線機胜を搭茉したRaspberryPi Pico Wが発売されたしたね
これを䜿えば、りェブブラりザから簡単にラズピコを操䜜できるみたいです。

しかしここには普通のラズピコしかありたせんので、音波通信でブラりザからラズピコを操䜜しおみたしょう

完成図

電波の代わりに、音波を䜿っお通信したす。
速床は160bps。通信距離は音声呚りのアナログ回路が貧匱な堎合は数cmです。
※アナログ回路をきちんず䜜れば1mでくらいは頑匵れるずかも

ブラりザは送信画面の為だけに利甚しお、ラズピコずブラりザは盎接音波でお話ししたす。

楜しそうですね

ラズピコ

たずラズピコ偎から䜜っおいきたしょう。

ハヌドの準備

保護回路を経由しお枚の圧電玠子をラズピコに盎結したす。
この貧盞な回路は、本来別々に甚意するべき音声入力/出力回路が䞀䜓化しおおり、ずおもたずもに動きそうに思えたせんが、非垞にシビアですが動䜜したした。

手元の装眮では、圧電玠子に秋月電子で賌入したSPT08を䜿いたしたが、その蟺に萜ちおいる盎埄くらいのものなら䜕でもよろしいかず思いたす。

回路図はこのようになりたす。それっぜいオヌディオ入力回路ず過電圧保護回路です。
アナログ回路のわかる方の突っ蟌みをお埅ちしおおりたす。

重芁 たいせ぀なラズピコを砎壊しないために、クリッピング甚の保護ダむオヌドを忘れずに

※過電圧分は3.3Vのラむンに捚おおいたすが、ラズピコの回路的には少々危険な気がしたす。この堎合どうしたらよいのか 。

圧電玠子は䞡面テヌプでしっかりず固定しおください。振動するず波圢が乱れお良くありたせん。

゜フトの準備

ラスピコの゜フトりェアは、TBSKmodemMicroのArudino版を䜿いたす。TBSKmodemMicroは32ビットマむコン向けにC++14で実装したラむブラリです。

チュヌトリアルに埓っおラむブラリをArduinoIDEにセットアップしおください。

  1. https://github.com/nyatla/TBSKmodemMicro/releasesからTbskModemMicro-Ardiuno.zipをダりンロヌドしたす。
  2. Arduino IDEを起動し、スケッチ→ラむブラリをむンクルヌド→Zip圢匏のラむブラリをむンストヌル...を遞択したす。
  3. ダりンロヌドしたラむブラリを遞択したす。
  4. ラむブラリを有効化するためにArduino IDEを再起動しおください。

送信テスト

送信テストをしたす。

サンプルにある、SendHelloを少し改造しお䜿いたす。
SendHelloは、数秒間隔でメッセヌゞを送信するビヌコンのスケッチです。

ファヌル→スケッチ䟋→TBSKmodemMicro→SendHelloを遞択したす。
スケッチを開き、SPK_PINをAD0(26)に曞き換えたす。
コンパむルしお、ラズピコにバむナリを曞き蟌んでください。

#include "TbskModemMicro.h"
using namespace TBSKmodemMicro;

#define LED_PIN 25
#define SPK_PIN 26 //←ここ
TbskPulseModulator<100> tpm;
void setup() {
  pinMode(LED_PIN, OUTPUT);  //LED
  pinMode(SPK_PIN, OUTPUT);   //OutputPin
}
void loop()
{
  digitalWrite(LED_PIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  tpm.write(SPK_PIN,16000,"Hello arduino");  //send message via GPIO pulse audio.
  digitalWrite(LED_PIN, LOW);  // turn the LED on (HIGH is the voltage level)
  delay(1000);

}

ラズピコからず音が鳎ったら、適圓なスマホかPCでhttps://nyatla.jp/tbskmodem/ を開いおStartボタンを抌したす。

アプリ偎ににメッセヌゞが衚瀺されればOKです
TBSK倉調ぱラヌ蚂正がないので、文字化けが発生するこずがありたす。たた、生掻音環境䞋では末尟にゎミが混じりやすくなりたす。

https://www.youtube.com/watch?v=sXGtD-wOdPk

送受信テスト

送受信ができるかテストしたす。
圧電玠子をセンサにした音波受信は結構シビアなので忍耐力が必芁です。

サンプルにある、EchoBackのスケッチを䜿いたす。

#include "TbskModemMicro.h"
using namespace TBSKmodemMicro;

TbskPulseModulator<100> tpm;
TbskDemodulator<100> dem;

#define LED_PIN 25
#define AD_PIN 26
#define SP_PIN 26

void setup() {
  pinMode(LED_PIN, OUTPUT);  //LED
}

void loop()
{
  int r=-1;
	TMM_UINT8 recv[10] = {};  
  digitalWrite (LED_PIN,HIGH);
  analogReadResolution(12);

  while(r==-1){
     r=dem.read(AD_PIN,16000,recv,10,5000);
  }
  digitalWrite (LED_PIN,LOW);
  delay(1000);
  //send back data
  TMM_UINT8 send[16]={};
  memcpy(send,"echo:",5);
  memcpy(send+5,recv,r);
  pinMode(SP_PIN, OUTPUT);
  tpm.write(SP_PIN,16000,(const char*)send,r+5);

  return;
}

このスケッチは、音波通信を受信するず、その内容に"echo:"プレフィクスを぀けおそのたた送り返しおくれたす。

コンパむルしお、ラズピコにバむナリを曞き蟌んでください。
ラスピコ基板にあるLEDが点灯したら準備完了です。

送信偎は、https://nyatla.jp/tbskmodem/ を䜿甚したす。
ブラりザで開いおStartボタンを抌したら、送信欄に"test"を入力しお送信ボタンを抌したす。

さお、ここで぀倧きな問題がありたす。
圧電玠子をマむクの代わりに䜿う回路では、数センチの至近距離で圧電玠子ず氎平に送信偎の出力を配眮し、倧きめの音で送信しないず、音波がラズピコのセンサに到達したせん。

送受信機は出来るだけ氎平に向かい合わせで配眮する必芁がありたす。

䜕床か音を出しお受信しおくれる配眮を探すこずを繰り返しおください。ラズピコが受信に成功するず、LEDが䞀旊消灯し、信号を送り返しおくれるはずです。

https://www.youtube.com/watch?v=B9rHDmMfdlc

数十回詊しおもダメな堎合は、別にマむクモゞュヌルを甚意しお、入力ず出力回路の分離を怜蚎したしょう。

ラズピコのファヌムを䜜る

Echobackのコヌドを基に、"ON"を受信したらLEDをON、"OFF"を受信したらLEDをOFFするように改造したす。

#include "TbskModemMicro.h"
using namespace TBSKmodemMicro;

TbskPulseModulator<100> tpm;
TbskDemodulator<100> dem;
#define LED_PIN 25
#define AD_PIN 26
#define SP_PIN 26

bool current_led=true;
void setup() {
  pinMode(LED_PIN, OUTPUT);  //LED
  pinMode(AD_PIN, INPUT);
  pinMode(SP_PIN, OUTPUT);
  analogReadResolution(12);
}
void loop()
{
  int r=-1;
  TMM_UINT8 recv[10] = {};
  digitalWrite (LED_PIN,current_led?HIGH:LOW);

  pinMode(AD_PIN, INPUT);
  while(r==-1){
     r=dem.read(AD_PIN,16000,recv,10,5000);
  }
  char status[7+3+1];
  if(memcmp(recv,"on",2)==0){
    //on
    sprintf(status,"status:on\0");    
    current_led=true;
  }else if(memcmp(recv,"off",3)==0){
    //off
    sprintf(status,"status:off\0");    
    current_led=false;
  }else{
    sprintf(status,"ERROR");
  }
  delay(.5);
  pinMode(SP_PIN, OUTPUT);
  tpm.write(SP_PIN,16000,(const char*)status);
  return;
}

このコヌドは、受信したデヌタをif文刀定し、フラグを切り替えおいたす。
LED切替だけだず぀たらないので、぀いでに応答も返すようにしたした。

やたらず同じピンのpinModeを操䜜しおいたすが、これは圧電玠子を入出力兌甚しおいるためです。ADCピンずDIGITALOUTをピンで切り替える堎合、pinモヌドをこの順番で操䜜しないずADCが正垞動䜜しないこずがありたす。

コンパむルしお、ラズピコに曞き蟌んでおきたしょう。

ブラりザアプリ

次は操䜜するためのブラりザアプリケヌションを䜜りたす。
ラむブラリは、Javascript甚のTbskmodemJSを䜿いたす。

ラむブラリの準備

https://github.com/nyatla/TBSKmodemJS/releases からTBSKmodemJS.zipをダりンロヌドしたす。

TBSKmodemJS.zipを展開したら、サンプルを起動したしょう。
サンプルの起動にはWebサヌバが必芁です。ここではPythonのりェブサヌバを利甚したす。

$cd TBSKmodemJS
$python -m http.server 8000

http://127.0.0.1:8000 にアクセスしおください。getstarted/*.htmlにスタンドアロン版のサンプルがありたす。

続いお、tbsksocket_send.htmlを開きたす。これは送信ボタンを抌すず短いメッセヌゞを送信するサンプルアプリケヌションです。

Startボタンを抌した埌にSendボタンを抌すず、ず音波が送信されたす。
途䞭でマむクアクセスを求める通知がありたすので、蚱可しおください。
(ディベロッパヌツヌルのConsoleを芋るず賑やかになりたす。)

これでブラりザアプリの実行環境が敎いたした。

泚意 WebAudioのAPIは、HTTPSサヌバ、もしくはロヌカルPC䞊のHTTPサヌバでしか動䜜したせん。これはブラりザの仕様です。

LEDを぀けたり消したりするアプリを䜜る

tbsksocket_send.htmlをベヌスにしお、ラズピコのLEDをON/OFFするアプリを䜜っおいきたす。

はいできたした

<!doctype html>
<html lang=en-us>
<head>
  <meta charset=utf-8>
  <meta content="text/html; charset=utf-8" http-equiv=Content-Type>
  <title>TBSKmodemJS</title>
</head>
<body>
    <h1>LED ON/OFF.</h1>
    <hr/>
    <script async src="../dist/tbskmodem.js"></script>
    <script>

        window.addEventListener('load', ()=>
        {
          window.addEventListener('unload',()=>{
            console.log("Shutdown sequence.");
            shutdown=true;
            socket.close();
          });
          let started=false;
          document.getElementById("start").addEventListener("click",()=>{
            if(started){
              return;
            }
            started=true;
            let env=TBSKmodemJS.checkEnvironment();
            if(env.success!=true){
              alert("Insufficient environment required for TBSKmodemJS");
              console.log(JSON.stringify(env)+"\n");
              throw Error();
            }
            console.log("env",env);
            
            //tbsk setup
            TBSKmodemJS.load().then((tbsk)=>{
              console.log(tbsk.version);
              socket=new tbsk.misc.TbskSocket({carrier:16000,encoding:"utf8"});
              socket.addEventListener("open",(event)=>{
                console.log("Socket open!");
                document.getElementById("on").addEventListener("click",()=>{
                  socket.send("on");
                });
                document.getElementById("off").addEventListener("click",()=>{
                  socket.send("off");
                });
              });
              let msg;
              socket.addEventListener("detected",(event)=>{
                msg="";
              });
              socket.addEventListener("message",(event)=>{
                msg+=event.data;
              });
              socket.addEventListener("lost",(event)=>{
                alert(msg);
              });
            });
        });
      });
  </script>
  <style>
  body{text-align:center;}
  #start,#on,#off{font-size:3em;width:5em;margin:.2em auto;}
  </style>
<div>
	<button id="start">START</button><br/>
	<button id="on">ON</button><br/>
	<button id="off">OFF</button>
</div>
</body>
</html>

䞻な倉曎点はボタンの远加ず、その䞭でむベントを凊理する郚分です。

ファむルを保存しお、サヌバヌに配眮しおからブラりザから開きたしょう。Startボタンを抌すずアプリケヌションが開始され、ON/OFFボタンを抌すずず音が出るず思いたす。

サヌバに配眮するのが面倒な方はこちらからどうぞ。
https://nyatla.jp/tbskmodem/v0.4.1/getstarted/_on_off_sample_for_zenn.html

コヌドの説明

たずラむブラリを初期化したす。
TBSKmodemJS.load関数は非同期関数なので解決しおから次に移りたす。

TBSKmodemJS.load().then((tbsk)=>{

搬送波呚波数を指定しおTbskSocketのむンスタンスを生成したす。
TbskSocketクラスは通信システムの䞭栞です。Websocketず同じようなむンタフェむスで音波通信を䜿うこずができたす。

socket=new tbsk.misc.TbskSocket({carrier:16000,encoding:"utf8"});

むンスタンスを生成したら、むベントハンドラを蚭定しおいきたす。
openむベントは゜ケットが有効になるず呌び出されるハンドラです。有効になるたではボタンを無効化しおおきたいので、このハンドラの䞭でボタンのむベントを蚭定したした。

socket.addEventListener("open",(event)=>{

detected,message,lostはメッセヌゞの受信に関するむベントです。TbskSocketの通信速床は遅いので、1぀のメッセヌゞを受信し終わるのに長い時間がかかりたす。

そこで、たず初めにdetected(怜出)むベントを呌び出し、䞀文字づ぀messageで通知しお、最埌に信号を芋倱ったこずを䌝えるlostむベントを呌び出すようになっおいたす。

detectedは必ずlostむベントで終了したす。その間にあるmsgを結合しお、メッセヌゞ党䜓を埩元しおいたす。

let msg;
socket.addEventListener("detected",(event)=>{
  msg="";
});
socket.addEventListener("message",(event)=>{
  msg+=event.data;
});
socket.addEventListener("lost",(event)=>{
  alert(msg);
});

テスト

䜜成したWebアプリをスマホで開いお、ラズピコの近くでをボタンを抌すず、LEDを぀けたり消したりできたす。やったね

https://youtu.be/i5aVXhBLn18

蚭眮枈みのスマホアプリ

https://nyatla.jp/tbskmodem/v0.4.1/getstarted/_on_off_sample_for_zenn.html

あずがき

性胜の改善

今回のハヌドりェアは、単発の圧電玠子でデゞタルデヌタ通信ができるずカッコ良さそうだったのでこの圢になりたした。が  、実甚䞊はかなり蟛い感じです。特に受信偎

入出力回路を分離しお、入力をコンデンサマむク、出力を小型のスピヌカヌに眮き換えれば、送受信の性胜はかなり良くなるず思いたす。

䜿いどころ

TBSKの音波通信は、普及しおいる通信方匏ず比べるず速床も遅く到達距離も短いので、他の技術の代わりにのような目的には適したせん。

しかしながら、単玔な゜フトりェアず芏制のない音波だけで実装できるため、特殊なトランシヌバヌデバむスやそのための耇雑怪奇な環境蚭定が䞍芁で、電波ず違っお技適の心配もありたせんし。

ブラりザ経由でちょっずしたデヌタをオンラむンず亀換したり、他の無線方匏の初期コンフィギュレヌション亀換、無線機胜の無いデバむスでシリアル回線を生やしたい時等に、䟿利に䜿えるず思いたす。

ちなみに、ラズパむから送信だけであれば、MicroPythonでも可胜です。
詳しくはこちらをご芧ください。
https://github.com/nyatla/TBSKmodemMicro/blob/main/MicroPython/README.ja.md

Discussion