0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于Mobile SDK V5版固件开发大疆无人机手机端遥控器(5)

jf_Vqngj70R 来源:美男子玩编程 2023-07-07 12:21 次阅读

v5.x版本的功能与v4.x基本相同,都是获取飞机的姿态信息、获取无人机多媒体文件、操作多媒体文件、航线规划等。不过在上一章节中也大致说了一些两个版本的中API的差别,下面是根据一些API使用所完成的一些功能,因为项目原因只能提供部分代码供参考,后续如果有这方面需求的小伙伴可以对其进行开发指导。

1获取姿态信息

1、KeyManager调用

KeyManager类提供了一组方法来访问硬件模块的参数和控制硬件模块的行为,包括DJIKey的Value设置,Value获取,Value监听和Action执行。通过KeyTools类提供的createKey方法可以更加方便的创建DJIKey实例。

下图展示了使用KeyManager的接口判断飞控正常连接并且GPS信号等级大于等于2级,然后给飞行器设置返航点,最后执行返航操作的调用流程。

a9b693fc-1c7b-11ee-962d-dac502259ad0.png

此处是示例的操作方式,后面有在项目中使用的过程。

2、示例

//获取飞机信息、云台信息
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()方法为获取飞机经纬度信息。

getAttitude()方法获取飞机的姿态信息(分别是航偏角、旋转角、俯仰角)。

getVelocity()方法获取飞机的飞行速度(分别是X、Y、Z三个方向的速度值)。

getIsFly()方法获取当前飞机的状态值(是否正在飞行)。

getGimbalAttitude()方法获取镜头的姿态信息(分别是航偏角、旋转角、俯仰角)。

getPower()获取飞机的电池电量

getTemperature()获取飞机的电池温度

onValueChange()方法为1秒执行10次,这个可以根据后续要求进行获取;

2多媒体使用

1、Sample介绍

拍照、录像是无人机的重要功能,对拍摄的照片、视频等多媒体文件进行管理也就必不可少。多媒体文件的管理包括访问飞机存储空间内的多媒体文件资源、获取多媒体文件列表与列表状态、视频文件播放等。

下图为完整的接口展示以及接口调用流程示例。

多媒体文件管理调用流程

a9ebb1a4-1c7b-11ee-962d-dac502259ad0.png

视频文件播放调用流程

aa27d6b6-1c7b-11ee-962d-dac502259ad0.png

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< List.size(); i++) {
                                    mediaFileList.add(List.get(i));
                                }
                                break;
                            case 1:
                                for (int i = 0; i < List.size(); i++) {
                                    if (List.get(i).getFileType()== MediaFileType.JPEG) {
                                        mediaFileList.add(List.get(i));
                                        MyLog.d("图片名称:"+List.get(i).getFileName());
                                    }
                                }
                                break;
                            case 2:
                                for (int i = 0; i < List.size(); i++) {
                                    if ((List.get(i).getFileType() == MediaFileType.MOV) || (List.get(i).getFileType() == MediaFileType.MP4)) {
                                        mediaFileList.add(List.get(i));
                                        MyLog.d("视频名称:"+List.get(i).getFileName());
                                    }
                                }
                                break;
                        }
                        if (mediaFileList != null) {
                            Collections.sort(mediaFileList, (lhs, rhs) ->{
if(getDate(lhs.getDate())< getDate(rhs.getDate())) {
                                    return 1;
                                } else 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 < mediaFileList.size(); i++) {
            getThumbnailByIndex(i);
        }
    }

    private void getThumbnailByIndex(final int index) {
        mediaFileList.get(index).pullThumbnailFromCamera(new CommonCallbacks.CompletionCallbackWithParam(){
@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()方法获取所有媒体文件,文件包括视频及照片,可以对照片视频进行分类处理了

getThumbnails()方法获取缩略图信息,用于在界面展示缩略图

deleteFileByIndex()方法为删除到媒体文件(可以进行单个删除或者多个删除)

downloadFileByIndex()方法为多媒体文件下载

playVideo()方法为多媒体文件视频播放

3直播的调用

1、Sample介绍

直播功能是Mobile SDK重要的功能,可支持声网、RTMP、RTSP、GB28181 四种直播模式。在安防,公共安全,巡检等场景都需要有直播模块。

下图为完整的接口展示以及接口调用流程示例。详细的使用方法请查看Mobile SDK API 文档中的直播管理类 ILiveStreamManager。直播管理类用于直播的参数设置和直播的开启和停止等功能。

aa554a6a-1c7b-11ee-962d-dac502259ad0.png

2、示例

项目中使用到了其中的一种方式 ,使用RTMP方式进行推流直播。代码如下:

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直播参数:"+MediaDataCenter.getInstance().getLiveStreamManager().getLiveStreamSettings());
Log.i("LiveStreamManager","LiveStreamManager视频质量:"+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("是否结束推流?");
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("结束推流");
}

@Override
publicvoidonFailure(@NonNullIDJIErrorerror){

}
});
}
});
Builder.setNegativeButton("取消",null);
Builder.show();
}

