v5.x版本的功能與v4.x基本相同,都是獲取飛機(jī)的姿態(tài)信息、獲取無人機(jī)多媒體文件、操作多媒體文件、航線規(guī)劃等。不過在上一章節(jié)中也大致說了一些兩個版本的中API的差別,下面是根據(jù)一些API使用所完成的一些功能,因?yàn)轫椖吭蛑荒芴峁┎糠执a供參考,后續(xù)如果有這方面需求的小伙伴可以對其進(jìn)行開發(fā)指導(dǎo)。
1獲取姿態(tài)信息
1、KeyManager調(diào)用
KeyManager類提供了一組方法來訪問硬件模塊的參數(shù)和控制硬件模塊的行為,包括DJIKey的Value設(shè)置,Value獲取,Value監(jiān)聽和Action執(zhí)行。通過KeyTools類提供的createKey方法可以更加方便的創(chuàng)建DJIKey實(shí)例。
下圖展示了使用KeyManager的接口判斷飛控正常連接并且GPS信號等級大于等于2級,然后給飛行器設(shè)置返航點(diǎn),最后執(zhí)行返航操作的調(diào)用流程。

此處是示例的操作方式,后面有在項目中使用的過程。
2、示例
//獲取飛機(jī)信息、云臺信息
privatevoidget3DLocation(){
KeyManager.getInstance().listen(KeyTools.createKey(FlightControllerKey.KeyAircraftLocation3D),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableLocationCoordinate3DoldValue,@NullableLocationCoordinate3DnewValue){
if(newValue!=null){
lat=newValue.latitude;
lon=newValue.longitude;
high=newValue.altitude;
}
}
});
}
privatevoidgetAttitude(){
KeyManager.getInstance().listen(KeyTools.createKey(FlightControllerKey.KeyAircraftAttitude),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableAttitudeoldValue,@NullableAttitudenewValue){
if(newValue!=null){
pitch=newValue.pitch;
roll=newValue.roll;
yaw=newValue.yaw;
}
}
});
}
privatevoidgetVelocity(){
KeyManager.getInstance().listen(KeyTools.createKey(FlightControllerKey.KeyAircraftVelocity),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableVelocity3DoldValue,@NullableVelocity3DnewValue){
if(newValue!=null){
velocity_X=newValue.x;
velocity_Y=newValue.y;
velocity_Z=newValue.z;
}
}
});
}
privatevoidgetIsFly(){
KeyManager.getInstance().listen(KeyTools.createKey(FlightControllerKey.KeyIsFlying),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableBooleanoldValue,@NullableBooleannewValue){
if(newValue!=null){
isFlying=newValue;
}
}
});
}
privatevoidgetGimbalAttitude(){
KeyManager.getInstance().listen(KeyTools.createKey(GimbalKey.KeyGimbalAttitude),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableAttitudeoldValue,@NullableAttitudenewValue){
if(newValue!=null){
g_pitch=newValue.pitch;
g_roll=newValue.roll;
g_yaw=newValue.yaw;
}
}
});
}
privatevoidgetPower(){
KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.KeyChargeRemainingInPercent),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableIntegeroldValue,@NullableIntegernewValue){
power=newValue;
}
});
}
privatevoidgetTemperature(){
KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.KeyBatteryTemperature),this,newCommonCallbacks.KeyListener(){
@Override
publicvoidonValueChange(@NullableDoubleoldValue,@NullableDoublenewValue){
temperature=newValue;
}
});
}
get3DLocation()方法為獲取飛機(jī)經(jīng)緯度信息。
getAttitude()方法獲取飛機(jī)的姿態(tài)信息(分別是航偏角、旋轉(zhuǎn)角、俯仰角)。
getVelocity()方法獲取飛機(jī)的飛行速度(分別是X、Y、Z三個方向的速度值)。
getIsFly()方法獲取當(dāng)前飛機(jī)的狀態(tài)值(是否正在飛行)。
getGimbalAttitude()方法獲取鏡頭的姿態(tài)信息(分別是航偏角、旋轉(zhuǎn)角、俯仰角)。
getPower()獲取飛機(jī)的電池電量
getTemperature()獲取飛機(jī)的電池溫度
onValueChange()方法為1秒執(zhí)行10次,這個可以根據(jù)后續(xù)要求進(jìn)行獲取;
2多媒體使用
1、Sample介紹
拍照、錄像是無人機(jī)的重要功能,對拍攝的照片、視頻等多媒體文件進(jìn)行管理也就必不可少。多媒體文件的管理包括訪問飛機(jī)存儲空間內(nèi)的多媒體文件資源、獲取多媒體文件列表與列表狀態(tài)、視頻文件播放等。
下圖為完整的接口展示以及接口調(diào)用流程示例。
多媒體文件管理調(diào)用流程
視頻文件播放調(diào)用流程

