flyto适配

This commit is contained in:
cxf 2026-06-06 20:09:36 +08:00
parent cb22c7e73b
commit 32698dd1cc
38 changed files with 4210 additions and 467 deletions

View File

@ -7,10 +7,12 @@ import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.view.Window
import android.view.WindowManager
import android.widget.Button
import android.widget.Toast
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
@ -49,6 +51,7 @@ import com.aros.apron.mix.Aprongim
import com.aros.apron.tools.AlternateArucoDetect
import com.aros.apron.tools.ApronArucoDetect
import com.aros.apron.tools.ApronArucoDetectPort
import com.aros.apron.tools.ApronArucodownmany
import com.aros.apron.tools.DroneHelper
import com.aros.apron.tools.LogUtil
import com.aros.apron.tools.MqttManager
@ -128,6 +131,8 @@ open class MainActivity : BaseActivity() {
// 如果不需要改变 isAppStarted 的值,可以直接这样声明
var isAppStarted: Boolean = false
var streamReceive: Boolean = false
var isscousse: Boolean=false;
private var instance: MainActivity? = null
fun getInstance(): MainActivity? {
@ -136,6 +141,9 @@ open class MainActivity : BaseActivity() {
private var vtxHeartbeatHandler: Handler? = null
private var lastVtxFrameTime: Long = 0
private var lastPortToastTime: Long = 0
private var lastFpvToastTime: Long = 0
private const val TOAST_INTERVAL_MS = 3000L
private const val VTX_HEARTBEAT_TIMEOUT = 2000L // 3秒没有收到帧就认为图传异常
private var isVtxHeartbeatRunning = false
@ -242,7 +250,7 @@ open class MainActivity : BaseActivity() {
private var cameraManager: ICameraStreamManager =
MediaDataCenter.getInstance().cameraStreamManager
private var startArucoType = 0 //1执行机库二维码识别 2执行备降点二维码识别 3扫到任何码触发刹停
private var startArucoType = 0 //1执行机库二维码识别 2执行备降点二维码识别 3扫到任何码触发刹停
private var dictionary: Dictionary? = null
override fun useEventBus(): Boolean {
return true
@ -282,7 +290,12 @@ open class MainActivity : BaseActivity() {
.throttleLast(500, TimeUnit.MILLISECONDS)
.subscribeOn(io())
.subscribe(Consumer { result: CameraSource ->
runOnUiThread { onCameraSourceUpdated(result.devicePosition, result.lensType) }
runOnUiThread {
onCameraSourceUpdated(
result.devicePosition,
result.lensType
)
}
})
)
compositeDisposable!!.add(
@ -513,7 +526,7 @@ open class MainActivity : BaseActivity() {
primaryFpvWidget?.post {
refreshVideoStream()
}
//LogUtil.log(TAG, "智能刷新:无云台,直接刷新主视频流")
//LogUtil.log(TAG, "智能刷新:无云台,直接刷新主视频流")
}
}
@ -740,13 +753,14 @@ open class MainActivity : BaseActivity() {
// 根据 cameraLocationType 轮询等待连接
while (true) {
val flightConnected = isFlightControllerConnect != null && isFlightControllerConnect == true
val flightConnected =
isFlightControllerConnect != null && isFlightControllerConnect == true
val cameraConnected = isCameraConnect != null && isCameraConnect == true
val shouldInit = when (cameraLocationType) {
3 -> flightConnected
4, 5 -> flightConnected || cameraConnected
else -> flightConnected || cameraConnected
1, 2, 4, 5 -> flightConnected && cameraConnected
else -> flightConnected && cameraConnected
}
if (shouldInit) break
@ -762,7 +776,12 @@ open class MainActivity : BaseActivity() {
KeyManager.getInstance().getValue(DJIKey.create(FlightControllerKey.KeyConnection))
isCameraConnect =
KeyManager.getInstance()
.getValue(KeyTools.createKey(CameraKey.KeyConnection, ComponentIndexType.PORT_1))
.getValue(
KeyTools.createKey(
CameraKey.KeyConnection,
ComponentIndexType.PORT_1
)
)
}
// 飞控/相机连接后,在主线程执行初始化
@ -804,16 +823,18 @@ open class MainActivity : BaseActivity() {
GimbalManager.getInstance().setmode()
PayloadWidgetManager.getInstance().initPayloadInfo()
if (PreferenceUtils.getInstance().lteEnable){
if (PreferenceUtils.getInstance().lteEnable) {
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
MLTEManager.getInstance().initLTEManager()
Handler().postDelayed(Runnable { MLTEManager.getInstance().setLTEEnhancedTransmissionType()},3000)
Handler().postDelayed(Runnable {
MLTEManager.getInstance().setLTEEnhancedTransmissionType()
}, 3000)
}
LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
LogUtil.log("qwq", "lteEnable" + PreferenceUtils.getInstance().lteEnable)
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
@ -848,10 +869,12 @@ open class MainActivity : BaseActivity() {
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
if (PreferenceUtils.getInstance().lteEnable){
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
if (PreferenceUtils.getInstance().lteEnable) {
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
MLTEManager.getInstance().initLTEManager()
Handler().postDelayed(Runnable { MLTEManager.getInstance().setLTEEnhancedTransmissionType()},3000)
Handler().postDelayed(Runnable {
MLTEManager.getInstance().setLTEEnhancedTransmissionType()
}, 3000)
}
@ -914,12 +937,14 @@ open class MainActivity : BaseActivity() {
PayloadWidgetManager.getInstance().initPayloadInfo()
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
if (PreferenceUtils.getInstance().lteEnable){
if (PreferenceUtils.getInstance().lteEnable) {
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
MLTEManager.getInstance().initLTEManager()
Handler().postDelayed(Runnable { MLTEManager.getInstance().setLTEEnhancedTransmissionType()},3000)
Handler().postDelayed(Runnable {
MLTEManager.getInstance().setLTEEnhancedTransmissionType()
}, 3000)
}
@ -947,17 +972,24 @@ open class MainActivity : BaseActivity() {
private fun initMixedStream() {
// 初始化融合视觉降落识别器
//val mixedLanding = MixedVisionLanding.getInstance()
// 为 PORT_1云台相机添加帧监听器
cameraManager.addFrameListener(
ComponentIndexType.PORT_1,
ICameraStreamManager.FrameFormat.YUV420_888
) { frameData, _, _, width, height, _ ->
// LogUtil.log(TAG,"port监听回调了addFrameListener")
// runOnUiThread {
// val now = System.currentTimeMillis()
// if (now - lastPortToastTime >= TOAST_INTERVAL_MS) {
// lastPortToastTime = now
// Toast.makeText(this, "port监听回调了addFrameListener", Toast.LENGTH_SHORT).show()
// }
// }
Movement.getInstance().isVtx = true
updateVtxHeartbeat()
streamReceive = true
// 使用融合视觉识别器处理云台相机帧
//mixedLanding.processGimbalFrame(height, width, frameData, dictionary)
//使用云台
@ -965,6 +997,12 @@ open class MainActivity : BaseActivity() {
if (!Synchronizedstatus.isIsruningframe() && Synchronizedstatus.isAprongim() && Synchronizedstatus.isSwitchtime()) {
try {
Synchronizedstatus.setIsruningframe(true)
if(!isscousse){
isscousse=true;
LogUtil.log(TAG,"mix视频帧回调了")
}
if (startArucoType == 1) {
Aprongim.getInstance()?.detectArucoTags(
height,
@ -990,10 +1028,8 @@ open class MainActivity : BaseActivity() {
} finally {
Synchronizedstatus.setIsruningframe(false)
}
}
}
}
// 为 FPV下视相机添加帧监听器
@ -1001,6 +1037,15 @@ open class MainActivity : BaseActivity() {
ComponentIndexType.FPV,
ICameraStreamManager.FrameFormat.YUV420_888
) { frameData, _, _, width, height, _ ->
//LogUtil.log(TAG,"fpv监听回调了addFrameListener")
// runOnUiThread {
// val now = System.currentTimeMillis()
// if (now - lastFpvToastTime >= TOAST_INTERVAL_MS) {
// lastFpvToastTime = now
// Toast.makeText(this, "fpv监听回调了addFrameListener", Toast.LENGTH_SHORT).show()
// }
// }
Movement.getInstance().isVtx = true
updateVtxHeartbeat()
streamReceive = true
@ -1011,6 +1056,9 @@ open class MainActivity : BaseActivity() {
if (!Synchronizedstatus.isIsruningframe() && !Synchronizedstatus.isAprongim() && Synchronizedstatus.isSwitchtime()) {
try {
Synchronizedstatus.setIsruningframe(true)
if (startArucoType == 1) {
Aprondown.getInstance()?.detectArucoTags(
height,
@ -1042,7 +1090,6 @@ open class MainActivity : BaseActivity() {
}
}
@SuppressLint("SuspiciousIndentation")
private fun initFpvStream() {
cameraManager.addFrameListener(
@ -1059,6 +1106,12 @@ open class MainActivity : BaseActivity() {
if (!Synchronizedstatus.isIsruningframe()) {
try {
Synchronizedstatus.setIsruningframe(true)
if(!isscousse){
isscousse=true;
LogUtil.log(TAG,"port视频帧回调了")
}
if (startArucoType == 1) {
ApronArucoDetect.getInstance()?.detectArucoTags(
height,
@ -1091,8 +1144,6 @@ open class MainActivity : BaseActivity() {
}
@SuppressLint("SuspiciousIndentation")
private fun initCameraStream() {
cameraManager.addFrameListener(
@ -1109,6 +1160,12 @@ open class MainActivity : BaseActivity() {
if (!Synchronizedstatus.isIsruningframe()) {
try {
Synchronizedstatus.setIsruningframe(true)
if(!isscousse){
isscousse=true;
LogUtil.log(TAG,"fpv视频帧回调了")
}
if (startArucoType == 1) {
ApronArucoDetectPort.getInstance()?.detectArucoTags(
height,
@ -1156,7 +1213,6 @@ open class MainActivity : BaseActivity() {
fun onEvent(message: String?) {
when (message) {
FLAG_START_DETECT_ARUCO_APRON -> {
MediaDataCenter.getInstance().getCameraStreamManager().setVisionAssistViewDirection(
VisionAssistDirection.DOWN,
object : CompletionCallback {
@ -1201,8 +1257,8 @@ open class MainActivity : BaseActivity() {
}, 6000)
} else if (PreferenceUtils.getInstance().cameraLocationType == 4 || PreferenceUtils.getInstance().cameraLocationType == 5) {
Handler().postDelayed(Runnable {
if (!Aprondown.getInstance().isTriggerSuccess) {
LogUtil.log(TAG, "图传异常:飞往备降点")
if (!Aprongim.getInstance().isTriggerSuccess) {
LogUtil.log(TAG, "图传异常:飞往备降点"+ Movement.getInstance().isVtx)
//测试图传丢失
AlternateLandingManager.getInstance().startTaskProcess(null)
}
@ -1251,6 +1307,7 @@ open class MainActivity : BaseActivity() {
}
})
}
FLAG_START_DETECT_ARUCO_ALTERNATE ->
KeyManager.getInstance().performAction<EmptyMsg>(
KeyTools.createKey<EmptyMsg, EmptyMsg>(FlightControllerKey.KeyStopAutoLanding),
@ -1268,11 +1325,11 @@ open class MainActivity : BaseActivity() {
} else if (PreferenceUtils.getInstance().cameraLocationType == 4 || PreferenceUtils.getInstance().cameraLocationType == 5) {
Handler().postDelayed(Runnable {
if (!Aprongim.getInstance().isTriggerSuccess) {
LogUtil.log(TAG, "图传异常:飞往备降点")
//测试图传丢失
LogUtil.log(TAG, "备降点图传异常:飞往备降点")
AlternateLandingManager.getInstance().startTaskProcess(null)
}
}, 6000)
} else {
Handler().postDelayed(Runnable {
if (!ApronArucoDetectPort.getInstance().isTriggerSuccess) {

View File

@ -86,26 +86,29 @@ public abstract class BaseManager {
* @param entity
*/
public void sendMsg2Server(MessageDown entity) {
try {
if (MqttManager.getInstance().mqttAndroidClient.isConnected()) {
MessageReply messageReply = new MessageReply();
messageReply.setBid(entity.getBid());
messageReply.setTid(entity.getTid());
messageReply.setTimestamp(entity.getTimestamp());
messageReply.setMethod(entity.getMethod());
MessageReply.Data data=new MessageReply.Data();
data.setResult(0);
messageReply.setData(data);
MqttMessage mqttMessage = new MqttMessage(new Gson().toJson(messageReply).getBytes("UTF-8"));
mqttMessage.setQos(0);
MqttManager.getInstance().mqttAndroidClient.publish(AMSConfig.UP_UAV_SERVICES_REPLY, mqttMessage);
} else {
LogUtil.log(TAG, "回复失败mqtt 未连接");
// 延迟 500ms 发送避开媒体/日志上传等突发流量高峰
mainHandler.postDelayed(() -> {
try {
if (MqttManager.getInstance().mqttAndroidClient.isConnected()) {
MessageReply messageReply = new MessageReply();
messageReply.setBid(entity.getBid());
messageReply.setTid(entity.getTid());
messageReply.setTimestamp(entity.getTimestamp());
messageReply.setMethod(entity.getMethod());
MessageReply.Data data = new MessageReply.Data();
data.setResult(0);
messageReply.setData(data);
MqttMessage mqttMessage = new MqttMessage(new Gson().toJson(messageReply).getBytes("UTF-8"));
mqttMessage.setQos(1);
MqttManager.getInstance().mqttAndroidClient.publish(AMSConfig.UP_UAV_SERVICES_REPLY, mqttMessage);
} else {
LogUtil.log(TAG, "回复失败mqtt 未连接");
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.log(TAG, "回复异常:" + e.toString());
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.log(TAG, "回复异常:" + e.toString());
}
}, 500);
}
final Handler mainHandler = new Handler(Looper.getMainLooper());
@ -355,9 +358,23 @@ public abstract class BaseManager {
breakPoint.setWayline_id(Movement.getInstance().getTask_wayline_id());
ext.setBreak_point(breakPoint);
output.setStatus("partially_done");
//如果飞备降点了
if(Movement.getInstance().isAlternate()){
output.setStatus("failed");
}else{
output.setStatus("partially_done");
}
} else {
output.setStatus("ok");
//如果飞备降点了
if(Movement.getInstance().isAlternate()){
output.setStatus("failed");
}else{
output.setStatus("ok");
}
LogUtil.log(TAG, "未查询到断点信息");
}
@ -391,7 +408,12 @@ public abstract class BaseManager {
public void onFailure(@NonNull IDJIError idjiError) {
// 查询失败也要发status=ok
FlightTaskProgress.Data.Output output = new FlightTaskProgress.Data.Output();
output.setStatus("ok");
//如果飞备降点了
if(Movement.getInstance().isAlternate()){
output.setStatus("failed");
}else{
output.setStatus("ok");
}
output.setExt(ext);
output.setProgress(progress);
@ -406,6 +428,10 @@ public abstract class BaseManager {
flightTaskProgress.setMethod(Constant.FLIGHT_TASK_PROGRESS);
flightTaskProgress.setData(data);
try {
MqttMessage mqttMessage = new MqttMessage(new Gson().toJson(flightTaskProgress).getBytes("UTF-8"));
mqttMessage.setQos(0);
@ -418,6 +444,7 @@ public abstract class BaseManager {
}
});
} else {
// 不是结束状态 立即发
FlightTaskProgress.Data.Output output = new FlightTaskProgress.Data.Output();
@ -460,7 +487,7 @@ public abstract class BaseManager {
if (breakPointInfo != null) {
LogUtil.log(TAG, "查询断点成功:" + new Gson().toJson(breakPointInfo));
Movement.getInstance().setTask_attitude_head(Movement.getInstance().getAttitude_head());
Movement.getInstance().setTask_break_reason(2);
//Movement.getInstance().setTask_break_reason(2);
Movement.getInstance().setTask_index(Movement.getInstance().getTask_current_waypoint_index());
Movement.getInstance().setHeight(breakPointInfo.getLocation().getAltitude());
Movement.getInstance().setTask_latitude(breakPointInfo.getLocation().getLatitude());

View File

@ -1,6 +1,8 @@
package com.aros.apron.callback;
import static dji.sdk.keyvalue.key.KeyTools.createKey;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
@ -191,14 +193,10 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
//存储最新消息并开始自检
MissionV3Manager.getInstance().taskExecute(message);
Synchronizedstatus.setIsruning(true);
Synchronizedstatus.setFlighttaskExecuteStatus(true);
}else{
sendFailMsg2Server(message,"已经收到航线");
}
}
}
break;
@ -223,7 +221,6 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
// }else{
// FlightManager.getInstance().startGoHome(message);
// }
FlightManager.getInstance().startGoHome(message);
} else {
sendFailMsg2Server(message,"正在视觉或飞往备降不允许返航");
@ -255,7 +252,6 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
// //1.检查图传是否连接
// MissionDataBean data = new Gson().fromJson(new Gson().toJson(message.getData()), MissionDataBean.class);
// Boolean generateKmz = Generakmztools.getInstance().generateKmz(data);
synchronized (lock) {
if (Synchronizedstatus.isIsruning()) {
LogUtil.log(TAG, "自检正在运行");
@ -269,7 +265,6 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
});
} else if (Synchronizedstatus.getInitStatus()) {
if(!Synchronizedstatus.isTakeoff_to_point()){
LogUtil.log(TAG, "收到:一键起飞" + jsonString);
//设置modecode
Movement.getInstance().setMode_code(1);
@ -289,7 +284,12 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
break;
case Constant.FLY_TO_POINT:
LogUtil.log(TAG, "收到:飞向目标点" + jsonString);
FlyToPointManager.getInstance().taskExecute(message);
if(!Synchronizedstatus.isFlyto()){
FlyToPointManager.getInstance().taskExecute(message);
Synchronizedstatus.setFlyto(true);
}else{
return;
}
break;
case Constant.FLY_TO_POINT_STOP:
LogUtil.log(TAG, "收到:结束 flyto 飞向目标点任务" + jsonString);
@ -297,6 +297,11 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
break;
case Constant.FLY_TO_POINT_STOP_UPDATE:
LogUtil.log(TAG, "收到:更新 flyto 目标点" + jsonString);
if(KeyManager.getInstance().getValue(createKey(FlightControllerKey.KeyIsFlying))==true){
FlyToPointManager.getInstance().updateTarget(message);
}else{
sendEvent2Server("飞机没起飞不允许指点",2);
}
break;
case Constant.FLIGHT_AUTHORITY_GRAB:
LogUtil.log(TAG, "收到:飞行控制权抢夺" + jsonString);
@ -434,7 +439,6 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
break;
case Constant.IR_METERING_POINT_SET:
LogUtil.log(TAG, "收到:负载控制—红外测温点设置" + jsonString);
CameraManager.getInstance().setThermalSpotMetersurePoint(message);
break;
case Constant.IR_METERING_AREA_SET:
@ -521,7 +525,6 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
return;
}
}
break;
case Constant.SPEAKER_PLAY_MODE_SET:
LogUtil.log(TAG, "收到:喊话器-设置播放模式" + jsonString);
@ -679,6 +682,8 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended {
// //获取控制权
// case 60007:
// LogUtil.log(TAG, "收到:获取控制权" + jsonString);

View File

@ -0,0 +1,162 @@
package com.aros.apron.entity;
import java.util.List;
/**
* 飞向目标点进度上报事件
* Method: fly_to_point_progress
* Topic: thing/product/{gateway_sn}/events (up)
*/
public class FlyToPointProgress {
private String bid;
private String tid;
private Long timestamp;
private String method;
private Integer needReply;
private Data data;
public String getBid() {
return bid;
}
public void setBid(String bid) {
this.bid = bid;
}
public String getTid() {
return tid;
}
public void setTid(String tid) {
this.tid = tid;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Integer getNeedReply() {
return needReply;
}
public void setNeedReply(Integer needReply) {
this.needReply = needReply;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public static class Data {
private String fly_to_id;
private String status; // wayline_cancel | wayline_failed | wayline_ok | wayline_progress
private int result; // 非0代表错误
private int way_point_index;
private Float remaining_distance; //
private Float remaining_time; //
private List<PlannedPathPoint> planned_path_points;
public String getFly_to_id() {
return fly_to_id;
}
public void setFly_to_id(String fly_to_id) {
this.fly_to_id = fly_to_id;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
public int getWay_point_index() {
return way_point_index;
}
public void setWay_point_index(int way_point_index) {
this.way_point_index = way_point_index;
}
public Float getRemaining_distance() {
return remaining_distance;
}
public void setRemaining_distance(Float remaining_distance) {
this.remaining_distance = remaining_distance;
}
public Float getRemaining_time() {
return remaining_time;
}
public void setRemaining_time(Float remaining_time) {
this.remaining_time = remaining_time;
}
public List<PlannedPathPoint> getPlanned_path_points() {
return planned_path_points;
}
public void setPlanned_path_points(List<PlannedPathPoint> planned_path_points) {
this.planned_path_points = planned_path_points;
}
}
public static class PlannedPathPoint {
private double latitude;
private double longitude;
private float height;
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
}
}

View File

@ -0,0 +1,151 @@
package com.aros.apron.entity;
import java.util.List;
public class HMS {
private String bid;
private Data data;
private String tid;
private long timestamp;
private String method;
public String getBid() {
return bid;
}
public void setBid(String bid) {
this.bid = bid;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public String getTid() {
return tid;
}
public void setTid(String tid) {
this.tid = tid;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public static class Data {
private List<ListItem> list;
public List<ListItem> getList() {
return list;
}
public void setList(List<ListItem> list) {
this.list = list;
}
public static class ListItem {
private Args args;
private String code;
private String device_type;
private int imminent;
private int in_the_sky;
private int level;
private int module;
public Args getArgs() {
return args;
}
public void setArgs(Args args) {
this.args = args;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDevice_type() {
return device_type;
}
public void setDevice_type(String device_type) {
this.device_type = device_type;
}
public int getImminent() {
return imminent;
}
public void setImminent(int imminent) {
this.imminent = imminent;
}
public int getIn_the_sky() {
return in_the_sky;
}
public void setIn_the_sky(int in_the_sky) {
this.in_the_sky = in_the_sky;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getModule() {
return module;
}
public void setModule(int module) {
this.module = module;
}
public static class Args {
private int component_index;
private int sensor_index;
public int getComponent_index() {
return component_index;
}
public void setComponent_index(int component_index) {
this.component_index = component_index;
}
public int getSensor_index() {
return sensor_index;
}
public void setSensor_index(int sensor_index) {
this.sensor_index = sensor_index;
}
}
}
}
}

View File

@ -76,13 +76,13 @@ public class MessageDown {
private String seq;
private String w;
//摇杆和云台
private String x;
private String y;
private double x;
private double y;
private String camera_type;
private String payload_index;
private float height;
private double height;
private double latitude;
private boolean locked;
private double longitude;
@ -95,7 +95,7 @@ public class MessageDown {
private double commander_flight_height;
private int commander_mode_lost_action;
private String max_speed;
private int max_speed;
private int rc_lost_action;
private int rth_altitude;
private String security_takeoff_height;
@ -110,7 +110,7 @@ public class MessageDown {
private double yaw_speed;
private float width;
private double width;
@ -267,10 +267,6 @@ public class MessageDown {
private int speed;
public void setHeight(float height) {
this.height = height;
}
public void setCommander_flight_height(double commander_flight_height) {
this.commander_flight_height = commander_flight_height;
}
@ -327,11 +323,11 @@ public class MessageDown {
this.language = language;
}
public float getWidth() {
public double getWidth() {
return width;
}
public void setWidth(float width) {
public void setWidth(double width) {
this.width = width;
}
@ -377,15 +373,15 @@ public class MessageDown {
}
public static class Points {
private int height;
private double latitude;
private double longitude;
private double height; // 目标点高度(椭球高)WGS84模型
private double latitude; // 目标点纬度南纬负北纬正
private double longitude; // 目标点经度东经正西经负
public int getHeight() {
public double getHeight() {
return height;
}
public void setHeight(int height) {
public void setHeight(double height) {
this.height = height;
}
@ -421,11 +417,11 @@ public class MessageDown {
this.commander_mode_lost_action = commander_mode_lost_action;
}
public String getMax_speed() {
public int getMax_speed() {
return max_speed;
}
public void setMax_speed(String max_speed) {
public void setMax_speed(int max_speed) {
this.max_speed = max_speed;
}
@ -517,11 +513,11 @@ public class MessageDown {
this.zoom_factor = zoom_factor;
}
public float getHeight() {
public double getHeight() {
return height;
}
public void setHeight(int height) {
public void setHeight(double height) {
this.height = height;
}
@ -589,19 +585,19 @@ public class MessageDown {
this.w = w;
}
public String getX() {
public double getX() {
return x;
}
public void setX(String x) {
public void setX(double x) {
this.x = x;
}
public String getY() {
public double getY() {
return y;
}
public void setY(String y) {
public void setY(double y) {
this.y = y;
}

View File

@ -1,6 +1,7 @@
package com.aros.apron.entity;
import java.util.ArrayList;
import java.util.List;
@ -79,6 +80,8 @@ public class Movement {
private String LTELinkType;//图传类型 1cusync 图传 3LTE 增强图传
private String ltePhoneAreaCode = "";//LTE认证手机号区号
private String ltePhoneNumber = "";//LTE认证手机号
private boolean ocuSyncLte;//增强图传是否开启
private int ocuSyncLteTime;//增强图传剩余时间()
private int goHomeHeight;//返航高度
private int failsafeAction;//失控动作
private int heightLimit;//限高
@ -199,9 +202,21 @@ public class Movement {
private int camera_mode = 0;
private int ir_metering_mode;
private int temperature;
private int temperature=65535;
private double x;
private double y;
// 区域测温相关
private double ir_region_x;
private double ir_region_y;
private double ir_region_width;
private double ir_region_height;
private double ir_region_aver_temperature=65535;
private double ir_region_min_temperature_x;
private double ir_region_min_temperature_y;
private double ir_region_min_temperature;
private double ir_region_max_temperature_x;
private double ir_region_max_temperature_y;
private double ir_region_max_temperature;
private int ir_zoom_factor = 2;
private double bottom;
private double left;
@ -282,6 +297,16 @@ public class Movement {
private boolean waylineinterpter = true;
private volatile boolean opentemperate=false;
public boolean isOpentemperate() {
return opentemperate;
}
public void setOpentemperate(boolean opentemperate) {
this.opentemperate = opentemperate;
}
public boolean isWaylineinterpter() {
return waylineinterpter;
@ -334,6 +359,13 @@ public class Movement {
private double takeofftargetlongitude;
private double takeofftargetheight;
// 返航轨迹相关字段
private List<ReturnHomeInfo.PathPoint> return_home_path_points = new ArrayList<>(); // 返航轨迹点列表
private double rth_start_latitude; // 返航起点纬度
private double rth_start_longitude; // 返航起点经度
private double rth_start_altitude; // 返航起点高度
private boolean is_rth_tracking; // 是否正在返航轨迹采集中
private int mission_type;
public int getMission_type() {
@ -707,6 +739,36 @@ public class Movement {
private volatile int flightmode = 0; //0代表没有操作 1代表航线飞行 2一键代表指令飞行 3flyto一键和flyto
private boolean takeofftopoint;
private boolean opendrc = false; //true 是开启 false 是关闭
private String fly_to_id; // 飞向目标点任务ID
// flyto 飞向目标点进度
private double flyto_target_latitude; // 目标点纬度
private double flyto_target_longitude; // 目标点经度
private float flyto_target_height; // 目标点高度
private float flyto_remaining_distance; // 剩余距离()
private float flyto_remaining_time; // 剩余时间()
private int flyto_max_speed = 10; // 最大速度(m/s)
private String fly_to_point_progress;
public String getFly_to_point_progress() {
return fly_to_point_progress;
}
public void setFly_to_point_progress(String fly_to_point_progress) {
this.fly_to_point_progress = fly_to_point_progress;
}
public boolean isTakeofftopoint() {
return takeofftopoint;
@ -724,6 +786,62 @@ public class Movement {
this.opendrc = opendrc;
}
public String getFly_to_id() {
return fly_to_id;
}
public void setFly_to_id(String fly_to_id) {
this.fly_to_id = fly_to_id;
}
public double getFlyto_target_latitude() {
return flyto_target_latitude;
}
public void setFlyto_target_latitude(double flyto_target_latitude) {
this.flyto_target_latitude = flyto_target_latitude;
}
public double getFlyto_target_longitude() {
return flyto_target_longitude;
}
public void setFlyto_target_longitude(double flyto_target_longitude) {
this.flyto_target_longitude = flyto_target_longitude;
}
public float getFlyto_target_height() {
return flyto_target_height;
}
public void setFlyto_target_height(float flyto_target_height) {
this.flyto_target_height = flyto_target_height;
}
public float getFlyto_remaining_distance() {
return flyto_remaining_distance;
}
public void setFlyto_remaining_distance(float flyto_remaining_distance) {
this.flyto_remaining_distance = flyto_remaining_distance;
}
public float getFlyto_remaining_time() {
return flyto_remaining_time;
}
public void setFlyto_remaining_time(float flyto_remaining_time) {
this.flyto_remaining_time = flyto_remaining_time;
}
public int getFlyto_max_speed() {
return flyto_max_speed;
}
public void setFlyto_max_speed(int flyto_max_speed) {
this.flyto_max_speed = flyto_max_speed;
}
public int getFlightmode() {
return flightmode;
}
@ -1148,6 +1266,95 @@ public class Movement {
this.ir_metering_mode = ir_metering_mode;
}
// 区域测温 getter/setter
public double getIr_region_x() {
return ir_region_x;
}
public void setIr_region_x(double ir_region_x) {
this.ir_region_x = ir_region_x;
}
public double getIr_region_y() {
return ir_region_y;
}
public void setIr_region_y(double ir_region_y) {
this.ir_region_y = ir_region_y;
}
public double getIr_region_width() {
return ir_region_width;
}
public void setIr_region_width(double ir_region_width) {
this.ir_region_width = ir_region_width;
}
public double getIr_region_height() {
return ir_region_height;
}
public void setIr_region_height(double ir_region_height) {
this.ir_region_height = ir_region_height;
}
public double getIr_region_aver_temperature() {
return ir_region_aver_temperature;
}
public void setIr_region_aver_temperature(double ir_region_aver_temperature) {
this.ir_region_aver_temperature = ir_region_aver_temperature;
}
public double getIr_region_min_temperature_x() {
return ir_region_min_temperature_x;
}
public void setIr_region_min_temperature_x(double ir_region_min_temperature_x) {
this.ir_region_min_temperature_x = ir_region_min_temperature_x;
}
public double getIr_region_min_temperature_y() {
return ir_region_min_temperature_y;
}
public void setIr_region_min_temperature_y(double ir_region_min_temperature_y) {
this.ir_region_min_temperature_y = ir_region_min_temperature_y;
}
public double getIr_region_min_temperature() {
return ir_region_min_temperature;
}
public void setIr_region_min_temperature(double ir_region_min_temperature) {
this.ir_region_min_temperature = ir_region_min_temperature;
}
public double getIr_region_max_temperature_x() {
return ir_region_max_temperature_x;
}
public void setIr_region_max_temperature_x(double ir_region_max_temperature_x) {
this.ir_region_max_temperature_x = ir_region_max_temperature_x;
}
public double getIr_region_max_temperature_y() {
return ir_region_max_temperature_y;
}
public void setIr_region_max_temperature_y(double ir_region_max_temperature_y) {
this.ir_region_max_temperature_y = ir_region_max_temperature_y;
}
public double getIr_region_max_temperature() {
return ir_region_max_temperature;
}
public void setIr_region_max_temperature(double ir_region_max_temperature) {
this.ir_region_max_temperature = ir_region_max_temperature;
}
public int getIr_zoom_factor() {
return ir_zoom_factor;
@ -2188,6 +2395,22 @@ public class Movement {
this.ltePhoneNumber = ltePhoneNumber;
}
public boolean isOcuSyncLte() {
return ocuSyncLte;
}
public void setOcuSyncLte(boolean ocuSyncLte) {
this.ocuSyncLte = ocuSyncLte;
}
public int getOcuSyncLteTime() {
return ocuSyncLteTime;
}
public void setOcuSyncLteTime(int ocuSyncLteTime) {
this.ocuSyncLteTime = ocuSyncLteTime;
}
public int getIsVirtualStickAdvancedModeEnabled() {
return isVirtualStickAdvancedModeEnabled;
}
@ -2618,5 +2841,45 @@ public class Movement {
this.planeMessage = planeMessage;
}
public List<ReturnHomeInfo.PathPoint> getReturn_home_path_points() {
return return_home_path_points;
}
public void setReturn_home_path_points(List<ReturnHomeInfo.PathPoint> return_home_path_points) {
this.return_home_path_points = return_home_path_points;
}
public double getRth_start_latitude() {
return rth_start_latitude;
}
public void setRth_start_latitude(double rth_start_latitude) {
this.rth_start_latitude = rth_start_latitude;
}
public double getRth_start_longitude() {
return rth_start_longitude;
}
public void setRth_start_longitude(double rth_start_longitude) {
this.rth_start_longitude = rth_start_longitude;
}
public double getRth_start_altitude() {
return rth_start_altitude;
}
public void setRth_start_altitude(double rth_start_altitude) {
this.rth_start_altitude = rth_start_altitude;
}
public boolean is_rth_tracking() {
return is_rth_tracking;
}
public void set_rth_tracking(boolean rth_tracking) {
is_rth_tracking = rth_tracking;
}
}

View File

@ -116,6 +116,8 @@ public class Osd {
private double vertical_speed;
private int wind_direction;
private int wind_speed;
private boolean ocu_sync_lte;
private int ocu_sync_lte_time;
public double getRtk_takeoff_altitude() {
@ -150,6 +152,22 @@ public class Osd {
this._$5300 = _$5300;
}
public boolean isOcu_sync_lte() {
return ocu_sync_lte;
}
public void setOcu_sync_lte(boolean ocu_sync_lte) {
this.ocu_sync_lte = ocu_sync_lte;
}
public int getOcu_sync_lte_time() {
return ocu_sync_lte_time;
}
public void setOcu_sync_lte_time(int ocu_sync_lte_time) {
this.ocu_sync_lte_time = ocu_sync_lte_time;
}
public int getActivation_time() {
return activation_time;
}

View File

@ -0,0 +1,121 @@
package com.aros.apron.entity;
import java.util.List;
/**
* PSDK Widget Values 上报实体类
*/
public class PsdkWidgetValuesReport {
private String tid;
private String bid;
private long timestamp;
private String method;
private String gateway;
private Data data;
public String getTid() { return tid; }
public void setTid(String tid) { this.tid = tid; }
public String getBid() { return bid; }
public void setBid(String bid) { this.bid = bid; }
public long getTimestamp() { return timestamp; }
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public String getGateway() { return gateway; }
public void setGateway(String gateway) { this.gateway = gateway; }
public Data getData() { return data; }
public void setData(Data data) { this.data = data; }
public static class Data {
private List<PsdkWidgetValue> psdk_widget_values;
public List<PsdkWidgetValue> getPsdk_widget_values() { return psdk_widget_values; }
public void setPsdk_widget_values(List<PsdkWidgetValue> psdk_widget_values) { this.psdk_widget_values = psdk_widget_values; }
}
public static class PsdkWidgetValue {
private int psdk_index;
private String psdk_lib_version;
private String psdk_name;
private String psdk_sn;
private int psdk_type;
private String psdk_version;
private SpeakerData speaker;
private List<Object> values;
public int getPsdk_index() { return psdk_index; }
public void setPsdk_index(int psdk_index) { this.psdk_index = psdk_index; }
public String getPsdk_lib_version() { return psdk_lib_version; }
public void setPsdk_lib_version(String psdk_lib_version) { this.psdk_lib_version = psdk_lib_version; }
public String getPsdk_name() { return psdk_name; }
public void setPsdk_name(String psdk_name) { this.psdk_name = psdk_name; }
public String getPsdk_sn() { return psdk_sn; }
public void setPsdk_sn(String psdk_sn) { this.psdk_sn = psdk_sn; }
public int getPsdk_type() { return psdk_type; }
public void setPsdk_type(int psdk_type) { this.psdk_type = psdk_type; }
public String getPsdk_version() { return psdk_version; }
public void setPsdk_version(String psdk_version) { this.psdk_version = psdk_version; }
public SpeakerData getSpeaker() { return speaker; }
public void setSpeaker(SpeakerData speaker) { this.speaker = speaker; }
public List<Object> getValues() { return values; }
public void setValues(List<Object> values) { this.values = values; }
}
public static class SpeakerData {
private String play_file_md5;
private String play_file_name;
private int play_mode;
private int play_volume;
private int system_state;
private int work_mode;
private int tts_language;
private int tts_speed;
private int tts_type;
private int tts_volume;
public String getPlay_file_md5() { return play_file_md5; }
public void setPlay_file_md5(String play_file_md5) { this.play_file_md5 = play_file_md5; }
public String getPlay_file_name() { return play_file_name; }
public void setPlay_file_name(String play_file_name) { this.play_file_name = play_file_name; }
public int getPlay_mode() { return play_mode; }
public void setPlay_mode(int play_mode) { this.play_mode = play_mode; }
public int getPlay_volume() { return play_volume; }
public void setPlay_volume(int play_volume) { this.play_volume = play_volume; }
public int getSystem_state() { return system_state; }
public void setSystem_state(int system_state) { this.system_state = system_state; }
public int getWork_mode() { return work_mode; }
public void setWork_mode(int work_mode) { this.work_mode = work_mode; }
public int getTts_language() { return tts_language; }
public void setTts_language(int tts_language) { this.tts_language = tts_language; }
public int getTts_speed() { return tts_speed; }
public void setTts_speed(int tts_speed) { this.tts_speed = tts_speed; }
public int getTts_type() { return tts_type; }
public void setTts_type(int tts_type) { this.tts_type = tts_type; }
public int getTts_volume() { return tts_volume; }
public void setTts_volume(int tts_volume) { this.tts_volume = tts_volume; }
}
}

View File

@ -0,0 +1,124 @@
package com.aros.apron.entity;
import java.util.ArrayList;
import java.util.List;
/**
* 返航轨迹信息上报
*/
public class ReturnHomeInfo {
private String tid;
private String bid;
private long timestamp;
private String method = "return_home_info";
private Data data;
public String getTid() {
return tid;
}
public void setTid(String tid) {
this.tid = tid;
}
public String getBid() {
return bid;
}
public void setBid(String bid) {
this.bid = bid;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public static class Data {
private String flight_id;
private int last_point_type;
private List<PathPoint> planned_path_points = new ArrayList<>();
public String getFlight_id() {
return flight_id;
}
public void setFlight_id(String flight_id) {
this.flight_id = flight_id;
}
public int getLast_point_type() {
return last_point_type;
}
public void setLast_point_type(int last_point_type) {
this.last_point_type = last_point_type;
}
public List<PathPoint> getPlanned_path_points() {
return planned_path_points;
}
public void setPlanned_path_points(List<PathPoint> planned_path_points) {
this.planned_path_points = planned_path_points;
}
}
public static class PathPoint {
private double latitude;
private double longitude;
private float height;
public PathPoint() {
}
public PathPoint(double latitude, double longitude, float height) {
this.latitude = latitude;
this.longitude = longitude;
this.height = height;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
}
}

View File

@ -40,6 +40,21 @@ public class Synchronizedstatus {
private static volatile boolean takeoff_to_point=false;
//flyto
private static volatile boolean flyto=false;
public static boolean isFlyto() {
return flyto;
}
public static void setFlyto(boolean flyto) {
Synchronizedstatus.flyto = flyto;
}
public static boolean isTakeoff_to_point() {
return takeoff_to_point;
}

View File

@ -295,7 +295,7 @@ public class AlternateLandingManager extends BaseManager {
public void onSuccess() {
sendEvent2Server( "备降点航线上传成功",1);
if (PreferenceUtils.getInstance().getHaveRTK() && !(Movement.getInstance().getIs_fixed()==2)) {
RTKManager.getInstance().enableRtk(false);
//TKManager.getInstance().enableRtk(false);
}
new Handler().postDelayed(new Runnable() {
@ -311,8 +311,23 @@ public class AlternateLandingManager extends BaseManager {
PreferenceUtils.getInstance().setNeedTriggerApronArucoLand(false);
sendEvent2Server( "开始飞往备降点",1);
PerceptionManager.getInstance().setPerceptionEnable(false);
sendFlyToAlternateLandPointEvent();
// 发送3次每次延迟500毫秒
new Handler().post(new Runnable() {
int count = 0;
@Override
public void run() {
if (count < 3) {
sendFlyToAlternateLandPointEvent();
count++;
if (count < 3) {
new Handler().postDelayed(this, 500);
}
}
}
});
Movement.getInstance().setTakeoff_result(316052);
Movement.getInstance().setResult(316052);

View File

@ -85,28 +85,42 @@ public class BatteryManager extends BaseManager {
/**************************************************************************************************************/
KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.
KeyChargeRemainingInPercent, 0), this, new CommonCallbacks.KeyListener<Integer>() {
KeyChargeRemainingInPercent), this, new CommonCallbacks.KeyListener<Integer>() {
@Override
public void onValueChange(@Nullable Integer oldValue, @Nullable Integer newValue) {
if (newValue != null) {
Movement.getInstance().setBattery_a_capacity_percent(newValue);
Movement.getInstance().setCapacity_percent(newValue);
checkForcedBatteryRTH(newValue, Movement.getInstance().getBattery_b_capacity_percent());
LogUtil.log(TAG,"电池电量"+newValue);
checkForcedBatteryRTH(newValue);
}
}
});
KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.
KeyChargeRemainingInPercent, 1), this, new CommonCallbacks.KeyListener<Integer>() {
@Override
public void onValueChange(@Nullable Integer oldValue, @Nullable Integer newValue) {
if (newValue != null) {
Movement.getInstance().setBattery_b_capacity_percent(newValue);
checkForcedBatteryRTH(Movement.getInstance().getBattery_a_capacity_percent(), newValue);
}
}
});
// KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.
// KeyChargeRemainingInPercent, 0), this, new CommonCallbacks.KeyListener<Integer>() {
// @Override
// public void onValueChange(@Nullable Integer oldValue, @Nullable Integer newValue) {
// if (newValue != null) {
// Movement.getInstance().setBattery_a_capacity_percent(newValue);
// Movement.getInstance().setCapacity_percent(newValue);
// // checkForcedBatteryRTH(newValue, Movement.getInstance().getBattery_b_capacity_percent());
// }
// }
// });
//
// KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.
// KeyChargeRemainingInPercent, 1), this, new CommonCallbacks.KeyListener<Integer>() {
// @Override
// public void onValueChange(@Nullable Integer oldValue, @Nullable Integer newValue) {
// if (newValue != null) {
// Movement.getInstance().setBattery_b_capacity_percent(newValue);
// // checkForcedBatteryRTH(Movement.getInstance().getBattery_a_capacity_percent(), newValue);
// }
// }
// });
KeyManager.getInstance().listen(KeyTools.createKey(BatteryKey.
KeyVoltage, 0), this, new CommonCallbacks.KeyListener<Integer>() {
@ -290,18 +304,13 @@ public class BatteryManager extends BaseManager {
/**
* 检查双电池平均电量是否低于强制返航阈值低于则触发返航
*/
private void checkForcedBatteryRTH(int batteryA, int batteryB) {
private void checkForcedBatteryRTH(int batteryA) {
if (forcedRTHTriggered) return;
if (!getGimbalAndCameraEnabled()) {
return;
}
// 过滤空值/无效电量0或负数不参与计算
if (batteryA <= 0 || batteryB <= 0) return;
if (batteryA <= 0 ) return;
String forcedBatteryStr = PreferenceUtils.getInstance().getForcedBattery();
if (TextUtils.isEmpty(forcedBatteryStr)) return;
@ -313,14 +322,12 @@ public class BatteryManager extends BaseManager {
return;
}
int avgBattery = (batteryA + batteryB) / 2;
if (avgBattery >= forcedBattery) return;
if (batteryA >= forcedBattery) return;
// 仅在飞行中触发
if (!Movement.getInstance().isPlaneWing()) return;
forcedRTHTriggered = true;
LogUtil.log(TAG, "平均电量" + avgBattery + "%低于强制返航阈值" + forcedBattery + "%,触发自动返航");
LogUtil.log(TAG, "平均电量" + batteryA + "%低于强制返航阈值" + forcedBattery + "%,触发自动返航");
sendEvent2Server("触发低电量返航",1);
Movement.getInstance().setTakeoff_result(321773);

View File

@ -44,6 +44,7 @@ import dji.sdk.keyvalue.value.camera.RecordingState;
import dji.sdk.keyvalue.value.camera.TapZoomMode;
import dji.sdk.keyvalue.value.camera.ThermalDigitalZoomFactor;
import dji.sdk.keyvalue.value.camera.ThermalDisplayMode;
import dji.sdk.keyvalue.value.camera.ThermalAreaMetersureTemperature;
import dji.sdk.keyvalue.value.camera.ThermalGainMode;
import dji.sdk.keyvalue.value.camera.ThermalTemperatureMeasureMode;
import dji.sdk.keyvalue.value.camera.VideoRecordingStatus;
@ -327,8 +328,9 @@ public class CameraManager extends BaseManager {
@Override
public void onValueChange(@Nullable DoublePoint2D doublePoint2D, @Nullable DoublePoint2D t1) {
if (t1 != null) {
Movement.getInstance().setX(t1.getX());
Movement.getInstance().setX(t1.getY());
// Movement.getInstance().setX(t1.getX());
// Movement.getInstance().setY(t1.getY());
// Movement.getInstance().setIr_metering_mode(1);
}
}
});
@ -339,11 +341,60 @@ public class CameraManager extends BaseManager {
@Override
public void onValueChange(@Nullable Double aDouble, @Nullable Double t1) {
if (t1 != null) {
Movement.getInstance().setTemperature(t1.intValue());
if(Movement.getInstance().isOpentemperate()){
Movement.getInstance().setTemperature(t1.intValue());
}
}
}
});
//区域测温区域位置
KeyManager.getInstance().listen(KeyTools.createCameraKey(CameraKey.KeyThermalRegionMetersureArea,
ComponentIndexType.PORT_1, CameraLensType.CAMERA_LENS_THERMAL), this,
new CommonCallbacks.KeyListener<DoubleRect>() {
@Override
public void onValueChange(@Nullable DoubleRect oldValue,
@Nullable DoubleRect t1) {
if (t1 != null) {
// Movement.getInstance().setIr_region_x(t1.getX());
// Movement.getInstance().setIr_region_y(t1.getY());
// Movement.getInstance().setIr_region_width(t1.getWidth());
// Movement.getInstance().setIr_region_height(t1.getHeight());
}
}
});
//区域测温温度信息平均温度最低温度点最高温度点
KeyManager.getInstance().listen(KeyTools.createCameraKey(CameraKey.KeyThermalRegionMetersureTemperature,
ComponentIndexType.PORT_1, CameraLensType.CAMERA_LENS_THERMAL), this,
new CommonCallbacks.KeyListener<ThermalAreaMetersureTemperature>() {
@Override
public void onValueChange(@Nullable ThermalAreaMetersureTemperature oldValue,
@Nullable ThermalAreaMetersureTemperature t1) {
LogUtil.log(TAG,"ThermalAreaMetersureTemperature"+t1.toString());
if (t1 != null) {
Movement.getInstance().setIr_metering_mode(2);
// 平均温度
Movement.getInstance().setIr_region_aver_temperature(t1.getAverageAreaTemperature());
// 最低温度点
DoublePoint2D minPoint = t1.getMinTemperaturePoint();
if (minPoint != null) {
Movement.getInstance().setIr_region_min_temperature_x(minPoint.getX());
Movement.getInstance().setIr_region_min_temperature_y(minPoint.getY());
}
Movement.getInstance().setIr_region_min_temperature(t1.getMinAreaTemperature());
// 最高温度点
DoublePoint2D maxPoint = t1.getMaxTemperaturePoint();
if (maxPoint != null) {
Movement.getInstance().setIr_region_max_temperature_x(maxPoint.getX());
Movement.getInstance().setIr_region_max_temperature_y(maxPoint.getY());
}
Movement.getInstance().setIr_region_max_temperature(t1.getMaxAreaTemperature());
}
}
});
//当前红外变焦倍率
KeyManager.getInstance().listen(KeyTools.createCameraKey(CameraKey.KeyThermalZoomRatios,
ComponentIndexType.PORT_1, CameraLensType.CAMERA_LENS_THERMAL), this, new CommonCallbacks.KeyListener<Double>() {
@ -1389,7 +1440,7 @@ public class CameraManager extends BaseManager {
KeyConnection, ComponentIndexType.PORT_1));
if (isConnect != null && isConnect && getGimbalAndCameraEnabled()) {
if (message != null) {
int type = 1;
final int type;
switch (message.getData().getVideo_type()) {
case "ir":
type = 3;
@ -1403,6 +1454,9 @@ public class CameraManager extends BaseManager {
case "zoom":
type = 2;
break;
default:
type = 1;
break;
}
KeyManager.getInstance().setValue(KeyTools.createKey(CameraKey.KeyCameraVideoStreamSource,
@ -1411,7 +1465,27 @@ public class CameraManager extends BaseManager {
new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
// 切换到红外视频源时自动设置调色盘为铁红色6
if (type == 3) {
KeyManager.getInstance().setValue(
KeyTools.createCameraKey(CameraKey.KeyThermalPalette,
ComponentIndexType.PORT_1,
CameraLensType.CAMERA_LENS_THERMAL),
CameraThermalPalette.find(6),
new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "红外切换成功,已设置调色盘为铁红");
}
@Override
public void onFailure(@NonNull IDJIError error) {
LogUtil.log(TAG, "设置红外调色盘失败:" + getIDJIErrorMsg(error));
}
});
}
sendMsg2Server(message);
}
@Override
@ -1804,6 +1878,7 @@ public class CameraManager extends BaseManager {
ThermalTemperatureMeasureMode.find(message.getData().getMode()), new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
Movement.getInstance().setIr_metering_mode(message.getData().getMode());
sendMsg2Server(message);
}
@ -1820,22 +1895,26 @@ public class CameraManager extends BaseManager {
//
//设置需要测温的点的位置
public void setThermalSpotMetersurePoint(MessageDown message) {
Boolean isConnect =KeyManager.getInstance().getValue(KeyTools.createKey(CameraKey.
KeyConnection,ComponentIndexType.PORT_1));
Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(CameraKey.
KeyConnection, ComponentIndexType.PORT_1));
if (isConnect != null && isConnect && getGimbalAndCameraEnabled()) {
DoublePoint2D doublePoint2D = new DoublePoint2D();
doublePoint2D.setX(Double.parseDouble(message.getData().getX()));
doublePoint2D.setY(Double.parseDouble(message.getData().getY()));
doublePoint2D.setX(message.getData().getX());
doublePoint2D.setY(message.getData().getY());
KeyManager.getInstance().setValue(KeyTools.createCameraKey(CameraKey.KeyThermalSpotMetersurePoint,
ComponentIndexType.PORT_1, CameraLensType.CAMERA_LENS_THERMAL), doublePoint2D, new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
Movement.getInstance().setOpentemperate(true);
Movement.getInstance().setIr_metering_mode(1);
Movement.getInstance().setX(message.getData().getX());
Movement.getInstance().setY(message.getData().getY());
sendMsg2Server(message);
}
@Override
public void onFailure(@NonNull IDJIError error) {
LogUtil.log(TAG,"设置点测温失败:"+new Gson().toJson(error));
LogUtil.log(TAG, "设置点测温失败:" + new Gson().toJson(error));
sendFailMsg2Server(message, "设置点测温失败:" + getIDJIErrorMsg(error));
}
@ -1852,14 +1931,19 @@ public class CameraManager extends BaseManager {
KeyConnection,ComponentIndexType.PORT_1));
if (isConnect != null && isConnect) {
DoubleRect doubleRect = new DoubleRect();
doubleRect.setX(Double.parseDouble(message.getData().getX()));
doubleRect.setY(Double.parseDouble(message.getData().getY()));
doubleRect.setHeight((double) message.getData().getHeight());
doubleRect.setWidth((double) message.getData().getWidth());
doubleRect.setX(message.getData().getX());
doubleRect.setY(message.getData().getY());
doubleRect.setHeight(message.getData().getHeight());
doubleRect.setWidth(message.getData().getWidth());
KeyManager.getInstance().setValue(KeyTools.createCameraKey(CameraKey.KeyThermalRegionMetersureArea,
ComponentIndexType.PORT_1, CameraLensType.CAMERA_LENS_THERMAL), doubleRect, new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
Movement.getInstance().setIr_metering_mode(2);
Movement.getInstance().setIr_region_x(message.getData().getX());
Movement.getInstance().setIr_region_y(message.getData().getY());
Movement.getInstance().setIr_region_width(message.getData().getWidth());
Movement.getInstance().setIr_region_height(message.getData().getHeight());
sendMsg2Server(message);
}

View File

@ -81,7 +81,7 @@ public class DockCloseManager extends BaseManager {
MqttManager.getInstance().mqttAndroidClient.publish(AMSConfig.UP_UAV_EVENT, mqttMessage, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
LogUtil.log(TAG, "关舱发送成功:"+sendDockCloseSuccessTimes+"clientId:"+MqttManager.getInstance().mqttAndroidClient.getClientId());
LogUtil.log(TAG, "关舱发送成功:"+sendDockCloseSuccessTimes+"clientId:"+MqttManager.getInstance().mqttAndroidClient.getClientId());
sendEvent2Server("AMS通知机库关舱",1);
isSendDockCloseSuccess = true;
}

View File

@ -23,6 +23,8 @@ import com.aros.apron.tools.AlternateArucoDetect;
import com.aros.apron.tools.ApronArucoDetect;
import com.aros.apron.tools.ApronArucoDetectPort;
import com.aros.apron.tools.DroneHelper;
import com.aros.apron.tools.FlyToPointProgressScheduler;
import com.aros.apron.tools.Gpsdistance;
import com.aros.apron.tools.LocationUtils;
import com.aros.apron.tools.LogUtil;
import com.aros.apron.tools.MqttManager;
@ -33,6 +35,7 @@ import com.google.gson.Gson;
import org.greenrobot.eventbus.EventBus;
import java.security.Key;
import java.util.List;
import java.util.Objects;
@ -74,6 +77,7 @@ import dji.v5.common.callback.CommonCallbacks;
import dji.v5.common.error.IDJIError;
import dji.v5.common.utils.GpsUtils;
import dji.v5.manager.KeyManager;
import dji.v5.manager.SDKManager;
import dji.v5.manager.aircraft.perception.data.PerceptionInfo;
import dji.v5.manager.aircraft.perception.listener.PerceptionInformationListener;
import dji.v5.manager.aircraft.virtualstick.VirtualStickManager;
@ -130,10 +134,10 @@ public class FlightManager extends BaseManager {
PsdkWidgetScheduler.getInstance().start();
PerceptionManager.getInstance().setPerceptionEnable(false);
PerceptionManager.getInstance().setObstacleAvoidanceupEnabled(false);
PerceptionManager.getInstance().setObstacleAvoidancedownEnabled(false);
PerceptionManager.getInstance().closeRadarManager(false);
// PerceptionManager.getInstance().setPerceptionEnable(false);
// PerceptionManager.getInstance().setObstacleAvoidanceupEnabled(false);
// PerceptionManager.getInstance().setObstacleAvoidancedownEnabled(false);
// PerceptionManager.getInstance().closeRadarManager(false);
if (count == 0) {
sendEvent2Server("开始上传日志文件", 1);
@ -247,8 +251,15 @@ public class FlightManager extends BaseManager {
OSDManager.getInstance().pushFlightAttitude();
}
isFlying = newValue;
// 起飞时开启返航轨迹定时上报
if (!isFlying) {
RTHTrackerManager.getInstance().reset();
}else{
RTHTrackerManager.getInstance().startReporting();
}
Movement.getInstance().setPlaneWing(newValue);
pushFlightAttitude();
@ -299,11 +310,15 @@ public class FlightManager extends BaseManager {
@Override
public void onValueChange(@Nullable String s, @Nullable String t1) {
if (t1 != null) {
Movement.getInstance().setFirmware_version(t1);
//Movement.getInstance().setFirmware_version(t1);
Movement.getInstance().setFirmware_version(SDKManager.getInstance().getSDKVersion());
pushFlightAttitude();
}
}
});
//RID状态
KeyManager.getInstance().listen(createKey(FlightControllerKey.KeyRidWorkingStatusPush), this, new CommonCallbacks.KeyListener<RidWorkingStatusPushMsg>() {
@Override
@ -320,6 +335,7 @@ public class FlightManager extends BaseManager {
@Override
public void onValueChange(@Nullable RTKTakeoffAltitudeInfo rtkTakeoffAltitudeInfo, @Nullable RTKTakeoffAltitudeInfo t1) {
if (t1 != null) {
//LogUtil.log(TAG,"KeyRTKTakeoffAltitudeInfo"+t1.getAltitude());
Movement.getInstance().setRtk_takeoff_altitude(t1.getAltitude());
pushFlightAttitude();
}
@ -342,14 +358,43 @@ public class FlightManager extends BaseManager {
String.valueOf(newValue.getLatitude()));
Movement.getInstance().setHome_distance(distance);
Movement.getInstance().setHeight(GpsUtils.egm96Altitude((Movement.getInstance().getRtk_takeoff_altitude() +
Movement.getInstance().getElevation()),
newValue.getLatitude(), newValue.getLongitude()));
// Movement.getInstance().setHeight(Movement.getInstance().getRtk_takeoff_altitude() + Movement.getInstance().getElevation());
Movement.getInstance().setLatitude(newValue.getLatitude());
Movement.getInstance().setLongitude(newValue.getLongitude());
pushFlightAttitude();
// ========== 判断是否到达FlyTo目标点 ==========
double targetLat = Movement.getInstance().getFlyto_target_latitude();
double targetLon = Movement.getInstance().getFlyto_target_longitude();
if (targetLat != 0 && targetLon != 0) {
// 计算到目标点的距离
double targetDistance = Gpsdistance.calculateDistance(
newValue.getLatitude(), newValue.getLongitude(),
targetLat, targetLon);
double horizontalSpeed = Movement.getInstance().getHorizontal_speed();
// 距离目标点 < 3米 速度 < 0.2m/s 悬停 判定到达
if (targetDistance < 3 && horizontalSpeed < 0.2) {
LogUtil.log(TAG, "【FlyTo到达目标点】距离=" + String.format("%.1f", targetDistance)
+ "m 速度=" + String.format("%.2f", horizontalSpeed) + "m/s → 停止上报");
FlyToPointProgressScheduler.getInstance().markSuccess();
// 清除目标点避免重复触发
Movement.getInstance().setFlyto_target_latitude(0);
Movement.getInstance().setFlyto_target_longitude(0);
}
}
}
}
@ -553,6 +598,7 @@ public class FlightManager extends BaseManager {
Movement.getInstance().setFlightmode(0);
break;
case FORCE_LANDING:
LogUtil.log(TAG,"强制降落触发");
Movement.getInstance().setMode_code(11);
break;
case POI:
@ -624,6 +670,7 @@ public class FlightManager extends BaseManager {
triggerLandOrGoHome = true;
Movement.getInstance().setVirtualStickQuitMission(false);
}
pushFlightAttitude();
}
}
@ -899,7 +946,6 @@ public class FlightManager extends BaseManager {
}
}
public void resetOpenCabinDoorState() {
sendOpenCabinDoorMsg = false;
LogUtil.log(TAG, "开舱门状态已重置");
@ -1034,7 +1080,6 @@ public class FlightManager extends BaseManager {
}
}
private void setkuaim() {
Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(CameraKey.
KeyConnection, ComponentIndexType.PORT_1));
@ -1099,7 +1144,6 @@ public class FlightManager extends BaseManager {
LogUtil.log(TAG, "相机未连接");
}
}
//快门优先
private void setCameraExposureMode() {
Boolean cameraConnect = KeyManager.getInstance().getValue(KeyTools.createKey(CameraKey.
@ -1120,7 +1164,6 @@ public class FlightManager extends BaseManager {
LogUtil.log(TAG, "相机未连接");
}
}
//设置成
public void setCameraExposureModePROGRAM() {
Boolean cameraConnect = KeyManager.getInstance().getValue(KeyTools.createKey(CameraKey.
@ -1156,7 +1199,6 @@ public class FlightManager extends BaseManager {
isGimbalReset = true;
}
}
// 检查是否满足开始视觉识别降落的条件
private void checkAndStartVisionLanding() {
boolean shouldStartVisionLanding = (PreferenceUtils.getInstance().getLandType() == 2);
@ -1164,11 +1206,8 @@ public class FlightManager extends BaseManager {
startVisionLanding();
// 检查是否满足降落条件
checkLandingConditions();
}
}
private static final double FLYING_HEIGHT_THRESHOLD_MAX = 20;
private static final double FLYING_HEIGHT_THRESHOLD_MAX_ALTERNATE = 10;
private static final double FLYING_HEIGHT_THRESHOLD_MIN = -2;
@ -1176,7 +1215,7 @@ public class FlightManager extends BaseManager {
// 打印相对高度的节流计数器(约每秒一次)
private int heightLogCounter = 0;
private static final int HEIGHT_LOG_INTERVAL = 30; // startVisionLanding大约每秒回调一次
private static final int HEIGHT_LOG_INTERVAL = 60; // startVisionLanding大约每秒回调一次
private void startVisionLanding() {
@ -1188,13 +1227,10 @@ public class FlightManager extends BaseManager {
// 节流打印相对高度和超声波高度(约每秒1次)
if (++heightLogCounter >= HEIGHT_LOG_INTERVAL) {
LogUtil.log(TAG, "[高度监控] 相对高度=" + Movement.getInstance().getElevation() + "m, 超声波高度=" + Movement.getInstance().getUltrasonicHeight() + "dm");
LogUtil.log(TAG, "[高度监控] 相对高度=" + Movement.getInstance().getElevation() + "m, 超声波高度=" + Movement.getInstance().getUltrasonicHeight() + "dm"+"限高"+KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyHeightLimitRange)));
heightLogCounter = 0;
}
if (isFlying && (Movement.getInstance().getElevation() < 15 && Movement.getInstance().getUltrasonicHeight() < 50 || forceTriggerDetection) && !isSendDetect) {
double flyingHeight = Movement.getInstance().getElevation();
double thresholdMin = triggerToAlternatePoint ? FLYING_HEIGHT_THRESHOLD_MIN_ALTERNATE : FLYING_HEIGHT_THRESHOLD_MIN;
@ -1231,7 +1267,7 @@ public class FlightManager extends BaseManager {
if (PreferenceUtils.getInstance().getTriggerToAlternatePoint()) {
LogUtil.log(TAG, "识别AlterTag:" + PreferenceUtils.getInstance().getNeedTriggerAlterArucoLand());
//EventBus.getDefault().post(FLAG_START_DETECT_ARUCO_ALTERNATE);
PreferenceUtils.getInstance().setNeedTriggerAlterArucoLand(true);
PreferenceUtils.getInstance().setNeedTriggerAlterArucoLand(false);
PreferenceUtils.getInstance().setNeedTriggerApronArucoLand(false);
LogUtil.log(TAG, "开始识别备降点二维码,椭球高度:" + Movement.getInstance().getElevation() + "" + "--超声波高度:" + Movement.getInstance().getUltrasonicHeight() + "分米");
sendEvent2Server("开始备降点视觉降落", 1);
@ -1350,7 +1386,11 @@ public class FlightManager extends BaseManager {
if (Movement.getInstance().isIstakeoffex() == true && !Objects.equals(Movement.getInstance().getTakeoff_status(), "wayline_cancel")) {
Movement.getInstance().setTakeoff_status("task_finish");
if(Movement.getInstance().isAlternate()){
Movement.getInstance().setTakeoff_status("wayline_failed");
}else{
Movement.getInstance().setTakeoff_status("task_finish");
}
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
@ -1359,7 +1399,11 @@ public class FlightManager extends BaseManager {
}, 1000);
sendEvent2Server("一键起飞已发送task_finish", 1);
} else if (Movement.getInstance().isIstakeoffex() == true && Objects.equals(Movement.getInstance().getTakeoff_status(), "wayline_cancel")) {
Movement.getInstance().setTakeoff_status("wayline_failed");
if(Movement.getInstance().isAlternate()){
Movement.getInstance().setTakeoff_status("wayline_failed");
}else{
Movement.getInstance().setTakeoff_status("wayline_failed");
}
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
@ -1455,12 +1499,14 @@ public class FlightManager extends BaseManager {
public void onSuccess(EmptyMsg emptyMsg) {
//只有在取消返航时才能显示取消返航失败
Movement.getInstance().setMode_code(3);
isGimbalReset = false;
sendMsg2Server(message);
}
@Override
public void onFailure(@NonNull IDJIError error) {
LogUtil.log(TAG, "取消返航执行失败" + error);
//isGimbalReset = false;
sendFailMsg2Server(message, "取消返航执行失败:" + getIDJIErrorMsg(error));
}
});

View File

@ -1,41 +1,42 @@
package com.aros.apron.manager;
import static android.os.Environment.getExternalStoragePublicDirectory;
import static com.aros.apron.tools.Utils.getIDJIErrorMsg;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
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.entity.Synchronizedstatus;
import com.aros.apron.tools.FlyToPointProgressScheduler;
import com.aros.apron.tools.LogUtil;
import com.aros.apron.tools.PreferenceUtils;
import com.aros.apron.tools.Utils;
import com.aros.apron.tools.ZipUtil;
import com.google.gson.Gson;
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.LocationCoordinate3D;
import dji.sdk.keyvalue.value.flightcontroller.FlyToMode;
import dji.v5.common.callback.CommonCallbacks;
import dji.v5.common.error.IDJIError;
import dji.v5.manager.KeyManager;
import dji.v5.manager.aircraft.waypoint3.WaypointMissionManager;
import dji.v5.manager.interfaces.IWaypointMissionManager;
import dji.v5.manager.intelligent.IntelligentFlightManager;
import dji.v5.manager.intelligent.flyto.FlyToMissionManager;
import dji.v5.manager.intelligent.flyto.FlyToParam;
import dji.v5.manager.intelligent.flyto.FlyToTarget;
import dji.v5.manager.intelligent.flyto.IFlyToMissionManager;
/**
* 飞向目标点任务管理器
* 使用 DJI MSDK 5.14+ 原生 IFlyToMissionManager API
* 对应 MQTT 协议:
* - fly_to_point 开始飞向目标点
* - fly_to_point_stop 结束飞向目标点任务
* - fly_to_point_update 更新目标点
*/
public class FlyToPointManager extends BaseManager {
final Handler mainHandler = new Handler(Looper.getMainLooper());
private static final String TAG = "FlyToPointManager";
private FlyToPointManager() {
}
@ -48,202 +49,394 @@ public class FlyToPointManager extends BaseManager {
return FlyToPointHolder.INSTANCE;
}
public boolean isReceiverMission = false;
public volatile boolean isReceiverMission = false;
//收到飞往目标点航线
public boolean isReceiverMission() {
return isReceiverMission;
}
public void setReceiverMission(boolean receiverMission) {
isReceiverMission = receiverMission;
}
// ==================== MQTT 入口 ====================
/**
* 收到飞往目标点指令 (fly_to_point)
*/
public void taskExecute(MessageDown message) {
// PreferenceUtils.getInstance().setMissionType(2);
PreferenceUtils.getInstance().setIsNewRoute(true);
//避免重复执行
if (isReceiverMission == false) {
isReceiverMission = true;
}
if (message.getData().getPoints() != null && message.getData().getPoints().size() > 0) {
sendMsg2Server(message);
} else {
sendFailMsg2Server(message, "指点飞行经纬度有误");
// PreferenceUtils.getInstance().setIsNewRoute(true);
// // 避免重复执行
// if (!isReceiverMission) {
// isReceiverMission = true;
// }
// 参数校验
if (message.getData() == null || message.getData().getPoints() == null
|| message.getData().getPoints().isEmpty()) {
sendFailMsg2Server(message, "指点飞行目标点为空");
Synchronizedstatus.setFlyto(false);
return;
}
toGenerateKMZFile(message);
// 检查飞控连接
Boolean isConnect = KeyManager.getInstance().getValue(
KeyTools.createKey(FlightControllerKey.KeyConnection));
if (isConnect == null || !isConnect) {
sendFailMsg2Server(message, "设备未连接");
Synchronizedstatus.setFlyto(false);
return;
}
startMission(message);
}
// ==================== 开始任务 ====================
/**
* 5.生成航线
*
* @param message
* 开始飞向目标点
* 协议: fly_to_point
* 参数: fly_to_id, max_speed, points[{latitude, longitude, height}]
*/
public void toGenerateKMZFile(MessageDown message) {
Movement.getInstance().setTask_current_step(16);
// 创建第一个 MissionPoint 对象
MissionPoint missionPoint = new MissionPoint();
missionPoint.setLat(String.valueOf(Movement.getInstance().getLatitude()));
missionPoint.setLng(String.valueOf(Movement.getInstance().getLongitude()));
missionPoint.setSpeed(Double.parseDouble(message.getData().getMax_speed()));
missionPoint.setExecuteHeight(message.getData().getHeight());
// 创建第二个 MissionPoint 对象
MissionPoint missionPoint1 = new MissionPoint();
missionPoint1.setLat(message.getData().getPoints().get(0).getLatitude() + "");
missionPoint1.setLng(message.getData().getPoints().get(0).getLongitude() + "");
missionPoint1.setSpeed(Double.parseDouble(message.getData().getMax_speed()));
missionPoint1.setExecuteHeight(message.getData().getHeight());
// 创建一个 MissionPoint 列表
List<MissionPoint> missionPoints = new ArrayList<>();
missionPoints.add(missionPoint);
missionPoints.add(missionPoint1);
// 创建 FlightMission 对象并设置其属性
FlightMission flightMission = new FlightMission();
flightMission.setPoints(missionPoints);
flightMission.setMissionId(2);
flightMission.setFinishAction("noAction");
flightMission.setTakeOffSecurityHeight(
Float.parseFloat(Movement.getInstance().getElevation() + ""));
flightMission.setSpeed(Double.parseDouble(message.getData().getMax_speed()));
LogUtil.log(TAG, "当前高度:" + Movement.getInstance().getElevation()
+ "-指点飞行安全起飞高度:" + message.getData().getSecurity_takeoff_height());
sendEvent2Server("开始生成指点飞行航线", 1);
// 生成xml文件
File file1 = new File(
getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "wpmz");
if (!file1.exists()) {
if (file1.mkdirs()) {
sendEvent2Server("指点飞行航线文件生成成功", 1);
} else {
sendEvent2Server("指点飞行航线文件生成失败", 2);
private void startMission(MessageDown message) {
try {
MessageDown.Data data = message.getData();
List<MessageDown.Data.Points> points = data.getPoints();
if (points == null || points.isEmpty()) {
sendFailMsg2Server(message, "目标点为空");
return;
}
MessageDown.Data.Points target = points.get(0);
// 当前椭球高起飞点椭球高)
//double currentEllipsoid = Movement.getInstance().getRtk_takeoff_altitude();
// 目标相对高度 = 目标椭球高(WGS84) - 当前椭球高全程 WGS84 椭球系
double targetRelative = target.getHeight() - Movement.getInstance().getHeight()+Movement.getInstance().getElevation();
// 防止高度过低炸机最低限制20米
if (targetRelative < 20) {
LogUtil.log(TAG, "计算目标相对高=" + targetRelative + " < 20限制为20米防炸机");
targetRelative = 20;
}
LogUtil.log(TAG, "目标椭球高=" + target.getHeight() + " 当前椭球高=" + Movement.getInstance().getHeight()
+ " 当前相对高=" + Movement.getInstance().getElevation() + " 最终目标相对高=" + targetRelative);
// 构建 FlyToTarget
FlyToTarget flyToTarget = new FlyToTarget();
LocationCoordinate3D locationCoordinate3D=new LocationCoordinate3D();
locationCoordinate3D.setLatitude(target.getLatitude());
locationCoordinate3D.setLongitude(target.getLongitude());
locationCoordinate3D.setAltitude(targetRelative);
flyToTarget.setTargetLocation(locationCoordinate3D);
flyToTarget.setSecurityTakeoffHeight(20);
if (data.getMax_speed() > 0) {
flyToTarget.setMaxSpeed(data.getMax_speed());
} else {
flyToTarget.setMaxSpeed(10); // 默认 10m/s
}
// 构建 FlyToParam
FlyToParam flyToParam = new FlyToParam();
// max_speed 协议定义为 int(/)范围 0-15
flyToParam.setFlyToMode(FlyToMode.SET_HEIGHT);
flyToParam.setHeight((int) targetRelative);
// 如果协议携带了 fly_to_id记录下来
if (data.getFly_to_id() != null) {
Movement.getInstance().setFly_to_id(data.getFly_to_id());
LogUtil.log(TAG, "fly_to_id: " + data.getFly_to_id());
}
int maxSpeed = data.getMax_speed() > 0 ? data.getMax_speed() : 10;
sendEvent2Server("开始飞向目标点: lat=" + target.getLatitude()
+ ", lng=" + target.getLongitude()
+ ", height=" + target.getHeight()+"targetRelative"+targetRelative, 1);
IFlyToMissionManager manager = IntelligentFlightManager.getInstance().getFlyToMissionManager();
manager.startMission(flyToTarget, flyToParam, new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "飞向目标点任务开始成功");
//Movement.getInstance().setTask_current_step(23);
Movement.getInstance().setMode_code(17); // 指令飞行模式
//开始上报
FlyToPointProgressScheduler.getInstance().startReporting();
// 保存目标点信息到 Movement供进度上报使用
Movement.getInstance().setFlyto_target_latitude(target.getLatitude());
Movement.getInstance().setFlyto_target_longitude(target.getLongitude());
Movement.getInstance().setFlyto_target_height((float) target.getHeight());
Movement.getInstance().setFlyto_max_speed(maxSpeed);
// 回复成功
sendMsg2Server(message);
sendEvent2Server("飞向目标点任务已启动", 1);
Synchronizedstatus.setFlyto(false);
}
@Override
public void onFailure(@NonNull IDJIError error) {
String errorMsg = "飞向目标点启动失败: " + error.description();
LogUtil.log(TAG, errorMsg);
sendFailMsg2Server(message, errorMsg);
sendEvent2Server(errorMsg, 2);
FlyToPointProgressScheduler.getInstance().markFailed();
Synchronizedstatus.setFlyto(false);
}
});
} catch (Exception e) {
sendFailMsg2Server(message, "飞向目标点参数异常: " + e.getMessage());
Synchronizedstatus.setFlyto(false);
}
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 + "FlyTo.kmz");
kmzFile.getParentFile().mkdirs();
/**
* 结束飞向目标点任务 (fly_to_point_stop)
*/
public void stopMission(MessageDown message) {
Boolean isConnect = KeyManager.getInstance().getValue(
KeyTools.createKey(FlightControllerKey.KeyConnection));
if (isConnect == null || !isConnect) {
sendFailMsg2Server(message, "设备未连接");
return;
}
IFlyToMissionManager manager = IntelligentFlightManager.getInstance().getFlyToMissionManager();
manager.stopMission(new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "飞向目标点任务终止成功");
sendMsg2Server(message);
FlyToPointProgressScheduler.getInstance().markCancel();
}
@Override
public void onFailure(@NonNull IDJIError error) {
String errorMsg = "飞向目标点终止失败: " + error.description();
LogUtil.log(TAG, errorMsg);
sendFailMsg2Server(message, errorMsg);
}
});
}
// ==================== 更新目标点 ====================
/**
* 更新飞向目标点 (fly_to_point_update)
* 可在一键起飞flyto 飞向目标点执行过程中调用
* 参数: max_speed, points[{latitude, longitude, height}]
*/
public void updateTarget(MessageDown message) {
Boolean isConnect = KeyManager.getInstance().getValue(
KeyTools.createKey(FlightControllerKey.KeyConnection));
if (isConnect == null || !isConnect) {
sendFailMsg2Server(message, "设备未连接");
return;
}
try {
ZipUtil.zip(getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + "/wpmz",
getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + File.separator + "FlyTo.kmz");
} catch (IOException e) {
sendEvent2Server("指点飞行任务生成异常", 2);
throw new RuntimeException(e);
}
pushKMZFileToAircraft(message);
}
// MessageDown.Data data = message.getData();
// if (data == null || data.getPoints() == null || data.getPoints().isEmpty()) {
// sendFailMsg2Server(message, "更新目标点为空");
// return;
// }
//
// MessageDown.Data.Points target = data.getPoints().get(0);
//
// // 当前椭球高起飞点椭球高 + 相对起飞点高度
// //double currentEllipsoid = Movement.getInstance().getRtk_takeoff_altitude();
//
// // 目标相对高度 = 目标椭球高(WGS84) - 当前椭球高全程 WGS84 椭球系
// double targetRelative = target.getHeight() - Movement.getInstance().getHeight() + Movement.getInstance().getElevation();
//
// // 防止高度过低炸机最低限制20米
// if (targetRelative < 20) {
// LogUtil.log(TAG, "计算目标相对高=" + targetRelative + " < 20限制为20米防炸机");
// targetRelative = 20;
// }
//
// // 构建 FlyToTarget
// FlyToTarget flyToTarget = new FlyToTarget();
// LocationCoordinate3D locationCoordinate3D=new LocationCoordinate3D();
// locationCoordinate3D.setLatitude(target.getLatitude());
// locationCoordinate3D.setLongitude(target.getLongitude());
// locationCoordinate3D.setAltitude(targetRelative);
// flyToTarget.setTargetLocation(locationCoordinate3D);
//
//
//
// flyToTarget.setSecurityTakeoffHeight(20);
//
// int maxspeed;
// if (data.getMax_speed() > 0) {
// flyToTarget.setMaxSpeed(data.getMax_speed());
// maxspeed=data.getMax_speed();
// } else {
// flyToTarget.setMaxSpeed(10); // 默认 10m/s
// maxspeed=10;
// }
//
// sendEvent2Server("更新目标点: lat=" + target.getLatitude()
// + ", lng=" + target.getLongitude()
// + ", height=" + target.getHeight()+"targetRelative"+targetRelative, 1);
//
// LogUtil.log(TAG, "updateTarget: 目标高=" + target.getHeight()
// + " getHeight=" + Movement.getInstance().getHeight()
// + " getElevation=" + Movement.getInstance().getElevation()
// + " targetRelative=" + targetRelative);
IFlyToMissionManager manager = IntelligentFlightManager.getInstance().getFlyToMissionManager();
/**
* 6.上传指点航线
*
* @param message
*/
private void pushKMZFileToAircraft(MessageDown message) {
Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.
KeyConnection));
if (isConnect != null && isConnect) {
WaypointMissionManager.getInstance().pushKMZFileToAircraft(getExternalStoragePublicDirectory("KMZ").getAbsolutePath() + "/" + "FlyTo.kmz", new CommonCallbacks.CompletionCallbackWithProgress<Double>() {
@Override
public void onProgressUpdate(Double progress) {
sendEvent2Server("指点航线上传进度:" + progress, 1);
Movement.getInstance().setTask_current_step(17);
}
@Override
public void onSuccess() {
sendEvent2Server("指点航线上传成功,准备执行任务", 1);
mainHandler.postDelayed(new Runnable() {
@Override
public void run() {
/**
* 7.开始任务
*/
Movement.getInstance().setTask_current_step(22);
startMission(message);
}
}, 2000);
}
@Override
public void onFailure(@NonNull IDJIError error) {
sendFailMsg2Server(message,"指点航线上传失败:"+ Utils.getIDJIErrorMsg(error));
sendEvent2Server("指点航线上传失败:"+ Utils.getIDJIErrorMsg(error),2);
//待机
Movement.getInstance().setMode_code(0);
}
});
}
}
/**
* 6.开始航线
*
* @param message
*/
public void startMission(MessageDown message) {
Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.
KeyConnection));
if (isConnect != null && isConnect) {
CommonCallbacks.CompletionCallback callback = new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "指点航线开始成功");
Movement.getInstance().setTask_status("paused");
sendEvent2Server("任务开始执行", 1);
Movement.getInstance().setTask_current_step(23);
// Movement.getInstance().setMode_code(5);
//指令飞行( 指点前置不需要起飞准备这些因为没有指点起飞的航线)
Movement.getInstance().setMode_code(17);
}
@Override
public void onFailure(@NonNull IDJIError error) {
sendFailMsg2Server(message,"指点航线执行失败:" + new Gson().toJson(error));
sendEvent2Server("指点航线执行失败:" + new Gson().toJson(error),2);
//待机
Movement.getInstance().setMode_code(0);
}
};
WaypointMissionManager.getInstance().startMission("FlyTo", callback);
} else {
sendEvent2Server("指点任务开始失败,设备未连接", 2);
}
}
public void stopMission(MessageDown message) {
Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.
KeyConnection));
if (isConnect != null && isConnect) {
IWaypointMissionManager missionManager = WaypointMissionManager.getInstance();
missionManager.stopMission("FlyTo", new CommonCallbacks.CompletionCallback() {
manager.stopMission(new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "目标点更新成功");
sendMsg2Server(message);
LogUtil.log(TAG, "指点任务终止成功");
Movement.getInstance().setTask_status("paused");
sendEvent2Server("目标点已更新", 1);
new Handler().postDelayed(()->{
startMissionupdate(message);
},1000);
}
@Override
public void onFailure(@NonNull IDJIError idjiError) {
String errorMsg = "目标点更新失败: " + idjiError;
LogUtil.log(TAG, errorMsg);
sendFailMsg2Server(message, errorMsg);
}
});
} catch (Exception e) {
sendFailMsg2Server(message, "更新目标点参数异常: " + e.getMessage());
}
}
private void startMissionupdate(MessageDown message) {
try {
MessageDown.Data data = message.getData();
List<MessageDown.Data.Points> points = data.getPoints();
if (points == null || points.isEmpty()) {
sendFailMsg2Server(message, "目标点为空");
return;
}
MessageDown.Data.Points target = points.get(0);
// 当前椭球高起飞点椭球高)
//double currentEllipsoid = Movement.getInstance().getRtk_takeoff_altitude();
// 目标相对高度 = 目标椭球高(WGS84) - 当前椭球高全程 WGS84 椭球系
double targetRelative = target.getHeight() - Movement.getInstance().getHeight()+Movement.getInstance().getElevation();
// 防止高度过低炸机最低限制20米
if (targetRelative < 20) {
LogUtil.log(TAG, "计算目标相对高=" + targetRelative + " < 20限制为20米防炸机");
targetRelative = 20;
}
LogUtil.log(TAG, "目标椭球高=" + target.getHeight() + " 当前椭球高=" + Movement.getInstance().getHeight()
+ " 当前相对高=" + Movement.getInstance().getElevation() + " 最终目标相对高=" + targetRelative);
// 构建 FlyToTarget
FlyToTarget flyToTarget = new FlyToTarget();
LocationCoordinate3D locationCoordinate3D=new LocationCoordinate3D();
locationCoordinate3D.setLatitude(target.getLatitude());
locationCoordinate3D.setLongitude(target.getLongitude());
locationCoordinate3D.setAltitude(targetRelative);
flyToTarget.setTargetLocation(locationCoordinate3D);
flyToTarget.setSecurityTakeoffHeight(20);
if (data.getMax_speed() > 0) {
flyToTarget.setMaxSpeed(data.getMax_speed());
} else {
flyToTarget.setMaxSpeed(10); // 默认 10m/s
}
// 构建 FlyToParam
FlyToParam flyToParam = new FlyToParam();
// max_speed 协议定义为 int(/)范围 0-15
flyToParam.setFlyToMode(FlyToMode.SET_HEIGHT);
flyToParam.setHeight((int) targetRelative);
// 如果协议携带了 fly_to_id记录下来
if (data.getFly_to_id() != null) {
Movement.getInstance().setFly_to_id(data.getFly_to_id());
LogUtil.log(TAG, "fly_to_id: " + data.getFly_to_id());
}
int maxSpeed = data.getMax_speed() > 0 ? data.getMax_speed() : 10;
sendEvent2Server("开始飞向目标点: lat=" + target.getLatitude()
+ ", lng=" + target.getLongitude()
+ ", height=" + target.getHeight()+"targetRelative"+targetRelative, 1);
IFlyToMissionManager manager = IntelligentFlightManager.getInstance().getFlyToMissionManager();
manager.startMission(flyToTarget, flyToParam, new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "飞向目标点任务开始成功");
//Movement.getInstance().setTask_current_step(23);
Movement.getInstance().setMode_code(17); // 指令飞行模式
//开始上报
FlyToPointProgressScheduler.getInstance().startReporting();
// 保存目标点信息到 Movement供进度上报使用
Movement.getInstance().setFlyto_target_latitude(target.getLatitude());
Movement.getInstance().setFlyto_target_longitude(target.getLongitude());
Movement.getInstance().setFlyto_target_height((float) target.getHeight());
Movement.getInstance().setFlyto_max_speed(maxSpeed);
}
@Override
public void onFailure(@NonNull IDJIError error) {
sendFailMsg2Server(message, "指点任务终止失败:" + getIDJIErrorMsg(error));
String errorMsg = "飞向目标点启动失败: " + error.description();
LogUtil.log(TAG, errorMsg);
FlyToPointProgressScheduler.getInstance().markFailed();
}
});
} else {
LogUtil.log(TAG, "指点任务终止失败:设备未连接");
} catch (Exception e) {
sendFailMsg2Server(message, "飞向目标点参数异常: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,304 @@
package com.aros.apron.manager;
import android.os.Handler;
import android.os.Looper;
import com.aros.apron.base.BaseManager;
import com.aros.apron.constant.AMSConfig;
import com.aros.apron.constant.Constant;
import com.aros.apron.entity.ApronExecutionStatus;
import com.aros.apron.entity.MessageEvent;
import com.aros.apron.entity.Movement;
import com.aros.apron.tools.LogUtil;
import com.aros.apron.tools.MqttManager;
import com.aros.apron.tools.PreferenceUtils;
import com.google.gson.Gson;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* 舱门开关统一管理类
*
* 核心规则
* 1. 开舱优先级绝对大于关舱 两者冲突时永远以开舱为准
* 2. 同一时刻只允许存在一个有效指令OPEN > NONE > CLOSE
* 3. 收到服务端 MQTT 回复后才认为操作完成
*/
public class HatchDoorManager extends BaseManager {
private final Handler mainHandler = new Handler(Looper.getMainLooper());
// 期望的舱门指令优先级OPEN(1) > NONE(0) > CLOSE(-1)
private int desiredCommand = COMMAND_NONE;
private static final int COMMAND_OPEN = 1;
private static final int COMMAND_NONE = 0;
private static final int COMMAND_CLOSE = -1;
// 当前执行状态
private volatile State currentState = State.IDLE;
// 重试计数
private int retryCount = 0;
private static final int MAX_CLOSE_RETRIES = 2;
private static final int MAX_OPEN_RETRIES = 20;
private static final long RETRY_DELAY_MS = 2000;
public enum State {
/** 空闲,无操作 */
IDLE,
/** 正在发送开舱指令 */
OPENING,
/** 已开舱(服务端已确认) */
OPEN,
/** 正在发送关舱指令 */
CLOSING,
/** 已关舱(服务端已确认) */
CLOSED
}
private HatchDoorManager() {
}
private static class Holder {
private static final HatchDoorManager INSTANCE = new HatchDoorManager();
}
public static HatchDoorManager getInstance() {
return Holder.INSTANCE;
}
// ==================== 公开 API ====================
/**
* 请求开舱优先级最高覆盖任何进行中的关舱操作
*/
public synchronized void requestOpen() {
if (currentState == State.OPEN || currentState == State.OPENING) {
LogUtil.log(TAG, "舱门已处于开启/开启中,忽略重复请求");
return;
}
// 开舱覆盖关舱取消进行中的关舱重试
if (desiredCommand != COMMAND_OPEN) {
LogUtil.log(TAG, "开舱请求覆盖关舱请求(开舱优先级最高)");
}
desiredCommand = COMMAND_OPEN;
retryCount = 0;
sendOpenCommand();
}
/**
* 请求关舱
*/
public synchronized void requestClose() {
// 如果当前期望开舱关舱请求被忽略
if (desiredCommand == COMMAND_OPEN) {
LogUtil.log(TAG, "开舱优先级高于关舱,忽略关舱请求");
return;
}
if (currentState == State.CLOSED || currentState == State.CLOSING) {
LogUtil.log(TAG, "舱门已处于关闭/关闭中,忽略重复请求");
return;
}
desiredCommand = COMMAND_CLOSE;
retryCount = 0;
sendCloseCommand();
}
/**
* MqttCallBack 回调调用服务端确认开舱
*/
public synchronized void onServerReplyOpen() {
LogUtil.log(TAG, "服务端确认开舱");
ApronExecutionStatus.getInstance().setServerReplyDockOpen(true);
currentState = State.OPEN;
desiredCommand = COMMAND_NONE;
retryCount = 0;
}
/**
* MqttCallBack 回调调用服务端确认关舱
*/
public synchronized void onServerReplyClose() {
LogUtil.log(TAG, "服务端确认关舱");
ApronExecutionStatus.getInstance().setServerReplyDockIn(true);
currentState = State.CLOSED;
desiredCommand = COMMAND_NONE;
retryCount = 0;
}
/**
* 重置所有状态每次新任务起飞前调用
*/
public synchronized void reset() {
desiredCommand = COMMAND_NONE;
currentState = State.IDLE;
retryCount = 0;
ApronExecutionStatus.getInstance().setServerReplyDockOpen(false);
LogUtil.log(TAG, "舱门状态已重置");
}
/**
* 当前舱门状态供外部查询
*/
public synchronized State getState() {
return currentState;
}
// ==================== 内部实现 ====================
private void sendOpenCommand() {
if (currentState == State.OPEN) {
return;
}
int maxRetries = MAX_OPEN_RETRIES;
if (retryCount >= maxRetries) {
LogUtil.log(TAG, "开舱达到最大重试次数: " + retryCount);
return;
}
if (!MqttManager.getInstance().mqttAndroidClient.isConnected()) {
LogUtil.log(TAG, "开舱发送失败mqtt 未连接,准备重试 " + (retryCount + 1));
retryCount++;
mainHandler.postDelayed(this::sendOpenCommand, RETRY_DELAY_MS);
return;
}
currentState = State.OPENING;
publishDoorMessage(Constant.OPEN_DOOR, true);
}
private void sendCloseCommand() {
if (currentState == State.CLOSED) {
return;
}
// 发关舱前再检查一次是否有开舱请求插队
if (desiredCommand == COMMAND_OPEN) {
LogUtil.log(TAG, "开舱请求插入,中止关舱");
return;
}
int maxRetries = MAX_CLOSE_RETRIES;
if (retryCount >= maxRetries) {
LogUtil.log(TAG, "关舱达到最大重试次数: " + retryCount);
return;
}
if (!MqttManager.getInstance().mqttAndroidClient.isConnected()) {
LogUtil.log(TAG, "关舱发送失败mqtt 未连接,准备重试 " + (retryCount + 1));
retryCount++;
mainHandler.postDelayed(this::sendCloseCommand, RETRY_DELAY_MS);
return;
}
currentState = State.CLOSING;
publishDoorMessage(Constant.CLOSE_DOOR, false);
}
private void publishDoorMessage(String method, boolean isOpen) {
MessageEvent messageEvent = new MessageEvent();
messageEvent.setBid(UUID.randomUUID().toString());
messageEvent.setTid(UUID.randomUUID().toString());
messageEvent.setTimestamp(System.currentTimeMillis());
messageEvent.setMethod(method);
MqttMessage mqttMessage = new MqttMessage(
new Gson().toJson(messageEvent).getBytes(StandardCharsets.UTF_8));
mqttMessage.setQos(1);
try {
MqttManager.getInstance().mqttAndroidClient.publish(
AMSConfig.UP_UAV_EVENT, mqttMessage, null,
new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
String action = isOpen ? "开舱" : "关舱";
LogUtil.log(TAG, action + "发送成功");
sendEvent2Server("AMS通知机库" + action, 1);
// 发送成功后等待服务端回复
mainHandler.postDelayed(() -> {
synchronized (HatchDoorManager.this) {
if (isOpen) {
if (ApronExecutionStatus.getInstance().isServerReplyDockOpen()) {
currentState = State.OPEN;
desiredCommand = COMMAND_NONE;
retryCount = 0;
} else {
LogUtil.log(TAG, "未收到服务端开舱回复,重试");
if (Movement.getInstance().isPlaneWing()
&& Movement.getInstance().getElevation() > 40) {
retryOpen();
}
}
} else {
if (ApronExecutionStatus.getInstance().isServerReplyDockIn()) {
currentState = State.CLOSED;
desiredCommand = COMMAND_NONE;
retryCount = 0;
} else {
LogUtil.log(TAG, "未收到服务端关舱回复,重试");
retryClose();
}
}
}
}, 2000);
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
String action = isOpen ? "开舱" : "关舱";
LogUtil.log(TAG, action + "发送回调失败:" + exception);
if (isOpen) {
retryOpen();
} else {
retryClose();
}
}
});
} catch (Exception e) {
LogUtil.log(TAG, "舱门指令发送异常:" + e);
}
}
private void retryOpen() {
// 开舱优先级最高重试时不再检查冲突
retryCount++;
if (retryCount < MAX_OPEN_RETRIES) {
LogUtil.log(TAG, "开舱重试 #" + retryCount);
mainHandler.postDelayed(() -> {
currentState = State.OPENING;
sendOpenCommand();
}, RETRY_DELAY_MS);
} else {
LogUtil.log(TAG, "开舱达到最大重试次数: " + retryCount);
}
}
private void retryClose() {
// 关舱重试前检查是否有开舱请求插入
if (desiredCommand == COMMAND_OPEN) {
LogUtil.log(TAG, "开舱请求插入,停止关舱重试");
return;
}
retryCount++;
if (retryCount < MAX_CLOSE_RETRIES) {
LogUtil.log(TAG, "关舱重试 #" + retryCount);
mainHandler.postDelayed(() -> {
currentState = State.CLOSING;
sendCloseCommand();
}, RETRY_DELAY_MS);
} else {
LogUtil.log(TAG, "关舱达到最大重试次数: " + retryCount);
}
}
}

View File

@ -0,0 +1,228 @@
package com.aros.apron.manager;
import android.content.Context;
import com.aros.apron.tools.LogUtil;
import java.util.EnumSet;
import java.util.Set;
import dji.v5.common.callback.CommonCallbacks;
import dji.v5.common.error.IDJIError;
import dji.v5.common.ldm.LDMExemptModule;
import dji.v5.manager.interfaces.ILDMManager;
import dji.v5.manager.SDKManager;
/**
* LDMLocal Data Mode / 本地数据模式管理
*
* 启用后 SDK 默认不再发起任何网络请求用于隐私/合规/离线场景
* 初始化注册获取 DJI License 始终允许联网不受 LDM 限制
*/
public class LDMManager {
private static final String TAG = "LDMManager";
private Context context;
private LDMManager() {
}
private static class Holder {
private static final LDMManager INSTANCE = new LDMManager();
}
public static LDMManager getInstance() {
return Holder.INSTANCE;
}
/**
* 初始化 Context SDK 注册成功后调用一次即可
*/
public void init(Context ctx) {
this.context = ctx.getApplicationContext();
}
// ==================== 获取 SDK 原生 ILDMManager ====================
private ILDMManager getLDMManager() {
return LDMManager.getInstance().getLDMManager();
}
// ==================== 核心方法 ====================
/**
* 启用 LDM所有模块全部添加为例外都可联网
*/
public void enableLDM() {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
LogUtil.log(TAG, "enableLDM 失败LDMManager 为 null");
return;
}
if (context == null) {
LogUtil.log(TAG, "enableLDM 失败context 未初始化,请先调用 init()");
return;
}
try {
Set<LDMExemptModule> allModules = EnumSet.allOf(LDMExemptModule.class);
LogUtil.log(TAG, "启用 LDM例外模块: " + allModules);
ldmManager.enableLDM(context, new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "LDM 启用成功");
}
@Override
public void onFailure(IDJIError error) {
LogUtil.log(TAG, "LDM 启用失败: " + (error != null ? error.description() : "unknown"));
}
}, allModules.toArray(new LDMExemptModule[0]));
} catch (Exception e) {
LogUtil.log(TAG, "LDM 启用异常: " + e);
}
}
/**
* 启用 LDM指定允许联网的例外模块
*
* @param exemptModules 允许联网的模块集合 null/空集合表示全部禁止
*/
public void enableLDMWithExempt(Set<LDMExemptModule> exemptModules) {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
LogUtil.log(TAG, "enableLDMWithExempt 失败LDMManager 为 null");
return;
}
if (context == null) {
LogUtil.log(TAG, "enableLDMWithExempt 失败context 未初始化,请先调用 init()");
return;
}
try {
Set<LDMExemptModule> modules = (exemptModules != null && !exemptModules.isEmpty())
? exemptModules : EnumSet.noneOf(LDMExemptModule.class);
LogUtil.log(TAG, "启用 LDM例外模块: " + modules);
ldmManager.enableLDM(context, new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "LDM 启用成功");
}
@Override
public void onFailure(IDJIError error) {
LogUtil.log(TAG, "LDM 启用失败: " + (error != null ? error.description() : "unknown"));
}
}, modules.toArray(new LDMExemptModule[0]));
} catch (Exception e) {
LogUtil.log(TAG, "LDM 启用异常: " + e);
}
}
/**
* 启用 LDM 并允许 RTK 模块联网
* 适合使用网络 RTK 服务的场景保证定位精度
*/
public void enableLDMAllowRTK() {
Set<LDMExemptModule> exempt = EnumSet.of(LDMExemptModule.RTK);
enableLDMWithExempt(exempt);
}
/**
* 关闭 LDM恢复所有模块的网络访问
*/
public void disableLDM() {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
LogUtil.log(TAG, "disableLDM 失败LDMManager 为 null");
return;
}
if (context == null) {
LogUtil.log(TAG, "disableLDM 失败context 未初始化,请先调用 init()");
return;
}
try {
LogUtil.log(TAG, "关闭 LDM");
ldmManager.disableLDM(new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "LDM 关闭成功");
}
@Override
public void onFailure(IDJIError error) {
LogUtil.log(TAG, "LDM 关闭失败: " + (error != null ? error.description() : "unknown"));
}
});
} catch (Exception e) {
LogUtil.log(TAG, "LDM 关闭异常: " + e);
}
}
// ==================== 状态查询 ====================
/**
* 查询 LDM 是否已启用
*/
public boolean isLDMEnabled() {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
return false;
}
try {
return ldmManager.isLDMEnabled();
} catch (Exception e) {
LogUtil.log(TAG, "isLDMEnabled 异常: " + e);
return false;
}
}
/**
* 查询 LDM License 是否已加载
*/
public boolean isLDMLicenseLoaded() {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
return false;
}
try {
return ldmManager.isLDMLicenseLoaded();
} catch (Exception e) {
LogUtil.log(TAG, "isLDMLicenseLoaded 异常: " + e);
return false;
}
}
/**
* 查询指定模块是否在 LDM 模式下仍可访问网络
*/
public boolean isNetworkEnabledForModule(LDMExemptModule module) {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
return false;
}
try {
return ldmManager.isNetworkServiceEnabledForModule(module);
} catch (Exception e) {
LogUtil.log(TAG, "isNetworkServiceEnabledForModule 异常: " + e);
return false;
}
}
// ==================== License 相关 ====================
/**
* 获取本地 LDM License 文件路径需要传入 context
*/
public String getLocalLDMLicensePath() {
ILDMManager ldmManager = getLDMManager();
if (ldmManager == null) {
return "";
}
try {
return ldmManager.getLocalLDMLicensePath(context);
} catch (Exception e) {
LogUtil.log(TAG, "getLocalLDMLicensePath 异常: " + e);
return "";
}
}
}

View File

@ -88,8 +88,15 @@ public class MLTEManager extends BaseManager {
if (!info.isLTEAuthenticationAvailable() || !info.isLTEAuthenticated()) {
sendEvent2Server("⚠ LTE认证已过期或未认证需要重新认证", 1);
Movement.getInstance().setOcuSyncLte(false);
Movement.getInstance().setOcuSyncLteTime(0);
} else if (info.getLTEAuthenticatedRemainingTime() > 0 && info.getLTEAuthenticatedRemainingTime() < 3 * 24 * 3600) {
sendEvent2Server("⚠ LTE认证剩余时间不足3天请尽快重新认证", 1);
Movement.getInstance().setOcuSyncLte(true);
Movement.getInstance().setOcuSyncLteTime((int) (info.getLTEAuthenticatedRemainingTime() / (24 * 3600)));
} else {
Movement.getInstance().setOcuSyncLte(info.isLTEAuthenticated());
Movement.getInstance().setOcuSyncLteTime((int) (info.getLTEAuthenticatedRemainingTime() / (24 * 3600)));
}

View File

@ -250,34 +250,25 @@ public class MediaManager extends BaseManager {
return;
}
mState = MediaDataCenter.getInstance().getMediaManager().getMediaFileListState();
LogUtil.log(TAG, "当前状态:" + mState + ",准备拉取文件列表(已耗时" + elapsed + "s");
MediaFileListState currentState = MediaDataCenter.getInstance().getMediaManager().getMediaFileListState();
LogUtil.log(TAG, "当前状态:" + currentState + ",准备拉取文件列表(已耗时" + elapsed + "s");
// 1. 当状态为IDLE时需要调用pullMediaFileListFromCamera拉取全量数据
// 2. 当状态为UP_TO_DATE时表示拉取完成可以获取数据
if (mState == MediaFileListState.IDLE) {
// 状态为IDLE开始拉取文件列表
if (currentState == MediaFileListState.IDLE) {
LogUtil.log(TAG, "状态为IDLE开始拉取文件列表");
MediaDataCenter.getInstance().getMediaManager().pullMediaFileListFromCamera(new PullMediaFileListParam.Builder().count(-1).build(), new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG, "拉取文件列表成功");
// 重置pullqwq标志下次调用重新从IDLE拉取
pullqwq = false;
// 拉取成功后等待状态变为UP_TO_DATE
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 1000);
LogUtil.log(TAG, "拉取请求已接受等待状态变为UP_TO_DATE");
pullMediaFileListFromCameraFailTimes = 0;
}
@Override
public void onFailure(@NonNull IDJIError idjiError) {
LogUtil.log(TAG, "拉取媒体文件失败: " + new Gson().toJson(idjiError));
// 失败后重试最多重试3次
LogUtil.log(TAG, "拉取请求失败: " + new Gson().toJson(idjiError));
if (pullMediaFileListFromCameraFailTimes < 5) {
pullMediaFileListFromCameraFailTimes++;
LogUtil.log(TAG, "" + pullMediaFileListFromCameraFailTimes + "次重试...");
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 2000);
} else {
LogUtil.log(TAG, "重试次数达到上限,拉取失败");
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
sendEvent2Server("拉取媒体文件失败",2);
disablePlayback();
@ -285,7 +276,9 @@ public class MediaManager extends BaseManager {
}
}
});
} else if (mState == MediaFileListState.UP_TO_DATE) {
// 不依赖回调续命无条件调度下一轮轮询
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 1000);
} else if (currentState == MediaFileListState.UP_TO_DATE) {
// 状态为UP_TO_DATE获取文件列表数据
LogUtil.log(TAG, "状态为UP_TO_DATE获取文件列表数据");
try {
@ -299,7 +292,7 @@ public class MediaManager extends BaseManager {
if (pullMediaFileListFromCameraFailTimes < 2) {
pullMediaFileListFromCameraFailTimes++;
LogUtil.log(TAG, "" + pullMediaFileListFromCameraFailTimes + "次重试...");
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 2000);
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 3000);
} else {
LogUtil.log(TAG, "UP_TO_DATE状态文件列表持续为空确认无文件");
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
@ -357,8 +350,8 @@ public class MediaManager extends BaseManager {
}
}
} else {
// 其他状态如UPDATING等待状态变化
LogUtil.log(TAG, "状态为" + mState + ",等待状态变化... (count=" + updatingWaitCount + ")");
// 其他状态如UPDATING等待状态变化不要重复调用pullMediaFileListFromCamera
LogUtil.log(TAG, "状态为" + currentState + ",等待状态变化... (count=" + updatingWaitCount + ")");
updatingWaitCount++;
// 增加超时处理避免无限等待
@ -369,24 +362,8 @@ public class MediaManager extends BaseManager {
disablePlayback();
LogUtil.log(TAG, "发送关闭无人机");
return;
} else {
if (pullqwq == false) {
MediaDataCenter.getInstance().getMediaManager().pullMediaFileListFromCamera(new PullMediaFileListParam.Builder().count(-1).build(), new CommonCallbacks.CompletionCallback() {
@Override
public void onSuccess() {
LogUtil.log(TAG,"拉取成功");
}
@Override
public void onFailure(@NonNull IDJIError idjiError) {
LogUtil.log(TAG,"拉取失败");
}
});
pullqwq = true;
}
}
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 1000);
}
}
@ -621,7 +598,7 @@ public class MediaManager extends BaseManager {
// 上传成功重置下载重试计数
downloadFailTimes = 0;
//上传完成发送事件
sendMediaUpload2Server(mediaFile.getFileName(),mediaFiles.size(),downLoadMediaFileIndex);
sendMediaUpload2Server(mediaFile.getFileName(), downLoadMediaFileIndex + 1, mediaFiles.size());
}
@RequiresApi(Build.VERSION_CODES.O)

View File

@ -187,12 +187,10 @@ public class MissionV3Manager extends BaseManager {
Movement.getInstance().setVirtualStickQuitMission(false);
break;
case PREPARING:
Movement.getInstance().setTask_status("in_progress");
// if (PreferenceUtils.getInstance().getMissionType() == 2
@ -235,8 +233,6 @@ public class MissionV3Manager extends BaseManager {
sendEvent2Server("任务状态:进入航线飞行,飞往指定航线的第一个航点", 1);
//航线飞行
if (Movement.getInstance().getFlightmode() == 1) {
Movement.getInstance().setMode_code(5);
@ -250,7 +246,7 @@ public class MissionV3Manager extends BaseManager {
sendEvent2Server("任务状态:航线任务执行中", 1);
Movement.getInstance().setTask_status("in_progress");
Movement.getInstance().setTask_break_reason(0);
// if (PreferenceUtils.getInstance().getMissionType() == 2
// ) {
// Movement.getInstance().setTask_status("paused");
@ -273,7 +269,7 @@ public class MissionV3Manager extends BaseManager {
sendEvent2Server("任务状态:航线任务执行中断", 1);
if(PreferenceUtils.getInstance().getMissionType()==0){
if (PreferenceUtils.getInstance().getMissionType() == 0) {
Movement.getInstance().setTask_status("paused");
sendFlightTaskProgress2Server();
}
@ -312,7 +308,7 @@ public class MissionV3Manager extends BaseManager {
break;
case FINISHED:
FlyToPointManager.getInstance().setReceiverMission(false);
//释放锁
Synchronizedstatus.setIsruning(false);
Synchronizedstatus.setInitStatus(false);
@ -402,9 +398,7 @@ public class MissionV3Manager extends BaseManager {
@Override
public void onWaylineExecutingInfoUpdate(WaylineExecutingInfo excutingWaylineInfo) {
if (excutingWaylineInfo != null) {
LogUtil.log(TAG,"航点"+excutingWaylineInfo.getCurrentWaypointIndex());
LogUtil.log(TAG, "航点" + excutingWaylineInfo.getCurrentWaypointIndex());
//状态等执行完发送再更新(测试暂停时不改变index为0)
if (excutingWaylineInfo.getCurrentWaypointIndex() != 0) {
@ -416,13 +410,115 @@ public class MissionV3Manager extends BaseManager {
@Override
public void onWaylineExecutingInterruptReasonUpdate(IDJIError error) {
LogUtil.log(TAG, "航线中断原因" + error.toString());
sendEvent2Server("航线中断原因" + error.toString(), 2);
LogUtil.log(TAG, "航线中断原因" + error);
sendEvent2Server("航线中断原因" + error,1);
if (error == null) {
LogUtil.log(TAG, "航线中断原因: error为null");
return;
}
String errorCode = error.errorCode();
switch (errorCode != null ? errorCode : "") {
case "USER_BREAK":
// 用户手动停止
Movement.getInstance().setTask_break_reason(1282);
LogUtil.log(TAG, "用户主动中断航线");
sendEvent2Server("用户主动中断航线", 2);
break;
case "INTERRUPT_REASON_AVOID":
// 触发避障
Movement.getInstance().setTask_break_reason(517);
LogUtil.log(TAG, "触发避障导致航线中断");
sendEvent2Server("触发避障导致航线中断", 2);
break;
case "INTERRUPT_REASON_AVOID_EMERGENCY_BREAK":
// 触发避障而紧急刹停
Movement.getInstance().setTask_break_reason(1565);
LogUtil.log(TAG, "触发避障紧急刹停");
sendEvent2Server("触发避障紧急刹停", 2);
break;
case "INTERRUPT_REASON_AVOID_HEIGHT_LIMIT":
// 被限高或限低
Movement.getInstance().setTask_break_reason(513);
LogUtil.log(TAG, "被限高或限低导致航线中断");
sendEvent2Server("被限高或限低导致航线中断", 2);
break;
case "INTERRUPT_REASON_AVOID_RTK_UNHEALTHY":
// RTK信号异常
Movement.getInstance().setTask_break_reason(518);
LogUtil.log(TAG, "RTK信号异常导致航线中断");
sendEvent2Server("RTK信号异常导致航线中断", 2);
break;
case "INTERRUPT_REASON_AVOID_AIRPORT_LIMIT":
// 靠近机场如民航机场
Movement.getInstance().setTask_break_reason(521);
LogUtil.log(TAG, "靠近机场导致航线中断");
sendEvent2Server("靠近机场导致航线中断", 2);
break;
case "BOUNDARY_LIMIT":
// 接近限飞区
Movement.getInstance().setTask_break_reason(515);
LogUtil.log(TAG, "接近限飞区导致航线中断");
sendEvent2Server("接近限飞区导致航线中断", 2);
break;
case "INTERRUPT_REASON_LOW_BATTERY":
// 低电量中断
Movement.getInstance().setTask_break_reason(773);
LogUtil.log(TAG, "低电量触发航线中断");
sendEvent2Server("低电量触发航线中断", 2);
break;
case "INTERRUPT_REASON_RC_SIGNAL_LOST":
// 遥控器信号丢失
Movement.getInstance().setTask_break_reason(775);
LogUtil.log(TAG, "遥控器信号丢失,航线中断");
sendEvent2Server("遥控器信号丢失,航线中断", 2);
break;
case "INTERRUPT_REASON_GPS_INVALID":
// GPS 信号无效
Movement.getInstance().setTask_break_reason(769);
LogUtil.log(TAG, "GPS信号无效航线中断");
sendEvent2Server("GPS信号无效航线中断", 2);
break;
default:
LogUtil.log(TAG, "未知航线中断原因: " + errorCode);
Movement.getInstance().setTask_break_reason(65535);
sendEvent2Server("未知航线中断原因", 2);
break;
}
//LogUtil.log(TAG, "航线中断: ---" + new Gson().toJson(error));
// sendEvent2Server("航线中断原因: " + errorCode, 2);
// LogUtil.log(TAG, "航线中断原因" + error);
if (error.errorCode().equals("USER_BREAK")
|| error.errorCode().equals("INTERRUPT_REASON_AVOID_USER_REQ_BREAK"))
{//如果是手动暂停航线,则不会触发返航或拉高
return;
} else {
if (PreferenceUtils.getInstance().getMissionInterruptAction() == 2) {
if (error.errorCode().equals("INTERRUPT_REASON_AVOID") ||
error.errorCode().equals("INTERRUPT_REASON_AVOID_HEIGHT_LIMIT")) {
mainHandler.postDelayed(new Runnable() {
@Override
public void run() {
resumeMission(null);
}
}, 1000);
} else {
WayLineExecutingInterruptManager.getInstance().onExecutingInterruptToDo();
}
} else if (PreferenceUtils.getInstance().getMissionInterruptAction() == 3) {
WayLineExecutingInterruptManager.getInstance().onExecutingInterruptToDo();
return;
}
}
}
});
waypointMissionManager.addWaypointActionListener(new WaypointActionListener() {
@Override
public void onExecutionStart(int actionId) {
@ -478,7 +574,6 @@ public class MissionV3Manager extends BaseManager {
Movement.getInstance().setTask_current_step(5);
//1.检查图传是否连接
//避免重复执行
if (isReceiverMission == false) {
@ -495,7 +590,7 @@ public class MissionV3Manager extends BaseManager {
verifyGpsAndMissionState(message);
}
// verifyGpsAndMissionState(message);
// verifyGpsAndMissionState(message);
}
@ -575,14 +670,14 @@ public class MissionV3Manager extends BaseManager {
boolean isMissionStateValid = (missionStateCode == 2 || missionStateCode == 0 || missionStateCode == 7);
boolean isPlaneMessageValid = !TextUtils.isEmpty(planeMessage) && !planeMessage.equals("无法起飞");
boolean isGpsQualityValid = (quality == 4 || quality == 5 || quality == 10 ||quality == 3);
boolean isGpsQualityValid = (quality == 4 || quality == 5 || quality == 10 || quality == 3);
boolean GPSSatelliteCountValid = GPSSatelliteCount > 12;
LogUtil.log(TAG, "isMissionStateValid" + isMissionStateValid + "isPlaneMessageValid" + isPlaneMessageValid + "isGpsQualityValid" + isGpsQualityValid);
// if (isMissionStateValid && isPlaneMessageValid && isGpsQualityValid) {
sendEvent2Server("卫星数量" + GPSSatelliteCount + "gps是否ok" + GPSSatelliteCountValid, 1);
if (isGpsQualityValid || GPSSatelliteCountValid ) {
if (isGpsQualityValid || GPSSatelliteCountValid) {
//5.下载航线
downLoadKMZFile(message);
sendEvent2Server("执行下载航线成功", 1);
@ -596,6 +691,13 @@ public class MissionV3Manager extends BaseManager {
public void run() {
verifyGpsAndMissionStateTimes++;
verifyGpsAndMissionState(message);
LogUtil.log(TAG, "航线状态第" + verifyGpsAndMissionStateTimes + "次检索失败:" +
WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
Movement.getInstance().getPlaneMessage() +
"-GPS信号等级:" + Movement.getInstance().getQuality());
sendEvent2Server("航线状态第" + verifyGpsAndMissionStateTimes + "次检索失败:" +
WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
@ -605,6 +707,11 @@ public class MissionV3Manager extends BaseManager {
}, 2000);
} else {
LogUtil.log(TAG, "飞行器自检异常:" + WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
Movement.getInstance().getPlaneMessage() +
"-GPS信号等级:" + Movement.getInstance().getQuality());
sendEvent2Server("飞行器自检异常:" + WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
Movement.getInstance().getPlaneMessage() +
@ -630,7 +737,7 @@ public class MissionV3Manager extends BaseManager {
@Override
public void onFailure(Call call, IOException e) {
sendEvent2Server("任务下载失败:" + e.toString(), 2);
// LogUtil.log(TAG, "任务下载失败");
LogUtil.log(TAG, "任务下载失败");
TaskFailManager.getInstance().sendTaskFailMsg2Server(-1);
}
@ -655,6 +762,7 @@ public class MissionV3Manager extends BaseManager {
}
fos.flush();
sendEvent2Server("航线下载成功 ", 1);
LogUtil.log(TAG, "航线下载成功2");
//LogUtil.log(TAG, "航线下载成功");
mainHandler.post(new Runnable() {
@Override
@ -664,7 +772,7 @@ public class MissionV3Manager extends BaseManager {
});
} catch (Exception e) {
sendEvent2Server("任务下载失败,网络异常:" + e.toString(), 2);
//LogUtil.log(TAG, "任务下载失败,网络异常");
LogUtil.log(TAG, "任务下载失败,网络异常");
TaskFailManager.getInstance().sendTaskFailMsg2Server(-1);
}
}
@ -798,7 +906,7 @@ public class MissionV3Manager extends BaseManager {
* @param message
*/
public void startMission(MessageDown message) {
Boolean isConnect =true;
Boolean isConnect = true;
if (isConnect != null && isConnect) {
int missionStateCode = Movement.getInstance().getMissionStateCode();
//每次航线开始时重置是否需要识别二维码状态避免刚起飞就识别二维码/并确保不是飞向备降点的航线
@ -892,13 +1000,12 @@ public class MissionV3Manager extends BaseManager {
public void onSuccess() {
sendMsg2Server(message);
if( PreferenceUtils.getInstance().getMissionType()==0){
if (PreferenceUtils.getInstance().getMissionType() == 0) {
Movement.getInstance().setTask_status("paused");
sendFlightTaskProgress2Server();
}
//暂停成功就是手动飞行
Movement.getInstance().setMode_code(3);
@ -920,7 +1027,7 @@ public class MissionV3Manager extends BaseManager {
KeyConnection));
if (isConnect != null && isConnect) {
if (isConnect == null || !isConnect || !getGimbalAndCameraEnabled()) {
LogUtil.log(TAG,"当前状态禁止恢复");
LogUtil.log(TAG, "当前状态禁止恢复");
sendFailMsg2Server(message, "当前状态禁止恢复");
return;
}
@ -937,14 +1044,14 @@ public class MissionV3Manager extends BaseManager {
sendMsg2Server(message);
Movement.getInstance().setTask_status("in_progress");
if( PreferenceUtils.getInstance().getMissionType()==0){
if (PreferenceUtils.getInstance().getMissionType() == 0) {
Movement.getInstance().setCameraMode(5);
}else if( PreferenceUtils.getInstance().getMissionType()==1){
} else if (PreferenceUtils.getInstance().getMissionType() == 1) {
Movement.getInstance().setCameraMode(17);
}
if(PreferenceUtils.getInstance().getMissionType()==0){
if (PreferenceUtils.getInstance().getMissionType() == 0) {
sendFlightTaskProgress2Server();
}
@ -972,15 +1079,15 @@ public class MissionV3Manager extends BaseManager {
sendMsg2Server(message);
PreferenceUtils.getInstance().setIsNewRoute(false);
if( PreferenceUtils.getInstance().getMissionType()==0){
if (PreferenceUtils.getInstance().getMissionType() == 0) {
Movement.getInstance().setCameraMode(5);
}else if( PreferenceUtils.getInstance().getMissionType()==1){
} else if (PreferenceUtils.getInstance().getMissionType() == 1) {
Movement.getInstance().setCameraMode(17);
}
LogUtil.log(TAG, "恢复断点航线成功");
Movement.getInstance().setTask_status("in_progress");
if(PreferenceUtils.getInstance().getMissionType()==0){
if (PreferenceUtils.getInstance().getMissionType() == 0) {
sendFlightTaskProgress2Server();
}
@ -1034,7 +1141,7 @@ public class MissionV3Manager extends BaseManager {
LogUtil.log(TAG, "图传仍未恢复,重启 AMS 第 " + (times + 1) + "");
mainHandler.postDelayed(() ->
RestartAPPTool.INSTANCE.restartApp(ApronApp.Companion.getContext()), 1000);
}else{
} else {
sendEvent2Server("达到重启最大次数还没有获得图传", 2);
TaskFailManager.getInstance().sendTaskFailMsg2Server(-1);
}

View File

@ -181,26 +181,31 @@ public class OSDManager extends BaseManager {
cameraA.setCamera_mode(Movement.getInstance().getCamera_mode());
cameraA.setIr_metering_mode(Movement.getInstance().getIr_metering_mode());
cameraA.setCamera_mode(Movement.getInstance().getCamera_mode());
irMeteringPoint.setTemperature(Movement.getInstance().getTemperature());
irMeteringPoint.setX(Movement.getInstance().getX());
irMeteringPoint.setY(Movement.getInstance().getY());
cameraA.setIr_metering_point(irMeteringPoint);
Osd.Data.Cameras.IrMeteringArea irMeteringArea = new Osd.Data.Cameras.IrMeteringArea();
irMeteringArea.setX(0);
irMeteringArea.setY(0);
irMeteringArea.setWidth(0);
irMeteringArea.setHeight(0);
irMeteringArea.setAver_temperature(0);
irMeteringArea.setX(Movement.getInstance().getIr_region_x());
irMeteringArea.setY(Movement.getInstance().getIr_region_y());
irMeteringArea.setWidth(Movement.getInstance().getIr_region_width());
irMeteringArea.setHeight(Movement.getInstance().getIr_region_height());
irMeteringArea.setAver_temperature(Movement.getInstance().getIr_region_aver_temperature());
Osd.Data.Cameras.IrTemperaturePoint irMinTemp = new Osd.Data.Cameras.IrTemperaturePoint();
irMinTemp.setX(0);
irMinTemp.setY(0);
irMinTemp.setTemperature(0);
irMinTemp.setX(Movement.getInstance().getIr_region_min_temperature_x());
irMinTemp.setY(Movement.getInstance().getIr_region_min_temperature_y());
irMinTemp.setTemperature(Movement.getInstance().getIr_region_min_temperature());
irMeteringArea.setMin_temperature_point(irMinTemp);
Osd.Data.Cameras.IrTemperaturePoint irMaxTemp = new Osd.Data.Cameras.IrTemperaturePoint();
irMaxTemp.setX(0);
irMaxTemp.setY(0);
irMaxTemp.setTemperature(0);
irMaxTemp.setX(Movement.getInstance().getIr_region_max_temperature_x());
irMaxTemp.setY(Movement.getInstance().getIr_region_max_temperature_y());
irMaxTemp.setTemperature(Movement.getInstance().getIr_region_max_temperature());
irMeteringArea.setMax_temperature_point(irMaxTemp);
cameraA.setIr_metering_area(irMeteringArea);
cameraA.setIr_zoom_factor(Movement.getInstance().getIr_zoom_factor());
cameraA.setPayload_index("53-0-0");
@ -276,6 +281,8 @@ public class OSDManager extends BaseManager {
data.setVertical_speed(Movement.getInstance().getVertical_speed());
data.setWind_direction(Movement.getInstance().getWind_direction());
data.setWind_speed(Movement.getInstance().getWind_speed());
data.setOcu_sync_lte(Movement.getInstance().isOcuSyncLte());
data.setOcu_sync_lte_time(Movement.getInstance().getOcuSyncLteTime());
Osd.Data.MaintainStatus maintainStatus = new Osd.Data.MaintainStatus();
Osd.Data.MaintainStatus.MaintainStatusArray maintainItem = new Osd.Data.MaintainStatus.MaintainStatusArray();

View File

@ -0,0 +1,158 @@
package com.aros.apron.manager;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import com.aros.apron.base.BaseManager;
import com.aros.apron.constant.AMSConfig;
import com.aros.apron.entity.Movement;
import com.aros.apron.entity.ReturnHomeInfo;
import com.aros.apron.entity.ReturnHomeInfo.PathPoint;
import com.aros.apron.tools.LogUtil;
import com.aros.apron.tools.PreferenceUtils;
import com.google.gson.Gson;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import dji.sdk.keyvalue.key.FlightControllerKey;
import dji.sdk.keyvalue.key.KeyTools;
import dji.sdk.keyvalue.value.common.LocationCoordinate3D;
import dji.v5.manager.KeyManager;
import com.aros.apron.tools.MqttManager;
/**
* 返航轨迹记录管理器
* 每2s上报3个点
* index 0: 飞机当前位置实时
* index 1: 飞机与返航点之间的中点实时计算
* index 2: 返航点固定
*/
public class RTHTrackerManager extends BaseManager {
private static final String TAG = "RTHTrackerManager";
private static final long REPORT_INTERVAL_MS = 2000;
private RTHTrackerManager() {
}
private static class RTHTrackerHolder {
private static final RTHTrackerManager INSTANCE = new RTHTrackerManager();
}
public static RTHTrackerManager getInstance() {
return RTHTrackerHolder.INSTANCE;
}
private final Handler mHandler = new Handler(Looper.getMainLooper());
private boolean isRunning = false;
private final Runnable reportRunnable = new Runnable() {
@Override
public void run() {
sendReturnHomeInfo();
if (isRunning) {
mHandler.postDelayed(this, REPORT_INTERVAL_MS);
}
}
};
/**
* 开始定时上报返航轨迹每2s一次
*/
public void startReporting() {
if (isRunning) {
LogUtil.log(TAG, "返航轨迹上报已在运行中");
return;
}
isRunning = true;
mHandler.post(reportRunnable);
LogUtil.log(TAG, "开启返航轨迹定时上报,间隔: " + REPORT_INTERVAL_MS + "ms");
}
/**
* 停止定时上报
*/
public void stopReporting() {
isRunning = false;
mHandler.removeCallbacks(reportRunnable);
LogUtil.log(TAG, "关闭返航轨迹定时上报");
}
/**
* 发送返航轨迹信息到服务器
* 3个点当前位置 -> 中间点 -> 返航点
*/
private void sendReturnHomeInfo() {
try {
if (!MqttManager.getInstance().mqttAndroidClient.isConnected()) {
return;
}
// 获取飞机当前位置
LocationCoordinate3D currentLocation =
KeyManager.getInstance().getValue(
KeyTools.createKey(FlightControllerKey.KeyAircraftLocation3D));
if (currentLocation == null) {
return;
}
double currentLat = currentLocation.getLatitude();
double currentLng = currentLocation.getLongitude();
Double altDouble = currentLocation.getAltitude();
double currentAlt = altDouble != null ? altDouble : 0;
// 获取返航点
double homeLat = Movement.getInstance().getHomepoint_latitude();
double homeLng = Movement.getInstance().getHomepoint_longitude();
// 计算中点
double midLat = (currentLat + homeLat) / 2.0;
double midLng = (currentLng + homeLng) / 2.0;
double midAlt = currentAlt;
// 构建3个点
List<PathPoint> pathPoints = new ArrayList<>(3);
pathPoints.add(new PathPoint(currentLat, currentLng, (float) currentAlt)); // index 0: 飞机当前位置
pathPoints.add(new PathPoint(midLat, midLng, (float) midAlt)); // index 1: 中间点
pathPoints.add(new PathPoint(homeLat, homeLng, (float) currentAlt)); // index 2: 返航点
ReturnHomeInfo returnHomeInfo = new ReturnHomeInfo();
returnHomeInfo.setBid(UUID.randomUUID().toString());
returnHomeInfo.setTid(UUID.randomUUID().toString());
returnHomeInfo.setTimestamp(System.currentTimeMillis());
returnHomeInfo.setMethod("return_home_info");
ReturnHomeInfo.Data data = new ReturnHomeInfo.Data();
String flightId = PreferenceUtils.getInstance().getFlightId();
data.setFlight_id(TextUtils.isEmpty(flightId) ? "null" : flightId);
data.setLast_point_type(0);
data.setPlanned_path_points(pathPoints);
returnHomeInfo.setData(data);
String json = new Gson().toJson(returnHomeInfo);
MqttMessage mqttMessage = new MqttMessage(json.getBytes("UTF-8"));
mqttMessage.setQos(0);
MqttManager.getInstance().mqttAndroidClient.publish(AMSConfig.UP_UAV_EVENT, mqttMessage);
// LogUtil.log(TAG, String.format("发送返航轨迹 - 飞机:[%.6f,%.6f,%.1f] 中点:[%.6f,%.6f,%.1f] 返航:[%.6f,%.6f,%.1f]",
// currentLat, currentLng, currentAlt, midLat, midLng, midAlt, homeLat, homeLng, currentAlt));
} catch (Exception e) {
LogUtil.log(TAG, "发送return_home_info异常: " + e.getMessage());
}
}
/**
* 重置状态
*/
public void reset() {
stopReporting();
}
}

View File

@ -307,13 +307,9 @@ public class StickManager extends BaseManager {
param.setVerticalControlMode(VerticalControlMode.VELOCITY);
param.setRollPitchCoordinateSystem(FlightCoordinateSystem.BODY);
if (!TextUtils.isEmpty(message.getData().getY())) {
param.setPitch(Double.valueOf(message.getData().getY()));//左右(速度模式-10m/s-10m/s)
}
if (!TextUtils.isEmpty(message.getData().getX())) {
param.setRoll(Double.valueOf(message.getData().getX()));//前后(速度模式-10m/s-10m/s)
param.setPitch(message.getData().getY());//左右(速度模式-10m/s-10m/s)
param.setRoll(message.getData().getX());//前后(速度模式-10m/s-10m/s)
}
if (!TextUtils.isEmpty(message.getData().getW())) {
param.setYaw(Double.valueOf(message.getData().getW()));//旋转(角速度模式-100-100)

View File

@ -276,6 +276,9 @@ public class StreamManager extends BaseManager {
private int isliveindex = 1; //1 代表 port 2 代表 fpv
public void switchptspfpv(ComponentIndexType ComponentIndex, MessageDown message) {
if(isliveindex==2){
return;
}
isliveindex = 2;
sendMsg2Server(message);
ILiveStreamManager liveStreamManager = MediaDataCenter.getInstance().getLiveStreamManager();
@ -298,6 +301,9 @@ public class StreamManager extends BaseManager {
}
public void switchptspport(ComponentIndexType ComponentIndex, MessageDown message) {
if(isliveindex==1){
return;
}
isliveindex = 1;
sendMsg2Server(message);
ILiveStreamManager liveStreamManager = MediaDataCenter.getInstance().getLiveStreamManager();
@ -330,7 +336,6 @@ public class StreamManager extends BaseManager {
streamExecutor.execute(() -> {
isStartingRTSP = true;
// 每次新推流尝试清零所有状态标志修复 Bug 1, 2, 5
if (startLiveFailTimes == 0) {
isLiveStreamAlreadyStart = false;
LogUtil.log(TAG, "========== 开始 RTSP 推流流程 ==========");
@ -350,7 +355,6 @@ public class StreamManager extends BaseManager {
return;
}
// 1. 检查是否已经在推流避免重复启动
if (liveStreamManager.isStreaming()) {
LogUtil.log(TAG, "RTSP 推流已在运行,无需重复启动");
isLiveStreamAlreadyStart = true;
@ -358,7 +362,6 @@ public class StreamManager extends BaseManager {
return;
}
// 2. 检查相机流是否准备好
if (!MainActivity.Companion.getStreamReceive()) {
LogUtil.log(TAG, "相机流未准备好,尝试模拟点击 FPV Widget 恢复");
mainHandler.post(() -> {
@ -381,7 +384,7 @@ public class StreamManager extends BaseManager {
return;
}
// 3. 检查 RTSP 配置
String rtspUser = PreferenceUtils.getInstance().getRtspUserName();
String rtspPort = PreferenceUtils.getInstance().getRtspPort();
String rtspPass = PreferenceUtils.getInstance().getRtspPassWord();
@ -395,14 +398,14 @@ public class StreamManager extends BaseManager {
LogUtil.log(TAG, "RTSP 配置检查通过user=" + rtspUser + ", port=" + rtspPort + ", camera=" + (isliveindex == 1 ? "PORT_1" : "FPV"));
// 4. 等待相机模式稳定避免刚切换模式就推流
//等待相机模式稳定避免刚切换模式就推流
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 5. 设置 RTSP 参数在主线程执行
//设置 RTSP 参数
final ILiveStreamManager finalLiveStreamManager = liveStreamManager;
mainHandler.post(() -> {
LiveStreamSettings.Builder streamSettingBuilder = new LiveStreamSettings.Builder();
@ -416,17 +419,15 @@ public class StreamManager extends BaseManager {
finalLiveStreamManager.setLiveStreamSettings(streamSettings);
// 6. 设置相机源
// 设置相机源
ComponentIndexType cameraIndex = (isliveindex == 1) ? ComponentIndexType.PORT_1 : ComponentIndexType.FPV;
finalLiveStreamManager.setCameraIndex(cameraIndex);
// 7. 设置推流质量
finalLiveStreamManager.setLiveStreamQuality(StreamQuality.FULL_HD);
finalLiveStreamManager.setLiveVideoBitrateMode(LiveVideoBitrateMode.AUTO);
LogUtil.log(TAG, "RTSP 参数设置完成,等待 500ms 后启动推流");
// 8. 等待设置生效
mainHandler.postDelayed(() -> {
streamExecutor.execute(() -> {
// 9. 启动推流前再次检查
@ -449,7 +450,6 @@ public class StreamManager extends BaseManager {
// ========== 新增实际启动流的私有方法确保在子线程执行 ==========
private void doStartLiveWithRTSP(ILiveStreamManager liveStreamManager, boolean isRestart) {
// 启动前再次检查状态
if (liveStreamManager.isStreaming()) {
LogUtil.log(TAG, "推流已在运行,跳过启动 (isRestart=" + isRestart + ")");
isLiveStreamAlreadyStart = true;

View File

@ -202,6 +202,13 @@ public class TakeOffToPointManager extends BaseManager {
public void run() {
verifyGpsAndMissionStateTimes++;
verifyGpsAndMissionState(message);
LogUtil.log(TAG,"航线状态第" + verifyGpsAndMissionStateTimes + "次检索失败:" +
WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
Movement.getInstance().getPlaneMessage() +
"-GPS信号等级:" + Movement.getInstance().getQuality());
sendEvent2Server("航线状态第" + verifyGpsAndMissionStateTimes + "次检索失败:" +
WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
@ -212,6 +219,12 @@ public class TakeOffToPointManager extends BaseManager {
} else {
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
LogUtil.log(TAG,"飞行器自检异常:" + WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
Movement.getInstance().getPlaneMessage() +
"-GPS信号等级:" + Movement.getInstance().getQuality());
sendEvent2Server("飞行器自检异常:" + WaypointMissionExecuteState.find(missionStateCode).name() +
"-RTK:" + Movement.getInstance().getIs_fixed() + "-飞行器状态:" +
Movement.getInstance().getPlaneMessage() +

View File

@ -0,0 +1,145 @@
package com.aros.apron.manager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import androidx.core.app.NotificationCompat;
import androidx.core.content.FileProvider;
import com.aros.apron.R;
import com.aros.apron.tools.LogUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class UpdateManager {
private static final String TAG = "UpdateManager";
private static final String CHANNEL_ID = "app_update_channel";
private static final int NOTIFICATION_ID = 1001;
private static UpdateManager instance;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private UpdateManager() {}
public static synchronized UpdateManager getInstance() {
if (instance == null) {
instance = new UpdateManager();
}
return instance;
}
/**
* 开始下载并安装APK
* @param context 上下文
* @param apkUrl APK下载链接
* @param replyCallback 下载完成后回复服务器的回调
*/
public void startUpdate(Context context, String apkUrl, Runnable replyCallback) {
LogUtil.log(TAG, "开始远程更新: " + apkUrl);
showNotification(context, 0);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(apkUrl).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtil.log(TAG, "APK下载失败: " + e.toString());
mainHandler.post(() -> {
if (replyCallback != null) replyCallback.run();
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response == null || !response.isSuccessful()) {
LogUtil.log(TAG, "APK下载失败, 状态码: " + (response != null ? response.code() : "null"));
mainHandler.post(() -> {
if (replyCallback != null) replyCallback.run();
});
return;
}
long totalSize = response.body().contentLength();
long downloaded = 0;
File apkFile = new File(context.getExternalFilesDir(null), "app_update.apk");
try (InputStream is = response.body().byteStream();
OutputStream os = new FileOutputStream(apkFile)) {
byte[] buffer = new byte[8192];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
downloaded += len;
final int progress = (int) ((downloaded * 100) / totalSize);
mainHandler.post(() -> showNotification(context, progress));
}
os.flush();
LogUtil.log(TAG, "APK下载完成: " + apkFile.getAbsolutePath());
mainHandler.post(() -> {
showNotification(context, 100);
installApk(context, apkFile);
if (replyCallback != null) replyCallback.run();
});
} catch (Exception e) {
LogUtil.log(TAG, "APK写入失败: " + e.toString());
mainHandler.post(() -> {
if (replyCallback != null) replyCallback.run();
});
}
}
});
}
private void showNotification(Context context, int progress) {
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "应用更新", NotificationManager.IMPORTANCE_LOW);
manager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("正在更新应用")
.setSmallIcon(R.mipmap.ic_launcher)
.setProgress(100, progress, false)
.setContentText(progress + "%")
.setOngoing(true);
manager.notify(NOTIFICATION_ID, builder.build());
}
private void installApk(Context context, File apkFile) {
Uri apkUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", apkFile);
} else {
apkUri = Uri.fromFile(apkFile);
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}

View File

@ -702,7 +702,7 @@ public class Aprondown {
@Override
public void run() {
performOperation();
if (handlerCallbackCount < 20) {
if (handlerCallbackCount < 15) {
handler.postDelayed(this, 50);
} else {
performNextStep();

View File

@ -269,7 +269,7 @@ public class Aprongim {
}else{
if (ultHeight <=5)
{
LENS_OFFSET_X=100;
LENS_OFFSET_X=120;
LENS_OFFSET_Y = 100;
}else if(ultHeight<10){
LENS_OFFSET_X=80;
@ -562,7 +562,7 @@ public class Aprongim {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 + 200.0;
double errX = cx - imgWidth / 2.0 + 120.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 55 && Math.abs(errY) < 70) { landingCounters[13]++; } else { landingCounters[13] = 0; }
if (landingCounters[13] >= 2 && !foundLanding) { foundLanding = true; landingId = 13; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
@ -577,7 +577,7 @@ public class Aprongim {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[15]++; } else { landingCounters[15] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[15]++; } else { landingCounters[15] = 0; }
if (landingCounters[15] >= 2 && !foundLanding) { foundLanding = true; landingId = 15; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[15] = 0; }
@ -588,7 +588,7 @@ public class Aprongim {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - 200.0;
double errX = cx - imgWidth / 2.0 - 150.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 55 && Math.abs(errY) < 70) { landingCounters[17]++; } else { landingCounters[17] = 0; }
if (landingCounters[17] >= 2 && !foundLanding) { foundLanding = true; landingId = 17; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
@ -601,9 +601,9 @@ public class Aprongim {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 + 200.0;
double errX = cx - imgWidth / 2.0 + 120.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[14]++; } else { landingCounters[14] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[14]++; } else { landingCounters[14] = 0; }
if (landingCounters[14] >= 2 && !foundLanding) { foundLanding = true; landingId = 14; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[14] = 0; }
@ -616,7 +616,7 @@ public class Aprongim {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (landingCounters[16] >= 2 && !foundLanding) { foundLanding = true; landingId = 16; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[16] = 0; }
@ -627,7 +627,7 @@ public class Aprongim {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - 200.0;
double errX = cx - imgWidth / 2.0 - 150.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 55 && Math.abs(errY) < 70) { landingCounters[18]++; } else { landingCounters[18] = 0; }
if (landingCounters[18] >= 2 && !foundLanding) { foundLanding = true; landingId = 18; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
@ -657,7 +657,7 @@ public class Aprongim {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[17]++; } else { landingCounters[17] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[17]++; } else { landingCounters[17] = 0; }
if (landingCounters[17] >= 2 && !foundLanding) { foundLanding = true; landingId = 17; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[17] = 0; }
@ -683,7 +683,7 @@ public class Aprongim {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 +240.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (landingCounters[16] >= 2 && !foundLanding) { foundLanding = true; landingId = 16; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[16] = 0; }
@ -696,7 +696,7 @@ public class Aprongim {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[18]++; } else { landingCounters[18] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[18]++; } else { landingCounters[18] = 0; }
if (landingCounters[18] >= 2 && !foundLanding) { foundLanding = true; landingId = 18; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[18] = 0; }
@ -740,8 +740,8 @@ public class Aprongim {
// 分段PID控制原有逻辑保持不变
if(z <= 0.4){
pidControlX.setInputFilterAll((float)offsetX/1750);
pidControlY.setInputFilterAll(-(float)offsetY/1750);
pidControlX.setInputFilterAll((float)offsetX/1800);
pidControlY.setInputFilterAll(-(float)offsetY/1800);
if (pidControlX.get_pid()<0){
if (pidControlX.get_pid()<-0.125){
outX=absX<120?0:-0.125;
@ -1085,7 +1085,7 @@ public class Aprongim {
@Override
public void run() {
performOperation();
if (handlerCallbackCount < 20) {
if (handlerCallbackCount < 15) {
handler.postDelayed(this, 50);
} else {
performNextStep();

View File

@ -823,7 +823,7 @@ public class ApronArucoDetect {
@Override
public void run() {
performOperation();
if (handlerCallbackCount < 20) {
if (handlerCallbackCount < 15) {
handler.postDelayed(this, 50);
} else {
performNextStep();

View File

@ -192,8 +192,8 @@ public class ApronArucoDetectPort {
}else{
if (ultHeight <=5)
{
LENS_OFFSET_X=100;
LENS_OFFSET_Y = 100;
LENS_OFFSET_X=120;
LENS_OFFSET_Y = 120;
}else if(ultHeight<10){
LENS_OFFSET_X=80;
LENS_OFFSET_Y = 80;
@ -484,7 +484,7 @@ public class ApronArucoDetectPort {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 + 200.0;
double errX = cx - imgWidth / 2.0 + 150.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 55 && Math.abs(errY) < 70) { landingCounters[13]++; } else { landingCounters[13] = 0; }
if (landingCounters[13] >= 2 && !foundLanding) { foundLanding = true; landingId = 13; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
@ -499,7 +499,7 @@ public class ApronArucoDetectPort {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[15]++; } else { landingCounters[15] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[15]++; } else { landingCounters[15] = 0; }
if (landingCounters[15] >= 2 && !foundLanding) { foundLanding = true; landingId = 15; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[15] = 0; }
@ -510,7 +510,7 @@ public class ApronArucoDetectPort {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - 200.0;
double errX = cx - imgWidth / 2.0 - 150.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 55 && Math.abs(errY) < 70) { landingCounters[17]++; } else { landingCounters[17] = 0; }
if (landingCounters[17] >= 2 && !foundLanding) { foundLanding = true; landingId = 17; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
@ -523,9 +523,9 @@ public class ApronArucoDetectPort {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 + 200.0;
double errX = cx - imgWidth / 2.0 + 150.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[14]++; } else { landingCounters[14] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[14]++; } else { landingCounters[14] = 0; }
if (landingCounters[14] >= 2 && !foundLanding) { foundLanding = true; landingId = 14; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[14] = 0; }
@ -538,7 +538,7 @@ public class ApronArucoDetectPort {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (landingCounters[16] >= 2 && !foundLanding) { foundLanding = true; landingId = 16; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[16] = 0; }
@ -549,7 +549,7 @@ public class ApronArucoDetectPort {
double cx = 0, cy = 0;
for (int i = 0; i < 4; i++) { double[] p = corner.get(0, i); cx += p[0]; cy += p[1]; }
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - 200.0;
double errX = cx - imgWidth / 2.0 - 150.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 55 && Math.abs(errY) < 70) { landingCounters[18]++; } else { landingCounters[18] = 0; }
if (landingCounters[18] >= 2 && !foundLanding) { foundLanding = true; landingId = 18; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
@ -579,7 +579,7 @@ public class ApronArucoDetectPort {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[17]++; } else { landingCounters[17] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[17]++; } else { landingCounters[17] = 0; }
if (landingCounters[17] >= 2 && !foundLanding) { foundLanding = true; landingId = 17; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[17] = 0; }
@ -605,7 +605,7 @@ public class ApronArucoDetectPort {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 +240.0;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[16]++; } else { landingCounters[16] = 0; }
if (landingCounters[16] >= 2 && !foundLanding) { foundLanding = true; landingId = 16; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[16] = 0; }
@ -618,7 +618,7 @@ public class ApronArucoDetectPort {
cx /= 4.0; cy /= 4.0;
double errX = cx - imgWidth / 2.0 - LENS_OFFSET_X;
double errY = cy - imgHeight / 2.0 + LENS_OFFSET_Y;
if (Math.abs(errX) < 70 && Math.abs(errY) < 70) { landingCounters[18]++; } else { landingCounters[18] = 0; }
if (Math.abs(errX) < 60 && Math.abs(errY) < 70) { landingCounters[18]++; } else { landingCounters[18] = 0; }
if (landingCounters[18] >= 2 && !foundLanding) { foundLanding = true; landingId = 18; isSpecialLanding = true; singleErrX = errX; singleErrY = errY; offsetX = singleErrX; offsetY = singleErrY; absX = Math.abs(singleErrX); absY = Math.abs(singleErrY); }
} else { landingCounters[18] = 0; }
@ -662,8 +662,8 @@ public class ApronArucoDetectPort {
// 分段PID控制原有逻辑保持不变
if(z <= 0.4){
pidControlX.setInputFilterAll((float)offsetX/1750);
pidControlY.setInputFilterAll(-(float)offsetY/1750);
pidControlX.setInputFilterAll((float)offsetX/1800);
pidControlY.setInputFilterAll(-(float)offsetY/1800);
if (pidControlX.get_pid()<0){
if (pidControlX.get_pid()<-0.125){
outX=absX<120?0:-0.125;
@ -1019,7 +1019,7 @@ public class ApronArucoDetectPort {
@Override
public void run() {
performOperation();
if (handlerCallbackCount < 20) {
if (handlerCallbackCount < 15) {
handler.postDelayed(this, 50);
} else {
performNextStep();

File diff suppressed because it is too large Load Diff

View File

@ -239,6 +239,28 @@ public class DroneHelper {
}
);
} else {
GimbalAngleRotation rotation = new GimbalAngleRotation();
rotation.setMode(GimbalAngleRotationMode.ABSOLUTE_ANGLE);
rotation.setYaw(0.0);
rotation.setRoll(0.0);
rotation.setPitch(-90.0);
KeyManager.getInstance().performAction(KeyTools.createKey(GimbalKey.KeyRotateByAngle, ComponentIndexType.PORT_1), rotation, new CommonCallbacks.CompletionCallbackWithParam<EmptyMsg>() {
@Override
public void onSuccess(EmptyMsg emptyMsg) {
LogUtil.log(TAG, "云台朝下");
isGimbalPitchDegree = true;
setGimbalPitchDegreeFailTimes = 0;
}
@Override
public void onFailure(@NonNull IDJIError error) {
LogUtil.log(TAG, "fail:" + error.toString());
retryGimbalPitchDegree();
}
}
);
LogUtil.log(TAG, "云台未连接");
retryGimbalPitchDegree();
}

View File

@ -0,0 +1,259 @@
package com.aros.apron.tools;
import android.os.Handler;
import android.os.Looper;
import com.aros.apron.constant.AMSConfig;
import com.aros.apron.entity.FlyToPointProgress;
import com.aros.apron.entity.Movement;
import com.google.gson.Gson;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import dji.sdk.keyvalue.key.FlightControllerKey;
import dji.sdk.keyvalue.key.KeyTools;
import dji.sdk.keyvalue.value.common.LocationCoordinate3D;
import dji.v5.manager.KeyManager;
/**
* 飞向目标点进度定时上报器
* 协议: fly_to_point_progress
*/
public class FlyToPointProgressScheduler {
private static final String TAG = "FlyToPointProgressScheduler";
private static volatile FlyToPointProgressScheduler instance;
private Handler reportHandler;
private Runnable reportRunnable;
private volatile boolean isRunning = false;
// 轨迹点缓存
private List<FlyToPointProgress.PlannedPathPoint> pathPoints;
// 采样间隔 1秒
private static final long REPORT_INTERVAL = 1000;
// 当前状态
private String currentStatus = "wayline_progress";
private int currentResult = 0;
private FlyToPointProgressScheduler() {
reportHandler = new Handler(Looper.getMainLooper());
pathPoints = new ArrayList<>();
}
public static FlyToPointProgressScheduler getInstance() {
if (instance == null) {
synchronized (FlyToPointProgressScheduler.class) {
if (instance == null) {
instance = new FlyToPointProgressScheduler();
}
}
}
return instance;
}
/**
* 开始定时上报
*/
public void startReporting() {
if (isRunning) {
LogUtil.log(TAG, "定时上报已在运行中");
return;
}
isRunning = true;
currentStatus = "wayline_progress";
currentResult = 0;
pathPoints.clear();
LogUtil.log(TAG, "启动飞向目标点进度定时上报");
reportRunnable = new Runnable() {
@Override
public void run() {
if (!isRunning) return;
try {
// 1. 采样飞机位置
new Thread(() -> sampleCurrentLocation()).start();
// 2. 发送上报
sendProgressReport();
} catch (Exception e) {
e.printStackTrace();
LogUtil.log(TAG, "定时任务异常:" + e.getMessage());
}
if (isRunning) {
reportHandler.postDelayed(this, REPORT_INTERVAL);
}
}
};
// 立即执行第一次
reportHandler.post(reportRunnable);
}
/**
* 停止定时上报
*/
public void stopReporting() {
if (!isRunning) return;
isRunning = false;
// 最后发送一次
sendProgressReport();
reportHandler.removeCallbacks(reportRunnable);
pathPoints.clear();
LogUtil.log(TAG, "停止飞向目标点进度定时上报");
}
/**
* 标记任务成功
*/
public void markSuccess() {
currentStatus = "wayline_ok";
currentResult = 0;
stopReporting();
}
/**
* 标记任务失败
*/
public void markFailed() {
currentStatus = "wayline_failed";
currentResult = -1;
stopReporting();
}
/**
* 标记任务取消
*/
public void markCancel() {
currentStatus = "wayline_cancel";
currentResult = 0;
stopReporting();
}
/**
* 采样当前飞机位置
*/
private void sampleCurrentLocation() {
try {
LocationCoordinate3D location = KeyManager.getInstance().getValue(
KeyTools.createKey(FlightControllerKey.KeyAircraftLocation3D));
if (location == null) return;
double lat = location.getLatitude();
double lng = location.getLongitude();
double alt = location.getAltitude();
// 过滤无效坐标
if (Math.abs(lat) < 0.0001 && Math.abs(lng) < 0.0001) return;
FlyToPointProgress.PlannedPathPoint point = new FlyToPointProgress.PlannedPathPoint();
point.setLatitude(lat);
point.setLongitude(lng);
point.setHeight((float) alt);
// 计算剩余距离和时间
double remaining_distance = Gpsdistance.calculate3DDistance(
lat, lng, alt,
Movement.getInstance().getFlyto_target_latitude(),
Movement.getInstance().getFlyto_target_longitude(),
Movement.getInstance().getFlyto_target_height());
int speed = Movement.getInstance().getFlyto_max_speed();
double remaining_time = speed > 0 ? remaining_distance / speed : 0;
Movement.getInstance().setFlyto_remaining_distance((float) remaining_distance);
Movement.getInstance().setFlyto_remaining_time((float) remaining_time);
// 刷新规划路径点3个飞机当前位置 中间点 目标点
pathPoints.clear();
pathPoints.add(point);
// 中间点 = 当前位置与目标点连线的中点
FlyToPointProgress.PlannedPathPoint midPoint = new FlyToPointProgress.PlannedPathPoint();
midPoint.setLatitude((lat + Movement.getInstance().getFlyto_target_latitude()) / 2.0);
midPoint.setLongitude((lng + Movement.getInstance().getFlyto_target_longitude()) / 2.0);
midPoint.setHeight((float) ((alt + Movement.getInstance().getFlyto_target_height()) / 2.0));
pathPoints.add(midPoint);
// 目标点
FlyToPointProgress.PlannedPathPoint targetPoint = new FlyToPointProgress.PlannedPathPoint();
targetPoint.setLatitude(Movement.getInstance().getFlyto_target_latitude());
targetPoint.setLongitude(Movement.getInstance().getFlyto_target_longitude());
targetPoint.setHeight((float) Movement.getInstance().getFlyto_target_height());
pathPoints.add(targetPoint);
} catch (Exception e) {
LogUtil.log(TAG, "采样位置失败:" + e.getMessage());
}
}
/**
* 发送进度上报
*/
public void sendProgressReport() {
try {
if (!MqttManager.getInstance().mqttAndroidClient.isConnected()) {
LogUtil.log(TAG, "MQTT未连接跳过上报");
return;
}
FlyToPointProgress.Data data = new FlyToPointProgress.Data();
data.setFly_to_id(Movement.getInstance().getFly_to_id());
data.setStatus(currentStatus);
data.setResult(currentResult);
data.setWay_point_index(1);
data.setRemaining_distance(Movement.getInstance().getFlyto_remaining_distance());
data.setRemaining_time(Movement.getInstance().getFlyto_remaining_time());
data.setPlanned_path_points(new ArrayList<>(pathPoints));
FlyToPointProgress progress = new FlyToPointProgress();
progress.setBid(UUID.randomUUID().toString());
progress.setTid(UUID.randomUUID().toString());
progress.setTimestamp(System.currentTimeMillis());
progress.setMethod("fly_to_point_progress");
progress.setNeedReply(1);
progress.setData(data);
String json = new Gson().toJson(progress);
MqttMessage mqttMessage = new MqttMessage(json.getBytes("UTF-8"));
mqttMessage.setQos(0);
MqttManager.getInstance().mqttAndroidClient.publish(AMSConfig.UP_UAV_EVENT, mqttMessage);
LogUtil.log(TAG, "上报进度status=" + currentStatus + ",轨迹点:" + pathPoints.size() + "");
} catch (Exception e) {
e.printStackTrace();
LogUtil.log(TAG, "上报异常:" + e.getMessage());
}
}
/**
* 释放资源
*/
public void release() {
stopReporting();
instance = null;
}
}

View File

@ -104,13 +104,18 @@ public class Generakmzaltheratools extends BaseManager {
//全局返航高度
double wpellheight=GpsUtils.wgs84Altitude(Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLat()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLon()));
LogUtil.log(TAG,"全局返航高度wpellheight"+wpellheight);
config.setGlobalRTHHeight(wpellheight);
config.setIsGlobalRTHHeightSet(true);
//安全起飞高度
config.setSecurityTakeOffHeight(wpellheight);
if(wpellheight<100.0){
config.setSecurityTakeOffHeight(wpellheight);
}else{
config.setSecurityTakeOffHeight(100.0);
}
config.setIsSecurityTakeOffHeightSet(true);

View File

@ -59,9 +59,6 @@ public class MqttManager {
/**
* 连接MQTT服务器
*/
private void doClientConnection() {
if (mqttAndroidClient.isConnected()) {
return;
@ -89,9 +86,7 @@ public class MqttManager {
}
}
/**
* 判断网络是否连接仅做日志记录不阻塞连接尝试
*/
private boolean isConnectIsNomarl() {
ConnectivityManager connectivityManager = (ConnectivityManager) ApronApp.Companion.getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

View File

@ -0,0 +1,182 @@
package com.aros.apron.tools;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import com.aros.apron.constant.AMSConfig;
import com.aros.apron.entity.Movement;
import com.aros.apron.entity.PsdkWidgetValuesReport;
import com.google.gson.Gson;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* PSDK widget 值定时上报器
*/
public class PsdkWidgetScheduler {
private static final String TAG = "PsdkWidgetScheduler";
private static volatile PsdkWidgetScheduler instance;
private Handler handler;
private Runnable runnable;
private volatile boolean isRunning = false;
private static final long INTERVAL = 5000;
private PsdkWidgetScheduler() {
handler = new Handler(Looper.getMainLooper());
}
public static PsdkWidgetScheduler getInstance() {
if (instance == null) {
synchronized (PsdkWidgetScheduler.class) {
if (instance == null) {
instance = new PsdkWidgetScheduler();
}
}
}
return instance;
}
public void start() {
if (isRunning) {
LogUtil.log(TAG, "PSDK定时上报已在运行中");
return;
}
isRunning = true;
LogUtil.log(TAG, "启动PSDK widget定时上报间隔5s");
runnable = new Runnable() {
@Override
public void run() {
if (!isRunning) return;
try {
sendPsdkWidgetValues();
} catch (Exception e) {
e.printStackTrace();
LogUtil.log(TAG, "PSDK定时任务异常" + e.getMessage());
}
if (isRunning) {
handler.postDelayed(this, INTERVAL);
}
}
};
handler.post(runnable);
}
public void stop() {
if (!isRunning) return;
isRunning = false;
handler.removeCallbacks(runnable);
LogUtil.log(TAG, "停止PSDK widget定时上报");
}
public boolean isRunning() {
return isRunning;
}
public void release() {
stop();
instance = null;
}
private void sendPsdkWidgetValues() {
try {
MqttAndroidClient client = MqttManager.getInstance().mqttAndroidClient;
if (client == null || !client.isConnected()) {
LogUtil.log(TAG, "MQTT未连接跳过PSDK widget上报");
return;
}
String psdkIndex = Movement.getInstance().getPsdk_index();
if (TextUtils.isEmpty(psdkIndex) || psdkIndex.equals("0")) {
LogUtil.log(TAG, "psdk_index为空或为0(" + psdkIndex + "),跳过上报");
return;
}
PsdkWidgetValuesReport report = new PsdkWidgetValuesReport();
report.setBid(UUID.randomUUID().toString());
report.setTid(UUID.randomUUID().toString());
report.setTimestamp(System.currentTimeMillis());
report.setMethod("psdk_widget_values");
report.setGateway("gateway_sn");
PsdkWidgetValuesReport.Data data = new PsdkWidgetValuesReport.Data();
PsdkWidgetValuesReport.PsdkWidgetValue widget = new PsdkWidgetValuesReport.PsdkWidgetValue();
widget.setPsdk_index(safeParseInt(psdkIndex, 0));
widget.setPsdk_lib_version(safeString(Movement.getInstance().getPsdk_lib_version(), ""));
widget.setPsdk_name(safeString(Movement.getInstance().getPsdk_name(), "Speaker"));
widget.setPsdk_sn(safeString(Movement.getInstance().getPsdk_sn(), ""));
widget.setPsdk_type(safeParseInt(Movement.getInstance().getPsdk_type(), 5));
widget.setPsdk_version(safeString(Movement.getInstance().getPsdk_version(), "01.00.01.11"));
PsdkWidgetValuesReport.SpeakerData speaker = new PsdkWidgetValuesReport.SpeakerData();
speaker.setPlay_file_md5(safeString(Movement.getInstance().getPlay_file_md5(), ""));
speaker.setPlay_file_name(safeString(Movement.getInstance().getPlay_file_name(), ""));
speaker.setPlay_mode(safeParseInt(Movement.getInstance().getPlay_mode(), 0));
speaker.setPlay_volume(safeParseInt(Movement.getInstance().getPlay_volume(), 0));
speaker.setSystem_state(safeParseInt(Movement.getInstance().getSystem_state(), 0));
speaker.setWork_mode(safeParseInt(Movement.getInstance().getWork_mode(), 0));
speaker.setTts_language(safeParseInt(Movement.getInstance().getTts_language(), 0));
speaker.setTts_speed(safeParseInt(Movement.getInstance().getTts_speed(), 0));
speaker.setTts_type(safeParseInt(Movement.getInstance().getTts_type(), 0));
speaker.setTts_volume(safeParseInt(Movement.getInstance().getTts_volume(), 0));
widget.setSpeaker(speaker);
int[] valuesArray = Movement.getInstance().getValues();
if (valuesArray != null && valuesArray.length > 0) {
List<Object> valuesList = new ArrayList<>();
for (int v : valuesArray) {
valuesList.add(v);
}
widget.setValues(valuesList);
}
List<PsdkWidgetValuesReport.PsdkWidgetValue> widgets = new ArrayList<>();
widgets.add(widget);
data.setPsdk_widget_values(widgets);
report.setData(data);
String jsonPayload = new Gson().toJson(report);
LogUtil.log(TAG, "PSDK widget JSON payload: " + jsonPayload);
MqttMessage mqttMessage = new MqttMessage(jsonPayload.getBytes("UTF-8"));
mqttMessage.setQos(1);
client.publish(AMSConfig.UP_UAV_EVENT, mqttMessage);
LogUtil.log(TAG, "上传PSDK widget值成功");
} catch (Exception e) {
e.printStackTrace();
LogUtil.log(TAG, "PSDK widget上传异常" + e.toString());
}
}
private int safeParseInt(String value, int defaultVal) {
if (TextUtils.isEmpty(value)) return defaultVal;
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return defaultVal;
}
}
private String safeString(String value, String defaultVal) {
return TextUtils.isEmpty(value) ? defaultVal : value;
}
}