startLiveShow()方法为开启直播,并设置一些直播参数

stopLiveShow()方法为停止直播,进行缓存回收

4航线规划

1、Sample介绍

航线任务管理是用于无人机自主作业的重要功能,通过MSDK提供的接口可以实现对航线任务的上传、执行、暂停、恢复以及对航线任务执行状态与航线信息的监听等。

我们将航点任务定义在航线文件中,该文件遵循 DJI 自定义的航线文件格式标准(WPML)。航线文件实际为“.kmz”结尾的压缩文件,文件结构如下:

waypoints_name.kmz
└──wpmz
├──res
├──template.kml
└──waylines.wpml

其中,template.kml文件为“模板文件”,waylines.wpml文件为“执行文件”,res为资源文件。详细的介绍请阅读航线文件格式标准。航线文件格式标准的文档中有对template.kml文件与waylines.wpml文件的编写说明。

2、接口调用流程

MSDK提供的航线功能相关接口较为简单,调用方式如下图。详细的使用方法请查看Mobile SDK API文档中的航线任务管理类 IWaypointMissionManager。图中虚线框内容为可选接口。aa845094-1c7b-11ee-962d-dac502259ad0.png

5总结

以上内容为v5.x版本中使用到的一些内容,当然还有一些API没有在项目中使用到,后续给大家也更新到整个专栏内容中,希望喜欢的小伙伴可以进行订阅,如果后续有共同开发的同道中人可以联系我帮你解决一些问题。现阶段v5.x还在持续更新中,为了适配更多的飞机它的一些功能也是在不断的完善。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Mobile
    +关注

    关注

    0

    文章

    518

    浏览量

    26506
  • 多媒体
    +关注

    关注

    0

    文章

    499

    浏览量

    36994
  • 遥控器
    +关注

    关注

    18

    文章

    837

    浏览量

    66155
  • 无人机
    +关注

    关注

    230

    文章

    10439

    浏览量

    180530
  • SDK
    SDK
    +关注

    关注

    3

    文章

    1037

    浏览量

    45964

原文标题:基于Mobile SDK V5版固件开发大疆无人机手机端遥控器(5)

