package com.aros.apron.manager; import static android.os.Environment.getExternalStoragePublicDirectory; import static com.aros.apron.manager.FlightManager.FLAG_STOP_ARUCO; import static com.aros.apron.tools.Utils.getIDJIErrorMsg; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.aros.apron.base.BaseManager; import com.aros.apron.entity.FlightMission; import com.aros.apron.entity.MessageDown; import com.aros.apron.entity.MissionPoint; import com.aros.apron.entity.Movement; import com.aros.apron.tools.DomParserKML; import com.aros.apron.tools.DomParserWPML; import com.aros.apron.tools.LogUtil; import com.aros.apron.tools.PreferenceUtils; import com.aros.apron.tools.ZipUtil; import com.google.gson.Gson; import org.greenrobot.eventbus.EventBus; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import dji.sdk.keyvalue.key.FlightControllerKey; import dji.sdk.keyvalue.key.KeyTools; import dji.sdk.keyvalue.value.common.EmptyMsg; import dji.sdk.keyvalue.value.flightcontroller.FlightCoordinateSystem; import dji.sdk.keyvalue.value.flightcontroller.FlightMode; import dji.sdk.keyvalue.value.flightcontroller.RemoteControllerFlightMode; import dji.sdk.keyvalue.value.flightcontroller.RollPitchControlMode; import dji.sdk.keyvalue.value.flightcontroller.VerticalControlMode; import dji.sdk.keyvalue.value.flightcontroller.VirtualStickFlightControlParam; import dji.sdk.keyvalue.value.flightcontroller.YawControlMode; import dji.v5.common.callback.CommonCallbacks; import dji.v5.common.error.IDJIError; import dji.v5.manager.KeyManager; import dji.v5.manager.aircraft.virtualstick.VirtualStickManager; import dji.v5.manager.aircraft.waypoint3.WaypointMissionManager; import dji.v5.manager.interfaces.IWaypointMissionManager; /** * 备降点 */ public class AlternateLandingManager extends BaseManager { Handler handler = new Handler(Looper.getMainLooper()); VirtualStickFlightControlParam param; private boolean isRemoteControllerFlightModeChange; private AlternateLandingManager() { } public static AlternateLandingManager getInstance() { return AlternateLandingHolder.INSTANCE; } public void initAlterLandingInfo() { KeyManager.getInstance().listen(KeyTools.createKey(FlightControllerKey.KeyRemoteControllerFlightMode), this, new CommonCallbacks.KeyListener() { @Override public void onValueChange(@Nullable RemoteControllerFlightMode remoteControllerFlightMode, @Nullable RemoteControllerFlightMode t1) { if (t1 != null) { LogUtil.log(TAG, "监听到挡位切换:" + t1.name()); if (t1 != RemoteControllerFlightMode.P && t1 != RemoteControllerFlightMode.F) { isRemoteControllerFlightModeChange = true; PreferenceUtils.getInstance().setNeedTriggerAlterArucoLand(false); PreferenceUtils.getInstance().setNeedTriggerApronArucoLand(false); PreferenceUtils.getInstance().setTriggerToAlternatePoint(false); } } } }); } public void startTaskProcess(MessageDown message) { //飞往备降点,关闭视觉识别 EventBus.getDefault().post(FLAG_STOP_ARUCO); if (isRemoteControllerFlightModeChange) { LogUtil.log(TAG, "挡位切换过:不触发去备降点"); return; } Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey. KeyConnection)); if (isConnect != null && isConnect) { Boolean areMotorOn = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyAreMotorsOn)); Boolean isFlying = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyIsFlying)); if ((areMotorOn != null && areMotorOn) && (isFlying != null && isFlying)) { RemoteControllerFlightMode remoteControllerFlightMode = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyRemoteControllerFlightMode)); if (remoteControllerFlightMode != null && remoteControllerFlightMode == RemoteControllerFlightMode.P) { checkDroneState(message); } else { if (message != null) { sendEvent2Server("挡位不正确,不触发去备降点",2); } } } else { if (message != null) { sendEvent2Server( "飞机未起飞,不触发去备降点",2); } } } } private void checkDroneState(MessageDown message) { FlightMode flightMode = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyFlightMode)); if (flightMode != null) { switch (flightMode) { case GO_HOME: KeyManager.getInstance().performAction(KeyTools.createKey(FlightControllerKey.KeyStopGoHome), new CommonCallbacks.CompletionCallbackWithParam() { @Override public void onSuccess(EmptyMsg emptyMsg) { toAlternatePoint(); sendEvent2Server( "取消返航:去备降点",1); } @Override public void onFailure(@NonNull IDJIError error) { LogUtil.log(TAG, "取消返航失败:" + new Gson().toJson(error)); toAlternatePoint(); sendEvent2Server( "取消返航失败:" + new Gson().toJson(error),2); } }); break; case WAYPOINT: IWaypointMissionManager missionManager = WaypointMissionManager.getInstance(); missionManager.stopMission(TextUtils.isEmpty(Movement.getInstance().getMissionName()) ? "aros" : Movement.getInstance().getMissionName(), new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { LogUtil.log(TAG, "终止任务成功"); sendEvent2Server( "终止任务成功:去备降点",1); toAlternatePoint(); } @Override public void onFailure(@NonNull IDJIError error) { LogUtil.log(TAG, "终止任务失败:" + new Gson().toJson(error)); sendEvent2Server( "终止任务失败:去备降点",2); toAlternatePoint(); } }); break; case AUTO_LANDING: KeyManager.getInstance().performAction(KeyTools.createKey(FlightControllerKey.KeyStopAutoLanding), new CommonCallbacks.CompletionCallbackWithParam() { @Override public void onSuccess(EmptyMsg emptyMsg) { sendEvent2Server( "取消降落成功:去备降点",1); toAlternatePoint(); } @Override public void onFailure(@NonNull IDJIError error) { sendEvent2Server( "取消降落失败:去备降点",2); toAlternatePoint(); } }); break; case VIRTUAL_STICK: // VirtualStickManager.getInstance().disableVirtualStick(new CommonCallbacks.CompletionCallback() { // @Override // public void onSuccess() { // LogUtil.log(TAG, "控制权取消成功"); toAlternatePoint(); // } // @Override // public void onFailure(@NonNull IDJIError error) { // LogUtil.log(TAG, "控制权取消失败:" + new Gson().toJson(error)); // toAlternatePoint(); // } // }); break; default: toAlternatePoint(); break; } } } public void toAlternatePoint() { if (Movement.getInstance().getElevation() < 10) { sendEvent2Server( "正在拉高去备降点",1); raisesDrone(); } else { sendEvent2Server( "开始创建备降任务",1); creatMissionAndUpload(); } } public void raisesDrone() { Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyConnection)); if (isConnect != null && isConnect) { Boolean isVirtualStickControlModeEnabled = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyVirtualStickControlModeEnabled)); if (isVirtualStickControlModeEnabled != null && isVirtualStickControlModeEnabled) { pullUp(); } else { VirtualStickManager.getInstance().enableVirtualStick(new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { LogUtil.log(TAG, "备降拉高,控制权获取成功"); VirtualStickManager.getInstance().setVirtualStickAdvancedModeEnabled(true); pullUp(); } @Override public void onFailure(@NonNull IDJIError error) { LogUtil.log(TAG, "备降拉高,控制权获取失败,直接上传备降航线:" + error.description()); creatMissionAndUpload(); } }); } } else { LogUtil.log(TAG, "备降拉高,飞控未连接"); } } public void pullUp() { Runnable runnable = new Runnable() { @Override public void run() { if (Movement.getInstance().getElevation() < 10) { sendVirtualStickAdvancedParam(); handler.postDelayed(this, 200); } else { VirtualStickManager.getInstance().disableVirtualStick(new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { LogUtil.log(TAG, "到达10米,开始上传备降点航线"); creatMissionAndUpload(); } @Override public void onFailure(@NonNull IDJIError idjiError) { LogUtil.log(TAG, "到达10米,取消虚拟摇杆控制失败:" + new Gson().toJson(idjiError)); creatMissionAndUpload(); } }); handler.removeCallbacks(this); } } }; // 开始循环 handler.post(runnable); } //飞行器虚拟摇杆 public void sendVirtualStickAdvancedParam() { Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyConnection)); if (isConnect != null && isConnect) { if (param == null) { param = new VirtualStickFlightControlParam(); param.setRollPitchControlMode(RollPitchControlMode.VELOCITY); param.setYawControlMode(YawControlMode.ANGULAR_VELOCITY); param.setVerticalControlMode(VerticalControlMode.VELOCITY); param.setRollPitchCoordinateSystem(FlightCoordinateSystem.BODY); } param.setPitch(0.0);//左右 param.setRoll(0.0);//前后 param.setYaw(0.0);//旋转 param.setVerticalThrottle(4.0);//上下 VirtualStickManager.getInstance().sendVirtualStickAdvancedParam(param); } } public void creatMissionAndUpload() { // 创建第一个 MissionPoint 对象 MissionPoint missionPoint = new MissionPoint(); missionPoint.setLat(String.valueOf(Movement.getInstance().getLatitude())); missionPoint.setLng(String.valueOf(Movement.getInstance().getLongitude())); missionPoint.setSpeed(8.0); missionPoint.setExecuteHeight(Movement.getInstance().getElevation() > Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()) ? Movement.getInstance().getElevation() : Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight())); // 创建第二个 MissionPoint 对象 MissionPoint missionPoint1 = new MissionPoint(); missionPoint1.setLat(PreferenceUtils.getInstance().getAlternatePointLat()); missionPoint1.setLng(PreferenceUtils.getInstance().getAlternatePointLon()); LogUtil.log(TAG, "备降点经纬度:" + PreferenceUtils.getInstance().getAlternatePointLat() + "/" + PreferenceUtils.getInstance().getAlternatePointLon()); missionPoint1.setSpeed(7.0); missionPoint1.setExecuteHeight(Movement.getInstance().getElevation() > Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()) ? Movement.getInstance().getElevation() - 1 : Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight())); // 创建一个 MissionPoint 列表 List missionPoints = new ArrayList<>(); missionPoints.add(missionPoint); missionPoints.add(missionPoint1); // 创建 FlightMission 对象并设置其属性 FlightMission flightMission = new FlightMission(); flightMission.setPoints(missionPoints); flightMission.setMissionId(2); flightMission.setFinishAction("autoLand"); flightMission.setTakeOffSecurityHeight(Float.parseFloat(PreferenceUtils.getInstance().getAlternatePointSecurityHeight())); flightMission.setSpeed(15.0); LogUtil.log(TAG, "当前高度:" + Movement.getInstance().getElevation() + "---飞往备降点高度:" + Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()) + "---航线安全起飞高度:" + Float.parseFloat(PreferenceUtils.getInstance().getAlternatePointSecurityHeight())); sendEvent2Server( "开始生成备降点航线",1); // 生成xml文件 File file1 = new File( getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "wpmz"); if (!file1.exists()) { if (file1.mkdirs()) { LogUtil.log(TAG, "生成备降航线成功"); sendEvent2Server( "生成备降路线文件成功",1); } else { LogUtil.log(TAG, "生成备降航线失败"); sendEvent2Server( "生成备降航线失败",2); sendEvent2Server( "生成备降航线失败",2); } } DomParserKML domParserKML = new DomParserKML(getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "wpmz", "/template.kml"); domParserKML.createKml(flightMission); DomParserWPML domParserWPML = new DomParserWPML(getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "wpmz", "/waylines.wpml"); domParserWPML.createWpml(flightMission); File kmzFile = new File(getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + File.separator + "alternate.kmz"); kmzFile.getParentFile().mkdirs(); try { ZipUtil.zip(getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + "/wpmz", getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "alternate.kmz"); } catch (IOException e) { sendEvent2Server( "备降任务生成异常",2); throw new RuntimeException(e); } IWaypointMissionManager missionManager = WaypointMissionManager.getInstance(); missionManager.pushKMZFileToAircraft(getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "alternate.kmz", new CommonCallbacks.CompletionCallbackWithProgress() { @Override public void onProgressUpdate(Double aDouble) { LogUtil.log(TAG, "备降点航线上传进度:" + aDouble + "%"); sendEvent2Server( "备降任务上传中:" + aDouble + "%",1); } @Override public void onSuccess() { sendEvent2Server( "备降点航线上传成功",1); if (PreferenceUtils.getInstance().getHaveRTK() && !(Movement.getInstance().getIs_fixed()==2)) { RTKManager.getInstance().enableRtk(false); } new Handler().postDelayed(new Runnable() { @Override public void run() { missionManager.startMission("alternate", new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { PreferenceUtils.getInstance().setTriggerToAlternatePoint(true); PreferenceUtils.getInstance().setNeedTriggerAlterArucoLand(false); PreferenceUtils.getInstance().setNeedTriggerApronArucoLand(false); sendEvent2Server( "开始飞往备降点",1); //设置为未开始识别二维码状态 FlightManager.getInstance().setSendDetect(false); EventBus.getDefault().post(FLAG_STOP_ARUCO); } @Override public void onFailure(@NonNull IDJIError idjiError) { PreferenceUtils.getInstance().setTriggerToAlternatePoint(false); LogUtil.log(TAG, "飞往备降点失败:" + new Gson().toJson(idjiError)); sendEvent2Server( "飞往备降点失败",2); } }); } }, 1000); } @Override public void onFailure(@NonNull IDJIError error) { PreferenceUtils.getInstance().setTriggerToAlternatePoint(false); sendEvent2Server( "备降航线上传失败",2); } }); } private static class AlternateLandingHolder { private static final AlternateLandingManager INSTANCE = new AlternateLandingManager(); } }