2、示例
privatevoidgetFileList(intindex){
if(MediaManager.getInstance()!=null){
//if(mMediaFileListState==MediaFileListState.UPDATING){
//DJILog.e(TAG,"媒體管理器正忙.");
//}elseif(mMediaFileListState==MediaFileListState.IDLE){
MediaManager.getInstance().pullMediaFileListFromCamera((newPullMediaFileListParam.Builder()).build(),newCommonCallbacks.CompletionCallback(){
@Override
publicvoidonSuccess(){
hideProgressDialog();
if(mMediaFileListState!=MediaFileListState.UP_TO_DATE){
//List.clear();
mediaFileList.clear();
lastClickViewIndex=-1;
}
List=MediaManager.getInstance().getMediaFileListData().getData();
switch(index){
case0:
for(inti=0;i{
if(getDate(lhs.getDate())getDate(rhs.getDate())){
return-1;
}
return0;
});
}
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
mListAdapter.notifyDataSetChanged();
}
});
//scheduler.resume(error->{
//if(error==null){
//
//}
//});
getThumbnails();
}
@Override
publicvoidonFailure(@NonNullIDJIErrorerror){
hideProgressDialog();
showToasts("獲取媒體文件列表失敗:"+error.description());
}
});
//}
}
}
privatevoidgetThumbnails(){
if(mediaFileList.size()<=?0)?{
????????????showToasts("沒有用于下載縮略圖的文件信息");
????????????return;
????????}
????????for?(int?i?=?0;?i?(){
@Override
publicvoidonSuccess(Bitmapbitmap){
}
@Override
publicvoidonFailure(@NonNullIDJIErrorerror){
}
});
}
privatevoiddeleteFileByIndex(finalintindex){
ArrayListfileToDelete=newArrayList();
if(mediaFileList.size()>index){
fileToDelete.add(mediaFileList.get(index));
MediaManager.getInstance().deleteMediaFiles(fileToDelete,newCommonCallbacks.CompletionCallback(){
@Override
publicvoidonSuccess(){
mediaFileList.remove(index);
//Resetselectview
lastClickViewIndex=-1;
lastClickView=null;
//UpdaterecyclerView
mListAdapter.notifyDataSetChanged();
}
@Override
publicvoidonFailure(@NonNullIDJIErrorerror){
showToasts("刪除失敗");
}
});
}
}
privatevoiddownloadFileByIndex(finalintindex){
if((mediaFileList.get(index).getFileType()==MediaFileType.MOV)||(mediaFileList.get(index).getFileType()==MediaFileType.MP4)){
SavePath=MyStatic.FLY_FILE_VIDEO;
}elseif(mediaFileList.get(index).getFileType()==MediaFileType.JPEG){
SavePath=MyStatic.FLY_FILE_PHOTO;
}
FiledestDir=newFile(FileUtil.checkDirPath(SavePath));
Stringpath=SavePath+"/"+mediaFileList.get(index).getFileName();
FiledestPath=newFile(path);
try{
outputStream=newFileOutputStream(destPath);
}catch(FileNotFoundExceptione){
e.printStackTrace();
}
bos=newBufferedOutputStream(outputStream);
mediaFileList.get(index).pullOriginalMediaFileFromCamera(0,newMediaFileDownloadListener(){
@Override
publicvoidonStart(){
currentProgress=-1;
ShowDownloadProgressDialog();
}
@Override
publicvoidonProgress(longtotal,longcurrent){
inttmpProgress=(int)(1.0*current/total*100);
if(tmpProgress!=currentProgress){
mDownloadDialog.setProgress(tmpProgress);
currentProgress=tmpProgress;
}
}
@Override
publicvoidonRealtimeDataUpdate(byte[]data,longposition){
try{
bos.write(data,0,data.length);
bos.flush();
}catch(IOExceptione){
e.printStackTrace();
}
}
@Override
publicvoidonFinish(){
HideDownloadProgressDialog();
currentProgress=-1;
try{
outputStream.close();
bos.close();
}catch(Exceptione){
e.printStackTrace();
}
}
@Override
publicvoidonFailure(IDJIErrorerror){
}
});
}
privatevoidplayVideo(){
mImageView.setVisibility(View.INVISIBLE);
MediaFileselectedMediaFile=mediaFileList.get(lastClickViewIndex);
if((selectedMediaFile.getFileType()==MediaFileType.MOV)||(selectedMediaFile.getFileType()==MediaFileType.MP4)){
MediaManager.getInstance().playVideo(selectedMediaFile,newCommonCallbacks.CompletionCallbackWithParam(){
@Override
publicvoidonSuccess(IVideoFrameiVideoFrame){
videoDecoder.queueInFrame(iVideoFrame);
DJILog.e(TAG,"播放成功");
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
mImageViewVideoPlay.setEnabled(false);
mImageViewVideoPause.setEnabled(true);
}
});
}
@Override
publicvoidonFailure(@NonNullIDJIErrorerror){
showToasts("播放失敗"+error.description());
}
});
}
}
getFileList()方法獲取所有媒體文件,文件包括視頻及照片,可以對照片視頻進(jìn)行分類處理了
getThumbnails()方法獲取縮略圖信息,用于在界面展示縮略圖
deleteFileByIndex()方法為刪除到媒體文件(可以進(jìn)行單個刪除或者多個刪除)
downloadFileByIndex()方法為多媒體文件下載
playVideo()方法為多媒體文件視頻播放
3直播的調(diào)用
1、Sample介紹
直播功能是Mobile SDK重要的功能,可支持聲網(wǎng)、RTMP、RTSP、GB28181 四種直播模式。在安防,公共安全,巡檢等場景都需要有直播模塊。
下圖為完整的接口展示以及接口調(diào)用流程示例。詳細(xì)的使用方法請查看Mobile SDK API 文檔中的直播管理類 ILiveStreamManager。直播管理類用于直播的參數(shù)設(shè)置和直播的開啟和停止等功能。

