Romo×iPhoneで楽しむロボット体験

第2回Romoを自由に動かしてみよう!

はじめに

前回スマートフォンで動くエデュケーショナルロボット Romo について概要をご説明させていただきました。今回はいよいよ、Romo SDKを使用しての開発について、ご紹介させていただきたいと思います。

Romo SDKで提供されている2つのFramework
  • RMCore
  • RMCharacter

の内、実際のデバイスと接続して開発を行うRMCoreを使用してみます(RomoのキャラクターUIを提供するRMCharacterについては、次回ご紹介させていただきます⁠⁠。

RMCoreを利用したわかりやすい作例の動画があるのでご紹介します。

Controlling Romo with Pebble from John Brewer on Vimeo.

RomoをスマートウォッチのPebbleでコントロールしていますが、Romoに接続したiPhoneのカメラからの画像を表示している様子が見えます。たとえば、これを音声認識でコントロールできるようにしたり、色々なことが試せそうですね。

デバイスの発売は7月24日になります。公式オンラインストアで予約することができます。

サンプルの実行

さて、まずは気軽にサンプルコードを実行してみたいと思います。SDKはこちらからダウンロードが可能です。詳細は前回の記事をご参考いただけると幸いです。

RMCoreを利用したサンプルコードはHelloRMCoreになります。さっそく実行してiPhoneにインストールしてみると、デバイスにつなげて欲しいとの表示が出ます。

つなげるとこの画面が
つなげるとこの画面が

おお、動きました!

※Romoに充電用のUSBケーブルを接続していると動作しないので注意です。

SDKでできること

RMCore Frameworkでできることは何になるのでしょうか? 以下に簡単にまとめさせていただきました。

  • LEDの制御
  • iPhoneの角度の制御
  • 左右のキャタピラの回転

左右のキャタピラの回転の制御により、Romoを回転させたり、前進、行進などの制御を行うことができます。詳細なAPIのドキュメントはこちらになります。

SDKをプロジェクトに追加

では、実際に SDK をプロジェクトに追加して動かしてみましょう。サンプルファイルをそのまま改変するのが簡単ですが、ここでは新しいプロジェクトファイルにフレームワークを追加してみます。

まずはRMCore.frameworkをFrameworksにドラッグ&ドロップ。続いて、Build PhasesタブでCoreMotion.frameworkとExternalAccessory.frameworkを追加します。

RMCore.frameworkをFrameworksにドラッグ&ドロップ
RMCore.frameworkをFrameworksにドラッグ&ドロップ

続いて、外部アクセサリとの接続を許可する設定をします。作成したプロジェクトのinfo.plistファイルを開き、新しく"Supported external accessory protocols"という項目を追加し、"item 0"の箇所に"com.romotive.romo"と追記します。これでアプリがRomoをExternal Accessoryとして認識することができます。

外部アクセサリとの接続を許可
外部アクセサリとの接続を許可

デバイスとの接続

それでは、デバイスとの接続を検知するところからはじめて見ましょう。ベースとなるViewController.hにRMCoreをimportします。

ViewController.h
#import <RMCore/RMCore.h>

接続の検知は、RMCoreクラスのdelegateとして通知されます。起動時にdelegateの設定を行います。

ViewController.h
@interface ViewController : UIViewController <RMCoreDelegate>
ViewController.m
- (void)viewDidLoad
{
    [super viewDidLoad];
    [RMCore setDelegate:self];
}

実際のDelegateメソッドを以下のように記述します。ここで1つの問題、iPhoneをPCから切り離してデバイスに接続しないと動作しないので、デバッグのテキストを画面上のUILabelに表示するようにしました。

ViewController.h
// デバッグ用テキスト表示
@property IBOutlet UILabel* debugText;

delegateでRomoの各種処理を提供するRMCoreRobotオブジェクトが渡されるのですが、Romoは今後の機能拡張を想定してRMCoreRobotに各機能を表すインターフェースを実装する形で拡張される設計になっています。HeadTiltProtocolがiPhoneの角度を変更するインターフェース、DriveProtocolが左右のキャタピラを操作するインターフェース、LEDProtocolがLEDの点灯を制御するインターフェースとなっています。

やや複雑な表記ですが、それぞれのインターフェースを指定した記述で、以下のようにRMCoreRobotオブジェクトを持つようにします。

ViewController.h
@property (nonatomic, strong) RMCoreRobot<HeadTiltProtocol, DriveProtocol, LEDProtocol> *myRobot;
ViewController.m
- (void)robotDidConnect:(RMCoreRobot *)robot
{
if (robot.isDrivable && robot.isHeadTiltable && robot.isLEDEquipped) {
       self.debugText.text = @"connected!";
       self.myRobot = (RMCoreRobot<HeadTiltProtocol, DriveProtocol, LEDProtocol> *) robot;
    }
}

なお、Romo から iPhone を外すと以下のメソッドが呼ばれます。

- (void)robotDidDisconnect:(RMCoreRobot *)robot
{
    if (robot == self.myRobot) {
       self.myRobot = nil;
       self.debugText.text = @"disconnected!";
    }
}

ちなみに今回は利用をしないのですが、開発する上で接続が手間となり、とりあえずデバイスに接続しなくてもシミュレータなどで処理を確認したい場合、deviceとの接続をダミーで知らせるRMCoreのconnectToSimulatedRobotというクラスメソッドと、接続解除をダミーで知らせるdisconnectFromSimulatedRobotというクラスメソッドがそれぞれ用意されています。

ViewController.m
// Romo との接続をシミュレーターで再現
[RMCore connectToSimulatedRobot];

以上のようにダミーで知らせると、robotDidConnectがdelegateで呼ばれます。

LED

続いて何かアクションをさせてみましょう。

画面にUIButtonを配置し、タップするとLEDを光らせるようにしました。RMCoreRobotオブジェクトが実装しているLEDProtocolインターフェースに、LEDsというRMCoreLEDsクラスのプロパティがあります。こちらのメソッドを呼び出して処理を行います。

ViewController.m
- (IBAction)pushLEDBtn:(id)sender
{
    [self.myRobot.LEDs blinkWithPeriod:0.5 dutyCycle:0.1];
}

この書き方で、0.5秒間隔で点灯と消灯を1:9の割合で行うようにできます。一瞬チカッと光るイメージです。

点灯や点滅、決められた明るさでの点灯など、より詳しいメソッドはクラスドキュメントRMCoreLEDsで確認することができます。

前傾、後傾

続いて、Romoに接続したiPhoneの傾斜を動かす方法です。RMCoreRobotオブジェクトが実装しているHeadTiltProtocolに各種プロパティとメソッドが用意されています。

ViewController.m
- (IBAction)pushTiltBtn:(id)sender
{
    // HeadTild
    if (self.myRobot.robot.headAngle < self.myRobot.robot.maximumHeadTiltAngle - 1) {
        [self.myRobot.robot tiltToAngle:self.myRobot.robot.maximumHeadTiltAngle completion:nil];
    } else {
        [self.myRobot.robot tiltToAngle:self.myRobot.robot.minimumHeadTiltAngle completion:nil];
    }
}

タップするごとに、頭が前後に傾くようになります。ちなみに最初の判定で-1を入れているのは、headAngleがモーターの状態などにより誤差が少し生じるためです。このあたりの調整が、デバイスをプログラミングしている実感を感じさせますね。

ちなみに、completionにblockを設定することで、処理の完了を受け取ることができます。

移動

最後に、Romoの左右のキャタピラを使って移動させる方法です。RMCoreRobotオブジェクトが実装しているDriveProtocolに各種プロパティとメソッドが用意されています。

ViewController.m
- (IBAction)pushMoveBtn:(id)sender
{
    // Drive
    if (self.myRobot.robot.driving) {
        [self.myRobot.robot stopDriving];
    } else {
        [self.myRobot.robot driveWithRadius:1.0 speed:1.0];
    }
}

タップすると、半径1m、秒速1mで回転移動を始めます(状況により誤差は出るようです⁠⁠。もう一度タップすると停止します。回転以外にも前後の移動、その場での回転などざまざまなメソッドが用意されています。

まとめ

さて、いかがでしたでしょうか?

実際にRomoが動き出すと手応えがあり、デバイスを利用したプログラミングの楽しさを実感できます。今回は比較的制御しやすい方法をご紹介させていただきましたが、直接それぞれのモーターを制御するなど、もっと掘り下げた処理を行うこともできるので、ぜひ一度クラスドキュメントに目を通されることをおすすめします。

Romoは現在、エデュケーショナルロボットとして販売していますが、スマートフォンで動かすことのできるロボットデバイスと捉えることで、皆さんが開発するアプリ次第で、エデュケーショナル以外にもさまざまな用途を見出すこともできるかと思います。

次回は、RomoのCharacter UIを制御するRMCharacterをご紹介します。

おすすめ記事

記事・ニュース一覧