| device.properties | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/dengoff.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/dengon.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/off.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/onanddown.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/starton.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/xia1.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/xia10.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/xia2.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| image/xia20.png | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| set.properties | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/gecaoji/Device.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/yaokong/Control03.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/yaokong/Control05.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/yaokong/Control06.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/yaokong/Control07.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/yaokong/RemoteControlDialog.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
device.properties
@@ -24,3 +24,6 @@ positioningStatus=-1 satelliteCount=-1 differentialAge=-1 mowerStartStatus=-1 mowerLightStatus=-1 mowerBladeHeight=-1 image/dengoff.png
image/dengon.png
image/off.png
image/onanddown.png
image/starton.png
image/xia1.png
image/xia10.png
image/xia2.png
image/xia20.png
set.properties
@@ -1,5 +1,5 @@ #Current work land selection updated #Fri Dec 12 17:21:33 CST 2025 #Serial Port Preferences Updated #Mon Dec 15 15:45:14 CST 2025 appVersion=-1 currentWorkLandNumber=LAND1 cuttingWidth=200 @@ -9,5 +9,5 @@ mowerId=1234 serialAutoConnect=true serialBaudRate=115200 serialPortName=COM13 serialPortName=COM15 simCardNumber=-1 src/gecaoji/Device.java
@@ -2,7 +2,10 @@ import baseStation.BaseStation; import set.Setsys; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.Properties; @@ -74,6 +77,12 @@ // å·®åæ¶é´ private String selfCheckStatus = "-1"; // å²èæºèªæ£ç¶æ private String mowerStartStatus = "-1"; // å²èæºå¯å¨ç¶æï¼1å¼å¯ï¼0çç«ï¼-1æªç¥ private String mowerLightStatus = "-1"; // å²èæºç¯å¼å ³ç¶æï¼1å¼å¯ï¼0å ³éï¼-1æªç¥ private String mowerBladeHeight = "-1"; // å²èæºåçé«åº¦ï¼-1æªç¥ private static final double METERS_PER_DEGREE_LAT = 111320.0d; @@ -104,6 +113,58 @@ applyDefaults(gecaoji); } /** * ä¿åææå±æ§å°device.propertiesæä»¶ */ public void saveToProperties() { Properties properties = new Properties(); // å è½½ç°æå±æ§ï¼ä¿çå ¶ä»å±æ§ï¼ try (FileInputStream input = new FileInputStream("device.properties")) { properties.load(input); } catch (IOException e) { // 妿æä»¶ä¸åå¨ï¼ç»§ç»åå»ºæ°æä»¶ } // 设置ææè®¾å¤å±æ§ if (mowerName != null) properties.setProperty("mowerName", mowerName); if (mowerModel != null) properties.setProperty("mowerModel", mowerModel); if (mowerNumber != null) properties.setProperty("mowerNumber", mowerNumber); if (mowingWidth != null) properties.setProperty("mowingWidth", mowingWidth); if (mowingHeight != null) properties.setProperty("mowingHeight", mowingHeight); if (baseStationNumber != null) properties.setProperty("baseStationNumber", baseStationNumber); if (baseStationCardNumber != null) properties.setProperty("baseStationCardNumber", baseStationCardNumber); if (baseStationCoordinates != null) properties.setProperty("baseStationCoordinates", baseStationCoordinates); if (deviceCardnumber != null) properties.setProperty("deviceCardnumber", deviceCardnumber); if (createTime != null) properties.setProperty("createTime", createTime); if (GupdateTime != null) properties.setProperty("GupdateTime", GupdateTime); if (BupdateTime != null) properties.setProperty("BupdateTime", BupdateTime); if (realtimeLatitude != null) properties.setProperty("realtimeLatitude", realtimeLatitude); if (realtimeLongitude != null) properties.setProperty("realtimeLongitude", realtimeLongitude); if (realtimeAltitude != null) properties.setProperty("realtimeAltitude", realtimeAltitude); if (realtimeX != null) properties.setProperty("realtimeX", realtimeX); if (realtimeY != null) properties.setProperty("realtimeY", realtimeY); if (realtimeSpeed != null) properties.setProperty("realtimeSpeed", realtimeSpeed); if (heading != null) properties.setProperty("heading", heading); if (pitch != null) properties.setProperty("pitch", pitch); if (battery != null) properties.setProperty("battery", battery); if (positioningStatus != null) properties.setProperty("positioningStatus", positioningStatus); if (satelliteCount != null) properties.setProperty("satelliteCount", satelliteCount); if (differentialAge != null) properties.setProperty("differentialAge", differentialAge); if (selfCheckStatus != null) properties.setProperty("selfCheckStatus", selfCheckStatus); if (mowerStartStatus != null) properties.setProperty("mowerStartStatus", mowerStartStatus); if (mowerLightStatus != null) properties.setProperty("mowerLightStatus", mowerLightStatus); if (mowerBladeHeight != null) properties.setProperty("mowerBladeHeight", mowerBladeHeight); // ä¿åå°æä»¶ try (FileOutputStream output = new FileOutputStream("device.properties"); OutputStreamWriter writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) { properties.store(writer, "Updated device properties"); } catch (IOException ex) { System.err.println("æ æ³ä¿å device.properties: " + ex.getMessage()); } } private void loadPropertiesInto(Device target, Properties properties) { if (target == null) { return; @@ -133,7 +194,10 @@ target.positioningStatus = properties.getProperty("positioningStatus", "-1"); target.satelliteCount = properties.getProperty("satelliteCount", "-1"); target.differentialAge = properties.getProperty("differentialAge", "-1"); target.selfCheckStatus = properties.getProperty("selfCheckStatus", "-1"); target.selfCheckStatus = properties.getProperty("selfCheckStatus", "-1"); target.mowerStartStatus = properties.getProperty("mowerStartStatus", "-1"); target.mowerLightStatus = properties.getProperty("mowerLightStatus", "-1"); target.mowerBladeHeight = properties.getProperty("mowerBladeHeight", "-1"); } private void applyDefaults(Device target) { @@ -165,7 +229,10 @@ target.positioningStatus = "-1"; target.satelliteCount = "-1"; target.differentialAge = "-1"; target.selfCheckStatus = "-1"; target.selfCheckStatus = "-1"; target.mowerStartStatus = "-1"; target.mowerLightStatus = "-1"; target.mowerBladeHeight = "-1"; } public static synchronized Device initializeActiveDevice(String mowerId) { // æ ¹æ®è®¾å¤IDåå§åæ´»è·è®¾å¤ @@ -267,6 +334,15 @@ case "selfCheckStatus": this.selfCheckStatus = value; return true; case "mowerStartStatus": this.mowerStartStatus = value; return true; case "mowerLightStatus": this.mowerLightStatus = value; return true; case "mowerBladeHeight": this.mowerBladeHeight = value; return true; default: System.err.println("æªç¥å段: " + fieldName); return false; @@ -711,6 +787,30 @@ this.selfCheckStatus = selfCheckStatus; } public String getMowerStartStatus() { // è·åå²èæºå¯å¨ç¶æ return mowerStartStatus; } public void setMowerStartStatus(String mowerStartStatus) { // 设置å²èæºå¯å¨ç¶æ this.mowerStartStatus = mowerStartStatus; } public String getMowerLightStatus() { // è·åå²èæºç¯å¼å ³ç¶æ return mowerLightStatus; } public void setMowerLightStatus(String mowerLightStatus) { // 设置å²èæºç¯å¼å ³ç¶æ this.mowerLightStatus = mowerLightStatus; } public String getMowerBladeHeight() { // è·åå²èæºåçé«åº¦ return mowerBladeHeight; } public void setMowerBladeHeight(String mowerBladeHeight) { // 设置å²èæºåçé«åº¦ this.mowerBladeHeight = mowerBladeHeight; } @Override public String toString() { // è¾åºå¯¹è±¡ä¿¡æ¯ return "Device{" + @@ -739,6 +839,9 @@ ", satelliteCount='" + satelliteCount + '\'' + ", differentialAge='" + differentialAge + '\'' + ", selfCheckStatus='" + selfCheckStatus + '\'' + ", mowerStartStatus='" + mowerStartStatus + '\'' + ", mowerLightStatus='" + mowerLightStatus + '\'' + ", mowerBladeHeight='" + mowerBladeHeight + '\'' + '}'; } } src/yaokong/Control03.java
@@ -198,6 +198,16 @@ return currentSteeringSpeed; } /** * ç´æ¥è®¾ç½®å¹¶åé转åååè¿é度ï¼ç¨äºæç»åéæ§å¶æä»¤ï¼ * @param steeringSpeed 转åé度ï¼èå´-100å°100 * @param forwardSpeed åè¿é度ï¼èå´-100å°100 * @return æ¯å¦åéæå */ public static synchronized boolean setAndSendSpeeds(int steeringSpeed, int forwardSpeed) { return sendSpeedsIfDebugSerialOpen(steeringSpeed, forwardSpeed); } private static boolean sendSpeedsIfDebugSerialOpen(int nextSteering, int nextForward) { SerialPortService service = sendmessage.getActiveService(); if (service == null || !service.isOpen()) { src/yaokong/Control05.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,199 @@ package yaokong; import java.nio.ByteBuffer; import java.nio.ByteOrder; import chuankou.SerialPortService; import chuankou.sendmessage; /** * Control05.java - 饿§æºå¨å¯å¨å ³éæä»¤ç±» * * æä»¤ç±»å: 0x05 * åè½: æ§å¶å²èæºæ´æºçµæºçå¯å¨ä¸å ³é * * æ°æ®æ ¼å¼: * æ§å¶å¼(1åè): 0=å ³éï¼1=å¯å¨ * ä¿çåæ®µ(3åè): 0x00å¡«å * * 示ä¾ç¨æ³: * 1. å¯å¨æºå¨: Control05.buildPowerCommandHex("1") æ Control05.powerOn() * 2. å ³éæºå¨: Control05.buildPowerCommandHex("0") æ Control05.powerOff() * 3. åéæä»¤: Control05.sendPowerOnIfDebugSerialOpen() */ public class Control05 { /** * æå»ºé¥æ§æºå¨å¯å¨å ³éæä»¤ï¼æä»¤ç±»å0x05ï¼çHEXæ ¼å¼å符串 * * @param powerValue çµæºæ§å¶å¼å符串ï¼"0"è¡¨ç¤ºå ³éï¼"1"表示å¯å¨ * @return çµæºæ§å¶æä»¤çHEXæ ¼å¼å符串 */ public static String buildPowerCommandHex(String powerValue) { // è§£ææ§å¶å¼ int power = parsePowerValue(powerValue); byte[] commandBytes = buildPowerCommandBytes((byte) power); return bytesToHex(commandBytes); } /** * æå»ºé¥æ§æºå¨å¯å¨å ³éæä»¤çåèæ°ç» * * @param powerValue çµæºæ§å¶å¼ï¼0=å ³éï¼1=å¯å¨ * @return çµæºæ§å¶æä»¤çåèæ°ç» */ public static byte[] buildPowerCommandBytes(byte powerValue) { // éªè¯æ§å¶å¼èå´ if (powerValue != 0 && powerValue != 1) { throw new IllegalArgumentException("çµæºæ§å¶å¼å¿ é¡»æ¯0æ1"); } int dataLength = 4; // æ§å¶å¼1åè + ä¿çåæ®µ3åè ByteBuffer buffer = ByteBuffer.allocate(14); // æ»é¿åº¦14åè buffer.order(ByteOrder.LITTLE_ENDIAN); // 帧头 buffer.put(BluetoothProtocol.FRAME_HEADER); // æä»¤ç±»å (0x05) buffer.put((byte) 0x05); // æ°æ®é¿åº¦ buffer.putShort((short) dataLength); // åºåå· short sequence = (short) BluetoothProtocol.getNextSequence(); buffer.putShort(sequence); // æ§å¶å¼ buffer.put(powerValue); // ä¿çåæ®µ (3åèï¼å ¨é¨å¡«0) buffer.put((byte) 0x00); buffer.put((byte) 0x00); buffer.put((byte) 0x00); // 计ç®CRC16ï¼ä»æä»¤ç±»åå¼å§å°æ°æ®å å®¹ç»æï¼ byte[] dataForCRC = new byte[9]; ByteBuffer tempBuffer = ByteBuffer.allocate(9); tempBuffer.order(ByteOrder.LITTLE_ENDIAN); tempBuffer.put((byte) 0x05); // æä»¤ç±»å tempBuffer.putShort((short) dataLength); // æ°æ®é¿åº¦ tempBuffer.putShort(sequence); // åºåå· tempBuffer.put(powerValue); // æ§å¶å¼ tempBuffer.put((byte) 0x00); // ä¿çåæ®µ1 tempBuffer.put((byte) 0x00); // ä¿çåæ®µ2 tempBuffer.put((byte) 0x00); // ä¿çåæ®µ3 dataForCRC = tempBuffer.array(); int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length); buffer.putShort((short) crc); // 帧尾 buffer.put((byte) 0x0D); return buffer.array(); } /** * å½è°è¯ä¸²å£æå¼æ¶åéå¯å¨æºå¨æä»¤ * * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendPowerOnIfDebugSerialOpen() { return sendPowerCommandIfDebugSerialOpen((byte) 1); } /** * å½è°è¯ä¸²å£æå¼æ¶åéå ³éæºå¨æä»¤ * * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendPowerOffIfDebugSerialOpen() { return sendPowerCommandIfDebugSerialOpen((byte) 0); } /** * å¿«æ·æ¹æ³ï¼æå»ºå¯å¨æºå¨æä»¤ * * @return å¯å¨æä»¤çHEXå符串 */ public static String powerOn() { return buildPowerCommandHex("1"); } /** * å¿«æ·æ¹æ³ï¼æå»ºå ³éæºå¨æä»¤ * * @return å ³éæä»¤çHEXå符串 */ public static String powerOff() { return buildPowerCommandHex("0"); } /** * è§£ææ§å¶å¼å符串 */ private static int parsePowerValue(String powerStr) { try { int power = Integer.parseInt(powerStr.trim()); if (power != 0 && power != 1) { throw new IllegalArgumentException("çµæºæ§å¶å¼å¿ é¡»æ¯0æ1"); } return power; } catch (NumberFormatException e) { throw new IllegalArgumentException("çµæºæ§å¶å¼å¿ é¡»æ¯æ´æ°: " + powerStr); } } /** * åéçµæºæ§å¶æä»¤ï¼å 鍿¹æ³ï¼ */ private static boolean sendPowerCommandIfDebugSerialOpen(byte powerValue) { SerialPortService service = sendmessage.getActiveService(); if (service == null || !service.isOpen()) { return false; } byte[] payload = buildPowerCommandBytes(powerValue); // è°è¯ï¼æå°åéçæ°æ® System.out.println("åéçµæºæ§å¶æä»¤: " + bytesToHex(payload)); return sendmessage.sendViaActive(payload); } /** * åèæ°ç»è½¬æ¢ä¸ºHEXå符串 */ private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); if (i < bytes.length - 1) { hexString.append(' '); } } return hexString.toString().toUpperCase(); } /** * æµè¯å½æ°ï¼éªè¯çµæºæ§å¶æä»¤æå»º */ public static void testBuildPowerCommand() { System.out.println("=== æµè¯çµæºæ§å¶æä»¤æå»º ==="); // æµè¯1ï¼å¯å¨æä»¤ byte[] cmd1 = buildPowerCommandBytes((byte)1); System.out.println("å¯å¨æºå¨: " + bytesToHex(cmd1)); // æµè¯2ï¼å ³éæä»¤ byte[] cmd2 = buildPowerCommandBytes((byte)0); System.out.println("å ³éæºå¨: " + bytesToHex(cmd2)); } } src/yaokong/Control06.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,245 @@ package yaokong; import java.nio.ByteBuffer; import java.nio.ByteOrder; import chuankou.SerialPortService; import chuankou.sendmessage; /** * Control06.java - 饿§å²èåçåéæä»¤ç±» * * æä»¤ç±»å: 0x06 * åè½: æ§å¶å²èæºåççåéé«åº¦ * * æ°æ®æ ¼å¼: * åéå¼(1åè): -100~100ï¼æ£æ°è¡¨ç¤ºå䏿å * ä¿çåæ®µ(3åè): 0x00å¡«å * * 示ä¾ç¨æ³: * 1. æååç50%: Control06.buildBladeCommandHex("50") * 2. éä½åç30%: Control06.buildBladeCommandHex("-30") * 3. åéæåæä»¤: Control06.sendBladeUpIfDebugSerialOpen(50) * 4. åéé使令: Control06.sendBladeDownIfDebugSerialOpen(30) */ public class Control06 { private static final int MAX_BLADE_VALUE = 100; private static final int MIN_BLADE_VALUE = -100; private static final int BLADE_STEP = 10; // é»è®¤æ¥è¿å¼ private static int currentBladeHeight = 0; // å½ååçé«åº¦ç¾åæ¯ /** * æå»ºé¥æ§å²èåçåéæä»¤ï¼æä»¤ç±»å0x06ï¼çHEXæ ¼å¼å符串 * * @param bladeValueStr åçé«åº¦å¼å符串ï¼èå´-100å°100ï¼æ£æ°è¡¨ç¤ºå䏿å * @return åçåéæä»¤çHEXæ ¼å¼å符串 */ public static String buildBladeCommandHex(String bladeValueStr) { int bladeValue = parseBladeValue(bladeValueStr); byte[] commandBytes = buildBladeCommandBytes((byte) bladeValue); return bytesToHex(commandBytes); } /** * æå»ºé¥æ§å²èåçåéæä»¤çåèæ°ç» * * @param bladeValue åçé«åº¦å¼ï¼-100~100ï¼æ£æ°è¡¨ç¤ºå䏿å * @return åçåéæä»¤çåèæ°ç» */ public static byte[] buildBladeCommandBytes(byte bladeValue) { // éªè¯åçé«åº¦èå´ if (bladeValue < -100 || bladeValue > 100) { throw new IllegalArgumentException("åçé«åº¦å¼å¿ é¡»å¨-100å°100ä¹é´"); } int dataLength = 4; // åéå¼1åè + ä¿çåæ®µ3åè ByteBuffer buffer = ByteBuffer.allocate(14); // æ»é¿åº¦14åè buffer.order(ByteOrder.LITTLE_ENDIAN); // 帧头 buffer.put(BluetoothProtocol.FRAME_HEADER); // æä»¤ç±»å (0x06) buffer.put((byte) 0x06); // æ°æ®é¿åº¦ buffer.putShort((short) dataLength); // åºåå· short sequence = (short) BluetoothProtocol.getNextSequence(); buffer.putShort(sequence); // åçé«åº¦å¼ buffer.put(bladeValue); // ä¿çåæ®µ (3åèï¼å ¨é¨å¡«0) buffer.put((byte) 0x00); buffer.put((byte) 0x00); buffer.put((byte) 0x00); // 计ç®CRC16ï¼ä»æä»¤ç±»åå¼å§å°æ°æ®å å®¹ç»æï¼ byte[] dataForCRC = new byte[9]; ByteBuffer tempBuffer = ByteBuffer.allocate(9); tempBuffer.order(ByteOrder.LITTLE_ENDIAN); tempBuffer.put((byte) 0x06); // æä»¤ç±»å tempBuffer.putShort((short) dataLength); // æ°æ®é¿åº¦ tempBuffer.putShort(sequence); // åºåå· tempBuffer.put(bladeValue); // åçé«åº¦å¼ tempBuffer.put((byte) 0x00); // ä¿çåæ®µ1 tempBuffer.put((byte) 0x00); // ä¿çåæ®µ2 tempBuffer.put((byte) 0x00); // ä¿çåæ®µ3 dataForCRC = tempBuffer.array(); int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length); buffer.putShort((short) crc); // 帧尾 buffer.put((byte) 0x0D); return buffer.array(); } /** * å½è°è¯ä¸²å£æå¼æ¶åéæååçæä»¤ * * @param value æåç¾åæ¯å¼ï¼0-100ï¼ * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendBladeUpIfDebugSerialOpen(int value) { int targetHeight = Math.min(currentBladeHeight + value, MAX_BLADE_VALUE); return sendBladeHeightIfDebugSerialOpen(targetHeight); } /** * å½è°è¯ä¸²å£æå¼æ¶åééä½åçæä»¤ * * @param value éä½ç¾åæ¯å¼ï¼0-100ï¼ * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendBladeDownIfDebugSerialOpen(int value) { int targetHeight = Math.max(currentBladeHeight - value, MIN_BLADE_VALUE); return sendBladeHeightIfDebugSerialOpen(targetHeight); } /** * å½è°è¯ä¸²å£æå¼æ¶åéåçå½é¶æä»¤ * * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendBladeResetIfDebugSerialOpen() { return sendBladeHeightIfDebugSerialOpen(0); } /** * å¿«æ·æ¹æ³ï¼æå»ºæååçæä»¤ * * @param value æåç¾åæ¯å¼ï¼0-100ï¼ * @return æåæä»¤çHEXå符串 */ public static String bladeUp(int value) { int targetValue = Math.min(Math.max(value, 0), MAX_BLADE_VALUE); return buildBladeCommandHex(String.valueOf(targetValue)); } /** * å¿«æ·æ¹æ³ï¼æå»ºéä½åçæä»¤ * * @param value éä½ç¾åæ¯å¼ï¼0-100ï¼ * @return é使令çHEXå符串 */ public static String bladeDown(int value) { int targetValue = Math.max(Math.min(-value, 0), MIN_BLADE_VALUE); return buildBladeCommandHex(String.valueOf(targetValue)); } /** * è§£æåçé«åº¦å¼å符串 */ private static int parseBladeValue(String bladeStr) { try { int value = Integer.parseInt(bladeStr.trim()); if (value < MIN_BLADE_VALUE || value > MAX_BLADE_VALUE) { throw new IllegalArgumentException("åçé«åº¦å¼å¿ é¡»å¨-100å°100ä¹é´"); } return value; } catch (NumberFormatException e) { throw new IllegalArgumentException("åçé«åº¦å¼å¿ é¡»æ¯æ´æ°: " + bladeStr); } } /** * åéåçé«åº¦æ§å¶æä»¤ï¼å 鍿¹æ³ï¼ */ private static boolean sendBladeHeightIfDebugSerialOpen(int targetHeight) { SerialPortService service = sendmessage.getActiveService(); if (service == null || !service.isOpen()) { return false; } byte[] payload = buildBladeCommandBytes((byte) targetHeight); // è°è¯ï¼æå°åéçæ°æ® System.out.println("åéåçåéæä»¤: " + bytesToHex(payload)); boolean success = sendmessage.sendViaActive(payload); if (success) { currentBladeHeight = targetHeight; } return success; } /** * è·åå½ååçé«åº¦ * * @return å½ååçé«åº¦ç¾åæ¯ï¼-100å°100ï¼ */ public static int getCurrentBladeHeight() { return currentBladeHeight; } /** * éç½®åçé«åº¦ä¸º0 */ public static void resetBladeHeight() { currentBladeHeight = 0; } /** * åèæ°ç»è½¬æ¢ä¸ºHEXå符串 */ private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); if (i < bytes.length - 1) { hexString.append(' '); } } return hexString.toString().toUpperCase(); } /** * æµè¯å½æ°ï¼éªè¯åçåéæä»¤æå»º */ public static void testBuildBladeCommand() { System.out.println("=== æµè¯åçåéæä»¤æå»º ==="); // æµè¯1ï¼æåæä»¤ byte[] cmd1 = buildBladeCommandBytes((byte)50); System.out.println("æå50%: " + bytesToHex(cmd1)); // æµè¯2ï¼é使令 byte[] cmd2 = buildBladeCommandBytes((byte)-30); System.out.println("éä½30%: " + bytesToHex(cmd2)); // æµè¯3ï¼å½é¶æä»¤ byte[] cmd3 = buildBladeCommandBytes((byte)0); System.out.println("å½é¶: " + bytesToHex(cmd3)); } } src/yaokong/Control07.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,198 @@ package yaokong; import java.nio.ByteBuffer; import java.nio.ByteOrder; import chuankou.SerialPortService; import chuankou.sendmessage; /** * Control07.java - 饿§å¤§ç¯å¼å ³æä»¤ç±» * * æä»¤ç±»å: 0x07 * åè½: æ§å¶å²èæºå¤§ç¯çå¼å ³ * * æ°æ®æ ¼å¼: * å¼å ³ç¶æ(1åè): 0=å ³éï¼1=å¼å¯ * ä¿çåæ®µ(3åè): 0x00å¡«å * * 示ä¾ç¨æ³: * 1. å¼å¯å¤§ç¯: Control07.buildLightCommandHex("1") æ Control07.lightOn() * 2. å ³é大ç¯: Control07.buildLightCommandHex("0") æ Control07.lightOff() * 3. åéå¼ç¯æä»¤: Control07.sendLightOnIfDebugSerialOpen() * 4. åéå ³ç¯æä»¤: Control07.sendLightOffIfDebugSerialOpen() */ public class Control07 { /** * æå»ºé¥æ§å¤§ç¯å¼å ³æä»¤ï¼æä»¤ç±»å0x07ï¼çHEXæ ¼å¼å符串 * * @param lightValueStr 大ç¯å¼å ³ç¶æå符串ï¼"0"è¡¨ç¤ºå ³éï¼"1"表示å¼å¯ * @return å¤§ç¯æ§å¶æä»¤çHEXæ ¼å¼å符串 */ public static String buildLightCommandHex(String lightValueStr) { int lightValue = parseLightValue(lightValueStr); byte[] commandBytes = buildLightCommandBytes((byte) lightValue); return bytesToHex(commandBytes); } /** * æå»ºé¥æ§å¤§ç¯å¼å ³æä»¤çåèæ°ç» * * @param lightValue 大ç¯å¼å ³ç¶æï¼0=å ³éï¼1=å¼å¯ * @return å¤§ç¯æ§å¶æä»¤çåèæ°ç» */ public static byte[] buildLightCommandBytes(byte lightValue) { // éªè¯å¼å ³ç¶æèå´ if (lightValue != 0 && lightValue != 1) { throw new IllegalArgumentException("大ç¯å¼å ³ç¶æå¿ é¡»æ¯0æ1"); } int dataLength = 4; // å¼å ³ç¶æ1åè + ä¿çåæ®µ3åè ByteBuffer buffer = ByteBuffer.allocate(14); // æ»é¿åº¦14åè buffer.order(ByteOrder.LITTLE_ENDIAN); // 帧头 buffer.put(BluetoothProtocol.FRAME_HEADER); // æä»¤ç±»å (0x07) buffer.put((byte) 0x07); // æ°æ®é¿åº¦ buffer.putShort((short) dataLength); // åºåå· short sequence = (short) BluetoothProtocol.getNextSequence(); buffer.putShort(sequence); // 大ç¯å¼å ³ç¶æ buffer.put(lightValue); // ä¿çåæ®µ (3åèï¼å ¨é¨å¡«0) buffer.put((byte) 0x00); buffer.put((byte) 0x00); buffer.put((byte) 0x00); // 计ç®CRC16ï¼ä»æä»¤ç±»åå¼å§å°æ°æ®å å®¹ç»æï¼ byte[] dataForCRC = new byte[9]; ByteBuffer tempBuffer = ByteBuffer.allocate(9); tempBuffer.order(ByteOrder.LITTLE_ENDIAN); tempBuffer.put((byte) 0x07); // æä»¤ç±»å tempBuffer.putShort((short) dataLength); // æ°æ®é¿åº¦ tempBuffer.putShort(sequence); // åºåå· tempBuffer.put(lightValue); // 大ç¯å¼å ³ç¶æ tempBuffer.put((byte) 0x00); // ä¿çåæ®µ1 tempBuffer.put((byte) 0x00); // ä¿çåæ®µ2 tempBuffer.put((byte) 0x00); // ä¿çåæ®µ3 dataForCRC = tempBuffer.array(); int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length); buffer.putShort((short) crc); // 帧尾 buffer.put((byte) 0x0D); return buffer.array(); } /** * å½è°è¯ä¸²å£æå¼æ¶åéå¼å¯å¤§ç¯æä»¤ * * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendLightOnIfDebugSerialOpen() { return sendLightCommandIfDebugSerialOpen((byte) 1); } /** * å½è°è¯ä¸²å£æå¼æ¶åéå ³éå¤§ç¯æä»¤ * * @return åéæåè¿åtrueï¼å¦åè¿åfalse */ public static boolean sendLightOffIfDebugSerialOpen() { return sendLightCommandIfDebugSerialOpen((byte) 0); } /** * å¿«æ·æ¹æ³ï¼æå»ºå¼å¯å¤§ç¯æä»¤ * * @return å¼ç¯æä»¤çHEXå符串 */ public static String lightOn() { return buildLightCommandHex("1"); } /** * å¿«æ·æ¹æ³ï¼æå»ºå ³éå¤§ç¯æä»¤ * * @return å ³ç¯æä»¤çHEXå符串 */ public static String lightOff() { return buildLightCommandHex("0"); } /** * è§£æå¤§ç¯å¼å ³ç¶æå符串 */ private static int parseLightValue(String lightStr) { try { int light = Integer.parseInt(lightStr.trim()); if (light != 0 && light != 1) { throw new IllegalArgumentException("大ç¯å¼å ³ç¶æå¿ é¡»æ¯0æ1"); } return light; } catch (NumberFormatException e) { throw new IllegalArgumentException("大ç¯å¼å ³ç¶æå¿ é¡»æ¯æ´æ°: " + lightStr); } } /** * åéå¤§ç¯æ§å¶æä»¤ï¼å 鍿¹æ³ï¼ */ private static boolean sendLightCommandIfDebugSerialOpen(byte lightValue) { SerialPortService service = sendmessage.getActiveService(); if (service == null || !service.isOpen()) { return false; } byte[] payload = buildLightCommandBytes(lightValue); // è°è¯ï¼æå°åéçæ°æ® System.out.println("åéå¤§ç¯æ§å¶æä»¤: " + bytesToHex(payload)); return sendmessage.sendViaActive(payload); } /** * åèæ°ç»è½¬æ¢ä¸ºHEXå符串 */ private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); if (i < bytes.length - 1) { hexString.append(' '); } } return hexString.toString().toUpperCase(); } /** * æµè¯å½æ°ï¼éªè¯å¤§ç¯æ§å¶æä»¤æå»º */ public static void testBuildLightCommand() { System.out.println("=== æµè¯å¤§ç¯æ§å¶æä»¤æå»º ==="); // æµè¯1ï¼å¼ç¯æä»¤ byte[] cmd1 = buildLightCommandBytes((byte)1); System.out.println("å¼å¯å¤§ç¯: " + bytesToHex(cmd1)); // æµè¯2ï¼å ³ç¯æä»¤ byte[] cmd2 = buildLightCommandBytes((byte)0); System.out.println("å ³é大ç¯: " + bytesToHex(cmd2)); } } src/yaokong/RemoteControlDialog.java
@@ -20,6 +20,14 @@ private JLabel moveJoystickValueLabel; private JLabel turnJoystickValueLabel; private Timer speedUpdateTimer; // éåº¦æ´æ°å®æ¶å¨ // æææ§å¶å®æ¶å¨ï¼æç»å鿧嶿令 private Timer forwardControlTimer; // åè¿/åéæ§å¶å®æ¶å¨ private Timer steeringControlTimer; // è½¬åæ§å¶å®æ¶å¨ private int targetForwardSpeed = 0; // ç®æ åè¿/åéé度 private int targetSteeringSpeed = 0; // ç®æ 转åé度 private List<JButton> bladeButtons = new ArrayList<>(); // åå¨åçæ§å¶æé®ï¼ç¨äºæ¸ ç宿¶å¨ private String bladeUpDefaultText = "åçå"; // åçåæé®é»è®¤æå private String bladeDownDefaultText = "åçé"; // åçéæé®é»è®¤æå public RemoteControlDialog(Component parent, Color themeColor, JLabel speedLabel) { super(parent != null ? (JFrame) SwingUtilities.getWindowAncestor(parent) : null, @@ -31,7 +39,7 @@ Control03.resetSpeeds(); Control03.sendNeutralCommandIfDebugSerialOpen(); int dialogWidth = UIConfig.DIALOG_WIDTH; // ä¸é¦é¡µå®½åº¦ä¸è´ int dialogHeight = (int) (UIConfig.DIALOG_HEIGHT / 3.0 * 0.7) + 50 + 40; // å¢å 40åç´ int dialogHeight = (int) (UIConfig.DIALOG_HEIGHT / 3.0 * 0.7) +150; // å¢å 90åç´ ï¼å40+æ°å¢40+åå¢10ï¼ initializeDialog(dialogWidth, dialogHeight); initializeRemoteContent(); startSpeedUpdateTimer(); // å¯å¨éåº¦æ´æ°å®æ¶å¨ @@ -54,13 +62,69 @@ setSize(width, height); setLocationRelativeTo(getOwner()); setResizable(false); getContentPane().setBackground(new Color(26, 26, 46)); // æ·±è²èæ¯ Container contentPane = getContentPane(); if (contentPane instanceof JComponent) { JComponent jContentPane = (JComponent) contentPane; jContentPane.setBackground(new Color(0, 0, 0, 0)); // éæèæ¯ jContentPane.setOpaque(false); } } private void initializeRemoteContent() { JPanel contentPanel = new JPanel(new BorderLayout()); contentPanel.setBorder(BorderFactory.createEmptyBorder(16, 16, 16, 16)); contentPanel.setBackground(Color.WHITE); contentPanel.setOpaque(false); // è®¾ç½®ä¸ºéæ // å建顶é¨é¢æ¿ï¼å 嫿é®åæ°å¼æ¾ç¤º JPanel topPanel = new JPanel(new BorderLayout()); topPanel.setOpaque(false); // å建æé®é¢æ¿ï¼4个æé®ï¼é´é30åç´ ï¼ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 30, 0)); buttonPanel.setOpaque(false); buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0)); // åºé¨é´è·8åç´ // æé®1ï¼off.png <-> starton.pngï¼æåï¼å¯å¨ <-> çç« JLabel label1 = new JLabel("å¯å¨", SwingConstants.CENTER); label1.setFont(new Font("微软é é»", Font.PLAIN, 12)); label1.setForeground(new Color(40, 40, 40)); JButton button1 = createIconButtonWithLabel("image/off.png", "image/starton.png", 27, 27, label1, "å¯å¨", "çç«", "POWER"); JPanel panel1 = createButtonWithLabel(button1, label1); buttonPanel.add(panel1); // æé®2ï¼dengoff.png <-> dengon.pngï¼æåï¼å¼ç¯ <-> å ³ç¯ JLabel label2 = new JLabel("å¼ç¯", SwingConstants.CENTER); label2.setFont(new Font("微软é é»", Font.PLAIN, 12)); label2.setForeground(new Color(40, 40, 40)); JButton button2 = createIconButtonWithLabel("image/dengoff.png", "image/dengon.png", 30, 30, label2, "å¼ç¯", "å ³ç¯", "LIGHT"); JPanel panel2 = createButtonWithLabel(button2, label2); buttonPanel.add(panel2); // æé®3ï¼xia1.pngï¼åºå®å¾æ ï¼ï¼æåï¼åçå JButton button3 = createBladeControlButton("image/xia1.png", "image/xia20.png", 30, 30, true); JLabel label3 = new JLabel("åçå", SwingConstants.CENTER); label3.setFont(new Font("微软é é»", Font.PLAIN, 12)); label3.setForeground(new Color(40, 40, 40)); button3.putClientProperty("label", label3); button3.putClientProperty("defaultText", bladeUpDefaultText); bladeButtons.add(button3); // æ·»å å°åè¡¨ä»¥ä¾¿æ¸ ç JPanel panel3 = createButtonWithLabel(button3, label3); buttonPanel.add(panel3); // æé®4ï¼xia2.pngï¼åºå®å¾æ ï¼ï¼æåï¼åçé JButton button4 = createBladeControlButton("image/xia2.png", "image/xia10.png", 30, 30, false); JLabel label4 = new JLabel("åçé", SwingConstants.CENTER); label4.setFont(new Font("微软é é»", Font.PLAIN, 12)); label4.setForeground(new Color(40, 40, 40)); button4.putClientProperty("label", label4); button4.putClientProperty("defaultText", bladeDownDefaultText); bladeButtons.add(button4); // æ·»å å°åè¡¨ä»¥ä¾¿æ¸ ç JPanel panel4 = createButtonWithLabel(button4, label4); buttonPanel.add(panel4); topPanel.add(buttonPanel, BorderLayout.NORTH); // 卿¯ä¸ªææä¸æ¹å嫿¾ç¤ºå ¶ç¶æ/æ°å¼ï¼å两åï¼ JPanel valuesPanel = new JPanel(new GridLayout(1, 2, 20, 0)); @@ -80,14 +144,16 @@ valuesPanel.add(moveJoystickValueLabel); valuesPanel.add(turnJoystickValueLabel); contentPanel.add(valuesPanel, BorderLayout.NORTH); topPanel.add(valuesPanel, BorderLayout.CENTER); contentPanel.add(topPanel, BorderLayout.NORTH); // å建ææé¢æ¿ JPanel joystickPanel = new JPanel(new GridLayout(1, 2, 20, 0)); joystickPanel.setOpaque(false); // ç§»å¨ææï¼ç»¿è²ä¸»é¢ï¼ moveJoystick = new ModernJoystickComponent("åè¿/åé", moveJoystick = new ModernJoystickComponent(" ", new Color(46, 204, 113), true); // 绿è²ä¸»é¢ moveJoystick.setJoystickListener(new JoystickListener() { @Override @@ -98,10 +164,15 @@ // éå¶å¨ [-100, 100] forwardVal = Math.max(-100, Math.min(100, forwardVal)); // æ´æ°ç®æ é度 targetForwardSpeed = forwardVal; if (Math.abs(y) > 0.1) { applyForwardSpeed(forwardVal); // ææä¸å¨ä¸å¿ä½ç½®ï¼å¯å¨æç»åé宿¶å¨ startForwardControlTimer(); } else { // åå // ææåå°ä¸å¿ä½ç½®ï¼åæ¢åé stopForwardControlTimer(); stopForward(); } @@ -111,7 +182,7 @@ } }); // è½¬åææï¼èè²ä¸»é¢ï¼ turnJoystick = new ModernJoystickComponent("左转/å³è½¬", turnJoystick = new ModernJoystickComponent("", new Color(52, 152, 219), false); // èè²ä¸»é¢ turnJoystick.setJoystickListener(new JoystickListener() { @Override @@ -121,10 +192,15 @@ int steeringVal = (int) Math.round(x * 100.0); steeringVal = Math.max(-100, Math.min(100, steeringVal)); // æ´æ°ç®æ é度 targetSteeringSpeed = steeringVal; if (Math.abs(x) > 0.1) { applySteeringSpeed(steeringVal); // ææä¸å¨ä¸å¿ä½ç½®ï¼å¯å¨æç»åé宿¶å¨ startSteeringControlTimer(); } else { // å·¦å³ // ææåå°ä¸å¿ä½ç½®ï¼åæ¢åé stopSteeringControlTimer(); stopSteering(); } @@ -142,6 +218,360 @@ getContentPane().add(contentPanel); } /** * å建带æ ç¾çæé®é¢æ¿ï¼åç´å¸å±ï¼æé®å¨ä¸ï¼æ ç¾å¨ä¸ï¼ * @param button æé® * @param label æ ç¾ * @return å 嫿é®åæ ç¾ç颿¿ */ private JPanel createButtonWithLabel(JButton button, JLabel label) { JPanel panel = new JPanel(new BorderLayout()); panel.setOpaque(false); panel.add(button, BorderLayout.CENTER); panel.add(label, BorderLayout.SOUTH); panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); return panel; } /** * å建å¯åæ¢å¾æ çæé®ï¼å¸¦æ ç¾æååæ¢ï¼ * @param defaultIconPath é»è®¤å¾æ è·¯å¾ * @param clickedIconPath ç¹å»åç徿 è·¯å¾ * @param width 徿 宽度 * @param height 徿 é«åº¦ * @param label æ ç¾ç»ä»¶ * @param defaultText é»è®¤æå * @param clickedText ç¹å»åçæå * @param controlType æ§å¶æä»¤ç±»åï¼"POWER"表示å¯å¨/çç«ï¼"LIGHT"表示å¼ç¯/å ³ç¯ï¼nullè¡¨ç¤ºæ æ§å¶æä»¤ * @return é 置好çæé® */ private JButton createIconButtonWithLabel(String defaultIconPath, String clickedIconPath, int width, int height, JLabel label, String defaultText, String clickedText, String controlType) { JButton button = new JButton(); button.setPreferredSize(new Dimension(width, height)); button.setMinimumSize(new Dimension(width, height)); button.setMaximumSize(new Dimension(width, height)); button.setContentAreaFilled(false); button.setBorderPainted(false); button.setFocusPainted(false); // å è½½é»è®¤å¾æ åç¹å»å¾æ ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height); ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height); if (defaultIcon != null) { button.setIcon(defaultIcon); } // ä½¿ç¨ clientProperty æ¥è·è¸ªæé®ç¶æï¼false=é»è®¤å¾æ ï¼true=ç¹å»å¾æ ï¼ button.putClientProperty("isClicked", false); button.putClientProperty("defaultIcon", defaultIcon); button.putClientProperty("clickedIcon", clickedIcon); button.putClientProperty("label", label); button.putClientProperty("defaultText", defaultText); button.putClientProperty("clickedText", clickedText); button.putClientProperty("controlType", controlType); // æ·»å ç¹å»äºä»¶ï¼åæ¢å¾æ åæåï¼å¹¶å鿧嶿令 button.addActionListener(e -> { Boolean isClicked = (Boolean) button.getClientProperty("isClicked"); ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon"); ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon"); JLabel labelRef = (JLabel) button.getClientProperty("label"); String defaultTextRef = (String) button.getClientProperty("defaultText"); String clickedTextRef = (String) button.getClientProperty("clickedText"); String controlTypeRef = (String) button.getClientProperty("controlType"); if (isClicked == null || !isClicked) { // å½åæ¯é»è®¤å¾æ ï¼åæ¢å°ç¹å»å¾æ if (clickedIconRef != null) { button.setIcon(clickedIconRef); button.putClientProperty("isClicked", true); } // æ´æ°æ ç¾æå if (labelRef != null && clickedTextRef != null) { labelRef.setText(clickedTextRef); } // å鿧嶿令ï¼å¼å¯ï¼ if ("POWER".equals(controlTypeRef)) { boolean success = Control05.sendPowerOnIfDebugSerialOpen(); if (!success) { showSerialClosedWarning(); } } else if ("LIGHT".equals(controlTypeRef)) { boolean success = Control07.sendLightOnIfDebugSerialOpen(); if (!success) { showSerialClosedWarning(); } } } else { // å½åæ¯ç¹å»å¾æ ï¼åæ¢åé»è®¤å¾æ if (defaultIconRef != null) { button.setIcon(defaultIconRef); button.putClientProperty("isClicked", false); } // æ´æ°æ ç¾æå if (labelRef != null && defaultTextRef != null) { labelRef.setText(defaultTextRef); } // å鿧嶿令ï¼å ³éï¼ if ("POWER".equals(controlTypeRef)) { boolean success = Control05.sendPowerOffIfDebugSerialOpen(); if (!success) { showSerialClosedWarning(); } } else if ("LIGHT".equals(controlTypeRef)) { boolean success = Control07.sendLightOffIfDebugSerialOpen(); if (!success) { showSerialClosedWarning(); } } } }); return button; } /** * å建å¯åæ¢å¾æ çæé® * @param defaultIconPath é»è®¤å¾æ è·¯å¾ * @param clickedIconPath ç¹å»åç徿 è·¯å¾ * @param width 徿 宽度 * @param height 徿 é«åº¦ * @return é 置好çæé® */ private JButton createIconButton(String defaultIconPath, String clickedIconPath, int width, int height) { JButton button = new JButton(); button.setPreferredSize(new Dimension(width, height)); button.setMinimumSize(new Dimension(width, height)); button.setMaximumSize(new Dimension(width, height)); button.setContentAreaFilled(false); button.setBorderPainted(false); button.setFocusPainted(false); // å è½½é»è®¤å¾æ åç¹å»å¾æ ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height); ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height); if (defaultIcon != null) { button.setIcon(defaultIcon); } // ä½¿ç¨ clientProperty æ¥è·è¸ªæé®ç¶æï¼false=é»è®¤å¾æ ï¼true=ç¹å»å¾æ ï¼ button.putClientProperty("isClicked", false); button.putClientProperty("defaultIcon", defaultIcon); button.putClientProperty("clickedIcon", clickedIcon); // æ·»å ç¹å»äºä»¶ï¼åæ¢å¾æ button.addActionListener(e -> { Boolean isClicked = (Boolean) button.getClientProperty("isClicked"); ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon"); ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon"); if (isClicked == null || !isClicked) { // å½åæ¯é»è®¤å¾æ ï¼åæ¢å°ç¹å»å¾æ if (clickedIconRef != null) { button.setIcon(clickedIconRef); button.putClientProperty("isClicked", true); } } else { // å½åæ¯ç¹å»å¾æ ï¼åæ¢åé»è®¤å¾æ if (defaultIconRef != null) { button.setIcon(defaultIconRef); button.putClientProperty("isClicked", false); } } }); return button; } /** * å建åºå®å¾æ çæé® * @param iconPath 徿 è·¯å¾ * @param width 徿 宽度 * @param height 徿 é«åº¦ * @return é 置好çæé® */ private JButton createFixedIconButton(String iconPath, int width, int height) { JButton button = new JButton(); button.setPreferredSize(new Dimension(width, height)); button.setMinimumSize(new Dimension(width, height)); button.setMaximumSize(new Dimension(width, height)); button.setContentAreaFilled(false); button.setBorderPainted(false); button.setFocusPainted(false); ImageIcon icon = loadIcon(iconPath, width, height); if (icon != null) { button.setIcon(icon); } return button; } /** * å建åçåéæ§å¶æé®ï¼æ¯æç¹å»åé¿æï¼ * @param defaultIconPath é»è®¤å¾æ è·¯å¾ * @param clickedIconPath ç¹å»/é¿ææ¶ç徿 è·¯å¾ * @param width 徿 宽度 * @param height 徿 é«åº¦ * @param isUp true表示åçåï¼false表示åçé * @return é 置好çæé® */ private JButton createBladeControlButton(String defaultIconPath, String clickedIconPath, int width, int height, boolean isUp) { JButton button = new JButton(); button.setPreferredSize(new Dimension(width, height)); button.setMinimumSize(new Dimension(width, height)); button.setMaximumSize(new Dimension(width, height)); button.setContentAreaFilled(false); button.setBorderPainted(false); button.setFocusPainted(false); // å è½½å¾æ ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height); ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height); if (defaultIcon != null) { button.setIcon(defaultIcon); } button.putClientProperty("defaultIcon", defaultIcon); button.putClientProperty("clickedIcon", clickedIcon); button.putClientProperty("isUp", isUp); button.putClientProperty("isPressed", false); // é¿æå®æ¶å¨ Timer longPressTimer = new Timer(100, e -> { // æ¯100msæ§è¡ä¸æ¬¡ if (button.getClientProperty("isPressed") == Boolean.TRUE) { boolean isUpButton = (Boolean) button.getClientProperty("isUp"); int currentHeight = Control06.getCurrentBladeHeight(); // 使ç¨Control06çæ¹æ³åéæä»¤ boolean success; if (isUpButton) { success = Control06.sendBladeUpIfDebugSerialOpen(1); } else { success = Control06.sendBladeDownIfDebugSerialOpen(1); } if (!success) { showSerialClosedWarning(); } else { // æ´æ°æé®æ ç¾æ¾ç¤ºå½åæ°å¼ updateBladeButtonLabel(button); } } }); longPressTimer.setInitialDelay(500); // é¿æ500msåå¼å§è¿ç»åå button.putClientProperty("longPressTimer", longPressTimer); // åå¨å®æ¶å¨å¼ç¨ // é¼ æ æä¸äºä»¶ button.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { button.putClientProperty("isPressed", true); // ç«å³åæ¢å¾æ ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon"); if (clickedIconRef != null) { button.setIcon(clickedIconRef); } // ç¹å»æ¶ç«å³å¢å /åå°10ï¼ä½¿ç¨Control06çæ¹æ³åéæä»¤ boolean isUpButton = (Boolean) button.getClientProperty("isUp"); boolean success; if (isUpButton) { success = Control06.sendBladeUpIfDebugSerialOpen(10); } else { success = Control06.sendBladeDownIfDebugSerialOpen(10); } if (!success) { showSerialClosedWarning(); } else { // æ´æ°æé®æ ç¾æ¾ç¤ºå½åæ°å¼ updateBladeButtonLabel(button); } // å¯å¨é¿æå®æ¶å¨ longPressTimer.start(); } @Override public void mouseReleased(MouseEvent e) { button.putClientProperty("isPressed", false); // åæ¢é¿æå®æ¶å¨ longPressTimer.stop(); // æ¢å¤é»è®¤å¾æ ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon"); if (defaultIconRef != null) { button.setIcon(defaultIconRef); } // æ¢å¤é»è®¤æå JLabel labelRef = (JLabel) button.getClientProperty("label"); String defaultTextRef = (String) button.getClientProperty("defaultText"); if (labelRef != null && defaultTextRef != null) { labelRef.setText(defaultTextRef); } } }); return button; } /** * æ´æ°åçæé®æ ç¾æ¾ç¤ºå½åæ°å¼ * @param button æé® */ private void updateBladeButtonLabel(JButton button) { JLabel labelRef = (JLabel) button.getClientProperty("label"); if (labelRef != null) { String defaultTextRef = (String) button.getClientProperty("defaultText"); int currentHeight = Control06.getCurrentBladeHeight(); String displayText = defaultTextRef + " " + currentHeight; labelRef.setText(displayText); } } /** * å 载并缩æ¾å¾æ * @param iconPath 徿 è·¯å¾ * @param width ç®æ 宽度 * @param height ç®æ é«åº¦ * @return 缩æ¾åç徿 */ private ImageIcon loadIcon(String iconPath, int width, int height) { try { java.net.URL imgURL = getClass().getClassLoader().getResource(iconPath); if (imgURL == null) { // å°è¯ä»æä»¶ç³»ç»å è½½ java.io.File imgFile = new java.io.File(iconPath); if (imgFile.exists()) { ImageIcon originalIcon = new ImageIcon(imgFile.getAbsolutePath()); Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH); ImageIcon scaledIcon = new ImageIcon(scaledImage); scaledIcon.setDescription(iconPath); return scaledIcon; } } else { ImageIcon originalIcon = new ImageIcon(imgURL); Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH); ImageIcon scaledIcon = new ImageIcon(scaledImage); scaledIcon.setDescription(iconPath); return scaledIcon; } } catch (Exception e) { System.err.println("æ æ³å è½½å¾æ : " + iconPath + " - " + e.getMessage()); } return null; } private JPanel createStatusPanel(String label, String value, Color color) { JPanel panel = new JPanel(new BorderLayout(0, 5)); panel.setOpaque(false); @@ -235,6 +665,102 @@ } } /** * å¯å¨åè¿/åéæ§å¶å®æ¶å¨ï¼æç»å鿧嶿令 */ private void startForwardControlTimer() { // 妿宿¶å¨å·²ç»å¨è¿è¡ï¼å åæ¢å® if (forwardControlTimer != null && forwardControlTimer.isRunning()) { forwardControlTimer.stop(); } // å建æ°ç宿¶å¨ï¼æ¯100msåé䏿¬¡æä»¤ forwardControlTimer = new Timer(100, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // æç»åéç®æ é度çæä»¤ applyForwardSpeedContinuously(targetForwardSpeed); } }); forwardControlTimer.setInitialDelay(0); forwardControlTimer.start(); } /** * 忢åè¿/åéæ§å¶å®æ¶å¨ */ private void stopForwardControlTimer() { if (forwardControlTimer != null && forwardControlTimer.isRunning()) { forwardControlTimer.stop(); } } /** * å¯å¨è½¬åæ§å¶å®æ¶å¨ï¼æç»å鿧嶿令 */ private void startSteeringControlTimer() { // 妿宿¶å¨å·²ç»å¨è¿è¡ï¼å åæ¢å® if (steeringControlTimer != null && steeringControlTimer.isRunning()) { steeringControlTimer.stop(); } // å建æ°ç宿¶å¨ï¼æ¯100msåé䏿¬¡æä»¤ steeringControlTimer = new Timer(100, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // æç»åéç®æ é度çæä»¤ applySteeringSpeedContinuously(targetSteeringSpeed); } }); steeringControlTimer.setInitialDelay(0); steeringControlTimer.start(); } /** * åæ¢è½¬åæ§å¶å®æ¶å¨ */ private void stopSteeringControlTimer() { if (steeringControlTimer != null && steeringControlTimer.isRunning()) { steeringControlTimer.stop(); } } /** * æç»åéåè¿/åéé度æä»¤ */ private void applyForwardSpeedContinuously(int targetSpeed) { int currentSpeed = Control03.getCurrentForwardSpeed(); int currentSteeringSpeed = Control03.getCurrentSteeringSpeed(); // 妿已ç»è¾¾å°ç®æ é度ï¼ç´æ¥åé䏿¬¡ä»¥ä¿æç¶æ if (currentSpeed == targetSpeed) { // ç´æ¥åéç®æ é度æä»¤ä»¥ä¿æç¶æï¼å³ä½¿é度ç¸åä¹è¦åéï¼ Control03.setAndSendSpeeds(currentSteeringSpeed, targetSpeed); } else { // éæ¥è°æ´å°ç®æ é度 int delta = targetSpeed > currentSpeed ? 10 : -10; Control03.adjustForwardSpeed(delta); } } /** * æç»åé转åé度æä»¤ */ private void applySteeringSpeedContinuously(int targetSpeed) { int currentSpeed = Control03.getCurrentSteeringSpeed(); int currentForwardSpeed = Control03.getCurrentForwardSpeed(); // 妿已ç»è¾¾å°ç®æ é度ï¼ç´æ¥åé䏿¬¡ä»¥ä¿æç¶æ if (currentSpeed == targetSpeed) { // ç´æ¥åéç®æ é度æä»¤ä»¥ä¿æç¶æï¼å³ä½¿é度ç¸åä¹è¦åéï¼ Control03.setAndSendSpeeds(targetSpeed, currentForwardSpeed); } else { // éæ¥è°æ´å°ç®æ é度 int delta = targetSpeed > currentSpeed ? 15 : -15; Control03.adjustSteeringSpeed(delta); } } // æ´æ°é¡¶é¨æ¾ç¤ºçæææ°å¼ï¼å¨ EDT ä¸è°ç¨ï¼ï¼æåæ ¹æ®æ°å¼æ å°ä¸ºæ¹åæè¿° private void updateJoystickValues(int forwardVal, int steeringVal) { // 计ç®ç§»å¨/转åæè¿°ææ¬ @@ -330,6 +856,15 @@ @Override public void dispose() { // åæ¢å¹¶æ¸ çæ§å¶å®æ¶å¨ stopForwardControlTimer(); stopSteeringControlTimer(); if (forwardControlTimer != null) { forwardControlTimer = null; } if (steeringControlTimer != null) { steeringControlTimer = null; } // ååéåº¦æ´æ°å®æ¶å¨ if (speedUpdateTimer != null) { speedUpdateTimer.stop(); @@ -349,6 +884,14 @@ if (turnJoystick != null) { turnJoystick.dispose(); } // åæ¢å¹¶æ¸ çåçæé®ç宿¶å¨ for (JButton bladeButton : bladeButtons) { Timer timer = (Timer) bladeButton.getClientProperty("longPressTimer"); if (timer != null && timer.isRunning()) { timer.stop(); } } bladeButtons.clear(); super.dispose(); }