diff --git a/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java b/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java index 61b8949..b7edad5 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java +++ b/app/src/main/java/com/example/longyi_groundstation/Login/Activity/LoginActivity.java @@ -3,6 +3,8 @@ package com.example.longyi_groundstation.Login.Activity; import android.annotation.SuppressLint; import android.content.Intent; import android.os.Bundle; +import android.util.Log; + import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; @@ -12,7 +14,9 @@ import androidx.core.view.WindowInsetsCompat; import com.example.longyi_groundstation.Funcation.Activity.FuncationActivity; import com.example.longyi_groundstation.Login.Void.AllView; import com.example.longyi_groundstation.Main.Activity.MainActivity; +import com.example.longyi_groundstation.Main.Void.MyReceiver; import com.example.longyi_groundstation.R; +import com.example.longyi_groundstation.Util.Tool; public class LoginActivity extends AppCompatActivity { @@ -34,6 +38,10 @@ public class LoginActivity extends AppCompatActivity { return insets; }); +// Log.d("myReceiver_HEARTBEAT", Tool.getDecToFirstBin("128")); +// Log.d("myReceiver_HEARTBEAT", Tool.getDecToBinFull("128")); + + initData(); initView(); initOnClick(); diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_ack.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_ack.java index 55fe7b3..ef4d698 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_ack.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_ack.java @@ -12,6 +12,9 @@ import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload; import com.example.longyi_groundstation.MAVLink.Messages.Units; import com.example.longyi_groundstation.MAVLink.Messages.Description; +import org.json.JSONException; +import org.json.JSONObject; + /** * Acknowledgment message during waypoint handling. The type field states if this message is a positive ack (type=0) or if an error happened (type=non-zero). */ @@ -159,7 +162,27 @@ public class msg_mission_ack extends MAVLinkMessage { */ @Override public String toString() { - return "MAVLINK_MSG_ID_MISSION_ACK - sysid:"+sysid+" compid:"+compid+" target_system:"+target_system+" target_component:"+target_component+" type:"+type+" mission_type:"+mission_type+" opaque_id:"+opaque_id+""; + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("msgid",MAVLINK_MSG_ID_MISSION_ACK); + jsonObject.put("sysid",sysid); + jsonObject.put("compid",compid); + jsonObject.put("target_system",target_system); + jsonObject.put("target_component",target_component); + jsonObject.put("type",type); + jsonObject.put("mission_type",mission_type); + jsonObject.put("opaque_id",opaque_id); + return jsonObject.toString(); + } catch (JSONException e) { + return null; + } +// return "MAVLINK_MSG_ID_MISSION_ACK - sysid:"+sysid+ +// " compid:"+compid+ +// " target_system:"+target_system+ +// " target_component:"+target_component+ +// " type:"+type+ +// " mission_type:"+mission_type+ +// " opaque_id:"+opaque_id+""; } /** diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_count.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_count.java index 0fabb74..bbc965d 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_count.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_count.java @@ -12,6 +12,9 @@ import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload; import com.example.longyi_groundstation.MAVLink.Messages.Units; import com.example.longyi_groundstation.MAVLink.Messages.Description; +import org.json.JSONException; +import org.json.JSONObject; + /** * This message is emitted as response to MISSION_REQUEST_LIST by the MAV and to initiate a write transaction. The GCS can then request the individual mission item based on the knowledge of the total number of waypoints. */ @@ -159,7 +162,28 @@ public class msg_mission_count extends MAVLinkMessage { */ @Override public String toString() { - return "MAVLINK_MSG_ID_MISSION_COUNT - sysid:"+sysid+" compid:"+compid+" count:"+count+" target_system:"+target_system+" target_component:"+target_component+" mission_type:"+mission_type+" opaque_id:"+opaque_id+""; + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("msgid",MAVLINK_MSG_ID_MISSION_COUNT); + jsonObject.put("sysid",sysid); + jsonObject.put("compid",compid); + jsonObject.put("count",count); + jsonObject.put("target_system",target_system); + jsonObject.put("target_component",target_component); + jsonObject.put("mission_type",mission_type); + jsonObject.put("opaque_id",opaque_id); + return jsonObject.toString(); + } catch (JSONException e) { + return null; + } + +// return "MAVLINK_MSG_ID_MISSION_COUNT - sysid:"+sysid+ +// " compid:"+compid+ +// " count:"+count+ +// " target_system:"+target_system+ +// " target_component:"+target_component+ +// " mission_type:"+mission_type+ +// " opaque_id:"+opaque_id+""; } /** diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_item_int.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_item_int.java index a259599..e566fef 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_item_int.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_item_int.java @@ -12,6 +12,9 @@ import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload; import com.example.longyi_groundstation.MAVLink.Messages.Units; import com.example.longyi_groundstation.MAVLink.Messages.Description; +import org.json.JSONException; +import org.json.JSONObject; + /** * Message encoding a mission item. This message is emitted to announce the presence of a mission item and to set a mission item on the system. The mission item can be either in x, y, z meters (type: LOCAL) or x:lat, y:lon, z:altitude. Local frame is Z-down, right handed (NED), global frame is Z-up, right handed (ENU). NaN or INT32_MAX may be used in float/integer params (respectively) to indicate optional/default values (e.g. to use the component's current latitude, yaw rather than a specific value). See also https://mavlink.io/en/services/mission.html. @@ -270,7 +273,49 @@ public class msg_mission_item_int extends MAVLinkMessage { */ @Override public String toString() { - return "MAVLINK_MSG_ID_MISSION_ITEM_INT - sysid:"+sysid+" compid:"+compid+" param1:"+param1+" param2:"+param2+" param3:"+param3+" param4:"+param4+" x:"+x+" y:"+y+" z:"+z+" seq:"+seq+" command:"+command+" target_system:"+target_system+" target_component:"+target_component+" frame:"+frame+" current:"+current+" autocontinue:"+autocontinue+" mission_type:"+mission_type+""; + + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("msgid",MAVLINK_MSG_ID_MISSION_ITEM_INT); + jsonObject.put("sysid",sysid); + jsonObject.put("compid",compid); + jsonObject.put("param1",param1); + jsonObject.put("param2",param2); + jsonObject.put("param3",param3); + jsonObject.put("param4",param4); + jsonObject.put("x",x); + jsonObject.put("y",y); + jsonObject.put("z",z); + jsonObject.put("seq",seq); + jsonObject.put("command",command); + jsonObject.put("target_system",target_system); + jsonObject.put("target_component",target_component); + jsonObject.put("frame",frame); + jsonObject.put("current",current); + jsonObject.put("autocontinue",autocontinue); + jsonObject.put("mission_type",mission_type); + return jsonObject.toString(); + } catch (JSONException e) { + return null; + } + +// return "MAVLINK_MSG_ID_MISSION_ITEM_INT - sysid:"+sysid+ +// " compid:"+compid+ +// " param1:"+param1+ +// " param2:"+param2+ +// " param3:"+param3+ +// " param4:"+param4+ +// " x:"+x+ +// " y:"+y+ +// " z:"+z+ +// " seq:"+seq+ +// " command:"+command+ +// " target_system:"+target_system+ +// " target_component:"+target_component+ +// " frame:"+frame+ +// " current:"+current+ +// " autocontinue:"+autocontinue+ +// " mission_type:"+mission_type+""; } /** diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request.java index bd114d2..d003a29 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request.java @@ -12,6 +12,9 @@ import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkPayload; import com.example.longyi_groundstation.MAVLink.Messages.Units; import com.example.longyi_groundstation.MAVLink.Messages.Description; +import org.json.JSONException; +import org.json.JSONObject; + /** * Request the information of the mission item with the sequence number seq. The response of the system to this message should be a MISSION_ITEM message. https://mavlink.io/en/services/mission.html */ @@ -148,7 +151,27 @@ public class msg_mission_request extends MAVLinkMessage { */ @Override public String toString() { - return "MAVLINK_MSG_ID_MISSION_REQUEST - sysid:"+sysid+" compid:"+compid+" seq:"+seq+" target_system:"+target_system+" target_component:"+target_component+" mission_type:"+mission_type+""; + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("msgid",MAVLINK_MSG_ID_MISSION_REQUEST); + jsonObject.put("sysid",sysid); + jsonObject.put("compid",compid); + jsonObject.put("seq",seq); + jsonObject.put("target_system",target_system); + jsonObject.put("target_component",target_component); + jsonObject.put("mission_type",mission_type); + return jsonObject.toString(); + } catch (JSONException e) { + return null; + } + +// return "MAVLINK_MSG_ID_MISSION_REQUEST - sysid:"+sysid+ +// " compid:"+compid+ +// " seq:"+seq+ +// " target_system:"+target_system+ +// " target_component:"+target_component+ +// " mission_type:"+mission_type+""; + } /** diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_int.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_int.java index dd329bc..eec735d 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_int.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_int.java @@ -148,7 +148,12 @@ public class msg_mission_request_int extends MAVLinkMessage { */ @Override public String toString() { - return "MAVLINK_MSG_ID_MISSION_REQUEST_INT - sysid:"+sysid+" compid:"+compid+" seq:"+seq+" target_system:"+target_system+" target_component:"+target_component+" mission_type:"+mission_type+""; + return "MAVLINK_MSG_ID_MISSION_REQUEST_INT - sysid:"+sysid+ + " compid:"+compid+ + " seq:"+seq+ + " target_system:"+target_system+ + " target_component:"+target_component+ + " mission_type:"+mission_type+""; } /** diff --git a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_list.java b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_list.java index 8a44c09..f7668e6 100644 --- a/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_list.java +++ b/app/src/main/java/com/example/longyi_groundstation/MAVLink/common/msg_mission_request_list.java @@ -137,7 +137,14 @@ public class msg_mission_request_list extends MAVLinkMessage { */ @Override public String toString() { - return "MAVLINK_MSG_ID_MISSION_REQUEST_LIST - sysid:"+sysid+" compid:"+compid+" target_system:"+target_system+" target_component:"+target_component+" mission_type:"+mission_type+""; + + return "MAVLINK_MSG_ID_MISSION_REQUEST_LIST - sysid:"+sysid+ + " compid:"+compid+ + " target_system:"+target_system+ + " target_component:"+target_component+ + " mission_type:"+mission_type+""; + + } /** diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java b/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java index f765833..452cac4 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Activity/MainActivity.java @@ -74,6 +74,7 @@ import com.example.longyi_groundstation.Main.View.DpadView; import com.example.longyi_groundstation.Main.View.ErrorLogDialog; import com.example.longyi_groundstation.Main.View.FPV_Void; import com.example.longyi_groundstation.Main.View.LandDialog; +import com.example.longyi_groundstation.Main.View.SlideToUnlockView; import com.example.longyi_groundstation.Main.View.TakeOffDialog; import com.example.longyi_groundstation.Main.View.TurnBackDialog; import com.example.longyi_groundstation.Main.Void.AllView; @@ -90,6 +91,7 @@ import com.example.longyi_groundstation.Main.Void.SQLClass; import com.example.longyi_groundstation.Main.Void.XiangTuo.Protocol; import com.example.longyi_groundstation.Main.Void.XiangTuo.TcpClientUtil; import com.example.longyi_groundstation.R; +import com.example.longyi_groundstation.Util.Tool; import com.google.android.flexbox.FlexDirection; import com.google.android.flexbox.FlexWrap; import com.google.android.flexbox.FlexboxLayoutManager; @@ -126,7 +128,7 @@ public class MainActivity extends AppCompatActivity { //广播接收器 private MyReceiver myReceiver_ATTITUDE, myReceiver_GPS_RAW_INT, myReceiver_GLOBAL_POSITION_INT, myReceiver_POWER_STATUS, myReceiver_SYS_STATUS, myReceiver_STATUSTEXT, - myReceiver_HEARTBEAT, myReceiver_VFR_HUD; + myReceiver_HEARTBEAT, myReceiver_VFR_HUD,myReceiver_MISSION_REQUEST,myReceiver_MISSION_ACK; //所有组件 private AllView allView; private ArrayList typeList = new ArrayList<>(); @@ -157,6 +159,7 @@ public class MainActivity extends AppCompatActivity { // 在成员变量部分添加 private CreateLinkAdapter createLinkAdapter; private List createLinkList = new ArrayList<>(); + private ArrayList selectedLinkList = null;//当前选择的航线 @Override @@ -266,12 +269,29 @@ public class MainActivity extends AppCompatActivity { registerReceiver(myReceiver_VFR_HUD, filter8); } + //航线上传-接收 + myReceiver_MISSION_REQUEST = new MyReceiver(); + IntentFilter filter9 = new IntentFilter("Broadcast_MISSION_REQUEST"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + registerReceiver(myReceiver_MISSION_REQUEST, filter9, Context.RECEIVER_EXPORTED); + } else { + registerReceiver(myReceiver_MISSION_REQUEST, filter9); + } + + //航线上传-异常 + myReceiver_MISSION_ACK = new MyReceiver(); + IntentFilter filter10 = new IntentFilter("Broadcast_MISSION_ACK"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + registerReceiver(myReceiver_MISSION_ACK, filter10, Context.RECEIVER_EXPORTED); + } else { + registerReceiver(myReceiver_MISSION_ACK, filter10); + } // 初始化数据源 typeList = new ArrayList<>(); typeList.add(new Msg("relative_alt", "0", true)); typeList.add(new Msg("alt", "0", true)); - typeList.add(new Msg("throttle", "0", true)); + typeList.add(new Msg("throttle", "0%", true)); typeList.add(new Msg("time_boot_ms", "0", true)); typeList.add(new Msg("home_distance", "0", true)); typeList.add(new Msg("lat", "0", true)); @@ -285,13 +305,6 @@ public class MainActivity extends AppCompatActivity { Toast.makeText(this, "云台控制初始化失败", Toast.LENGTH_SHORT).show(); } -// typeList.add(new Msg("relative_alt", MyReceiver.GLOBAL_POSITION_INT_json.optString("relative_alt"), true)); -// typeList.add(new Msg("alt", MyReceiver.GLOBAL_POSITION_INT_json.optString("alt"), true)); -// typeList.add(new Msg("time_boot_ms", MyReceiver.GLOBAL_POSITION_INT_json.optString("time_usec"), true)); -// typeList.add(new Msg("satellites_visible", "", false)); -// typeList.add(new Msg("data2", "", false)); - - } /** @@ -372,6 +385,14 @@ public class MainActivity extends AppCompatActivity { //拿到数据库里所有的航线 setupAllLinkList(); + //设置滑动解锁的view属性 + allView.unlockView.setText("滑动解锁"); + // 设置背景圆角弧度为10dp + allView.unlockView.setCornerRadius(4); + // 设置滑块圆角弧度为5dp + allView.unlockView.setThumbCornerRadius(4); + // 设置组件半透明(50%透明度) + allView.unlockView.setComponentAlpha(128); } /** @@ -423,7 +444,11 @@ public class MainActivity extends AppCompatActivity { //获取到位置后移动视角到当前位置 if (islocation) { // 移动视图到Marker点 - mapVoid.aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lat", 0) / 10000000, MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lon", 0) / 10000000), 15)); // 15是缩放级别 + mapVoid.aMap.moveCamera(CameraUpdateFactory.newLatLngZoom( + new LatLng( + MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lat", 0) / 10000000, + MyReceiver.GLOBAL_POSITION_INT_json.optDouble("lon", 0) / 10000000), + 15)); // 15是缩放级别 islocation = false; homeLatLng = new LatLng(doubles[1], doubles[0]); } @@ -502,6 +527,20 @@ public class MainActivity extends AppCompatActivity { //广播接收-setHeartbeatlistener myReceiver_HEARTBEAT.setHeartbeatlistener(data -> { + + Log.d(TAG, "myReceiver_HEARTBEAT: " + data.toString()); + //判断飞控是否解锁 + if (Tool.getDecToFirstBin(MyReceiver.HEARTBEAT_json.optString("base_mode")).equals("1")){ + //已解锁 + allView.rl_unlock.setVisibility(View.GONE); + }else { + if (allView.rl_unlock.getVisibility() == View.GONE){ + //未解锁 + allView.rl_unlock.setVisibility(View.VISIBLE); + allView.unlockView.resetToInitialState("滑动解锁"); + } + } + // 这里可以更新 UI 或刷新数据 switch (MyReceiver.HEARTBEAT_json.optInt("custom_mode")) { case 0: @@ -557,7 +596,7 @@ public class MainActivity extends AppCompatActivity { // data.optDouble("throttle")/100, // 1 // ))); - if (data.optDouble("throttle") != 0){ + if (data.optDouble("throttle") > 0){ typeList.set(2, new Msg("throttle", String.format("%.1f", MyTool.getThrottle( Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MIN").getParam_value()), Double.parseDouble(FlyVoid.paramList.get("MOT_SPIN_MAX").getParam_value()), @@ -569,6 +608,16 @@ public class MainActivity extends AppCompatActivity { }); + //广播接收-setMissionAcklistener + myReceiver_MISSION_REQUEST.setMissionRequestlistener(data -> { + Log.d(TAG, "myReceiver_MISSION_REQUEST: "+data.toString()); + }); + + //广播接收-setMissionAcklistener + myReceiver_MISSION_ACK.setMissionAcklistener(data -> { + Log.d(TAG, "myReceiver_MISSION_ACK: "+data.toString()); + }); + } /** @@ -653,6 +702,7 @@ public class MainActivity extends AppCompatActivity { allView.ll_icon_land.setOnClickListener(v -> { landDialog.show(); }); + //进设置页面 allView.ll_setting.setOnClickListener(v -> { // Toast.makeText(this, "维护中..", Toast.LENGTH_SHORT).show(); @@ -662,6 +712,8 @@ public class MainActivity extends AppCompatActivity { //路线执行 allView.ll_line_fly_layout.setOnClickListener(v -> { + + //清空所有线路,并且退出执行页面 refreshLinkList(); allView.v_mainDisplay.setVisibility(GONE); allView.ll_open_layout.setVisibility(GONE); @@ -669,40 +721,43 @@ public class MainActivity extends AppCompatActivity { allView.ll_link_start.setVisibility(VISIBLE); allView.ll_all_link_layout.setVisibility(VISIBLE); allView.fpvWidget.setVisibility(GONE); - -// mapVoid.showLine(!mapVoid.polyline.isVisible()); - //清除现有任务 -// msg_mission_clear_all clearCmd = new msg_mission_clear_all(); -// clearCmd.target_system = 1; // 无人机系统ID -// clearCmd.target_component = 1; // 无人机组件ID -// flyVoid.sendMavlinkMessage(MyBoundService.type,clearCmd); -// -// // 创建航点消息 -// msg_mission_item waypoint = new msg_mission_item(); -// waypoint.target_system = 1; // 无人机系统ID -// waypoint.target_component = 1; // 无人机组件ID -// waypoint.seq = 0; // 航点序号 -// waypoint.frame = MAV_FRAME.MAV_FRAME_GLOBAL_RELATIVE_ALT; // 坐标系 -// waypoint.command = MAV_CMD.MAV_CMD_NAV_WAYPOINT; // 航点指令 -// waypoint.current = 0; // 0=不是当前航点 -// waypoint.autocontinue = 1; // 自动继续到下一个航点 -// waypoint.param1 = 10; // 停留时间(秒) -// waypoint.param2 = 0; // 接受半径(m) -// waypoint.param3 = 0; // 通过半径(m) -// waypoint.param4 = Float.NaN; // 航向角(NaN表示不指定) -// waypoint.x = (float)mapVoid.flyPointList.get(0).latitude; // 纬度 -// waypoint.y = (float) mapVoid.flyPointList.get(0).longitude; // 经度 -// waypoint.z = 15; // 高度(相对) -// flyVoid.sendMavlinkMessage(MyBoundService.type,waypoint); -// -// -// // 发送航点计数 -// msg_mission_count count = new msg_mission_count(); -// count.target_system = 1; -// count.target_component = 1; -// count.count = 1; // 航点数量 -// flyVoid.sendMavlinkMessage(MyBoundService.type,count); }); + + //路线执行-上传航线 + allView.ll_link_start_fun1.setOnClickListener(v -> { + // 添加航线发送功能 + if (selectedLinkList != null) { + // 调用FlyVoid中的方法发送航线到飞控 + flyVoid.sendMissionToFlightController(this,selectedLinkList); + + } +// // 清除当前地图上的所有航点和航线 +// clearWaypoints(); +// allView.v_mainDisplay.setVisibility(VISIBLE); +// allView.ll_open_layout.setVisibility(VISIBLE); +// allView.ll_text.setVisibility(VISIBLE); +// allView.ll_link_start.setVisibility(GONE); +// allView.ll_all_link_layout.setVisibility(GONE); +// allView.fpvWidget.setVisibility(VISIBLE); + }); + //开始执行 + allView.ll_link_start_fun2.setOnClickListener(v -> { + // 添加航线发送功能 + if (selectedLinkList != null) { + // 调用FlyVoid中的方法发送航线到飞控 + flyVoid.requestMissionStart(0,-1); + Toast.makeText(this, "开始执行", Toast.LENGTH_SHORT).show(); + } + // 清除当前地图上的所有航点和航线 + clearWaypoints(); + allView.v_mainDisplay.setVisibility(VISIBLE); + allView.ll_open_layout.setVisibility(VISIBLE); + allView.ll_text.setVisibility(VISIBLE); + allView.ll_link_start.setVisibility(GONE); + allView.ll_all_link_layout.setVisibility(GONE); + allView.fpvWidget.setVisibility(VISIBLE); + }); + //路线执行-退出 allView.ll_link_start_back.setOnClickListener(v -> { // 清除当前地图上的所有航点和航线 @@ -796,7 +851,6 @@ public class MainActivity extends AppCompatActivity { AlertDialog dialog = builder.create(); dialog.show(); }); - // 路线规划功能-2:清除所有线路 allView.ll_link_fun2.setOnClickListener(v -> { // 创建确认对话框 @@ -1195,7 +1249,6 @@ public class MainActivity extends AppCompatActivity { tcpClient.sendBytes(testData); }); - // 为ll_PTZ_amplify添加按下和抬起事件 allView.ll_PTZ_amplify.setOnTouchListener((v, event) -> { switch (event.getAction()) { @@ -1256,7 +1309,6 @@ public class MainActivity extends AppCompatActivity { return true; // 返回true表示处理了触摸事件 }); - // 设置地图点击监听器以添加航点 allView.map.getMap().setOnMapClickListener(latLng -> { if (isSetLink) { @@ -1298,6 +1350,15 @@ public class MainActivity extends AppCompatActivity { } }); + allView.unlockView.setOnUnlockListener(new SlideToUnlockView.OnUnlockListener() { + @Override + public void onUnlock() { + // 解锁飞机 + flyVoid.requestArm(); + allView.rl_unlock.setVisibility(View.GONE); + } + }); + } @@ -1499,9 +1560,9 @@ public class MainActivity extends AppCompatActivity { public void onItemClick(int listId, int position) { // 清除当前地图上的所有航点和航线 clearWaypoints(); - + selectedLinkList = null; // 从数据库中获取选中的航线数据 - ArrayList selectedLinkList = sqlClass.getCreateLinkList(listId); + selectedLinkList = sqlClass.getCreateLinkList(listId); if (selectedLinkList != null && !selectedLinkList.isEmpty()) { // 在地图上显示航线 @@ -1645,6 +1706,12 @@ public class MainActivity extends AppCompatActivity { unregisterReceiver(myReceiver_VFR_HUD); myReceiver_VFR_HUD.isReceiverRegistered = false; } + //注销广播接收器(避免内存泄漏) + if (myReceiver_MISSION_REQUEST.isReceiverRegistered) { + unregisterReceiver(myReceiver_MISSION_REQUEST); + myReceiver_MISSION_REQUEST.isReceiverRegistered = false; + } + fpvVoid.Fstop(allView.fpvWidget); } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java b/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java index ed45f43..5fd6a08 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Service/MyBoundService.java @@ -4,6 +4,9 @@ import static com.example.longyi_groundstation.MAVLink.common.msg_attitude.MAVLI import static com.example.longyi_groundstation.MAVLink.common.msg_attitude_target.MAVLINK_MSG_ID_ATTITUDE_TARGET; import static com.example.longyi_groundstation.MAVLink.common.msg_global_position_int.MAVLINK_MSG_ID_GLOBAL_POSITION_INT; import static com.example.longyi_groundstation.MAVLink.common.msg_gps_raw_int.MAVLINK_MSG_ID_GPS_RAW_INT; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_ack.MAVLINK_MSG_ID_MISSION_ACK; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_count.MAVLINK_MSG_ID_MISSION_COUNT; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_request.MAVLINK_MSG_ID_MISSION_REQUEST; import static com.example.longyi_groundstation.MAVLink.common.msg_param_request_list.MAVLINK_MSG_ID_PARAM_REQUEST_LIST; import static com.example.longyi_groundstation.MAVLink.common.msg_param_request_read.MAVLINK_MSG_ID_PARAM_REQUEST_READ; import static com.example.longyi_groundstation.MAVLink.common.msg_param_value.MAVLINK_MSG_ID_PARAM_VALUE; @@ -61,7 +64,7 @@ import tp.xmaihh.serialport.bean.ComBean; public class MyBoundService extends Service { - private ArrayList MsgList; + public static ArrayList MsgList; public static int type = 0;//0串口 1UDP //UDP @@ -337,7 +340,6 @@ public class MyBoundService extends Service { // Log.d("cuijigzhou_msg_all", msg.toString()); LogUtil.d("cuijigzhou_msg_all", msg.toString()); - MsgList.set(msg.msgid, msg.toString()); if (msgOld == null) { MsgList.set(msg.msgid, msg.toString()); @@ -388,9 +390,12 @@ public class MyBoundService extends Service { BroadcastUtil.Broadcast_RC_CHANNELS_RAW(getApplication(), MsgList.get(MAVLINK_MSG_ID_RC_CHANNELS_RAW)); } if (MsgList.get(MAVLINK_MSG_ID_VFR_HUD) != null) { -// Log.e("MAVLINK_MSG_ID_ATTITUDE_TARGET", 1+""); BroadcastUtil.Broadcast_VFR_HUD(getApplication(), MsgList.get(MAVLINK_MSG_ID_VFR_HUD)); } + if (MsgList.get(MAVLINK_MSG_ID_MISSION_ACK) != null) { + BroadcastUtil.Broadcast_MISSION_ACK(getApplication(), MsgList.get(MAVLINK_MSG_ID_MISSION_ACK)); + } + Thread.sleep(50); } @@ -432,6 +437,17 @@ public class MyBoundService extends Service { FlyVoid.setParamUpdateComplete(false); } + case MAVLINK_MSG_ID_MISSION_REQUEST: + if (MsgList.get(MAVLINK_MSG_ID_MISSION_REQUEST) != null) { + BroadcastUtil.Broadcast_MISSION_REQUEST(getApplication(), MsgList.get(MAVLINK_MSG_ID_MISSION_REQUEST)); + } + + case MAVLINK_MSG_ID_MISSION_COUNT: + Log.d(TAG, "wordT1: "); + if (MsgList.get(MAVLINK_MSG_ID_MISSION_REQUEST) != null) { + BroadcastUtil.Broadcast_MISSION_REQUEST(getApplication(), MsgList.get(MAVLINK_MSG_ID_MISSION_REQUEST)); + } + default: // Log.d("cuijigzhou_msg_all_id", "不做处理:"+msg.msgid); @@ -463,7 +479,6 @@ public class MyBoundService extends Service { getData(); getDataSerial(); - return binder; } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/View/SlideToUnlockView.java b/app/src/main/java/com/example/longyi_groundstation/Main/View/SlideToUnlockView.java index 72ed418..0b42c6a 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/View/SlideToUnlockView.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/View/SlideToUnlockView.java @@ -20,6 +20,11 @@ public class SlideToUnlockView extends View { private float thumbSize; // 滑块尺寸 private float minX, maxX; // 滑块X轴边界 + private float cornerRadius; // 背景圆角弧度 + private float thumbCornerRadius; // 滑块圆角弧度 + private int componentAlpha = 255; // 组件透明度,默认为完全不透明 + + public interface OnUnlockListener { void onUnlock(); } @@ -53,16 +58,29 @@ public class SlideToUnlockView extends View { reboundAnimator.addUpdateListener(animation -> { setProgress((float) animation.getAnimatedValue()); }); + + // 初始化默认圆角弧度 + cornerRadius = dpToPx(20); // 默认背景圆角 + thumbCornerRadius = dpToPx(10); // 默认滑块圆角 } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); + // 保存画笔原始透明度 + int originalPaintAlpha = paint.getAlpha(); + int originalTextPaintAlpha = textPaint.getAlpha(); + + // 应用组件透明度 + paint.setAlpha(componentAlpha); + textPaint.setAlpha(componentAlpha); + // 1. 绘制背景(渐变) int currentBgColor = blendColors(bgColor, activeColor, progress); paint.setColor(currentBgColor); - canvas.drawRoundRect(0, 0, getWidth(), getHeight(), getHeight()/2f, getHeight()/2f, paint); + canvas.drawRoundRect(0, 0, getWidth(), getHeight(), cornerRadius, cornerRadius, paint); // 2. 绘制滑块(严格限制边界) float thumbX = minX + progress * (maxX - minX); @@ -73,16 +91,22 @@ public class SlideToUnlockView extends View { getHeight()*0.9f ); paint.setColor(Color.WHITE); - canvas.drawOval(thumbRect, paint); + canvas.drawRoundRect(thumbRect, thumbCornerRadius, thumbCornerRadius, paint); // 3. 绘制文本(始终可见) - textPaint.setAlpha(255); // 固定不透明 + textPaint.setAlpha(componentAlpha); // 固定不透明度 canvas.drawText(DEFAULT_TEXT, getWidth()/2f, getHeight()/2f + textPaint.getTextSize()/3, textPaint); + + // 恢复画笔原始透明度 + paint.setAlpha(originalPaintAlpha); + textPaint.setAlpha(originalTextPaintAlpha); } + + @Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); @@ -117,7 +141,7 @@ public class SlideToUnlockView extends View { DEFAULT_TEXT = s; } - private void resetProgress() { + public void resetProgress() { ValueAnimator animator = ValueAnimator.ofFloat(progress, 0); animator.setDuration(300); animator.addUpdateListener(animation -> { @@ -141,5 +165,76 @@ public class SlideToUnlockView extends View { public void setOnUnlockListener(OnUnlockListener listener) { this.listener = listener; } + + /** + * 恢复到初始化状态 + */ + public void resetToInitialState(String text) { + // 重置进度为0 + progress = 0f; + + if (text != null){ + setText(text); + }else { + // 重置默认文本 + DEFAULT_TEXT = "滑动执行"; + } + + + // 重置颜色为默认值 + bgColor = Color.parseColor("#cfcfcf"); + activeColor = Color.parseColor("#029A45"); + + // 停止所有正在进行的动画 + if (reboundAnimator != null && reboundAnimator.isRunning()) { + reboundAnimator.cancel(); + } + + // 重新绘制视图 + invalidate(); + } + + /** + * 设置组件的圆角弧度 + * @param cornerRadiusDp 圆角弧度(单位:dp) + */ + public void setCornerRadius(float cornerRadiusDp) { + this.cornerRadius = dpToPx(cornerRadiusDp); + invalidate(); + } + + /** + * 设置滑块的圆角弧度 + * @param thumbCornerRadiusDp 滑块圆角弧度(单位:dp) + */ + public void setThumbCornerRadius(float thumbCornerRadiusDp) { + this.thumbCornerRadius = dpToPx(thumbCornerRadiusDp); + invalidate(); + } + + /** + * 设置组件的透明度 + * @param alpha 透明度值,范围为0-255,0为完全透明,255为完全不透明 + */ + public void setComponentAlpha(int alpha) { + // 限制alpha值在有效范围内 + this.componentAlpha = Math.max(0, Math.min(255, alpha)); + + // 重新绘制视图 + invalidate(); + } + + /** + * 获取当前组件的透明度 + * @return 当前透明度值,范围为0-255 + */ + public int getComponentAlpha() { + return componentAlpha; + } + + + + + } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/AllView.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/AllView.java index 5f33971..d70cff9 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/AllView.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/AllView.java @@ -14,6 +14,7 @@ import com.amap.api.maps.MapView; import com.example.longyi_groundstation.Main.View.AttitudeIndicatorView; import com.example.longyi_groundstation.Main.View.CircularLinearLayout; import com.example.longyi_groundstation.Main.View.DpadView; +import com.example.longyi_groundstation.Main.View.SlideToUnlockView; import com.example.longyi_groundstation.R; import com.skydroid.fpvplayer.FPVWidget; @@ -93,6 +94,9 @@ public class AllView { public LinearLayout ll_link_start_fun2; public LinearLayout ll_link_start_back; + public SlideToUnlockView unlockView; + public RelativeLayout rl_unlock; + public AllView(Activity activity) { @@ -171,6 +175,8 @@ public class AllView { ll_link_start_fun1 = activity.findViewById(R.id.ll_link_start_fun1); ll_link_start_fun2 = activity.findViewById(R.id.ll_link_start_fun2); ll_link_start_back = activity.findViewById(R.id.ll_link_start_back); + unlockView = activity.findViewById(R.id.unlockView); + rl_unlock = activity.findViewById(R.id.rl_unlock); } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java index 664a09c..636dbc1 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/CoordinateConverter.java @@ -11,15 +11,39 @@ public class CoordinateConverter { private static final double A = 6378245.0; private static final double EE = 0.00669342162296594323; - // 高德(GCJ02)转谷歌(WGS84) + /** + * 高德(GCJ02)转谷歌(WGS84) + * + * @param lng 经度 (GCJ02坐标) + * @param lat 纬度 (GCJ02坐标) + * @return double数组,[0]为转换后的经度,[1]为转换后的纬度(WGS84坐标) + */ public static double[] gcj02ToWgs84(double lng, double lat) { if (outOfChina(lng, lat)) { + // 如果不在中国境内,GCJ02和WGS84坐标基本一致 return new double[]{lng, lat}; } - double[] gcj = wgs84ToGcj02(lng, lat); - return new double[]{lng * 2 - gcj[0], lat * 2 - gcj[1]}; + + // 使用迭代法进行更精确的转换 + double dLat = transformLat(lng - 105.0, lat - 35.0); + double dLon = transformLng(lng - 105.0, lat - 35.0); + + double radLat = lat / 180.0 * PI; + double magic = Math.sin(radLat); + magic = 1 - EE * magic * magic; + double sqrtMagic = Math.sqrt(magic); + + dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI); + dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI); + + // 从GCJ02转换到WGS84需要减去偏移量 + double wgsLon = lng - dLon; + double wgsLat = lat - dLat; + + return new double[]{wgsLon, wgsLat}; } + // 谷歌(WGS84)转高德(GCJ02) public static double[] wgs84ToGcj02(double lng, double lat) { if (outOfChina(lng, lat)) { diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java index cdbe602..8c81cff 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/FlyVoid.java @@ -1,31 +1,53 @@ package com.example.longyi_groundstation.Main.Void; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_count.MAVLINK_MSG_ID_MISSION_COUNT; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_item_int.MAVLINK_MSG_ID_MISSION_ITEM_INT; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_request.MAVLINK_MSG_ID_MISSION_REQUEST; +import static com.example.longyi_groundstation.MAVLink.common.msg_mission_request_int.MAVLINK_MSG_ID_MISSION_REQUEST_INT; import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_LAND; import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_RETURN_TO_LAUNCH; import static com.example.longyi_groundstation.MAVLink.enums.MAV_CMD.MAV_CMD_NAV_TAKEOFF; +import static com.example.longyi_groundstation.Main.Service.MyBoundService.MsgList; import static com.example.longyi_groundstation.Main.Service.MyBoundService.type; +import android.app.Activity; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.ViewGroup; import android.widget.TextView; +import android.widget.Toast; +import com.amap.api.maps.model.LatLng; import com.amap.api.services.auto.ListData; import com.example.longyi_groundstation.MAVLink.MAVLinkPacket; import com.example.longyi_groundstation.MAVLink.Messages.MAVLinkMessage; import com.example.longyi_groundstation.MAVLink.common.msg_command_long; +import com.example.longyi_groundstation.MAVLink.common.msg_mission_clear_all; +import com.example.longyi_groundstation.MAVLink.common.msg_mission_count; +import com.example.longyi_groundstation.MAVLink.common.msg_mission_item; +import com.example.longyi_groundstation.MAVLink.common.msg_mission_item_int; +import com.example.longyi_groundstation.MAVLink.common.msg_mission_request_int; +import com.example.longyi_groundstation.MAVLink.common.msg_mission_request_list; import com.example.longyi_groundstation.MAVLink.common.msg_param_request_read; import com.example.longyi_groundstation.MAVLink.common.msg_param_set; import com.example.longyi_groundstation.MAVLink.enums.MAV_CMD; import com.example.longyi_groundstation.MAVLink.enums.MAV_COMPONENT; +import com.example.longyi_groundstation.MAVLink.enums.MAV_FRAME; +import com.example.longyi_groundstation.Main.Activity.MainActivity; +import com.example.longyi_groundstation.Main.Base.CreateLink; import com.example.longyi_groundstation.Main.Service.MyBoundService; import com.example.longyi_groundstation.Main.Setting.Base.Param; import com.example.longyi_groundstation.Main.Setting.Base.ParamGroup; +import org.json.JSONException; +import org.json.JSONObject; + +import java.math.BigDecimal; import java.net.DatagramPacket; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -54,6 +76,7 @@ public class FlyVoid { public static void setParamUpdateComplete(boolean isComplete) { isParamUpdateComplete = isComplete; } + public void setAttitude(Context content, AllView allView, double roll, double pitch, double yaw) { //设置偏航 // allView.iv_yaw.setRotation((int) Math.round(yaw * 57.2)); @@ -62,25 +85,24 @@ public class FlyVoid { //设置翻滚 allView.cll_layout.setPivotX((float) allView.cll_layout.getWidth() / 2); allView.cll_layout.setPivotY((float) allView.cll_layout.getHeight() / 2); - allView.cll_layout.setRotation((int) Math.round(roll * 57.2)*-1); + allView.cll_layout.setRotation((int) Math.round(roll * 57.2) * -1); // Log.d("setAttitude: ",allView.cll_layout.getWidth()+ "++"+allView.cll_layout.getHeight()); //设置俯仰 ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) allView.ll_pitch.getLayoutParams(); - params.topMargin = MyTool.dpToPx(content,(int) Math.round(pitch * 57.2)) / 2; // 设置上边距(像素单位) + params.topMargin = MyTool.dpToPx(content, (int) Math.round(pitch * 57.2)) / 2; // 设置上边距(像素单位) allView.ll_pitch.setLayoutParams(params); - allView.v_welkin.getLayoutParams().height = MyTool.dpToPx(content,35+(int) Math.round(pitch * 57.2)); + allView.v_welkin.getLayoutParams().height = MyTool.dpToPx(content, 35 + (int) Math.round(pitch * 57.2)); // 最后必须应用参数 allView.v_welkin.requestLayout(); // 或 view.setLayoutParams(view.getLayoutParams()); } - - /** * 请求特定参数 (MAVLINK_MSG_ID_PARAM_REQUEST_READ) + * * @param paramId 参数名称(如"COM_RC_IN_MODE") */ public void requestParamRead(String paramId) { @@ -93,7 +115,7 @@ public class FlyVoid { request.param_index = -1; // 使用名称查询时设为-1 // 编码为MAVLinkPacket - sendMavlinkMessage(type,request); + sendMavlinkMessage(type, request); } /** @@ -101,7 +123,7 @@ public class FlyVoid { * * @cuijingzhou */ - public void requestParamSet(String paramId,String paramValue,String paramType) { + public void requestParamSet(String paramId, String paramValue, String paramType) { msg_param_set paramSet = new msg_param_set(); paramSet.target_system = 1; // 目标系统ID (飞控) paramSet.target_component = 1; // 目标组件ID @@ -111,7 +133,7 @@ public class FlyVoid { paramSet.param_value = Float.parseFloat(paramValue);// 参数值 paramSet.param_type = Short.parseShort(paramType); // 参数类型 // 发送命令 - sendMavlinkMessage(MyBoundService.type,paramSet); + sendMavlinkMessage(MyBoundService.type, paramSet); paramList.get(paramId).setParam_value(paramValue); } @@ -120,7 +142,7 @@ public class FlyVoid { * * @cuijingzhou */ - public void requestParamSet(String paramId,String paramValue) { + public void requestParamSet(String paramId, String paramValue) { msg_param_set paramSet = new msg_param_set(); paramSet.target_system = 1; // 目标系统ID (飞控) paramSet.target_component = 1; // 目标组件ID @@ -130,7 +152,7 @@ public class FlyVoid { paramSet.param_value = Float.parseFloat(paramValue);// 参数值 paramSet.param_type = Short.parseShort(paramList.get(paramId).getParam_type()); // 参数类型 // 发送命令 - sendMavlinkMessage(MyBoundService.type,paramSet); + sendMavlinkMessage(MyBoundService.type, paramSet); paramList.get(paramId).setParam_value(paramValue); } @@ -139,7 +161,7 @@ public class FlyVoid { * * @cuijingzhou */ - public void rotateMotorForOneSecond(int param1,int param3, int param4) { + public void rotateMotorForOneSecond(int param1, int param3, int param4) { // 创建MAVLink命令 msg_command_long msg = new msg_command_long(); msg.target_system = 1; // 目标系统ID @@ -157,7 +179,7 @@ public class FlyVoid { // 发送MAVLink消息 (需要实现您的MAVLink发送接口) - sendMavlinkMessage(MyBoundService.type,msg); + sendMavlinkMessage(MyBoundService.type, msg); } @@ -181,7 +203,7 @@ public class FlyVoid { command.param7 = Float.parseFloat(height); // 发送命令 - sendMavlinkMessage(MyBoundService.type,command); + sendMavlinkMessage(MyBoundService.type, command); } /** @@ -205,7 +227,7 @@ public class FlyVoid { command.param7 = 0; // 发送命令 - sendMavlinkMessage(MyBoundService.type,command); + sendMavlinkMessage(MyBoundService.type, command); } /** @@ -229,7 +251,7 @@ public class FlyVoid { command.param7 = 0; // 发送命令 - sendMavlinkMessage(MyBoundService.type,command); + sendMavlinkMessage(MyBoundService.type, command); } /** @@ -245,31 +267,25 @@ public class FlyVoid { Log.d("串口2发送的数据", SerialTool.bytesToHex(testData)); // 发送命令 - sendMessage_com2(MyBoundService.type,testData); + sendMessage_com2(MyBoundService.type, testData); } - - - /** * 通用MAVLink消息发送方法-串口1 mavlink通道 */ - public void sendMavlinkMessage(int type,MAVLinkMessage msg) { + public void sendMavlinkMessage(int type, MAVLinkMessage msg) { MAVLinkPacket packet = msg.pack(); if (type == 0) { // 串口 if (MyBoundService.serialHelper != null) { +// Log.d("串口1发送的数据", SerialTool.bytesToHex(packet.encodePacket())); MyBoundService.serialHelper.send(packet.encodePacket()); } } else { // UDP try { InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 改为飞控IP - DatagramPacket udpPacket = new DatagramPacket( - packet.encodePacket(), - packet.encodePacket().length, - targetAddress, - 14553 // MAVLink标准端口 + DatagramPacket udpPacket = new DatagramPacket(packet.encodePacket(), packet.encodePacket().length, targetAddress, 14553 // MAVLink标准端口 ); MyBoundService.serverSocket.send(udpPacket); } catch (Exception e) { @@ -281,24 +297,20 @@ public class FlyVoid { /** * 通用MAVLink消息发送方法-串口2 其它硬件通道 */ - public void sendMessage_com2(int type,byte[] testData) { + public void sendMessage_com2(int type, byte[] testData) { if (type == 0) { // 串口 if (MyBoundService.serialHelper2 != null) { MyBoundService.serialHelper2.send(testData); - Log.e("cuijinggzhou-发送", "发送成功 " ); + Log.e("cuijinggzhou-发送", "发送成功 "); } } else { // UDP try { if (MyBoundService.serverSocket2 != null) { InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // IP - DatagramPacket udpPacket = new DatagramPacket( - testData, - testData.length, - targetAddress, - 13553 // 标准端口 + DatagramPacket udpPacket = new DatagramPacket(testData, testData.length, targetAddress, 13553 // 标准端口 ); MyBoundService.serverSocket2.send(udpPacket); - Log.e("cuijinggzhou-发送", "发送成功 " ); + Log.e("cuijinggzhou-发送", "发送成功 "); } } catch (Exception e) { @@ -314,6 +326,7 @@ public class FlyVoid { private static Handler handler = new Handler(Looper.getMainLooper()); private static Runnable updateProgressRunnable; private static TextView tvParamLoad; // 假设 tvParamLoad 是用于显示进度的 TextView + public static void startParamLoadMonitoring(TextView tvParamLoad) { FlyVoid.tvParamLoad = tvParamLoad; @@ -343,7 +356,338 @@ public class FlyVoid { handler.post(updateProgressRunnable); } + /** + * 方法:发送航线任务到飞控并启动任务执行 + * + * @param createLinkList 航线航点列表 + * @cuijingzhou + */ + public void sendMissionToFlightController(Activity context, ArrayList createLinkList) { + if (createLinkList == null || createLinkList.isEmpty()) { + return; + } + // 创建 ProgressDialog + android.app.ProgressDialog progressDialog = new android.app.ProgressDialog(context); + progressDialog.setTitle("任务执行中"); + progressDialog.setMessage("正在发送航线到飞控..."); + progressDialog.setProgressStyle(android.app.ProgressDialog.STYLE_HORIZONTAL); + progressDialog.setCancelable(false); // 设置不可手动关闭 + progressDialog.setMax(100); + progressDialog.show(); + MsgList.set(MAVLINK_MSG_ID_MISSION_REQUEST,null); + new Thread(() -> { + try { + // 2. 发送航点计数 + msg_mission_count count = new msg_mission_count(); + count.target_system = 1; + count.target_component = 1; + count.count = createLinkList.size() + 1; // 航点数量 + sendMavlinkMessage(type, count); + + boolean isOk = true; + int sentWaypoints = 0; + int totalWaypoints = createLinkList.size() + 1; + + while (isOk) { + try { + String msgRequest = MsgList.get(MAVLINK_MSG_ID_MISSION_REQUEST); + if (msgRequest != null) { + JSONObject jsonObject = new JSONObject(msgRequest); + int seq = jsonObject.optInt("seq"); + upDataLinkPoint(seq, createLinkList); + sentWaypoints = seq + 1; + + // 更新发送进度 + final int progress = (int) ((sentWaypoints / (float) totalWaypoints) * 50); // 发送占50%进度 + context.runOnUiThread(() -> { + progressDialog.setProgress(progress); + }); + + Log.d("Missions", "--" + seq); + // 如果当前序号+1大于等于航点总数,则结束循环 + if ((seq + 1) > createLinkList.size()) { + isOk = false; + } + } + + // 添加短暂延迟以避免过度占用CPU + Thread.sleep(100); + } catch (Exception e) { + Log.e("Mission", "Error processing mission request: " + e.getMessage()); + // 出错时也退出循环避免无限循环 + isOk = false; + } + } + + context.runOnUiThread(() -> { + progressDialog.setMessage("正在校验航线..."); + }); + + // 校验点位是否正常上传 + boolean verifyResult = verifyPoint(createLinkList); + + // 更新校验进度 + context.runOnUiThread(() -> { + progressDialog.setProgress(100); + progressDialog.dismiss(); + + if (verifyResult) { + Toast.makeText(context, "航线已发送到飞控并校验通过", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, "航线发送完成但校验失败", Toast.LENGTH_SHORT).show(); + } + + }); + + } catch (Exception e) { + context.runOnUiThread(() -> { + progressDialog.dismiss(); + Toast.makeText(context, "航线发送过程中出现错误", Toast.LENGTH_SHORT).show(); + }); + e.printStackTrace(); + } + + }).start(); + } + + + /** + * 方法:给飞控发送点位 + * + * @cuijingzhou + */ + private void upDataLinkPoint(int i,ArrayList createLinkList) throws InterruptedException { + + //由于第一个点是home点,所以要从第2个点开始上传 + if (i == 0){ + msg_mission_item_int waypoint = new msg_mission_item_int(); + waypoint.target_system = 1; // 无人机系统ID + waypoint.target_component = 1; // 无人机组件ID + waypoint.seq = 0; // 航点序号 + waypoint.frame = MAV_FRAME.MAV_FRAME_GLOBAL_RELATIVE_ALT; // 坐标系 + waypoint.command = MAV_CMD.MAV_CMD_NAV_WAYPOINT; // 航点指令 + waypoint.current = 0; // 第一个航点设为当前航点 + waypoint.autocontinue = 1; // 自动继续到下一个航点 + waypoint.param1 = 0; // 停留时间(秒) + waypoint.param2 = 0; // 接受半径(m) + waypoint.param3 = 0; // 通过半径(m) + waypoint.param4 = 0; // 航向角 + waypoint.x = 0; + waypoint.y = 0; + waypoint.z = 0; // 高度(相对) + sendMavlinkMessage(type, waypoint); + Thread.sleep(50); + } + //正常上传 + else { + CreateLink link = createLinkList.get(i-1); + LatLng latLng = link.getLatLng(); + double[] doubles = CoordinateConverter.gcj02ToWgs84(latLng.longitude, latLng.latitude); + if (doubles != null) { + msg_mission_item_int waypoint = new msg_mission_item_int(); + waypoint.target_system = 1; // 无人机系统ID + waypoint.target_component = 1; // 无人机组件ID + waypoint.seq = i; // 航点序号 + waypoint.frame = MAV_FRAME.MAV_FRAME_GLOBAL_RELATIVE_ALT; // 坐标系 + waypoint.command = MAV_CMD.MAV_CMD_NAV_WAYPOINT; // 航点指令 + waypoint.current = 0; // 第一个航点设为当前航点 + waypoint.autocontinue = 1; // 自动继续到下一个航点 + waypoint.param1 = 0; // 停留时间(秒) + waypoint.param2 = 0; // 接受半径(m) + waypoint.param3 = 0; // 通过半径(m) + waypoint.param4 = 0; // 航向角 + waypoint.x = (int) (doubles[1] * 10000000); + waypoint.y = (int) (doubles[0] * 10000000); + // 经度 + waypoint.z = (float) link.getHeight(); // 高度(相对) + sendMavlinkMessage(type, waypoint); + Thread.sleep(50); + } + } + + } + + /** + * 方法:校验发送的点位是否正确 + * + * @cuijingzhou + */ + private boolean verifyPoint(ArrayList createLinkList) { + try { + MsgList.set(MAVLINK_MSG_ID_MISSION_COUNT,null); + // 创建MISSION_REQUEST_LIST消息 + msg_mission_request_list requestList = new msg_mission_request_list(); + requestList.target_system = 1; // 飞控系统ID + requestList.target_component = 1; // 飞控组件ID + requestList.mission_type = 0; // 任务类型,0表示默认任务 + + // 发送消息请求航点列表 + sendMavlinkMessage(type, requestList); + boolean isTrue = true; + while (isTrue) { + Thread.sleep(120); + String countMsg = MsgList.get(MAVLINK_MSG_ID_MISSION_COUNT); + if (countMsg != null) { + JSONObject countObject = new JSONObject(countMsg); + int count = countObject.optInt("count", 0); + + // 检查飞控上的航点数是否与本地一致 + if ((count-1) != createLinkList.size()) { + Log.e("VerifyPoint", "航点数量不一致:本地=" + createLinkList.size() + ", 飞控=" + count); + return false; + } + + // 逐一比对每个航点 + for (int i = 1; i < count; ) { + // 请求飞控发送特定序号的航点 + // 这里需要飞控支持自动发送或我们主动请求 + // 由于MAVLink协议通常是飞控在收到MISSION_REQUEST_LIST后自动发送MISSION_ITEM, + // 我们需要监听并比对这些消息 + // 创建MISSION_REQUEST_LIST消息 + msg_mission_request_int requestLists = new msg_mission_request_int(); + requestLists.seq = i; + requestLists.target_system = 1; // 飞控系统ID + requestLists.target_component = 1; // 飞控组件ID this.seq = seq; + requestLists.mission_type = 0; // 任务类型,0表示默认任务 + // 发送消息请求航点列表 + sendMavlinkMessage(type, requestLists); + + + // 等待一段时间让飞控发送对应序号的航点信息 + Thread.sleep(50); + + + // 从MsgList获取飞控发送的航点信息 + String missionItemMsg = MsgList.get(MAVLINK_MSG_ID_MISSION_ITEM_INT); + if (missionItemMsg != null) { + JSONObject missionItemObject = new JSONObject(missionItemMsg); + int seq = missionItemObject.optInt("seq", -1); + Log.e("VerifyPoint", "第几个:" + seq + "+"+ i); + // 确保是当前要检查的序号 + // 修复:确保seq有效且i在有效范围内 + if (seq == i) { + // 获取飞控发送的航点坐标 + double flyLat = Double.parseDouble(missionItemObject.optString("x")) / 10000000; + double flyLng = Double.parseDouble(missionItemObject.optString("y")) / 10000000; + double flyAlt = Double.parseDouble(missionItemObject.optString("z") ); + + Log.e("VerifyPoint", "坐标"+seq+"-" + flyLat + "+"+flyLng); + // 获取本地对应序号的航点 + CreateLink localLink = createLinkList.get(i-1); + LatLng localLatLng = localLink.getLatLng(); + double localHeight = localLink.getHeight(); + + // 坐标转换(如果需要) + double[] convertedCoords = CoordinateConverter.gcj02ToWgs84(localLatLng.longitude, localLatLng.latitude); + if (convertedCoords != null) { + double localLat = convertedCoords[1]; + double localLng = convertedCoords[0]; + + // 比对坐标(允许小误差) + if (Math.abs(flyLat - localLat) > 0.000001 || + Math.abs(flyLng - localLng) > 0.000001 || + Math.abs(flyAlt - localHeight) > 0.1) { + Log.e("VerifyPoint", "航点" + i + "坐标不一致"); + return false; + } + } else { + Log.e("VerifyPoint", "坐标转换失败,航点" + i); + return false; + } + i++; + } + + } else { + Log.e("VerifyPoint", "未收到飞控返回的航点" + i); +// return false; + } + } + + Log.d("VerifyPoint", "所有航点校验通过"); + isTrue = false; + return true; + } else { + Log.e("VerifyPoint", "未收到飞控返回的航点数量"); + } + } + return true; + } catch (Exception e) { + Log.e("VerifyPoint", "校验过程中发生错误: " + e + " at " + getClass().getSimpleName() + ".java:" + Thread.currentThread().getStackTrace()[2].getLineNumber()); + return false; + } + } + + + /** + * 方法:解锁飞机指令 + * + * @param arm 1表示解锁,0表示上锁 + * @cuijingzhou + */ + public void requestArmDisarm(int arm) { + // 构造命令 + msg_command_long command = new msg_command_long(); + command.target_system = 1; // 目标系统ID(飞控) + command.target_component = 1; // 目标组件ID + command.command = MAV_CMD.MAV_CMD_COMPONENT_ARM_DISARM; // 解锁/上锁命令 + command.confirmation = 0; // 确认位 + command.param1 = arm; // 1: 解锁, 0: 上锁 + command.param2 = 0; // 保留 + command.param3 = 0; // 保留 + command.param4 = 0; // 保留 + command.param5 = 0; // 保留 + command.param6 = 0; // 保留 + command.param7 = 0; // 保留 + + // 发送命令 + sendMavlinkMessage(MyBoundService.type, command); + } + + /** + * 方法:解锁飞机指令(简化版) + * + * @cuijingzhou + */ + public void requestArm() { + requestArmDisarm(1); // 1表示解锁 + } + + /** + * 方法:上锁飞机指令(简化版) + * + * @cuijingzhou + */ + public void requestDisarm() { + requestArmDisarm(0); // 0表示上锁 + } + + + /** + * 方法:执行航线任务(指定起始和结束点) + * + * @param startSeq 起始航点序号(从0开始) + * @param endSeq 结束航点序号(-1表示到最后一个航点) + * @cuijingzhou + */ + public void requestMissionStart(int startSeq, int endSeq) { + // 构造命令 + msg_command_long command = new msg_command_long(); + command.target_system = 1; // 目标系统ID(飞控) + command.target_component = 1; // 目标组件ID + command.command = MAV_CMD.MAV_CMD_MISSION_START; // 开始任务命令 + command.confirmation = 0; // 确认位 + command.param1 = startSeq; // 首先要执行的任务项索引 + command.param2 = endSeq; // 最后要执行的任务项索引 + command.param3 = 0; // 保留 + command.param4 = 0; // 保留 + command.param5 = 0; // 保留 + command.param6 = 0; // 保留 + command.param7 = 0; // 保留 + + // 发送命令 + sendMavlinkMessage(MyBoundService.type, command); + } diff --git a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MyReceiver.java b/app/src/main/java/com/example/longyi_groundstation/Main/Void/MyReceiver.java index b0619be..483b97c 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Main/Void/MyReceiver.java +++ b/app/src/main/java/com/example/longyi_groundstation/Main/Void/MyReceiver.java @@ -20,7 +20,8 @@ public class MyReceiver extends BroadcastReceiver { public static JSONObject PARAM_VALUE_json = null;//飞机基础飞行模式 public static JSONObject RC_CHANNELS_json = null;//RC通道监控 public static JSONObject VFR_HUD_json = null;//油门量 - + public static JSONObject MISSION_REQUEST_json = null;//路线上传报错回调 + public static JSONObject MISSION_ACK_json = null;//路线上传穿插回调 //ATTITUDE @@ -82,6 +83,18 @@ public class MyReceiver extends BroadcastReceiver { } private OnVfrHudListener VfrHudlistener; + public interface OnMissionRequestListener { + void onMissionRequest(JSONObject data); + } + private OnMissionRequestListener MissionRequestlistener; + + public interface OnMissionAckListener { + void onMissionAck(JSONObject data); + } + private OnMissionAckListener MissionAcklistener; + + + public void setATTITUDEListener(OnATTITUDEListener listener) { this.ATTITUDElistener = listener; @@ -116,6 +129,14 @@ public class MyReceiver extends BroadcastReceiver { this.VfrHudlistener = listener; } + public void setMissionRequestlistener(OnMissionRequestListener listener) { + this.MissionRequestlistener = listener; + } + + public void setMissionAcklistener(OnMissionAckListener listener) { + this.MissionAcklistener = listener; + } + @Override public void onReceive(Context context, Intent intent) { @@ -281,7 +302,7 @@ public class MyReceiver extends BroadcastReceiver { } } catch (Exception e) { - Log.e("cuijingzhou-e Broadcast_RC_CHANNELS_RAW", e.toString()); + Log.e("cuijingzhou-e Broadcast_RC_CHANNELS", e.toString()); } } @@ -300,7 +321,43 @@ public class MyReceiver extends BroadcastReceiver { } } catch (Exception e) { - Log.e("cuijingzhou-e Broadcast_RC_CHANNELS_RAW", e.toString()); + Log.e("cuijingzhou-e Broadcast_VFR_HUD", e.toString()); + } + } + + if ("Broadcast_MISSION_REQUEST".equals(intent.getAction())) { + try { + String receivedData = intent.getStringExtra("data"); + if (receivedData != null) { + MISSION_REQUEST_json = new JSONObject(receivedData); + MISSION_REQUEST_json.optString("jsonObject"); +// Log.d("cuijingzhou", "onReceive: " + receivedData); + // 触发回调 + if (MissionRequestlistener != null) { + MissionRequestlistener.onMissionRequest(MISSION_REQUEST_json); + } + } + + } catch (Exception e) { + Log.e("cuijingzhou-e Broadcast_MISSION_REQUEST", e.toString()); + } + } + + if ("Broadcast_MISSION_ACK".equals(intent.getAction())) { + try { + String receivedData = intent.getStringExtra("data"); + if (receivedData != null) { + MISSION_ACK_json = new JSONObject(receivedData); + MISSION_ACK_json.optString("jsonObject"); +// Log.d("cuijingzhou", "onReceive: " + receivedData); + // 触发回调 + if (MissionAcklistener != null) { + MissionAcklistener.onMissionAck(MISSION_ACK_json); + } + } + + } catch (Exception e) { + Log.e("cuijingzhou-e Broadcast_MISSION_ACK", e.toString()); } } } diff --git a/app/src/main/java/com/example/longyi_groundstation/Util/BroadcastUtil.java b/app/src/main/java/com/example/longyi_groundstation/Util/BroadcastUtil.java index abd8b7c..c3c2159 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Util/BroadcastUtil.java +++ b/app/src/main/java/com/example/longyi_groundstation/Util/BroadcastUtil.java @@ -146,5 +146,32 @@ public class BroadcastUtil { intent.clone(); } + /** + * MAVLINK_MSG_ID_MISSION_REQUEST + * + * @param context 上下文 + * @param data 数据-json + */ + public static void Broadcast_MISSION_REQUEST(Context context, String data) { + Intent intent = new Intent("Broadcast_MISSION_REQUEST"); + intent.putExtra("data", data); + context.sendBroadcast(intent); + intent.clone(); + } + + /** + * MAVLINK_MSG_ID_MISSION_ACK + * + * @param context 上下文 + * @param data 数据-json + */ + public static void Broadcast_MISSION_ACK(Context context, String data) { + Intent intent = new Intent("Broadcast_MISSION_ACK"); + intent.putExtra("data", data); + context.sendBroadcast(intent); + intent.clone(); + } + + } diff --git a/app/src/main/java/com/example/longyi_groundstation/Util/Tool.java b/app/src/main/java/com/example/longyi_groundstation/Util/Tool.java index e7bec58..ce42753 100644 --- a/app/src/main/java/com/example/longyi_groundstation/Util/Tool.java +++ b/app/src/main/java/com/example/longyi_groundstation/Util/Tool.java @@ -57,4 +57,59 @@ public class Tool { } + /** + * 方法:DEC转BIN(只获取第一位) - 8位表示 + * + * @param data 十进制字符串 + * @return 二进制表示的最高位(0或1) + * @cuijingzhou + */ + public static String getDecToFirstBin(String data) { + try { + // 将输入的十进制字符串转换为整数 + int decimal = Integer.parseInt(data); + + // 确保数值在byte范围内(0-255) + decimal = decimal & 0xFF; + + // 获取最高位(第8位): 右移7位后与1进行按位与操作 + int firstBit = (decimal >> 7) & 1; + + // 返回第一位作为字符串 + return String.valueOf(firstBit); + } catch (NumberFormatException e) { + // 如果输入不是有效的数字,返回默认值"0" + return "0"; + } + } + + /** + * 方法:DEC转BIN - 8位表示 + * + * @param data 十进制字符串 + * @return 8位二进制字符串表示 + * @cuijingzhou + */ + public static String getDecToBinFull(String data) { + try { + // 将输入的十进制字符串转换为整数 + int decimal = Integer.parseInt(data); + + // 确保数值在byte范围内(0-255) + decimal = decimal & 0xFF; + + // 将整数转换为二进制字符串 + String binaryString = Integer.toBinaryString(decimal); + + // 确保返回8位二进制字符串,不足位数前面补0 + return String.format("%8s", binaryString).replace(' ', '0'); + } catch (NumberFormatException e) { + // 如果输入不是有效的数字,返回默认值"00000000" + return "00000000"; + } + } + + + + } diff --git a/app/src/main/res/drawable/ff03a9f4_4round_1stroke_bg.xml b/app/src/main/res/drawable/ff03a9f4_4round_1stroke_bg.xml new file mode 100644 index 0000000..ec138e9 --- /dev/null +++ b/app/src/main/res/drawable/ff03a9f4_4round_1stroke_bg.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 84f9fdd..01d2f78 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -546,6 +546,24 @@ + + + + + + + + @@ -1619,27 +1637,26 @@ - + android:textSize="9sp" />