文章出处:【微信号:美男子玩编程,微信公众号:美男子玩编程】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    拆解大Mavic Air2无人机配套遥控器

    Mavic Air2遥控器内部多使用螺丝或卡扣固定部件,伸缩式天线一体化手机支架将原来位于遥控器下方的手机移到了手机上方,方便观察
    的头像 发表于 07-21 13:37 2.8w次阅读
    拆解大<b class='flag-5'>疆</b>Mavic Air2<b class='flag-5'>无人机</b>配套<b class='flag-5'>遥控器</b>

    【云智易申请】智能无人机通信

    申请理由:本次项目是基于STM32做无人机,主要用WiFi实现无人机遥控器之间通信,无人机的电机我们可以用云智易开发板上面的电机进行调试,
    发表于 08-07 11:02

    stm32四轴无人机遥控器资料

    stm32四轴无人机遥控器资料
    发表于 06-09 23:16

    无人机怎么悬停

    `  谁能阐述下大无人机怎么悬停?`
    发表于 08-27 15:13

    COCOFLY 教程 ——疯壳无人机·系列·快速上手【5遥控器固件烧写

    文件。如下图所示为遥控器代码编译出来的Hex文件。只要把这个固件烧写进遥控器的主核心STM32F103C8T6的Flash内,遥控器的代码就可以运行。这里已经把编译好
    发表于 03-26 13:55

    COCOFLY 教程 ——疯壳无人机·系列【5遥控器固件烧写

    遥控器的主核心STM32F103C8T6的Flash内,遥控器的代码就可以运行。这里已经把编译好固件放在了“【5遥控器
    发表于 04-03 18:06

    【快速上手教程6】疯壳·开源编队无人机-遥控器固件烧写

    COCOFLY 教程——疯壳·无人机·系列遥控器固件烧写 图1 一、遥控器固件烧写 这里的固件
    发表于 05-25 11:49

    【快速上手教程6】疯壳·开源编队无人机-遥控器固件烧写

    COCOFLY 教程——疯壳·无人机·系列遥控器固件烧写 图1 一、遥控器固件烧写 这里的固件
    发表于 07-07 10:05

    【疯壳·无人机教程6】开源编队无人机-遥控器固件烧写

    COCOFLY 教程——疯壳·无人机·系列遥控器固件烧写图1 一、遥控器固件烧写 这里的固件
    发表于 08-23 17:49

    CES 2019:大推出带屏无人机遥控器 便携式无线电源Yoolox亮相

    现如今航拍已成为年轻人的拍摄兴趣,但智能手机好像并不是最理想控制航拍的遥控器。作为无人机生产厂家,大在今年的国际消费类电子产品展览会上展出了专为Mavic 2航拍
    的头像 发表于 01-10 16:16 8044次阅读

    音圈马达装置在大无人机的应用

    音圈马达助力的大将发布多款新品,大家都知道大是一家专业生产无人机的厂家,就在近日,大新公布的一份专利文件中,发现大已经申请了一款新的
    发表于 08-31 15:55 735次阅读

    基于Mobile SDK V4版固件开发无人机手机遥控器(1)

    刚刚结束了项目交付,趁热打铁分享一下这次遇到的新东西。首先了解一下大无人机,它大致可以分为三级。
    的头像 发表于 06-07 09:53 1172次阅读
    基于<b class='flag-5'>Mobile</b> <b class='flag-5'>SDK</b> <b class='flag-5'>V</b>4版<b class='flag-5'>固件</b><b class='flag-5'>开发</b>大<b class='flag-5'>疆</b><b class='flag-5'>无人机手机</b><b class='flag-5'>端</b><b class='flag-5'>遥控器</b>(1)

    基于Mobile SDK V4版固件开发无人机手机遥控器(2)

    上一篇文章(基于Mobile SDK V4版固件开发无人
    的头像 发表于 06-09 11:33 1016次阅读
    基于<b class='flag-5'>Mobile</b> <b class='flag-5'>SDK</b> <b class='flag-5'>V</b>4版<b class='flag-5'>固件</b><b class='flag-5'>开发</b>大<b class='flag-5'>疆</b><b class='flag-5'>无人机手机</b><b class='flag-5'>端</b><b class='flag-5'>遥控器</b>(2)

    基于Mobile SDK V4版固件开发无人机手机遥控器(3)

    第三篇文章准备单独拿出来写,因为在大人机的所有功能中,航线规划的功能最为复杂,也相当的繁琐,这里需要说仔细一点,可能会将代码进行多步分解。
    的头像 发表于 06-15 12:22 1557次阅读
    基于<b class='flag-5'>Mobile</b> <b class='flag-5'>SDK</b> <b class='flag-5'>V</b>4版<b class='flag-5'>固件</b><b class='flag-5'>开发</b>大<b class='flag-5'>疆</b><b class='flag-5'>无人机手机</b><b class='flag-5'>端</b><b class='flag-5'>遥控器</b>(3)

    基于Mobile SDK V5固件开发无人机手机遥控器(4)

    出现bug,大开发人员也在不断的完善这整个V5开发包,已提供更全更优的开发模式。下面是使用V5
    的头像 发表于 06-25 12:24 2605次阅读
    基于<b class='flag-5'>Mobile</b> <b class='flag-5'>SDK</b> <b class='flag-5'>V5</b>版<b class='flag-5'>固件</b><b class='flag-5'>开发</b>大<b class='flag-5'>疆</b><b class='flag-5'>无人机手机</b><b class='flag-5'>端</b><b class='flag-5'>遥控器</b>(4)