シリアル通信とブラウザJavaScriptをブリッジする IchigoLink のご紹介

この記事は、IchigoJam Advent Calendar 2018 8日目の記事です。

1. はじめに

IchigoLink は Scratch 3.0 と IchigoJam を連携させるために開発している、
シリアル通信とブラウザJavaScriptのブリッジです。

Windows, Mac, Linux でコマンドラインアプリケーションとして動作し、
WebSocket を使って ローカルのシリアルポート と ブラウザのJavaScriptをつなぎます。
(ちなみに、micro:bit は同様のツールの BLE版を提供しています。)

本来は Scratch連携用 のツールですが、それ以外にも面白いことができます。

2. 何ができるのか

下記の動画にあるような IchigoJamと連携する作品を JavaScript と HTML だけで作成できます。

IchigoJam  のボタン操作でWebページを変化させる

IchigoJam から取得したアナログ値で Webページを変化させる

WebページからIchigoJam を操作する

3. [使い方] 準備するもの

  • パソコン
  • IchigoJam
  • シリアル通信に必要なデバイス(USBシリアル変換アダプタなど)
  • IchigoJamで使いたいデバイス(LED、ボタン、可変抵抗、各種センサー、各種モーターなど)

4. [使い方] ダウンロードから起動まで

開発中ということで仮の場所になりますが、下記からダウンロードできます。
http://shizentai.jp/ichigolink/

zip ファイルを解凍すると下記のような中身になっているので、コマンドプロンプトやターミナルを立ち上げて、このディレクトリに移動します。

シリアル通信デバイスを接続した状態で、下記のコマンドをたたきます。

Windows の場合

> ichigo-link [シリアルデバイス名]

Mac/Linux の場合

$ ./ichigo-link [シリアルデバイス名]

シリアルデバイス名は Windows の場合はCOM3やCOM4、Linux の場合は /dev/ttyUSB0 などになることが多いようです。

コマンドプロンプトやターミナルが上のような表示になり、
ブラウザで、 http://localhost:30110 を表示したときに下記のような画面になれば起動成功です。箇条書き程度ですが、仕様をまとめてあるので参考にしてください。

また、このページが ichigo-link-www フォルダの index.html に対応しており、ichigo-link-www フォルダ以下にファイルを置くと、localhost:30110 以下で公開されるようになっています。

5. [使い方] 付属デモアプリケーション

デモツールとして、簡易的なターミナルとコード送信ツールを添付しています。
ichigo-link-www/demo の下にファイルが存在します。

簡易ターミナル

http://localhost:30110/demo/terminal.html

connect ボタンを押すと接続します。
上のテキストボックスに入力したものを行単位で送信し、受信したものを下のテキストエリアに表示します。
RUNを中断したいときなどに esc ボタンを押してエスケープシーケンスも送れます。

現状、テキストエリアにデータを追加しているだけで解放処理をしていないので、
大量のデータを受け取ったり、長時間使用すると固まったりするかもしれません。あしからず。

コード送信ツール

http://localhost:30110/demo/send_source.html

まとめて何行か送りたいとき用のツールです。

6. 動画で紹介した作品の作り方

下記のソースコードをテキストエディタなどに貼り付けて、ichigo-link-www 以下に適当なファイル名で保存すれば、localhost:30110 以下でブラウザからアクセスできます。

IchigoJam 側のプログラムを最初に送って RUNするようにしていますが、この部分だけ IchigoJam 側に最初から用意しておいてもよいと思います。

IchigoJam のボタンを押すと背景色がつくページ

<!DOCTYPE html>
<html>
<head>
  <title>IchigoJamのボタンを押すと緑になるページ</title>
  <meta charset="UTF-8"/>
  <script>
    window.addEventListener('load', function () {
      var ws = new WebSocket('ws://localhost:30110/serial');
      ws.addEventListener('open', function () {
        ws.send(JSON.stringify({"type":"esc"}));
        ws.send(JSON.stringify({"type":"text","value":"NEW"}));
        ws.send(JSON.stringify({"type":"text","value":"10 ?BTN():WAIT3:GOTO10"}));
        ws.send(JSON.stringify({"type":"text","value":"RUN"}));
      });
    
      ws.addEventListener('message', function (event) {
        var obj = JSON.parse(event.data);
        if(obj.value == "0") {
          document.body.style.backgroundColor = "white";
        }
        if(obj.value == "1") {
          document.body.style.backgroundColor = "#00C000";
        }
      });
    
    });
  </script>
