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

    文章

    515

    浏览量

    26340
  • 多媒体
    +关注

    关注

    0

    文章

    482

    浏览量

    36677
  • 遥控器
    +关注

    关注

    18

    文章

    815

    浏览量

    64244
  • 无人机
    +关注

    关注

    224

    文章

    9884

    浏览量

    174812
  • SDK
    SDK
    +关注

    关注

    3

    文章

    966

    浏览量

    44696

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

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

收藏 人收藏

    评论

    相关推荐

    【Aworks申请】开放式无人机地面基站

    申请理由:我们是在校大学生EDA兴趣团队,正在设计制作无人机项目。我们发现,现在无人机只能通过遥控器或者电脑上位机控制飞行。所以,我们试图开发一个通用式地面基站,开放API和视频数据流
    发表于 06-27 08:59

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

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

    【MiCOKit申请】开放式无人机地面基站

    申请理由:我们是在校大学生EDA兴趣团队,正在设计制作无人机项目。我们发现,现在无人机只能通过遥控器或者电脑上位机控制飞行。所以,我们试图开发一个通用式地面基站,开放API和视频数据流
    发表于 08-10 13:04

    无人机遥控方向控制问题

    前段时间我弟弟买了个遥控无人机玩具,但是我发现一个问题。该无人机方向控制有问题,假设无人机有四个电机,分别为A,B,C,D,遥控器四个按键1
    发表于 05-10 11:26

    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

    DJI大创新推出首款农业无人机

    全球飞行影像系统的开拓者和领导者DJI大创新今日宣布推出一款智能农业喷洒防治无人机——大MG-1农业植保机,标志着大创新正式进入农业无人机
    发表于 05-12 07:22

    怎么实现STM32采集无人机遥控器PPM信号?

    怎么实现STM32采集无人机遥控器PPM信号?
    发表于 11-18 06:10

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

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

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

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

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

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

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

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

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

    出现bug,大疆的开发人员也在不断的完善这整个V5开发包,已提供更全更优的开发模式。下面是使用V5开发
    的头像 发表于 06-25 12:24 1343次阅读
    基于<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>(4)