概要

ROSを起動させているロボットに対して、スマートデバイスからROSで通信を行いたい時があるときは、Flutterを用いたネイティブアプリで実装するのがおすすめです。

https://rb-station.com/blogs/article/roslibjs-javascript-ros

手軽にROS通信を行いたい場合は、こちらの記事のように、Webアプリケーションを作って、スマートデバイスのブラウザで表示させれば大丈夫ですが、ブラウザは制限が強く(例えば、iOS Safariはclickなどのユーザー動作起点ではないと音声を再生できない、など)実装したい内容がWebアプリケーションで実現できない場合はネイティブアプリを作った方が良いと思います。

Flutterについて

flutter logo

FlutterとはGoogleが開発している、クロスプラットフォームのアプリ開発フレームワークです。Dartという言語を用いて開発をします。

iOSやAndroid、Webなど複数プラットフォームのアプリケーションをビルドできる他、ホットリロード機能でデバッグがかなり楽だったり、とても簡単にアプリ開発が可能です。

Flutterのアプリケーション開発については色々な記事にて解説がなされていますので、導入は他記事に任せるとして、本記事では、FlutterアプリにROSを載せるところの解説をします。

使用するライブラリ

ROS通信を行うには、roslibというライブラリをインポートする必要があります。

しかし、このroslib、あまりメンテナンスがされておらず、2021年5月現在、Null-Safetyが実装されていないため、Flutter 2系を使うとエラーになってしまいますので、Flutterのバージョンは1系を使うようにしましょう

自分の環境はこんな感じです。

$ flutter --version
Waiting for another flutter command to release the startup lock...
Flutter 1.20.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision fba99f6cf9 (8 months ago) • 2020-09-14 15:32:52 -0700
Engine • revision d1bc06f032
Tools • Dart 2.9.2 

ROSが動いているマシンの設定

roslibとはWebSocketで接続を行います。ROSが動いているマシンでは、rosbridge_serverパッケージのrosbridge_websocket.launchを起動しておくことで接続を受け入れ可能な状態にします。

  • コマンドでの起動
roslaunch rosbridge_server rosbridge_websocket.launch
  • launchファイルでの起動 
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch">
    </include>

roslibの導入

pubspec.yamlに下記を追加 

pubspec.yaml

dependencies:
  roslib: ^0.0.3

 ライブラリのインストール 

$ flutter pub get

dartファイル内でroslibライブラリをインポート

main.dart

import 'package:roslib/roslib.dart';
 

これでライブラリを使う準備は整いました。 

ROSトピックをsubscribe/publish

上記のlib/main.dartがメインのコードとなり、一部抜粋して解説をします。

rosのインスタンスを作成 

  Ros ros;
  @override
  void initState() {
    ros = Ros(url: 'ws://192.168.11.7:9090');
  ros.connect();

上記でrosのインスタンスを作成します。urlは、ROSが起動しているマシンのIPアドレスになります。ifconfig等で、確認をしましょう。次の例では、「wlan0」のinetに記載されている「192.168.11.7」がIPアドレスになっています。

ifconfig

また、FlutterアプリをインストールするデバイスもROSが起動しているマシンと同じWiFiに接続しておきましょう。ポートはrosbridge_serverでwebsocketを起動したポートを指定します。デフォルトでは9090になります。

また、ros.connect()によって、接続を確立します。

トピックのPublish

  Topic helloTopic;
    helloTopic = Topic(
        ros: ros,
        name: '/hello_from_flutter',
        type: "std_msgs/String",
        reconnectOnClose: true,
        queueLength: 10,
        queueSize: 10);

SubscriberもPublisherも上記のようにTopicのインスタンスをまず作成します。この例では「/hello_from_flutter」という名前でstd_msgs/String型のトピックを表すインスタンス、ということになります。

helloTopic.publish({"data": "Hello from flutter"});

次に、.publish()でPublishができます。型が合っているかは確認しましょう。

トピックのSubscribe

  Topic rosOutTopic;
    rosOutTopic = Topic(
        ros: ros,
        name: '/hello_to_flutter',
        type: "std_msgs/String",
        reconnectOnClose: true,
        queueLength: 10,
        queueSize: 10);

まずはTopicインスタンスを作成します。Subscribeの方はhello_to_flutterという名前のトピックにします。

  void initConnection() async {
    ros.connect();
    await rosOutTopic.subscribe();
    setState(() {});
  }
Container(
  child: StreamBuilder(
    stream: rosOutTopic.subscription,
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Text(snapshot.data["msg"]["data"]);
      } else {
        return Text('');
      }
    },
)),

ros.connect()で接続をした後にtopic.subscribe()でトピックのSubscribeをすることができます。

データを受信する場合はStreamBuilderで、topic.subscriptionをstreamに指定すると、データを受信した際にsnapshotの変数にデータが入って渡されます。データが含まれる場合はsnapshot.hasDataがtrueになります。データ自体はsnapshot.data["msg"]で取り出すことができます。

ROSトピック通信の確認

受信の確認(Subscribe)

ROSが起動しているマシンでrosbridge_serverを起動し、スマートデバイスでFlutterアプリを起動します。「Connect」ボタンを押すとWebSocketでの接続を行い、下のような状態になります。

ROS通信

続いて、ROSが起動しているマシンで何かしらのメッセージを送ります。

$ rostopic pub /hello_to_flutter std_msgs/String "Hello from Ubuntu"

 トピックの受信

このように送信したメッセージが表示されていれば成功です。

送信の確認(Publish)

WebSocketで接続するまでは受信の時と同じです。送信の確認をするので、ROSが起動しているマシン上で、rostopicをechoしましょう。

$ rostopic echo /hello_from_flutter

スマートデバイス側で「Hello」ボタンを押したときに、ROSが起動しているマシンで下記のように受信できていれば送信が正常にできています。

data: "Hello from flutter"
FlutterRosネイティブアプリ

Related Posts

Arduinoでコードからリセットをする方法
Arduinoでコードからリセットをする方法
概要 Arduinoでは、リセットボタンを押すと初期化がされ、setup()の関数がコールされますが、リセットボタンを押さずにコード上だけでリセットをさせたいときは、アドレス0を指定して実行をする方法があります。 参考: https:...
Read More
ArduinoのServoライブラリで接続を解除する方法
ArduinoのServoライブラリで接続を解除する方法
Arduinoでサーボモータを扱う時にはServoライブラリを使うのがおすすめです。 https://www.arduino.cc/reference/en/libraries/servo/ 電力消費を抑える、他の駆動系の影響を受...
Read More
VMWare FusionでUbuntu 18.04のディスク容量を上げる方法
VMWare FusionでUbuntu 18.04のディスク容量を上げる方法
概要 VMWare FusionでUbuntu 18.04の仮想ディスクを起動する際に、ハードディスクの容量を上げる方法について解説します。 手順 1. 仮想ディスクの電源をOFFにする 2. 設定ボタンを押して設定画面を開いた後に、...
Read More