【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);
}
}
}
|
|
||||
|
|
||||