</head>
<body>
    <h2>IchigoJamのボタンを押すと画面が緑になるページ</h2>
  
</body>
</html>

ANA(2)の値で背景色の濃さが変わるページ

背景色の計算ロジック、地味に苦労しました。改善求む!

<!DOCTYPE html>
<html>
<head>
  <title>ANA(2)の値で緑の濃さが変わるページ</title>
  <meta charset="UTF-8"/>
  <script>
    window.addEventListener('load', function () {
      var ws = new WebSocket('ws://localhost:30110/serial');
      ws.addEventListener('open', function () {
        ws.send(JSON.stringify({"type":"esc"}));
        ws.send(JSON.stringify({"type":"text","value":"NEW"}));
        ws.send(JSON.stringify({"type":"text","value":"10 ?ANA(2):WAIT3:GOTO10"}));
        ws.send(JSON.stringify({"type":"text","value":"RUN"}));
      });
    
      ws.addEventListener('message', function (event) {
        var obj = JSON.parse(event.data);
        var a = parseInt(obj.value,10);
        var b = Math.floor(a/2);
        var c, d;
        if ( b < 256 ) {
	  c = 255 - b;
	  d = 255;
        } else {
	  c = 0;
	  d = 255 - (b-255);
        }
	var color = "rgb(" + c + "," + d + "," + c + ")";
	console.log(color);	 
	document.body.style.backgroundColor = color;
      });
    
    });
  </script>
</head>
<body>
    <h2>ANA(2)の値で緑の濃さが変わるページ</h2>
  
</body>
</html>

LEDとPWMをコントロールするページ

<!DOCTYPE html>
<html>
<head>
  <title>IchigoJamのLEDとPWMをコントロールするページ</title>
  <meta charset="UTF-8"/>
  <script>
    window.addEventListener('load', function () {
      var ws = new WebSocket('ws://localhost:30110/serial');
      ws.addEventListener('open', function () {
        ws.send(JSON.stringify({"type":"esc"}));
        ws.send(JSON.stringify({"type":"text","value":"LED0"}));
        ws.send(JSON.stringify({"type":"text","value":"PWM3,50"}));
        ws.send(JSON.stringify({"type":"text","value":"PWM4,50"}));
        document.getElementById('ledon').addEventListener('click',function() {
          ws.send(JSON.stringify({"type":"text","value":"LED1"}));
        });
        document.getElementById('ledoff').addEventListener('click',function() {
          ws.send(JSON.stringify({"type":"text","value":"LED0"}));
        });
        document.getElementById('pwm3').addEventListener('change',function() {
          var a = parseInt(document.getElementById('pwm3').value,10);
          ws.send(JSON.stringify({"type":"text","value":"PWM3," + a}));
        });
        document.getElementById('pwm4').addEventListener('change',function() {
          var a = parseInt(document.getElementById('pwm4').value,10);
          ws.send(JSON.stringify({"type":"text","value":"PWM4," + a}));
        });
      });
    });
  </script>
</head>
<body>
  <h1>IchigoJamのLEDとPWMをコントロールするページ</h1>
  <form>
    <h3>LED</h3>
    <input type="radio" name="led" id="ledon" />On
    &nbsp;
    <input type="radio" name="led" id="ledoff" checked="checked"/>Off
    
    <h3>PWM3</h3>
    50 <input type="range" id="pwm3" value="0" min="50" max="240" step="10"/> 240
    
    <h3>PWM4</h3>
    50 <input type="range" id="pwm4" value="0" min="50" max="240" step="10"/> 240

  </form>

  
</body>
</html>  

7. まとめと課題

  • IchigoLink を使うと IchigoJam と連携するブラウザアプリケーションを簡単に作れます。
  • Scratch 対応として配布するまでに GUI化したいです。
  • Windows 版の反応がよくない気がするのが少々気になる。