2、示例
項目中使用到了其中的一種方式 ,使用RTMP方式進(jìn)行推流直播。代碼如下:
privatevoidstartLiveShow(){
LiveStreamSettings.Buildersettings=newLiveStreamSettings.Builder();
settings.setLiveStreamType(LiveStreamType.RTMP);
RtmpSettings.BuilderrtmpSetting=newRtmpSettings.Builder();
rtmpSetting.setUrl(liveShowUrl);
settings.setRtmpSettings(rtmpSetting.build());
MediaDataCenter.getInstance().getLiveStreamManager().setLiveStreamSettings(settings.build());
MediaDataCenter.getInstance().getLiveStreamManager().startStream(newCommonCallbacks.CompletionCallback(){
@Override
publicvoidonSuccess(){
Log.i("LiveStreamManager","LiveStreamManager開始直播");
booleanisStream=MediaDataCenter.getInstance().getLiveStreamManager().isStreaming();
Log.i("LiveStreamManager","LiveStreamManager開始直播:"+isStream);
Log.i("LiveStreamManager","LiveStreamManager直播參數(shù):"+MediaDataCenter.getInstance().getLiveStreamManager().getLiveStreamSettings());
Log.i("LiveStreamManager","LiveStreamManager視頻質(zhì)量:"+MediaDataCenter.getInstance().getLiveStreamManager().getLiveStreamQuality());
Log.i("LiveStreamManager","LiveStreamManager直播碼率:"+MediaDataCenter.getInstance().getLiveStreamManager().getLiveVideoBitrate());
Log.i("LiveStreamManager","LiveStreamManager碼流通道:"+MediaDataCenter.getInstance().getLiveStreamManager().getVideoChannelType());
Log.i("LiveStreamManager","LiveStreamManager碼率模式:"+MediaDataCenter.getInstance().getLiveStreamManager().getLiveVideoBitrateMode());
}
@Override
publicvoidonFailure(@NonNullIDJIErrorerror){
Log.i("LiveStreamManager","LiveStreamManager直播錯誤:"+error.description());
}
});
}
privatevoidstopLiveShow(){
AlertDialog.BuilderBuilder=newAlertDialog.Builder(MainActivity.this);
Builder.setTitle("提示");
Builder.setMessage("是否結(jié)束推流?");
Builder.setIcon(android.R.drawable.ic_dialog_alert);
Builder.setPositiveButton("確定",newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
if(!isLiveStreamManagerOn()){
return;
}
LiveStreamManager.getInstance().stopStream(newCommonCallbacks.CompletionCallback(){
@Override
publicvoidonSuccess(){
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
//LiveModulemodule=newLiveModule("liveStreamStateChanged","plane",planeId,false,trajectoryId+"");
mapData.put("type","liveStreamStateChanged");
mapData.put("sender","plane");
mapData.put("planeId",planeId+"");
mapData.put("liveStreamOpen","false");
mapData.put("liveStreamUrl",trajectoryId+"");
params.put("message",GsonUtil.GsonString(mapData));
http.getHttp(POST_LIVE_STATE,"GET",params);
}
});
showToast("結(jié)束推流");
}
@Override
publicvoidonFailure(@NonNullIDJIErrorerror){
}
});
}
});
Builder.setNegativeButton("取消",null);
Builder.show();
}
startLiveShow()方法為開啟直播,并設(shè)置一些直播參數(shù)
stopLiveShow()方法為停止直播,進(jìn)行緩存回收
4航線規(guī)劃
1、Sample介紹
航線任務(wù)管理是用于無人機(jī)自主作業(yè)的重要功能,通過MSDK提供的接口可以實(shí)現(xiàn)對航線任務(wù)的上傳、執(zhí)行、暫停、恢復(fù)以及對航線任務(wù)執(zhí)行狀態(tài)與航線信息的監(jiān)聽等。
我們將航點(diǎn)任務(wù)定義在航線文件中,該文件遵循 DJI 自定義的航線文件格式標(biāo)準(zhǔn)(WPML)。航線文件實(shí)際為“.kmz”結(jié)尾的壓縮文件,文件結(jié)構(gòu)如下:
waypoints_name.kmz └──wpmz ├──res ├──template.kml └──waylines.wpml
其中,template.kml文件為“模板文件”,waylines.wpml文件為“執(zhí)行文件”,res為資源文件。詳細(xì)的介紹請閱讀航線文件格式標(biāo)準(zhǔn)。航線文件格式標(biāo)準(zhǔn)的文檔中有對template.kml文件與waylines.wpml文件的編寫說明。
2、接口調(diào)用流程
MSDK提供的航線功能相關(guān)接口較為簡單,調(diào)用方式如下圖。詳細(xì)的使用方法請查看Mobile SDK API文檔中的航線任務(wù)管理類 IWaypointMissionManager。圖中虛線框內(nèi)容為可選接口。
5總結(jié)
以上內(nèi)容為v5.x版本中使用到的一些內(nèi)容,當(dāng)然還有一些API沒有在項目中使用到,后續(xù)給大家也更新到整個專欄內(nèi)容中,希望喜歡的小伙伴可以進(jìn)行訂閱,如果后續(xù)有共同開發(fā)的同道中人可以聯(lián)系我?guī)湍憬鉀Q一些問題?,F(xiàn)階段v5.x還在持續(xù)更新中,為了適配更多的飛機(jī)它的一些功能也是在不斷的完善。
審核編輯:湯梓紅
-
Mobile
+關(guān)注
關(guān)注
0文章
518瀏覽量
27061 -
多媒體
+關(guān)注
關(guān)注
0文章
516瀏覽量
38414 -
遙控器
+關(guān)注
關(guān)注
18文章
871瀏覽量
71137 -
無人機(jī)
+關(guān)注
關(guān)注
234文章
11139瀏覽量
193342 -
SDK
+關(guān)注
關(guān)注
3文章
1093瀏覽量
51201
原文標(biāo)題:基于Mobile SDK V5版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(5)
文章出處:【微信號:美男子玩編程,微信公眾號:美男子玩編程】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
拆解大疆Mavic Air2無人機(jī)配套遙控器
【云智易申請】智能無人機(jī)通信
COCOFLY 教程 ——瘋殼無人機(jī)·系列·快速上手【5】遙控器固件燒寫
COCOFLY 教程 ——瘋殼無人機(jī)·系列【5】遙控器固件燒寫
【快速上手教程6】瘋殼·開源編隊無人機(jī)-遙控器固件燒寫
【快速上手教程6】瘋殼·開源編隊無人機(jī)-遙控器固件燒寫
【瘋殼·無人機(jī)教程6】開源編隊無人機(jī)-遙控器固件燒寫
CES 2019:大疆推出帶屏無人機(jī)遙控器 便攜式無線電源Yoolox亮相
音圈馬達(dá)裝置在大疆無人機(jī)的應(yīng)用
基于Mobile SDK V4版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(1)
基于Mobile SDK V4版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(3)
基于Mobile SDK V5版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(4)

基于Mobile SDK V5版固件開發(fā)大疆無人機(jī)手機(jī)端遙控器(5)
評論