【Androidでドローン(マルチコプター)を飛ばそう】 ドローン探索機能を実装する
前回はプロジェクトにARDroneSDK3を導入する方法を書きました。
今回はARDroneSDK3を使ってAndroid端末周辺に存在するドローンを探査する機能を実装します。
1-ARDroneSDK3公式ドキュメントとサンプルプロジェクト
下記からARDroneSDK3公式ドキュメントとサンプルプロジェクトができます。
Parrot BEBOP DRONE For Developers
Parrot-Developers/Samples
2-Drone探査機能の実装に使うクラス
まずは、ARDroneSDK3を使ってAndroid端末周辺に存在するドローンを探査する機能を実装します。
下記のクラスを使います。
クラス名 | 説明 |
ARDiscoveryService | ドローンを探査するためのクラスです。このクラス自体はServiceを継承しています。 起動することで周辺にあるParrot社のドローンを探査し、探査済みドローンリストとして内部に保持します。 また、探査済みドローンリストが更新されるたびにAndroid内にブロードキャストを発行し知らせます。 このブロードキャストはARDroneSDK3内で提供されているARDiscoveryServicesDevicesListUpdatedReceiverで受け取ることになります。 |
ARDiscoveryServicesDevicesListUpdatedReceiver | BroadcastReceiverを継承しています。 ARDiscoveryServiceが発行した探査済みドローンリスト更新ブロードキャストを受け取るブロードキャストレシーバーです。 実装は簡単で、ブロードキャストを受け取ると、事前に設定されているARDiscoveryServicesDevicesListUpdatedReceiverDelegate内のコールバックメソッドを呼び出します。 |
ARDiscoveryServicesDevicesListUpdatedReceiverDelegate | コールバックインターフェースです。 ARDiscoveryServicesDevicesListUpdatedReceiverがブロードキャストを受け取ったときに呼ぶコールバックです。 探査済みドローン一覧が更新されるたびにonServicesDevicesListUpdatedが呼ばれます。 |
ARDiscoveryDeviceService | ドローンの情報を保持するクラスです。
他にも保持している情報はありますが、詳細は後のブログで書きます。 また、Parcelableインターフェースを実装しているため、Intentにセットすることができます。 |
3-ドローン探索機能クラスの実装
サンプルからの流用(そのままなのは内緒)します。クラス名はDroneDiscoverにします
ドローン探索機能クラスの要件は下記のとおりです。
- 機能1:ARDiscoveryServiceを起動し、ドローン探索機能を有効にする。
- 機能2:ARDiscoveryServicesDevicesListUpdatedReceiverに探索済みドローンリストが更新されたときに呼ばれるARDiscoveryServicesDevicesListUpdatedReceiverDelegateを設定すること
- 機能3:ARDiscoveryServiceが発行するブロードキャストを取得するブロードキャストレシーバーであるARDiscoveryServicesDevicesListUpdatedReceiverを登録すること
- 機能4:探索済みドローンリストが更新されたときに機能利用クラスに対するコールバックを行うこと
- 機能5:ARDiscoveryServiceを停止し、ドローン探索機能を無効にする。
4-実装1(初期化部)
まず、コンストラクタで各変数を初期化します。
特に重要な処理はブロードキャストレシーバー経由で探知済みドローンリストが更新されたときに呼ばれるARDiscoveryServicesDevicesListUpdatedReceiverをインスタンス化です。
このクラスは探知済みドローンリストが更新されたときに発行されるブロードキャストを受信するレシーバークラスです。
また、ブロードキャストを受信したときにARDiscoveryServicesDevicesListUpdatedReceiverはARDiscoveryServicesDevicesListUpdatedReceiverDelegate#onServicesDevicesListUpdatedを実行します。
今回、onServicesDevicesListUpdatedの実装ではARDiscoveryService#getDeviceServicesArrayを呼び探知済みドローンリストを取得します。
notifyServiceDiscoveredについて後述します。
/** * コンテキスト */ private final Context mContext; /** * リスナーリスト */ private final List<Listener> mListeners; /** * 発見した周囲のドローン一覧 */ private final List<ARDiscoveryDeviceService> mMatchingDrones; /** * ドローン発見時のブロードキャストレシーバー */ private final ARDiscoveryServicesDevicesListUpdatedReceiver mArDiscoveryServicesDevicesListUpdatedReceiver; /** * ブロードキャストレシーバー更新時のコールバックインターフェース */ private final ARDiscoveryServicesDevicesListUpdatedReceiverDelegate mArDiscoveryServicesDevicesListUpdatedReceiverDelegate = new ARDiscoveryServicesDevicesListUpdatedReceiverDelegate() { @Override public void onServicesDevicesListUpdated() { if (mArDiscoveryService != null) { // 検索済みのドローン一覧を削除 mMatchingDrones.clear(); //Service内で保持している検知したドローン一覧を取得する。 List<ARDiscoveryDeviceService> deviceList = mArDiscoveryService.getDeviceServicesArray(); //検知したドローンが存在した場合 if (deviceList != null) { //検知したドローンを検知したドローン一覧に追加する for (ARDiscoveryDeviceService service : deviceList) { mMatchingDrones.add(service); } } //検知したドローン一覧をコールバックする notifyServiceDiscovered(mMatchingDrones); } } }; /** * 接続用コネクション */ private ServiceConnection mServiceConnection; /** * 周囲のドローンを探すService */ private ARDiscoveryService mArDiscoveryService; /** * コンストラクタ * @param context コンテキスト */ public DroneDiscover(Context context) { mContext = context; mListeners = new ArrayList<>(); mMatchingDrones = new ArrayList<>(); //レシーバーの作成、コンストラクタの引数にコールバックインターフェースを渡す。 mArDiscoveryServicesDevicesListUpdatedReceiver = new ARDiscoveryServicesDevicesListUpdatedReceiver(mArDiscoveryServicesDevicesListUpdatedReceiverDelegate); }
5-実装2(探索機能の開始)
まず、ARDiscoveryServiceを登録します。
登録するときに使うIntentFilterのactionはARDiscoveryService#kARDiscoveryServiceNotificationServicesDevicesListUpdatedを使用します。
ARDiscoveryServiceを起動します。ServiceConnectionを使ったServiceの起動方法については説明を省略します。
ServiceConnection#onServiceConnectedの中でドローン探索機能を有効にするstartDiscoveringメソッドを呼びます。
startDiscoveringはARDiscoveryService#startを呼ぶことでドローン探索機能が有効にするメソッドです。
/** * 探索開始フラグ */ private boolean mStartDiscoveryAfterConnection; /** * クラスのセットアップをする */ public void setup() { // ARDiscoveryService(ブロードキャストレシーバー)を登録する LocalBroadcastManager localBroadcastMgr = LocalBroadcastManager.getInstance(mContext); localBroadcastMgr.registerReceiver(mArDiscoveryServicesDevicesListUpdatedReceiver, new IntentFilter(ARDiscoveryService.kARDiscoveryServiceNotificationServicesDevicesListUpdated)); // ServiceConnectionを使ってServiceのライフサイクルコールバックを受け取る if (mServiceConnection == null) { mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 起動したServiceのインスタンスを取得する。 mArDiscoveryService = ((ARDiscoveryService.LocalBinder) service).getService(); if (mStartDiscoveryAfterConnection) { //検知を開始する。 startDiscovering(); mStartDiscoveryAfterConnection = false; } } @Override public void onServiceDisconnected(ComponentName name) { mArDiscoveryService = null; } }; } //Serviceが起動していない場合は起動する if (mArDiscoveryService == null) { // ARDiscoveryServiceを起動する。 Intent i = new Intent(mContext, ARDiscoveryService.class); mContext.bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE); } } /** * ドローン探索機能を有効にする。 * ドローンが発見されたときは,{@link Listener#onDronesListUpdated(List)}にコールバックする */ public void startDiscovering() { if (mArDiscoveryService != null) { // ドローン検知Serviceを開始する mArDiscoveryServicesDevicesListUpdatedReceiverDelegate.onServicesDevicesListUpdated(); mArDiscoveryService.start(); mStartDiscoveryAfterConnection = false; } else { mStartDiscoveryAfterConnection = true; } }
6-実装3(コールバック機能の実装)
コールバックインターフェースのListenerを定義します。
このインターフェースには探索済みドローンリストが更新されたときにコールバックするためのonDronesListUpdatedメソッドがあります。
notifyServiceDiscoveredは登録されたすべてのコールバックインターフェースのonDronesListUpdatedを実行します。
onDronesListUpdatedは引数に探索済みドローンリストを取ります。
/** * 発見したドローンリストが更新されたときに呼ばれるコールバックリスナー */ public interface Listener { /** * 周囲に存在するドローンの情報(ARDiscoveryDeviceService)リストを * 返却する。 * * @param dronesList 周囲に存在するドローンの情報(ARDiscoveryDeviceService)リストを */ void onDronesListUpdated(List<ARDiscoveryDeviceService> dronesList); } /** * コールバックインターフェースの追加する * * @param listener コールバックインターフェース */ public void addListener(Listener listener) { mListeners.add(listener); notifyServiceDiscovered(mMatchingDrones); } /** * コールバックインターフェースの削除する * * @param listener コールバックインターフェース */ public void removeListener(Listener listener) { mListeners.remove(listener); } /** * 検知ドローン一覧をコールバックする。 * @param dronesList 検知ドローン一覧 */ private void notifyServiceDiscovered(List<ARDiscoveryDeviceService> dronesList) { List<Listener> listenersCpy = new ArrayList<>(mListeners); for (Listener listener : listenersCpy) { listener.onDronesListUpdated(dronesList); } }
7-実装4(探索機能の停止)
まずはARDiscoveryServiceの探索機能を停止します。
次にARDiscoveryServiceをアンバインドしServiceを停止します。
最後にArDiscoveryServicesDevicesListUpdatedReceiverをレシーバーを解除します。
/** * 後始末をする */ public void cleanup() { //検知を止める stopDiscovering(); if (mArDiscoveryService != null) { new Thread(new Runnable() { @Override public void run() { //Serviceを止める mArDiscoveryService.stop(); mContext.unbindService(mServiceConnection); mArDiscoveryService = null; } }).start(); } // ARDiscoveryService(ブロードキャストレシーバー)を解除する LocalBroadcastManager localBroadcastMgr = LocalBroadcastManager.getInstance(mContext); localBroadcastMgr.unregisterReceiver(mArDiscoveryServicesDevicesListUpdatedReceiver); } /** * ドローン検知機能を無効にする。 */ public void stopDiscovering() { if (mArDiscoveryService != null) { Log.i(TAG, "Stop discovering"); mArDiscoveryService.stop(); } mStartDiscoveryAfterConnection = false; }
8-まとめ
今回はDrone探査機能を実現するためにDroneDiscoverを実装しました。
次回はこのクラスを使ってAndroid端末の周辺に存在するドローンを探索します。
/** * ドローン探索機能 */ public class DroneDiscover { private static final String TAG = "DroneDiscoverer"; /** * 発見したドローンリストが更新されたときに呼ばれるコールバックリスナー */ public interface Listener { /** * 周囲に存在するドローンの情報(ARDiscoveryDeviceService)リストを * 返却する。 * * @param dronesList 周囲に存在するドローンの情報(ARDiscoveryDeviceService)リストを */ void onDronesListUpdated(List<ARDiscoveryDeviceService> dronesList); } /** * コンテキスト */ private final Context mContext; /** * リスナーリスト */ private final List<Listener> mListeners; /** * 発見した周囲のドローン一覧 */ private final List<ARDiscoveryDeviceService> mMatchingDrones; /** * ドローン発見時のブロードキャストレシーバー */ private final ARDiscoveryServicesDevicesListUpdatedReceiver mArDiscoveryServicesDevicesListUpdatedReceiver; /** * ブロードキャストレシーバー更新時のコールバックインターフェース */ private final ARDiscoveryServicesDevicesListUpdatedReceiverDelegate mArDiscoveryServicesDevicesListUpdatedReceiverDelegate = new ARDiscoveryServicesDevicesListUpdatedReceiverDelegate() { @Override public void onServicesDevicesListUpdated() { if (mArDiscoveryService != null) { // 検索済みのドローン一覧を削除 mMatchingDrones.clear(); //Service内で保持している検知したドローン一覧を取得する。 List<ARDiscoveryDeviceService> deviceList = mArDiscoveryService.getDeviceServicesArray(); //検知したドローンが存在した場合 if (deviceList != null) { //検知したドローンを検知したドローン一覧に追加する for (ARDiscoveryDeviceService service : deviceList) { mMatchingDrones.add(service); Log.d("you",service.toString()); } } //検知したドローン一覧をコールバックする notifyServiceDiscovered(mMatchingDrones); } } }; /** * 接続用コネクション */ private ServiceConnection mServiceConnection; /** * 周囲のドローンを探すService */ private ARDiscoveryService mArDiscoveryService; /** * コンストラクタ * @param context コンテキスト */ public DroneDiscover(Context context) { mContext = context; mListeners = new ArrayList<>(); mMatchingDrones = new ArrayList<>(); //レシーバーの作成 mArDiscoveryServicesDevicesListUpdatedReceiver = new ARDiscoveryServicesDevicesListUpdatedReceiver(mArDiscoveryServicesDevicesListUpdatedReceiverDelegate); } private boolean mStartDiscoveryAfterConnection; /** * クラスのセットアップをする */ public void setup() { // ARDiscoveryService(ブロードキャストレシーバー)を登録する LocalBroadcastManager localBroadcastMgr = LocalBroadcastManager.getInstance(mContext); localBroadcastMgr.registerReceiver(mArDiscoveryServicesDevicesListUpdatedReceiver, new IntentFilter(ARDiscoveryService.kARDiscoveryServiceNotificationServicesDevicesListUpdated)); // ServiceConnectionを使ってServiceのライフサイクルコールバックを受け取る if (mServiceConnection == null) { mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 起動したServiceのインスタンスを取得する。 mArDiscoveryService = ((ARDiscoveryService.LocalBinder) service).getService(); if (mStartDiscoveryAfterConnection) { //検知を開始する。 startDiscovering(); mStartDiscoveryAfterConnection = false; } } @Override public void onServiceDisconnected(ComponentName name) { mArDiscoveryService = null; } }; } //Serviceが起動していない場合は起動する if (mArDiscoveryService == null) { // ARDiscoveryServiceを起動する。 Intent i = new Intent(mContext, ARDiscoveryService.class); mContext.bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE); } } /** * ドローン検知機能を有効にする。 * ドローンが発見されたときは,{@link Listener#onDronesListUpdated(List)}にコールバックする */ public void startDiscovering() { if (mArDiscoveryService != null) { // ドローン検知Serviceを開始する mArDiscoveryServicesDevicesListUpdatedReceiverDelegate.onServicesDevicesListUpdated(); mArDiscoveryService.start(); mStartDiscoveryAfterConnection = false; } else { mStartDiscoveryAfterConnection = true; } } /** * 後始末をする */ public void cleanup() { //検知を止める stopDiscovering(); if (mArDiscoveryService != null) { new Thread(new Runnable() { @Override public void run() { //Serviceを止める mArDiscoveryService.stop(); mContext.unbindService(mServiceConnection); mArDiscoveryService = null; } }).start(); } // ARDiscoveryService(ブロードキャストレシーバー)を解除する LocalBroadcastManager localBroadcastMgr = LocalBroadcastManager.getInstance(mContext); localBroadcastMgr.unregisterReceiver(mArDiscoveryServicesDevicesListUpdatedReceiver); } /** * ドローン検知機能を無効にする。 */ public void stopDiscovering() { if (mArDiscoveryService != null) { Log.i(TAG, "Stop discovering"); mArDiscoveryService.stop(); } mStartDiscoveryAfterConnection = false; } /** * コールバックインターフェースの追加する * * @param listener コールバックインターフェース */ public void addListener(Listener listener) { mListeners.add(listener); notifyServiceDiscovered(mMatchingDrones); } /** * コールバックインターフェースの削除する * * @param listener コールバックインターフェース */ public void removeListener(Listener listener) { mListeners.remove(listener); } /** * 検知ドローン一覧をコールバックする。 * @param dronesList 検知ドローン一覧 */ private void notifyServiceDiscovered(List<ARDiscoveryDeviceService> dronesList) { List<Listener> listenersCpy = new ArrayList<>(mListeners); for (Listener listener : listenersCpy) { listener.onDronesListUpdated(dronesList); } } }
|
|
||||
|
|
||||