Swiftの学習をタブレットで手軽に試すことができるApple社の公式iPadアプリ "Swift Playgrounds" が2017年6月にバージョンアップされました。この Swift Playgrounds ver.1.5 にて、LEGO Mindstorms EV3への対応も追加されました。
そこで Swift Playgrounds で Mindstorms EV3 を制御する例としてライントレース・コードを実装してみました。
Swift Playgrounds を使い、Mindstorms EV3の3輪ロボットでライントレースを実行させてみた動画です。
感想
いちいち有線(USB)を抜き差しする必要がない、というのは想像以上に便利でした。初回にiPadとMindstorms EV3をBluetoothでペアリングする必要がありますが、それ以降はSwift Playgroundアプリで「EV3ブロックを接続」ボタンをタップするだけです。iPadからマインドストームに接続するときにはマインドストームに設定した名前から選ぶ必要があるため、もし教室のようなところで複数台のマインドストームがあるケースでは、一台一台異なる名前に変更しておかないと大変だと感じました。しかし1台しかマインドストームがない環境であればペアリングも、その後の接続も苦労はないとおもいます。
EV3の名前を変更するには – 株式会社アフレル
また、「コードを実行」ボタンを一発タップするだけで、「コンパイル」や「ダウンロード」といった冗長な手順を意識する必要なく、コードが実行されてマインドストームが動き出すというのも直感的でわかりやすいと感じました。コードに間違いや不足があると、1〜2ワード入力した途端に警告やサジェッションが表示されるため、慣れてくると若干うるさく感じるかもしれませんが、コードの入力を全て終えて(終えたつもりで)実行ボタンを押してから初めてコードの間違いに気づき作業を後戻りすることは避けられるように工夫されていると感じます。
モーターの回転角度の取得やセンサーによる測定に面倒な設定の必要がなく、メニュー切り替え一発で折れ線グラフで表示もできるのも、とてもよくできた工夫だと思います。コードを1行も書かなくても、ひとまずマインドストームとiPadをBluetoothで接続して、モーター(タイヤ)を手で回すと、その結果がiPadで見れるというのはとても便利です。「右のタイヤ(モーター)をポートBに繋いだつもりが、実はポートCに繋いでいた!」なんて単純な間違いに気づくまでに何分も頭をかかえることは、これでなくなりそうです。
一点だけ気になったのはiPadとマインドストームの間のBluetooth通信で生じる遅延です。Swift Playgroundsで作成したコードはコード全体を一括してマインドストームに送り込む(ダウンロードする)わけではなく、ダイレクトコマンドとよばれるコマンド単位で1ステップずつ小分けに送っています。
たとえば、次のコードは、どちらも
- 左(ポートAに繋がった)モーターを10.0のパワーで回転
- 右(ポートDに繋がった)モーターを10.0のパワーで回転
しているので動きは同じになるように思われます。
左右(2つ)のモーターのパワーを1度に送信する例
1 |
ev3.move(leftPort: .a, rightPort: .d, leftPower: 10.0, rightPower: 10.0) |
左右(2つ)のモーターのパワーを2度に分けて送信する例
1 2 |
ev3.motorOn(on:.a, withPower:10.0) ev3.motorOn(on:.d, withPower:10.0) |
ところが2つのコードを実際に動かしてみると、後者の「左右のモーターのパワーを2度に分けて送信する例」では左(ポートA)のモーターが先に回転してから少し(数百ミリ秒)遅れて、右(ポートD)のモーターが回転する、という現象が見られます。ロボットの構造によっては2つのモーターの回転が1秒以下の短い時間で遅れても(ずれても)問題にはならないとおもいますが、左右に並べたモーター(タイヤ)を並行して制御するようなケースでは、正面に向かって期待した通りには走らずに困ってしまうケースが発生するように思われます。だからSwift Playgroundsも「二つのモーターのパワーを1度に送信する」という一見冗長なメソッドを用意しているのだと思います。
この通信による遅延はライントレースにおける「光センサーの測定値を読み取って、その結果で左右のモーターの回転(パワー)をコントロールする」という処理でも悪い影響を及ぼします。したがって下記のサンプルコードでも、モーターのパワーを抑え気味にしてロボットの制御が間に合わなくなる事態を避けています。
実際に試して見たライントレースのコードは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 |
let threshold = Float(15.0) while true { let light = ev3.measureLightReflection(on: .three) if light > threshold { ev3.brickLightOn(withColor: .orange, inMode: .on) ev3.move(leftPort: .a, rightPort: .d, leftPower: 3.0, rightPower: 5.0) } else { ev3.brickLightOff() ev3.move(leftPort: .a, rightPort: .d, leftPower: 5.0, rightPower: 3.0) } } |