package yaokong; import java.nio.ByteBuffer; import java.nio.ByteOrder; import chuankou.SerialPortService; import chuankou.sendmessage; public class Control03 { private static final int MAX_SPEED = 100; private static final int MIN_SPEED = -100; private static final int SPEED_STEP = 10; private static int currentForwardSpeed = 0; private static int currentSteeringSpeed = 0; /** * 构建控制转向指令(指令类型0x03)的HEX格式字符串 * * @param steeringSpeedStr 转向速度字符串,范围-100到100,负数左转 * @param forwardSpeedStr 行进速度字符串,范围-100到100,负数倒退 * @return 控制转向指令的HEX格式字符串 */ public static String buildSteeringCommandHex(String steeringSpeedStr, String forwardSpeedStr) { // 解析速度值 int steeringSpeed = parseSpeed(steeringSpeedStr, "转向速度"); int forwardSpeed = parseSpeed(forwardSpeedStr, "行进速度"); byte[] commandBytes = buildSteeringCommandBytes((byte) steeringSpeed, (byte) forwardSpeed); return bytesToHex(commandBytes); } /** * 构建控制转向指令的字节数组(修正版本,按照协议1.docx格式) * 协议要求:转向速度(1) + 行进速度(1) + 保留字段(2) = 4字节 */ public static byte[] buildSteeringCommandBytes(byte steeringSpeed, byte forwardSpeed) { // 验证速度范围 if (steeringSpeed < -100 || steeringSpeed > 100) { throw new IllegalArgumentException("转向速度必须在-100到100之间"); } if (forwardSpeed < -100 || forwardSpeed > 100) { throw new IllegalArgumentException("行进速度必须在-100到100之间"); } // 数据长度:转向速度1 + 行进速度1 + 保留字段2 = 4字节 int dataLength = 4; // 总长度:帧头2 + 指令类型1 + 数据长度2 + 序列号2 + 数据内容4 + CRC16 2 + 帧尾1 = 14字节 ByteBuffer buffer = ByteBuffer.allocate(14); buffer.order(ByteOrder.LITTLE_ENDIAN); // 帧头 buffer.put(BluetoothProtocol.FRAME_HEADER); // 指令类型 buffer.put((byte) 0x03); // 数据长度 (4字节) buffer.putShort((short) dataLength); // 序列号 short sequence = (short) BluetoothProtocol.getNextSequence(); buffer.putShort(sequence); // 1. 转向速度 (1字节, int8_t, -100~100, 负数左转) buffer.put(steeringSpeed); // 2. 行进速度 (1字节, int8_t, -100~100, 负数倒退) buffer.put(forwardSpeed); // 3. 保留字段 (2字节,全部填0) buffer.put((byte) 0x00); buffer.put((byte) 0x00); // 计算CRC16(从指令类型开始到数据内容结束) // 范围:指令类型1 + 数据长度2 + 序列号2 + 数据4 = 9字节 byte[] dataForCRC = new byte[9]; // 临时构建CRC计算数据 ByteBuffer tempBuffer = ByteBuffer.allocate(9); tempBuffer.order(ByteOrder.LITTLE_ENDIAN); tempBuffer.put((byte) 0x03); // 指令类型 tempBuffer.putShort((short) dataLength); // 数据长度 tempBuffer.putShort(sequence); // 序列号 tempBuffer.put(steeringSpeed); // 转向速度 tempBuffer.put(forwardSpeed); // 行进速度 tempBuffer.put((byte) 0x00); // 保留字段1 tempBuffer.put((byte) 0x00); // 保留字段2 dataForCRC = tempBuffer.array(); int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length); buffer.putShort((short) crc); // 帧尾 buffer.put((byte) 0x0D); return buffer.array(); } // 以下方法保持不变... public static synchronized boolean increaseForwardSpeedIfDebugSerialOpen() { return adjustForwardSpeed(SPEED_STEP); } public static synchronized boolean decreaseForwardSpeedIfDebugSerialOpen() { return adjustForwardSpeed(-SPEED_STEP); } public static synchronized boolean turnLeftIfDebugSerialOpen() { return adjustSteeringSpeed(-SPEED_STEP); } public static synchronized boolean turnRightIfDebugSerialOpen() { return adjustSteeringSpeed(SPEED_STEP); } public static synchronized boolean sendNeutralCommandIfDebugSerialOpen() { return sendSpeedsIfDebugSerialOpen(0, 0); } public static synchronized boolean adjustForwardSpeed(int delta) { if (delta == 0) { return true; } int next; if (delta > 0 && currentForwardSpeed < 0) { next = Math.min(currentForwardSpeed + delta, 0); } else if (delta < 0 && currentForwardSpeed > 0) { next = Math.max(currentForwardSpeed + delta, 0); } else { next = clampSpeed(currentForwardSpeed + delta); } if (next == currentForwardSpeed) { return true; } return sendSpeedsIfDebugSerialOpen(currentSteeringSpeed, next); } public static synchronized boolean adjustSteeringSpeed(int delta) { if (delta == 0) { return true; } int next; if (delta > 0 && currentSteeringSpeed < 0) { next = Math.min(currentSteeringSpeed + delta, 0); } else if (delta < 0 && currentSteeringSpeed > 0) { next = Math.max(currentSteeringSpeed + delta, 0); } else { next = clampSpeed(currentSteeringSpeed + delta); } if (next == currentSteeringSpeed) { return true; } return sendSpeedsIfDebugSerialOpen(next, currentForwardSpeed); } public static synchronized boolean approachForwardSpeedToZero(int step) { int magnitude = Math.abs(step); if (magnitude == 0 || currentForwardSpeed == 0) { return true; } int next = currentForwardSpeed > 0 ? Math.max(currentForwardSpeed - magnitude, 0) : Math.min(currentForwardSpeed + magnitude, 0); if (next == currentForwardSpeed) { next = 0; } return sendSpeedsIfDebugSerialOpen(currentSteeringSpeed, next); } public static synchronized boolean approachSteeringSpeedToZero(int step) { int magnitude = Math.abs(step); if (magnitude == 0 || currentSteeringSpeed == 0) { return true; } int next = currentSteeringSpeed > 0 ? Math.max(currentSteeringSpeed - magnitude, 0) : Math.min(currentSteeringSpeed + magnitude, 0); if (next == currentSteeringSpeed) { next = 0; } return sendSpeedsIfDebugSerialOpen(next, currentForwardSpeed); } public static synchronized void resetSpeeds() { currentForwardSpeed = 0; currentSteeringSpeed = 0; } public static synchronized int getCurrentForwardSpeed() { return currentForwardSpeed; } public static synchronized int getCurrentSteeringSpeed() { 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()) { return false; } nextSteering = clampSpeed(nextSteering); nextForward = clampSpeed(nextForward); byte[] payload = buildSteeringCommandBytes((byte) nextSteering, (byte) nextForward); // 调试:打印发送的数据 System.out.println("发送转向指令: " + bytesToHex(payload)); boolean success = sendmessage.sendViaActive(payload); if (success) { currentSteeringSpeed = nextSteering; currentForwardSpeed = nextForward; } return success; } private static int clampSpeed(int value) { return Math.max(MIN_SPEED, Math.min(MAX_SPEED, value)); } /** * 解析速度字符串 */ private static int parseSpeed(String speedStr, String paramName) { try { int speed = Integer.parseInt(speedStr.trim()); if (speed < -100 || speed > 100) { throw new IllegalArgumentException(paramName + "必须在-100到100之间"); } return speed; } catch (NumberFormatException e) { throw new IllegalArgumentException(paramName + "必须是整数: " + speedStr); } } /** * 构建常用转向指令的快捷方法 */ // 前进 public static String forward(int speed) { speed = Math.min(speed, 100); return buildSteeringCommandHex("0", String.valueOf(speed)); } // 后退 public static String backward(int speed) { speed = Math.min(speed, 100); return buildSteeringCommandHex("0", String.valueOf(-speed)); } // 左转前进 public static String turnLeftForward(int steeringSpeed, int forwardSpeed) { steeringSpeed = Math.max(-steeringSpeed, -100); forwardSpeed = Math.min(forwardSpeed, 100); return buildSteeringCommandHex(String.valueOf(steeringSpeed), String.valueOf(forwardSpeed)); } // 右转前进 public static String turnRightForward(int steeringSpeed, int forwardSpeed) { steeringSpeed = Math.min(steeringSpeed, 100); forwardSpeed = Math.min(forwardSpeed, 100); return buildSteeringCommandHex(String.valueOf(steeringSpeed), String.valueOf(forwardSpeed)); } /** * 字节数组转换为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 testBuildSteeringCommand() { System.out.println("=== 测试修正后的转向指令构建 ==="); // 测试1:直行前进 byte[] cmd1 = buildSteeringCommandBytes((byte)0, (byte)50); System.out.println("直行前进50: " + bytesToHex(cmd1)); // 测试2:左转前进 byte[] cmd2 = buildSteeringCommandBytes((byte)-30, (byte)40); System.out.println("左转前进: " + bytesToHex(cmd2)); // 测试3:右转后退 byte[] cmd3 = buildSteeringCommandBytes((byte)20, (byte)-60); System.out.println("右转后退: " + bytesToHex(cmd3)); // 测试4:停止 byte[] cmd4 = buildSteeringCommandBytes((byte)0, (byte)0); System.out.println("停止: " + bytesToHex(cmd4)); } }