修改云台偏航向下
This commit is contained in:
parent
5fd8e30b97
commit
66db69f894
|
|
@ -245,62 +245,64 @@ open class MainActivity : BaseActivity() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
// while (!OpenCVLoader.initLocal()) {
|
||||
// LogUtil.log("qwq", "opencv 初始化失败,阻塞等待重试...")
|
||||
// try {
|
||||
// Thread.sleep(300) // 休眠 300ms 再试,防止 CPU 爆炸
|
||||
// } catch (e: InterruptedException) {
|
||||
// LogUtil.log("qwq", "初始化被中断,跳出循环")
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// LogUtil.log("qwq", "opencv 初始化完成,继续执行后续代码")
|
||||
|
||||
dictionary = Objdetect.getPredefinedDictionary(Objdetect.DICT_6X6_250)
|
||||
|
||||
compositeDisposable = CompositeDisposable()
|
||||
compositeDisposable!!.add(
|
||||
systemStatusListPanelWidget!!.closeButtonPressed()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { pressed: Boolean ->
|
||||
if (pressed) {
|
||||
systemStatusListPanelWidget!!.hide()
|
||||
}
|
||||
})
|
||||
compositeDisposable!!.add(
|
||||
simulatorControlWidget!!.getUIStateUpdates()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { simulatorControlWidgetState: SimulatorControlWidget.UIState? ->
|
||||
if (simulatorControlWidgetState is VisibilityUpdated) {
|
||||
if ((simulatorControlWidgetState as VisibilityUpdated).isVisible) {
|
||||
hideOtherPanels(simulatorControlWidget!!)
|
||||
// 延迟订阅 RxJava 流,避免在初始 layout 阶段触发大量 widget 更新导致 ANR
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
if (compositeDisposable == null) return@postDelayed
|
||||
compositeDisposable!!.add(
|
||||
systemStatusListPanelWidget!!.closeButtonPressed()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { pressed: Boolean ->
|
||||
if (pressed) {
|
||||
systemStatusListPanelWidget!!.hide()
|
||||
}
|
||||
}
|
||||
})
|
||||
compositeDisposable!!.add(
|
||||
cameraSourceProcessor.toFlowable()
|
||||
.observeOn(io())
|
||||
.throttleLast(500, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(io())
|
||||
.subscribe(Consumer { result: CameraSource ->
|
||||
runOnUiThread { onCameraSourceUpdated(result.devicePosition, result.lensType) }
|
||||
})
|
||||
)
|
||||
compositeDisposable!!.add(
|
||||
ObservableInMemoryKeyedStore.getInstance()
|
||||
.addObserver(UXKeys.create(GlobalPreferenceKeys.GIMBAL_ADJUST_CLICKED))
|
||||
.observeOn(ui())
|
||||
.subscribe { broadcastValues: BroadcastValues? ->
|
||||
isGimableAdjustClicked(
|
||||
broadcastValues!!
|
||||
)
|
||||
})
|
||||
})
|
||||
compositeDisposable!!.add(
|
||||
simulatorControlWidget!!.getUIStateUpdates()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { simulatorControlWidgetState: SimulatorControlWidget.UIState? ->
|
||||
if (simulatorControlWidgetState is VisibilityUpdated) {
|
||||
if ((simulatorControlWidgetState as VisibilityUpdated).isVisible) {
|
||||
hideOtherPanels(simulatorControlWidget!!)
|
||||
}
|
||||
}
|
||||
})
|
||||
compositeDisposable!!.add(
|
||||
cameraSourceProcessor.toFlowable()
|
||||
.observeOn(io())
|
||||
.throttleLast(500, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(io())
|
||||
.subscribe(Consumer { result: CameraSource ->
|
||||
runOnUiThread { onCameraSourceUpdated(result.devicePosition, result.lensType) }
|
||||
})
|
||||
)
|
||||
compositeDisposable!!.add(
|
||||
ObservableInMemoryKeyedStore.getInstance()
|
||||
.addObserver(UXKeys.create(GlobalPreferenceKeys.GIMBAL_ADJUST_CLICKED))
|
||||
.observeOn(ui())
|
||||
.subscribe { broadcastValues: BroadcastValues? ->
|
||||
isGimableAdjustClicked(
|
||||
broadcastValues!!
|
||||
)
|
||||
})
|
||||
}, 500)
|
||||
ViewUtil.setKeepScreen(this, true)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
if (compositeDisposable != null) {
|
||||
compositeDisposable!!.dispose()
|
||||
// 在后台线程 dispose RxJava 订阅,避免阻塞主线程导致 ANR
|
||||
// DJI UX widget 的 unregisterReactions() 会同步清理 RxJava 队列,可能耗时很长
|
||||
val disposable = compositeDisposable
|
||||
if (disposable != null && !disposable.isDisposed) {
|
||||
Thread {
|
||||
try {
|
||||
disposable.dispose()
|
||||
} catch (e: Exception) {
|
||||
LogUtil.log(TAG, "dispose compositeDisposable error: ${e.message}")
|
||||
}
|
||||
}.start()
|
||||
compositeDisposable = null
|
||||
}
|
||||
super.onPause()
|
||||
|
|
@ -471,6 +473,43 @@ open class MainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制刷新两个FPVWidget的视频流(重新向MediaDataCenter注册)
|
||||
* 用于起飞/航线执行后视频流卡死的场景
|
||||
*/
|
||||
fun refreshVideoStream() {
|
||||
val primarySource = primaryFpvWidget?.widgetModel?.getCameraIndex()
|
||||
val secondarySource = secondaryFPVWidget?.widgetModel?.getCameraIndex()
|
||||
if (primarySource != null && primarySource != ComponentIndexType.UNKNOWN) {
|
||||
primaryFpvWidget?.updateVideoSource(primarySource)
|
||||
}
|
||||
if (secondarySource != null && secondarySource != ComponentIndexType.UNKNOWN) {
|
||||
secondaryFPVWidget?.updateVideoSource(secondarySource)
|
||||
}
|
||||
LogUtil.log(TAG, "强制刷新视频流: primary=$primarySource, secondary=$secondarySource")
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能刷新视频流:有云台(secondary)就模拟点击切换,没有就直接刷新当前流
|
||||
* 兼容只有FPV没有云台的设备
|
||||
*/
|
||||
fun smartRefreshVideoStream() {
|
||||
val secondarySource = secondaryFPVWidget?.widgetModel?.getCameraIndex()
|
||||
if (secondarySource != null && secondarySource != ComponentIndexType.UNKNOWN) {
|
||||
// 有云台:模拟真实点击,触发 swapVideoSource()
|
||||
secondaryFPVWidget?.post {
|
||||
secondaryFPVWidget?.performClick()
|
||||
}
|
||||
LogUtil.log(TAG, "智能刷新:有云台,模拟点击 FPV Widget")
|
||||
} else {
|
||||
// 没有云台:直接刷新当前流
|
||||
primaryFpvWidget?.post {
|
||||
refreshVideoStream()
|
||||
}
|
||||
LogUtil.log(TAG, "智能刷新:无云台,直接刷新主视频流")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateInteractionEnabled() {
|
||||
fpvInteractionWidget!!.isInteractionEnabled = !CameraUtil.isFPVTypeView(
|
||||
primaryFpvWidget!!.widgetModel.getCameraIndex()
|
||||
|
|
@ -514,16 +553,13 @@ open class MainActivity : BaseActivity() {
|
|||
WPMZManager.getInstance().init(this)
|
||||
MqttManager.getInstance().needConnect()
|
||||
|
||||
initDJIManager()
|
||||
// //开启相机图传
|
||||
// enableStream()
|
||||
// if(PreferenceUtils.getInstance().cameraLocationType==3){
|
||||
// initFpvStream()
|
||||
// }else{
|
||||
// initCameraStream()
|
||||
// }
|
||||
initView()
|
||||
|
||||
// 后台线程初始化 DJI 相关模块,避免阻塞主线程导致 ANR
|
||||
Thread {
|
||||
initDJIManager()
|
||||
}.start()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -683,213 +719,181 @@ open class MainActivity : BaseActivity() {
|
|||
DJINetworkManager.getInstance().removeNetworkStatusListener(networkStatusListener)
|
||||
}
|
||||
|
||||
private val handler: Handler = Handler(Looper.getMainLooper())
|
||||
private var initTimes = 0
|
||||
|
||||
private fun initDJIManager() {
|
||||
val isFlightControllerConnect =
|
||||
// 在后台线程中轮询等待飞控/相机连接,避免阻塞主线程
|
||||
var isFlightControllerConnect =
|
||||
KeyManager.getInstance().getValue(DJIKey.create(FlightControllerKey.KeyConnection))
|
||||
val isCameraConnect =
|
||||
var isCameraConnect =
|
||||
KeyManager.getInstance()
|
||||
.getValue(KeyTools.createKey(CameraKey.KeyConnection, ComponentIndexType.PORT_1))
|
||||
// LogUtil.log(TAG,isCameraConnect.toString())
|
||||
if (PreferenceUtils.getInstance().cameraLocationType == 3) {
|
||||
if (isFlightControllerConnect == null || isFlightControllerConnect != true) {
|
||||
handler.postDelayed({
|
||||
initDJIManager()
|
||||
}, 1000)
|
||||
} else {
|
||||
|
||||
initTimes++
|
||||
LogUtil.log(TAG, "下视觉初始化$initTimes")
|
||||
cameraManager.setKeepAliveDecoding(true);
|
||||
FlightManager.getInstance().initFlightInfo()
|
||||
BatteryManager.getInstance().initBatteryInfo()
|
||||
StickManager.getInstance().initStickInfo()
|
||||
GimbalManager.getInstance().initGimbalInfo()
|
||||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||||
OSDManager.getInstance().initOsd()
|
||||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||||
MediaManager.getInstance().init()
|
||||
StreamManager.getInstance().initStreamManager()
|
||||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||||
RTKManager.getInstance().initRTKInfo()
|
||||
//负载
|
||||
//PayloadWidgetManager.getInstance().initPayloadInfo()
|
||||
//初始化上报
|
||||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||||
val cameraLocationType = PreferenceUtils.getInstance().cameraLocationType
|
||||
|
||||
// 根据 cameraLocationType 轮询等待连接
|
||||
while (true) {
|
||||
val flightConnected = isFlightControllerConnect != null && isFlightControllerConnect == true
|
||||
val cameraConnected = isCameraConnect != null && isCameraConnect == true
|
||||
|
||||
LTEManager.getInstance().initLTEInfo()
|
||||
WirelessLinkManager.getInstance().initWirelessLink()
|
||||
CameraManager.getInstance().initCameraInfo()
|
||||
//ApronArucoDetect.getInstance().init()
|
||||
GeoidManager.getInstance().init(this);
|
||||
|
||||
MissionV3Manager.getInstance().initMissionManager()
|
||||
enableStream()
|
||||
initFpvStream()
|
||||
startVtxHeartbeat()
|
||||
SpeakerManager.getInstance().initMegaphoneInfo()
|
||||
|
||||
GimbalManager.getInstance().setmode()
|
||||
|
||||
|
||||
//GimbalManager.getInstance().gimsetmode()
|
||||
//PayloadWidgetManager.getInstance().initPayloadInfo();
|
||||
|
||||
|
||||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||||
|
||||
|
||||
|
||||
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
when (PreferenceUtils.getInstance().customStreamType) {
|
||||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||||
}
|
||||
SimplePortScanner.getInstance().startScan()
|
||||
|
||||
}, 5000) // 参数别改:5秒延迟确保相机就绪
|
||||
|
||||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||||
val shouldInit = when (cameraLocationType) {
|
||||
3 -> flightConnected
|
||||
4, 5 -> flightConnected || cameraConnected
|
||||
else -> flightConnected || cameraConnected
|
||||
}
|
||||
|
||||
} else if (PreferenceUtils.getInstance().cameraLocationType == 4 || PreferenceUtils.getInstance().cameraLocationType == 5) {
|
||||
if ((isFlightControllerConnect == null || isFlightControllerConnect != true) && (isCameraConnect == null || isCameraConnect != true)) {
|
||||
handler.postDelayed({
|
||||
initDJIManager()
|
||||
}, 1000)
|
||||
} else {
|
||||
initTimes++
|
||||
cameraManager.setKeepAliveDecoding(true);
|
||||
LogUtil.log(TAG, "云台初始化$initTimes")
|
||||
FlightManager.getInstance().initFlightInfo()
|
||||
BatteryManager.getInstance().initBatteryInfo()
|
||||
StickManager.getInstance().initStickInfo()
|
||||
GimbalManager.getInstance().initGimbalInfo()
|
||||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||||
OSDManager.getInstance().initOsd()
|
||||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||||
MediaManager.getInstance().init()
|
||||
StreamManager.getInstance().initStreamManager()
|
||||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||||
RTKManager.getInstance().initRTKInfo()
|
||||
//负载
|
||||
//PayloadWidgetManager.getInstance().initPayloadInfo()
|
||||
//初始化上报
|
||||
LTEManager.getInstance().initLTEInfo()
|
||||
WirelessLinkManager.getInstance().initWirelessLink()
|
||||
CameraManager.getInstance().initCameraInfo()
|
||||
//
|
||||
if (shouldInit) break
|
||||
|
||||
|
||||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||||
|
||||
//ApronArucoDetect.getInstance().init()
|
||||
MissionV3Manager.getInstance().initMissionManager()
|
||||
enableStream()
|
||||
initMixedStream()
|
||||
startVtxHeartbeat()
|
||||
|
||||
SpeakerManager.getInstance().initMegaphoneInfo()
|
||||
|
||||
GeoidManager.getInstance().init(this);
|
||||
|
||||
GimbalManager.getInstance().setmode()
|
||||
//GimbalManager.getInstance().gimsetmode()
|
||||
//开启雷达监听器
|
||||
//PerceptionManager.getInstance().isladraopeninti()
|
||||
|
||||
|
||||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||||
|
||||
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
when (PreferenceUtils.getInstance().customStreamType) {
|
||||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||||
}
|
||||
SimplePortScanner.getInstance().startScan()
|
||||
|
||||
}, 5000) // 参数别改:5秒延迟确保相机就绪
|
||||
|
||||
|
||||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||||
try {
|
||||
Thread.sleep(1000)
|
||||
} catch (e: InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if ((isFlightControllerConnect == null || isFlightControllerConnect != true) && (isCameraConnect == null || isCameraConnect != true)) {
|
||||
handler.postDelayed({
|
||||
initDJIManager()
|
||||
}, 1000)
|
||||
} else {
|
||||
initTimes++
|
||||
cameraManager.setKeepAliveDecoding(true);
|
||||
LogUtil.log(TAG, "云台初始化$initTimes")
|
||||
FlightManager.getInstance().initFlightInfo()
|
||||
BatteryManager.getInstance().initBatteryInfo()
|
||||
StickManager.getInstance().initStickInfo()
|
||||
GimbalManager.getInstance().initGimbalInfo()
|
||||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||||
OSDManager.getInstance().initOsd()
|
||||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||||
MediaManager.getInstance().init()
|
||||
StreamManager.getInstance().initStreamManager()
|
||||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||||
RTKManager.getInstance().initRTKInfo()
|
||||
//负载
|
||||
//PayloadWidgetManager.getInstance().initPayloadInfo()
|
||||
//初始化上报
|
||||
LTEManager.getInstance().initLTEInfo()
|
||||
WirelessLinkManager.getInstance().initWirelessLink()
|
||||
CameraManager.getInstance().initCameraInfo()
|
||||
//
|
||||
|
||||
isFlightControllerConnect =
|
||||
KeyManager.getInstance().getValue(DJIKey.create(FlightControllerKey.KeyConnection))
|
||||
isCameraConnect =
|
||||
KeyManager.getInstance()
|
||||
.getValue(KeyTools.createKey(CameraKey.KeyConnection, ComponentIndexType.PORT_1))
|
||||
}
|
||||
|
||||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||||
|
||||
//ApronArucoDetect.getInstance().init()
|
||||
MissionV3Manager.getInstance().initMissionManager()
|
||||
enableStream()
|
||||
initCameraStream()
|
||||
startVtxHeartbeat()
|
||||
//
|
||||
SpeakerManager.getInstance().initMegaphoneInfo()
|
||||
|
||||
//GimbalManager.getInstance().gimsetmode()
|
||||
|
||||
GeoidManager.getInstance().init(this);
|
||||
|
||||
//开启雷达监听器
|
||||
//PerceptionManager.getInstance().isladraopeninti()
|
||||
GimbalManager.getInstance().setmode()
|
||||
|
||||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||||
|
||||
|
||||
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
when (PreferenceUtils.getInstance().customStreamType) {
|
||||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||||
}
|
||||
SimplePortScanner.getInstance().startScan()
|
||||
|
||||
}, 5000) // 参数别改:5秒延迟确保相机就绪
|
||||
|
||||
|
||||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||||
// 飞控/相机连接后,在主线程执行初始化
|
||||
runOnUiThread {
|
||||
when (cameraLocationType) {
|
||||
3 -> initForCameraLocationType3()
|
||||
4, 5 -> initForCameraLocationType4Or5()
|
||||
else -> initForCameraLocationTypeDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initForCameraLocationType3() {
|
||||
initTimes++
|
||||
LogUtil.log(TAG, "下视觉初始化$initTimes")
|
||||
cameraManager.setKeepAliveDecoding(true)
|
||||
FlightManager.getInstance().initFlightInfo()
|
||||
BatteryManager.getInstance().initBatteryInfo()
|
||||
StickManager.getInstance().initStickInfo()
|
||||
GimbalManager.getInstance().initGimbalInfo()
|
||||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||||
OSDManager.getInstance().initOsd()
|
||||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||||
MediaManager.getInstance().init()
|
||||
StreamManager.getInstance().initStreamManager()
|
||||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||||
RTKManager.getInstance().initRTKInfo()
|
||||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||||
LTEManager.getInstance().initLTEInfo()
|
||||
WirelessLinkManager.getInstance().initWirelessLink()
|
||||
CameraManager.getInstance().initCameraInfo()
|
||||
GeoidManager.getInstance().init(this)
|
||||
MissionV3Manager.getInstance().initMissionManager()
|
||||
enableStream()
|
||||
initFpvStream()
|
||||
startVtxHeartbeat()
|
||||
SpeakerManager.getInstance().initMegaphoneInfo()
|
||||
GimbalManager.getInstance().setmode()
|
||||
|
||||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||||
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
when (PreferenceUtils.getInstance().customStreamType) {
|
||||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||||
}
|
||||
SimplePortScanner.getInstance().startScan()
|
||||
}, 5000)
|
||||
|
||||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||||
}
|
||||
|
||||
private fun initForCameraLocationType4Or5() {
|
||||
initTimes++
|
||||
cameraManager.setKeepAliveDecoding(true)
|
||||
LogUtil.log(TAG, "云台初始化$initTimes")
|
||||
FlightManager.getInstance().initFlightInfo()
|
||||
BatteryManager.getInstance().initBatteryInfo()
|
||||
StickManager.getInstance().initStickInfo()
|
||||
GimbalManager.getInstance().initGimbalInfo()
|
||||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||||
OSDManager.getInstance().initOsd()
|
||||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||||
MediaManager.getInstance().init()
|
||||
StreamManager.getInstance().initStreamManager()
|
||||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||||
RTKManager.getInstance().initRTKInfo()
|
||||
LTEManager.getInstance().initLTEInfo()
|
||||
WirelessLinkManager.getInstance().initWirelessLink()
|
||||
CameraManager.getInstance().initCameraInfo()
|
||||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||||
MissionV3Manager.getInstance().initMissionManager()
|
||||
enableStream()
|
||||
initMixedStream()
|
||||
startVtxHeartbeat()
|
||||
SpeakerManager.getInstance().initMegaphoneInfo()
|
||||
GeoidManager.getInstance().init(this)
|
||||
GimbalManager.getInstance().setmode()
|
||||
|
||||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||||
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
when (PreferenceUtils.getInstance().customStreamType) {
|
||||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||||
}
|
||||
SimplePortScanner.getInstance().startScan()
|
||||
}, 5000)
|
||||
|
||||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||||
}
|
||||
|
||||
private fun initForCameraLocationTypeDefault() {
|
||||
initTimes++
|
||||
cameraManager.setKeepAliveDecoding(true)
|
||||
LogUtil.log(TAG, "云台初始化$initTimes")
|
||||
FlightManager.getInstance().initFlightInfo()
|
||||
BatteryManager.getInstance().initBatteryInfo()
|
||||
StickManager.getInstance().initStickInfo()
|
||||
GimbalManager.getInstance().initGimbalInfo()
|
||||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||||
OSDManager.getInstance().initOsd()
|
||||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||||
MediaManager.getInstance().init()
|
||||
StreamManager.getInstance().initStreamManager()
|
||||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||||
RTKManager.getInstance().initRTKInfo()
|
||||
LTEManager.getInstance().initLTEInfo()
|
||||
WirelessLinkManager.getInstance().initWirelessLink()
|
||||
CameraManager.getInstance().initCameraInfo()
|
||||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||||
MissionV3Manager.getInstance().initMissionManager()
|
||||
enableStream()
|
||||
initCameraStream()
|
||||
startVtxHeartbeat()
|
||||
SpeakerManager.getInstance().initMegaphoneInfo()
|
||||
GeoidManager.getInstance().init(this)
|
||||
GimbalManager.getInstance().setmode()
|
||||
|
||||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||||
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
when (PreferenceUtils.getInstance().customStreamType) {
|
||||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||||
}
|
||||
SimplePortScanner.getInstance().startScan()
|
||||
}, 5000)
|
||||
|
||||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||||
}
|
||||
|
||||
private fun enableStream() {
|
||||
cameraManager.enableStream(ComponentIndexType.PORT_1, true);
|
||||
cameraManager.enableStream(ComponentIndexType.FPV, true);
|
||||
|
|
@ -1075,8 +1079,7 @@ open class MainActivity : BaseActivity() {
|
|||
fun onEvent(message: String?) {
|
||||
when (message) {
|
||||
FLAG_START_DETECT_ARUCO_APRON -> {
|
||||
|
||||
|
||||
|
||||
MediaDataCenter.getInstance().getCameraStreamManager().setVisionAssistViewDirection(
|
||||
VisionAssistDirection.DOWN,
|
||||
object : CompletionCallback {
|
||||
|
|
@ -1106,12 +1109,6 @@ open class MainActivity : BaseActivity() {
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
KeyManager.getInstance().performAction<EmptyMsg>(
|
||||
KeyTools.createKey<EmptyMsg, EmptyMsg>(FlightControllerKey.KeyStopAutoLanding),
|
||||
object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg?> {
|
||||
|
|
@ -1261,9 +1258,8 @@ open class MainActivity : BaseActivity() {
|
|||
startArucoType = 0
|
||||
|
||||
"REFRESH_VIDEO_SOURCE" -> {
|
||||
// 起飞后刷新视频源,避免FPVWidget因相机状态变化卡死
|
||||
swapVideoSource()
|
||||
LogUtil.log(TAG,"刷新视频流")
|
||||
// 智能刷新:有云台模拟点击,没有云台直接刷新
|
||||
smartRefreshVideoStream()
|
||||
}
|
||||
|
||||
MqttCallBack.FLAG_RESET_CLEAN_MODE ->
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ public class MqttActionCallBack implements IMqttActionListener {
|
|||
|
||||
@Override
|
||||
public void onSuccess(IMqttToken asyncActionToken) {
|
||||
ToastUtil.showToast("MQtt连接成功");
|
||||
LogUtil.log(TAG, "MQtt连接成功:-------");
|
||||
// 异步显示Toast,避免Binder IPC阻塞当前主线程消息导致ANR
|
||||
new Handler().post(() -> ToastUtil.showToast("MQtt连接成功"));
|
||||
try {
|
||||
mqttAndroidClient.subscribe(AMSConfig.DOWN_UAV_SERVICES, 1);//订阅主题:注册
|
||||
} catch (MqttException e) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@ public class DockCloseManager extends BaseManager {
|
|||
// 是否允许继续重试(开门后设为false,防止关门重试把已开的门又关了)
|
||||
private volatile boolean allowRetry = true;
|
||||
|
||||
public void resetState() {
|
||||
sendDockCloseSuccessTimes = 0;
|
||||
isSendDockCloseSuccess = false;
|
||||
allowRetry = true;
|
||||
LogUtil.log(TAG, "关舱状态已重置");
|
||||
}
|
||||
|
||||
public void stopRetry() {
|
||||
allowRetry = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ public class DockOpenManager extends BaseManager {
|
|||
return DockOpenHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public void resetState() {
|
||||
sendDockOpenSuccessTimes = 0;
|
||||
isSendDockOpenSuccess = false;
|
||||
LogUtil.log(TAG, "开舱状态已重置");
|
||||
}
|
||||
|
||||
public void sendDockOpenMsg2Server() {
|
||||
if (sendDockOpenSuccessTimes >= maxRetries) {
|
||||
LogUtil.log(TAG, "达到最大重试次数或已发送开舱"+isSendDockOpenSuccess+sendDockOpenSuccessTimes);
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ public class FlightManager extends BaseManager {
|
|||
public void onValueChange(@Nullable Integer oldValue, @Nullable Integer newValue) {
|
||||
if (newValue != null) {
|
||||
Movement.getInstance().setWind_speed(newValue);
|
||||
|
||||
pushFlightAttitude();
|
||||
}
|
||||
}
|
||||
|
|
@ -888,6 +889,11 @@ public class FlightManager extends BaseManager {
|
|||
}
|
||||
|
||||
|
||||
public void resetOpenCabinDoorState() {
|
||||
sendOpenCabinDoorMsg = false;
|
||||
LogUtil.log(TAG, "开舱门状态已重置");
|
||||
}
|
||||
|
||||
private static final int FLYING_HEIGHT_THRESHOLD = 10; // 开舱门飞行高度阈值
|
||||
private static final int DISTANCE_THRESHOLD = 500; // 返航距离阈值
|
||||
|
||||
|
|
@ -1340,6 +1346,8 @@ public class FlightManager extends BaseManager {
|
|||
|
||||
Movement.getInstance().setTask_current_step(25);
|
||||
sendOpenCabinDoorMsg = false;
|
||||
DockOpenManager.getInstance().resetState();
|
||||
DockCloseManager.getInstance().resetState();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -269,41 +269,51 @@ public class GimbalManager extends BaseManager {
|
|||
break;
|
||||
//俯仰向下
|
||||
case 3:
|
||||
GimbalAngleRotation rotation1 = new GimbalAngleRotation();
|
||||
rotation1.setMode(GimbalAngleRotationMode.ABSOLUTE_ANGLE);
|
||||
if (!TextUtils.isEmpty(Movement.getInstance().getGimbal_yaw() + "")) {
|
||||
rotation1.setYaw(Movement.getInstance().getGimbal_yaw());
|
||||
LogUtil.log(TAG,"俯仰向下"+Movement.getInstance().getGimbal_yaw());
|
||||
}
|
||||
rotation1.setPitch(-90.0);
|
||||
KeyManager.getInstance().performAction(KeyTools.createKey(GimbalKey.KeyRotateByAngle, ComponentIndexType.PORT_1), rotation1, new CommonCallbacks.CompletionCallbackWithParam<EmptyMsg>() {
|
||||
// 跟随模式下发送ABSOLUTE_ANGLE旋转会冲突,先切FREE模式
|
||||
KeyManager.getInstance().setValue(KeyTools.createKey(GimbalKey.KeyGimbalMode, ComponentIndexType.PORT_1), GimbalMode.FREE, new CommonCallbacks.CompletionCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
LogUtil.log(TAG, "case3: 云台切换FREE模式成功");
|
||||
// 再发送绝对角度旋转
|
||||
GimbalAngleRotation rotation1 = new GimbalAngleRotation();
|
||||
rotation1.setMode(GimbalAngleRotationMode.ABSOLUTE_ANGLE);
|
||||
if (!TextUtils.isEmpty(Movement.getInstance().getGimbal_yaw() + "")) {
|
||||
rotation1.setYaw(Movement.getInstance().getGimbal_yaw());
|
||||
LogUtil.log(TAG,"俯仰向下 yaw="+Movement.getInstance().getGimbal_yaw());
|
||||
}
|
||||
rotation1.setPitch(-90.0);
|
||||
KeyManager.getInstance().performAction(KeyTools.createKey(GimbalKey.KeyRotateByAngle, ComponentIndexType.PORT_1), rotation1, new CommonCallbacks.CompletionCallbackWithParam<EmptyMsg>() {
|
||||
@Override
|
||||
public void onSuccess(EmptyMsg emptyMsg) {
|
||||
sendMsg2Server(message);
|
||||
LogUtil.log(TAG,"俯仰向下成功");
|
||||
// 旋转完成后恢复跟随模式
|
||||
KeyManager.getInstance().setValue(KeyTools.createKey(GimbalKey.KeyGimbalMode, ComponentIndexType.PORT_1), GimbalMode.YAW_FOLLOW, new CommonCallbacks.CompletionCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
LogUtil.log(TAG, "case3: 云台恢复跟随模式");
|
||||
sendMsg2Server(message);
|
||||
}
|
||||
@Override
|
||||
public void onFailure(@NonNull IDJIError idjiError) {
|
||||
sendMsg2Server(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull IDJIError error) {
|
||||
sendFailMsg2Server(message, "偏航向下失败:" + getIDJIErrorMsg(error));
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// GimbalAngleRotation rotation1 = new GimbalAngleRotation();
|
||||
// rotation1.setMode(GimbalAngleRotationMode.ABSOLUTE_ANGLE);
|
||||
// rotation1.setPitch(-90.0);
|
||||
// KeyManager.getInstance().performAction(KeyTools.createKey(GimbalKey.KeyRotateByAngle, ComponentIndexType.PORT_1), rotation1, new CommonCallbacks.CompletionCallbackWithParam<EmptyMsg>() {
|
||||
// @Override
|
||||
// public void onSuccess(EmptyMsg emptyMsg) {
|
||||
// sendMsg2Server(message);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(@NonNull IDJIError error) {
|
||||
// sendFailMsg2Server(message, "偏航向下失败:" + getIDJIErrorMsg(error));
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
@Override
|
||||
public void onFailure(@NonNull IDJIError idjiError) {
|
||||
LogUtil.log(TAG, "case3: 云台切换FREE模式失败");
|
||||
// 仍然尝试旋转(可能已经在FREE模式)
|
||||
sendMsg2Server(message);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +334,7 @@ public class GimbalManager extends BaseManager {
|
|||
// LookAtMode.LOOK_AT_GIMBAL_FOLLOWING : LookAtMode.LOOK_AT_GIMBAL_FREE);
|
||||
|
||||
lookAtInfo.setMode(message.getData().isLocked() ?
|
||||
LookAtMode.LOOK_AT_GIMBAL_FREE : LookAtMode.LOOK_AT_GIMBAL_FREE);
|
||||
LookAtMode.LOOK_AT_GIMBAL_FOLLOWING : LookAtMode.LOOK_AT_GIMBAL_FOLLOWING);
|
||||
|
||||
LocationCoordinate3D locationCoordinate3D = new LocationCoordinate3D();
|
||||
locationCoordinate3D.setLatitude(message.getData().getLatitude());
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.aros.apron.entity.ApronExecutionStatus;
|
|||
import com.aros.apron.entity.Movement;
|
||||
import com.aros.apron.tools.LogUtil;
|
||||
import com.aros.apron.tools.PreferenceUtils;
|
||||
import com.aros.apron.manager.StreamManager;
|
||||
import com.autonavi.base.amap.mapcore.FileUtil;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
|
|
@ -68,6 +69,11 @@ public class MediaManager extends BaseManager {
|
|||
|
||||
/* ===== 已上传文件名集合(本次任务内有效) ===== */
|
||||
private final Set<String> uploadedFileNames = new HashSet<>();
|
||||
/* ===== S3 bucket是否已检查 ===== */
|
||||
private volatile boolean bucketChecked = false;
|
||||
/* ===== 下载失败重试计数 ===== */
|
||||
private int downloadFailTimes = 0;
|
||||
private static final int MAX_DOWNLOAD_RETRY = 3;
|
||||
private MediaManager() {
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +106,8 @@ public class MediaManager extends BaseManager {
|
|||
public void enablePlayback() {
|
||||
// 每次进入媒体模式时清空已上传文件集合
|
||||
uploadedFileNames.clear();
|
||||
bucketChecked = false;
|
||||
downloadFailTimes = 0;
|
||||
// 重置失败计数和标志
|
||||
enterPlayBackFailTimes = 0;
|
||||
isEnablePlayback = false;
|
||||
|
|
@ -107,6 +115,7 @@ public class MediaManager extends BaseManager {
|
|||
pullMediaFileListFromCameraFailTimes = 0;
|
||||
updatingWaitCount = 0;
|
||||
pullqwq = false;
|
||||
pullStartTime = System.currentTimeMillis(); // 开始计时
|
||||
|
||||
LogUtil.log(TAG, "已清空上传文件集合");
|
||||
|
||||
|
|
@ -155,13 +164,25 @@ public class MediaManager extends BaseManager {
|
|||
private int pullMediaFileListFromCameraFailTimes;
|
||||
|
||||
private int updatingWaitCount = 0;
|
||||
private static final int MAX_UPDATING_WAIT = 60; // 最多等待30秒
|
||||
private static final int MAX_UPDATING_WAIT = 15; // 最多等待15秒,无文件时快速跳过
|
||||
private boolean pullqwq = false;
|
||||
private boolean isPullMediaFileListFromCameraSuccess;
|
||||
private long pullStartTime = 0; // 记录整个拉取流程开始时间
|
||||
private static final int MAX_PULL_DURATION = 25; // 整个拉取流程最多25秒,超时强制关机
|
||||
|
||||
private void pullMediaFileListFromCamera() {
|
||||
// 全局超时检查:防止状态机异常导致无限循环
|
||||
long elapsed = (System.currentTimeMillis() - pullStartTime) / 1000;
|
||||
if (elapsed >= MAX_PULL_DURATION) {
|
||||
LogUtil.log(TAG, "拉取流程总耗时 " + elapsed + "s,超时强制关机");
|
||||
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
|
||||
sendEvent2Server("媒体文件拉取超时", 2);
|
||||
disablePlayback();
|
||||
return;
|
||||
}
|
||||
|
||||
mState = MediaDataCenter.getInstance().getMediaManager().getMediaFileListState();
|
||||
LogUtil.log(TAG, "当前状态:" + mState + ",准备拉取文件列表");
|
||||
LogUtil.log(TAG, "当前状态:" + mState + ",准备拉取文件列表(已耗时" + elapsed + "s)");
|
||||
|
||||
// 1. 当状态为IDLE时,需要调用pullMediaFileListFromCamera拉取全量数据
|
||||
// 2. 当状态为UP_TO_DATE时,表示拉取完成,可以获取数据
|
||||
|
|
@ -172,6 +193,8 @@ public class MediaManager extends BaseManager {
|
|||
@Override
|
||||
public void onSuccess() {
|
||||
LogUtil.log(TAG, "拉取文件列表成功");
|
||||
// 重置pullqwq标志,下次调用重新从IDLE拉取
|
||||
pullqwq = false;
|
||||
// 拉取成功后,等待状态变为UP_TO_DATE
|
||||
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 1000);
|
||||
}
|
||||
|
|
@ -203,13 +226,13 @@ public class MediaManager extends BaseManager {
|
|||
// 检查文件列表是否为空
|
||||
if (rawList == null || rawList.isEmpty()) {
|
||||
LogUtil.log(TAG, "文件列表为空,重试拉取");
|
||||
// 重试拉取文件列表
|
||||
if (pullMediaFileListFromCameraFailTimes < 5) {
|
||||
// 状态已经是UP_TO_DATE时,空列表可能确实无文件,快速重试2次后放弃
|
||||
if (pullMediaFileListFromCameraFailTimes < 2) {
|
||||
pullMediaFileListFromCameraFailTimes++;
|
||||
LogUtil.log(TAG, "第" + pullMediaFileListFromCameraFailTimes + "次重试...");
|
||||
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 2000);
|
||||
} else {
|
||||
LogUtil.log(TAG, "重试次数达到上限,拉取失败");
|
||||
LogUtil.log(TAG, "UP_TO_DATE状态文件列表持续为空,确认无文件");
|
||||
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
|
||||
sendEvent2Server("拉取媒体文件失败",2);
|
||||
disablePlayback();
|
||||
|
|
@ -240,6 +263,8 @@ public class MediaManager extends BaseManager {
|
|||
if (mediaFiles.isEmpty()) {
|
||||
LogUtil.log(TAG, "所有文件均已上传,直接清理");
|
||||
downLoadMediaFileIndex = 0;
|
||||
// 提前设置关机标志,让 aircraftStoredReply 能立即回复成功
|
||||
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
|
||||
removeAllFiles();
|
||||
return;
|
||||
}
|
||||
|
|
@ -249,8 +274,8 @@ public class MediaManager extends BaseManager {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.log(TAG, "获取文件列表数据失败: " + e.getMessage());
|
||||
// 发生异常时重试
|
||||
if (pullMediaFileListFromCameraFailTimes < 5) {
|
||||
// 发生异常时快速重试2次
|
||||
if (pullMediaFileListFromCameraFailTimes < 2) {
|
||||
pullMediaFileListFromCameraFailTimes++;
|
||||
LogUtil.log(TAG, "第" + pullMediaFileListFromCameraFailTimes + "次重试...");
|
||||
new Handler().postDelayed(MediaManager.this::pullMediaFileListFromCamera, 2000);
|
||||
|
|
@ -319,6 +344,7 @@ public class MediaManager extends BaseManager {
|
|||
}
|
||||
|
||||
LogUtil.log(TAG, "File size: " + mediaFile.getFileSize());
|
||||
downloadFailTimes = 0;
|
||||
|
||||
File dirs = new File(getSDCardPath() + mediaFileDir);
|
||||
if (!dirs.exists()) {
|
||||
|
|
@ -341,7 +367,7 @@ public class MediaManager extends BaseManager {
|
|||
final BufferedOutputStream finalBos = new BufferedOutputStream(finalOutputStream);
|
||||
bos = finalBos;
|
||||
|
||||
mediaFile.pullOriginalMediaFileFromCamera(0L, new MediaFileDownloadListener() {
|
||||
mediaFile.pullOriginalMediaFileFromCamera(offset, new MediaFileDownloadListener() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
// No action needed for start
|
||||
|
|
@ -393,10 +419,19 @@ public class MediaManager extends BaseManager {
|
|||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error closing file: " + e.getMessage());
|
||||
}
|
||||
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
|
||||
sendEvent2Server("第" + downLoadMediaFileIndex + "个文件下载失败",2);
|
||||
disablePlayback();
|
||||
LogUtil.log(TAG, "发送关闭无人机");
|
||||
// 下载失败重试机制
|
||||
if (downloadFailTimes < MAX_DOWNLOAD_RETRY) {
|
||||
downloadFailTimes++;
|
||||
LogUtil.log(TAG, "第" + downloadFailTimes + "次下载失败,2秒后重试同一文件");
|
||||
new Handler().postDelayed(() -> {
|
||||
pullOriginalMediaFileFromCamera();
|
||||
}, 2000);
|
||||
} else {
|
||||
ApronExecutionStatus.getInstance().setAircraftWaitShutDown(true);
|
||||
sendEvent2Server("第" + downLoadMediaFileIndex + "个文件下载失败(已重试" + MAX_DOWNLOAD_RETRY + "次)",2);
|
||||
disablePlayback();
|
||||
LogUtil.log(TAG, "发送关闭无人机");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -427,7 +462,10 @@ public class MediaManager extends BaseManager {
|
|||
public String getAWSSecretKey() {
|
||||
return PreferenceUtils.getInstance().getSecretKey(); // minio的密钥
|
||||
}
|
||||
}, Region.getRegion(Regions.US_EAST_1), new ClientConfiguration());
|
||||
}, Region.getRegion(Regions.US_EAST_1), new ClientConfiguration()
|
||||
.withConnectionTimeout(30000)
|
||||
.withSocketTimeout(300000)
|
||||
.withMaxErrorRetry(3));
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
public void minIOUpLoad(final File file, final MediaFile mediaFile) {
|
||||
|
|
@ -437,9 +475,17 @@ public class MediaManager extends BaseManager {
|
|||
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
|
||||
// 服务器地址
|
||||
s3.setEndpoint(PreferenceUtils.getInstance().getUploadUrl()); // http://ip:端口号
|
||||
boolean bucketExists = s3.doesBucketExist(PreferenceUtils.getInstance().getBucketName());
|
||||
if (!bucketExists) {
|
||||
s3.createBucket(PreferenceUtils.getInstance().getBucketName());
|
||||
// Bucket只在首次上传时检查创建,后续上传不再重复请求
|
||||
if (!bucketChecked) {
|
||||
synchronized (this) {
|
||||
if (!bucketChecked) {
|
||||
boolean bucketExists = s3.doesBucketExist(PreferenceUtils.getInstance().getBucketName());
|
||||
if (!bucketExists) {
|
||||
s3.createBucket(PreferenceUtils.getInstance().getBucketName());
|
||||
}
|
||||
bucketChecked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 上传文件到网关MINIO存储服务
|
||||
|
|
@ -503,6 +549,8 @@ public class MediaManager extends BaseManager {
|
|||
|
||||
@Override
|
||||
public void onNext(String url) {
|
||||
// 上传成功,重置下载重试计数
|
||||
downloadFailTimes = 0;
|
||||
//上传完成发送事件
|
||||
sendMediaUpload2Server(mediaFile.getFileName(),mediaFiles.size(),downLoadMediaFileIndex);
|
||||
}
|
||||
|
|
@ -528,7 +576,8 @@ public class MediaManager extends BaseManager {
|
|||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
@Override
|
||||
public void onComplete() {
|
||||
// 每上传一张就清除缓存
|
||||
// 每上传一张就清除缓存,并记录已上传文件名
|
||||
uploadedFileNames.add(mediaFile.getFileName());
|
||||
FileUtil.deleteFile(file);
|
||||
LogUtil.log(TAG, "File " + downLoadMediaFileIndex + " uploaded successfully.");
|
||||
sendEvent2Server( "第" + downLoadMediaFileIndex + "个文件已上传",1);
|
||||
|
|
@ -579,6 +628,8 @@ public class MediaManager extends BaseManager {
|
|||
|
||||
//退出媒体模式
|
||||
public void disablePlayback() {
|
||||
// 任务结束,停止视频流刷新定时器
|
||||
StreamManager.getInstance().stopStreamRefreshTimer();
|
||||
MediaDataCenter.getInstance().getMediaManager().disable(new CommonCallbacks.CompletionCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
|
|
|
|||
|
|
@ -568,7 +568,7 @@ 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);
|
||||
boolean GPSSatelliteCountValid = GPSSatelliteCount > 15;
|
||||
boolean GPSSatelliteCountValid = GPSSatelliteCount > 14;
|
||||
|
||||
LogUtil.log(TAG, "isMissionStateValid" + isMissionStateValid + "isPlaneMessageValid" + isPlaneMessageValid + "isGpsQualityValid" + isGpsQualityValid);
|
||||
// if (isMissionStateValid && isPlaneMessageValid && isGpsQualityValid) {
|
||||
|
|
@ -794,6 +794,9 @@ public class MissionV3Manager extends BaseManager {
|
|||
PreferenceUtils.getInstance().setNeedTriggerApronArucoLand(false);
|
||||
PreferenceUtils.getInstance().setNeedTriggerAlterArucoLand(false);
|
||||
PreferenceUtils.getInstance().setTriggerToAlternatePoint(false);
|
||||
// 重置开舱门标志,避免上次任务未正常落地导致本次无法开舱
|
||||
FlightManager.getInstance().resetOpenCabinDoorState();
|
||||
DockOpenManager.getInstance().resetState();
|
||||
PreferenceUtils.getInstance().setFlightId(message.getData().getFlight_id());
|
||||
CommonCallbacks.CompletionCallback callback = new CommonCallbacks.CompletionCallback() {
|
||||
@Override
|
||||
|
|
@ -822,7 +825,7 @@ public class MissionV3Manager extends BaseManager {
|
|||
if (!isMissionStart) {
|
||||
if (missionStateCode != 3 && missionStateCode != 4 && missionStateCode != 5 && missionStateCode != 6
|
||||
&& missionStateCode != 7 && missionStateCode != 8 && missionStateCode != 9 && missionStateCode != 10) {
|
||||
if (startMissionFailTimes < 50) {
|
||||
if (startMissionFailTimes < 80) {
|
||||
mainHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class OSDManager extends BaseManager {
|
|||
return;
|
||||
}
|
||||
lastExecuteTime = now;
|
||||
Boolean isConnect = KeyManager.getInstance().getValue(createKey(FlightControllerKey.KeyConnection));
|
||||
Boolean isConnect = KeyManager.getInstance().getValue(createKey(FlightControllerKey.KeyAirSenseSystemConnected));
|
||||
if (!Movement.getInstance().isMissionFinish()) {
|
||||
if (isConnect != null && isConnect) {
|
||||
pushFlightAttitude();
|
||||
|
|
|
|||
|
|
@ -48,9 +48,60 @@ public class StreamManager extends BaseManager {
|
|||
private final ExecutorService streamExecutor = Executors.newSingleThreadExecutor();
|
||||
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
// ========== 5秒定时刷新视频流,防止起飞卡死 ==========
|
||||
private final Handler streamRefreshHandler = new Handler(Looper.getMainLooper());
|
||||
private Runnable streamRefreshRunnable = null;
|
||||
private volatile boolean isStreamRefreshing = false;
|
||||
private static final long STREAM_REFRESH_INTERVAL_MS = 5000;
|
||||
|
||||
private StreamManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动5秒定时刷新视频流(起飞/航线执行时调用,防止视频流卡死)
|
||||
* 原理:模拟真实的用户点击 FPVWidget 触发 swapVideoSource(),等同于用户手动点击屏幕
|
||||
*/
|
||||
public void startStreamRefreshTimer() {
|
||||
if (isStreamRefreshing) {
|
||||
LogUtil.log(TAG, "视频流刷新定时器已运行,跳过");
|
||||
return;
|
||||
}
|
||||
isStreamRefreshing = true;
|
||||
LogUtil.log(TAG, "启动5秒视频流刷新定时器");
|
||||
|
||||
streamRefreshRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isStreamRefreshing) return;
|
||||
|
||||
try {
|
||||
// 委托给 MainActivity 的统一刷新方法,自动处理 FPV-only 和 FPV+gimbal 两种设备
|
||||
MainActivity mainActivity = MainActivity.Companion.getInstance();
|
||||
if (mainActivity != null) {
|
||||
mainActivity.smartRefreshVideoStream();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.log(TAG, "定时刷新视频流异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
streamRefreshHandler.postDelayed(this, STREAM_REFRESH_INTERVAL_MS);
|
||||
}
|
||||
};
|
||||
streamRefreshHandler.postDelayed(streamRefreshRunnable, STREAM_REFRESH_INTERVAL_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止5秒定时刷新视频流(任务结束/航线完成时调用)
|
||||
*/
|
||||
public void stopStreamRefreshTimer() {
|
||||
isStreamRefreshing = false;
|
||||
if (streamRefreshRunnable != null) {
|
||||
streamRefreshHandler.removeCallbacks(streamRefreshRunnable);
|
||||
streamRefreshRunnable = null;
|
||||
}
|
||||
LogUtil.log(TAG, "停止视频流刷新定时器");
|
||||
}
|
||||
|
||||
private static class StreamHolder {
|
||||
private static final StreamManager INSTANCE = new StreamManager();
|
||||
}
|
||||
|
|
@ -61,6 +112,7 @@ public class StreamManager extends BaseManager {
|
|||
|
||||
// ========== 【新增】重置推流状态,用于端口关闭后重启 ==========
|
||||
public void resetStreamState() {
|
||||
stopStreamRefreshTimer(); // 重置时也停止定时器
|
||||
startLiveFailTimes = 0;
|
||||
isLiveStreamAlreadyStart = false;
|
||||
isStartingRTSP = false; // 重置并发标志
|
||||
|
|
@ -293,17 +345,18 @@ public class StreamManager extends BaseManager {
|
|||
LogUtil.log(TAG, "RTSP 推流已在运行,无需重复启动");
|
||||
isLiveStreamAlreadyStart = true;
|
||||
isStartingRTSP = false;
|
||||
startStreamRefreshTimer(); // 推流在运行就启动定时器
|
||||
SimplePortScanner.getInstance().startScan(); // 确保端口扫描在运行
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 检查相机流是否准备好
|
||||
if (!MainActivity.Companion.getStreamReceive()) {
|
||||
LogUtil.log(TAG, "相机流未准备好,尝试切换 FPV Widget 恢复");
|
||||
LogUtil.log(TAG, "相机流未准备好,尝试模拟点击 FPV Widget 恢复");
|
||||
mainHandler.post(() -> {
|
||||
MainActivity mainActivity = MainActivity.Companion.getInstance();
|
||||
if (mainActivity != null) {
|
||||
mainActivity.swapVideoSource();
|
||||
mainActivity.smartRefreshVideoStream();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -312,6 +365,7 @@ public class StreamManager extends BaseManager {
|
|||
if (startLiveFailTimes < 3) {
|
||||
startLiveFailTimes++;
|
||||
LogUtil.log(TAG, "相机流未准备好,第" + startLiveFailTimes + "次重试");
|
||||
isStartingRTSP = false; // 先重置标志,让重试调用能正常进入
|
||||
startLiveWithRTSP();
|
||||
} else {
|
||||
LogUtil.log(TAG, "相机流未准备好,重试次数已达上限,强制启动");
|
||||
|
|
@ -320,6 +374,7 @@ public class StreamManager extends BaseManager {
|
|||
}
|
||||
});
|
||||
}, 2000);
|
||||
isStartingRTSP = false; // 释放锁,让重试能正常进入
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -417,10 +472,14 @@ public class StreamManager extends BaseManager {
|
|||
public void onSuccess() {
|
||||
mainHandler.post(() -> {
|
||||
LogUtil.log(TAG, "强制启动 RTSP 推流成功");
|
||||
// 统一刷新视频流
|
||||
MainActivity mainActivity = MainActivity.Companion.getInstance();
|
||||
mainActivity.swapVideoSource();
|
||||
if (mainActivity != null) {
|
||||
mainActivity.smartRefreshVideoStream();
|
||||
}
|
||||
isLiveStreamAlreadyStart = true;
|
||||
isStartingRTSP = false; // 重置并发标志
|
||||
startStreamRefreshTimer(); // 强制启动成功也启动定时器
|
||||
SimplePortScanner.getInstance().startScan();
|
||||
});
|
||||
}
|
||||
|
|
@ -450,6 +509,7 @@ public class StreamManager extends BaseManager {
|
|||
LogUtil.log(TAG, "推流已在运行,跳过启动 (isRestart=" + isRestart + ")");
|
||||
isLiveStreamAlreadyStart = true;
|
||||
isStartingRTSP = false; // 重置并发标志
|
||||
startStreamRefreshTimer();
|
||||
SimplePortScanner.getInstance().startScan(); // 确保端口扫描在运行
|
||||
return;
|
||||
}
|
||||
|
|
@ -466,6 +526,8 @@ public class StreamManager extends BaseManager {
|
|||
startLiveFailTimes = 0; // 重置失败计数
|
||||
isStartingRTSP = false; // 重置并发标志
|
||||
LogUtil.log(TAG, "========== RTSP 推流启动成功 ==========");
|
||||
// 启动5秒定时刷新视频流,防止起飞卡死
|
||||
startStreamRefreshTimer();
|
||||
// 开始端口扫描
|
||||
SimplePortScanner.getInstance().startScan();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -383,6 +383,11 @@ public class TakeOffToPointManager extends BaseManager {
|
|||
PreferenceUtils.getInstance().setNeedTriggerApronArucoLand(false);
|
||||
PreferenceUtils.getInstance().setNeedTriggerAlterArucoLand(false);
|
||||
PreferenceUtils.getInstance().setTriggerToAlternatePoint(false);
|
||||
|
||||
// 重置开舱门标志,避免上次任务未正常落地导致本次无法开舱
|
||||
FlightManager.getInstance().resetOpenCabinDoorState();
|
||||
DockOpenManager.getInstance().resetState();
|
||||
|
||||
PreferenceUtils.getInstance().setFlightId(message.getData().getFlight_id());
|
||||
CommonCallbacks.CompletionCallback callback = new CommonCallbacks.CompletionCallback() {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -657,7 +657,7 @@ public class Aprondown {
|
|||
|
||||
private void performOperation() {
|
||||
LogUtil.log(TAG_LOG, "快速下拉中..." + handlerCallbackCount);
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -5.5);
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -6);
|
||||
handlerCallbackCount++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -907,7 +907,7 @@ public class Aprongim {
|
|||
|
||||
private void performOperation() {
|
||||
LogUtil.log(TAG_LOG, String.format("【执行移动】速降 vz=-4 count=%d/20", handlerCallbackCount));
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -5.5);
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -6);
|
||||
handlerCallbackCount++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -635,7 +635,7 @@ public class ApronArucoDetect {
|
|||
|
||||
private void performOperation() {
|
||||
LogUtil.log(TAG_LOG, "快速下拉中..." + handlerCallbackCount);
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -5.5);
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -6);
|
||||
handlerCallbackCount++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -870,7 +870,7 @@ public class ApronArucoDetectPort {
|
|||
|
||||
private void performOperation() {
|
||||
LogUtil.log(TAG_LOG, String.format("【执行移动】速降 vz=-4 count=%d/20", handlerCallbackCount));
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -5.5);
|
||||
DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, -6);
|
||||
handlerCallbackCount++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,11 +101,16 @@ public class Generakmzaltheratools extends BaseManager {
|
|||
|
||||
//全局过度速度
|
||||
config.setGlobalTransitionalSpeed(7.0);
|
||||
|
||||
//全局返航高度
|
||||
config.setGlobalRTHHeight(Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()));
|
||||
double wpellheight=GpsUtils.wgs84Altitude(Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLat()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLon()));
|
||||
|
||||
config.setGlobalRTHHeight(wpellheight);
|
||||
config.setIsGlobalRTHHeightSet(true);
|
||||
|
||||
|
||||
//安全起飞高度
|
||||
config.setSecurityTakeOffHeight(Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()));
|
||||
config.setSecurityTakeOffHeight(wpellheight);
|
||||
config.setIsSecurityTakeOffHeightSet(true);
|
||||
|
||||
|
||||
|
|
@ -125,7 +130,7 @@ public class Generakmzaltheratools extends BaseManager {
|
|||
//double wpheight=GpsUtils.egm96Altitude(data.getTargetHeight(),data.getTargetLatitude(),data.getTargetLongitude());
|
||||
|
||||
//double wp1ellheighet=GpsUtils.wgs84Altitude();
|
||||
double wpellheight=GpsUtils.wgs84Altitude(Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLat()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLon()));
|
||||
//double wpellheight=GpsUtils.wgs84Altitude(Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointSecurityHeight()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLat()),Double.parseDouble(PreferenceUtils.getInstance().getAlternatePointLon()));
|
||||
|
||||
wp1.setWaypointIndex(0);
|
||||
wp1.setLocation(new WaylineLocationCoordinate2D(lat.getLatitude(), lat.getLongitude()));
|
||||
|
|
|
|||
|
|
@ -180,6 +180,9 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/widget_remaining_flight_time"
|
||||
tools:ignore="TouchTargetSizeCheck,SpeakableTextPresentCheck" />
|
||||
|
||||
|
||||
|
||||
|
||||
<dji.v5.ux.cameracore.widget.cameracontrols.CameraControlsWidget
|
||||
android:id="@+id/widget_camera_controls"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
|||
Loading…
Reference in New Issue