diff --git a/maibu-common/src/main/java/com/maibu/constant/Constant.java b/maibu-common/src/main/java/com/maibu/constant/Constant.java index 33e589a..0d1f154 100644 --- a/maibu-common/src/main/java/com/maibu/constant/Constant.java +++ b/maibu-common/src/main/java/com/maibu/constant/Constant.java @@ -1,19 +1,19 @@ package com.maibu.constant; -import com.maibu.core.business.DeviceRunParam; -import com.maibu.core.enums.ConnectionCloseReason; -import io.netty.util.AttributeKey; -import lombok.Data; - import java.util.concurrent.CompletableFuture; -@Data +import com.maibu.core.business.DeviceRunParam; +import com.maibu.core.enums.ConnectionCloseReason; + +import io.netty.util.AttributeKey; + + public class Constant { public static final AttributeKey ATT_DEVICE_ID = AttributeKey.valueOf("deviceId"); - public static final AttributeKey> READ_CONFIG_KEY = - AttributeKey.valueOf("READ_CONFIG"); + public static final AttributeKey> READ_CONFIG_KEY = AttributeKey + .valueOf("READ_CONFIG"); public static final AttributeKey ATT_CLOSE_REASON = AttributeKey.valueOf("closeReason"); @@ -27,5 +27,10 @@ public class Constant { public static final String mqttHandleKey = "hostHandle"; - public static final Long hostOfflineInterval = 10000L; //单位毫秒 + public static final Long hostOfflineInterval = 10000L; // 单位毫秒 + + // ==================== 远程控制 ==================== + public static final String protocol_version = "1.4.3"; + public static final String remote_control_msg_prefix = "remote-msg"; + public static final String remote_control_cmd_prefix = "remote-cmd"; } diff --git a/maibu-web-middleware/src/main/java/com/maibu/dto/LawnMoverProtocolEntity.java b/maibu-common/src/main/java/com/maibu/core/business/LawnMoverProtocolEntity.java similarity index 65% rename from maibu-web-middleware/src/main/java/com/maibu/dto/LawnMoverProtocolEntity.java rename to maibu-common/src/main/java/com/maibu/core/business/LawnMoverProtocolEntity.java index 0ccb096..4637370 100644 --- a/maibu-web-middleware/src/main/java/com/maibu/dto/LawnMoverProtocolEntity.java +++ b/maibu-common/src/main/java/com/maibu/core/business/LawnMoverProtocolEntity.java @@ -1,4 +1,4 @@ -package com.maibu.dto; +package com.maibu.core.business; import lombok.Data; @@ -42,13 +42,13 @@ public class LawnMoverProtocolEntity { } public byte[] toBytes() { - ByteBuffer buffer = ByteBuffer.allocate(15); + ByteBuffer buffer = ByteBuffer.allocate(27); buffer.order(ByteOrder.LITTLE_ENDIAN); // 根据协议决定字节序 buffer.put(Header1); buffer.put(Header2); buffer.put(CommandType); - buffer.putShort(LeftWheelSpeed); - buffer.putShort(RightWheelSpeed); + buffer.putDouble(linearSpeed); + buffer.putDouble(angularSpeed); buffer.put(ChassisLiftFlag); buffer.put(MowerSpeedFlag); buffer.put(IgnitionFlag); @@ -67,7 +67,46 @@ public class LawnMoverProtocolEntity { return sb.toString().trim(); } + /** + * 将控制指令字节数组解析为实体对象 + */ + public static LawnMoverProtocolEntity parseControlCommand(byte[] data) { + if (data == null || data.length != 27) { + throw new IllegalArgumentException("控制指令长度必须为15字节"); + } + ByteBuffer buffer = ByteBuffer.wrap(data); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + LawnMoverProtocolEntity entity = new LawnMoverProtocolEntity(); + + // 帧头 + entity.setHeader1(buffer.get()); + entity.setHeader2(buffer.get()); + + // 命令类型 + entity.setCommandType(buffer.get()); + + // 左右轮速度:int16 + entity.setLinearSpeed(buffer.getDouble()); + entity.setAngularSpeed(buffer.getDouble()); + + // 控制标志:uint8 + entity.setChassisLiftFlag(buffer.get()); + entity.setMowerSpeedFlag(buffer.get()); + entity.setIgnitionFlag(buffer.get()); + entity.setEmergencyStopFlag(buffer.get()); + + // 预留字段 + buffer.get(); + buffer.get(); + + // 帧尾 + entity.setEndFlag1(buffer.get()); + entity.setEndFlag2(buffer.get()); + + return entity; + } // 包头起始字节1 private byte Header1; @@ -79,6 +118,10 @@ public class LawnMoverProtocolEntity { private short LeftWheelSpeed; // 右轮速度:16位有符号 private short RightWheelSpeed; + + private double linearSpeed; + + private double angularSpeed; // 底盘升降标志位 private byte ChassisLiftFlag; // 割刀速度标志位 diff --git a/maibu-common/src/main/java/com/maibu/core/business/device/NettyDevice.java b/maibu-common/src/main/java/com/maibu/core/business/device/NettyDevice.java index 0967e54..a8580c4 100644 --- a/maibu-common/src/main/java/com/maibu/core/business/device/NettyDevice.java +++ b/maibu-common/src/main/java/com/maibu/core/business/device/NettyDevice.java @@ -1,6 +1,7 @@ package com.maibu.core.business.device; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.maibu.constant.Constant; import com.maibu.core.business.*; import com.maibu.core.business.path.LatAndLngEntity; import com.maibu.core.business.path.RoutePlanSendEntity; @@ -148,7 +149,7 @@ public class NettyDevice extends Connector { dto.setMode(workRecord.getMode()); dto.setTimestamp(System.currentTimeMillis()); dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis()); - dto.setProtocol_version("1.4"); + dto.setProtocol_version(Constant.protocol_version); GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()), @@ -361,7 +362,7 @@ public class NettyDevice extends Connector { dto.setMode(workRecord.getMode()); dto.setTimestamp(System.currentTimeMillis()); dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis()); - dto.setProtocol_version("1.4"); + dto.setProtocol_version(Constant.protocol_version); PointEntity point = new PointEntity(); if (!StringUtils.isEmpty(workRecord.getMode())) { diff --git a/maibu-common/src/main/java/com/maibu/core/host/DeviceRemoteControlDTO.java b/maibu-common/src/main/java/com/maibu/core/host/DeviceRemoteControlDTO.java new file mode 100644 index 0000000..ead3d6d --- /dev/null +++ b/maibu-common/src/main/java/com/maibu/core/host/DeviceRemoteControlDTO.java @@ -0,0 +1,15 @@ +package com.maibu.core.host; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 上位机远程控制参数 + * DeviceRemoteControlDTO + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class DeviceRemoteControlDTO extends HostBase { + private String command_id; + private ParamDetail data; +} diff --git a/maibu-common/src/main/java/com/maibu/core/host/ParamDetail.java b/maibu-common/src/main/java/com/maibu/core/host/ParamDetail.java new file mode 100644 index 0000000..9c55784 --- /dev/null +++ b/maibu-common/src/main/java/com/maibu/core/host/ParamDetail.java @@ -0,0 +1,18 @@ +package com.maibu.core.host; + +import lombok.Data; + +@Data +public class ParamDetail { + private short left_wheel_rpm; // 左轮转速 + private short right_wheel_rpm; // 右轮转速 + + private double linear_speed; // 线速度 + private double angular_speed; // 角速度 + + private int chassis_lift; // 底盘升降 0:停止 1:升 2:降 + private int cutter; // 割刀加减速 0:停止 1:加速 2:减速 + private int ignition; // 点火熄火 0:停止 1:点火 2:熄火 + private int emergency_stop; // 急停 0:正常 1:急停 + private int valid_for_ms; // 指令有效时间,单位毫秒 +} diff --git a/maibu-common/src/main/java/com/maibu/mqtt/MqttTopic.java b/maibu-common/src/main/java/com/maibu/mqtt/MqttTopic.java index 028d779..63b9c9e 100644 --- a/maibu-common/src/main/java/com/maibu/mqtt/MqttTopic.java +++ b/maibu-common/src/main/java/com/maibu/mqtt/MqttTopic.java @@ -45,7 +45,7 @@ public class MqttTopic { // ==================== 远程控制 ==================== /** 远程控制指令下发:前进/后退/转向/割草等(平台->设备),对应 TCP 0x00 remoteControl */ - public static final String MOWER_CONTROL_SET = "mower/%s/action/control/set"; + public static final String MOWER_CONTROL_SET = "mower/%s/control/remote/set"; // ==================== 任务管理 ==================== /** 路径规划下发(平台->设备),对应 TCP 0x01 path */ diff --git a/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java b/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java index 603b5d3..9ef8ee2 100644 --- a/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java +++ b/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java @@ -116,7 +116,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { // 过滤请求 .authorizeRequests() // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - .antMatchers("/iot/host/upload-path-csv","/api/thermal/**","/iotDA/device/**", "/websocket/allMemory", "/iot/UAV/**", "/iot/api/**", "/iot/device/userDevice", "/external/sms/sendAliSmsCode", "/login", "/register", "/captchaImage", "/iot/tool/register", "/iot/tool/ntp", + .antMatchers("/system/param/list","/iot/host/upload-path-csv","/api/thermal/**","/iotDA/device/**", "/websocket/allMemory", "/iot/UAV/**", "/iot/api/**", "/iot/device/userDevice", "/external/sms/sendAliSmsCode", "/login", "/register", "/captchaImage", "/iot/tool/register", "/iot/tool/ntp", "/iot/tool/mqtt/auth", "/iot/workRecord/**", "/iot/tool/mqtt/authv5", "/iot/tool/mqtt/webhook", "/iot/tool/mqtt/webhookv5", "/auth/**/**", "/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll() .antMatchers("/zlmhook/**").permitAll() diff --git a/maibu-netty-server/src/main/java/com/maibu/netty/handler/CommandForwardHandler.java b/maibu-netty-server/src/main/java/com/maibu/netty/handler/CommandForwardHandler.java index e4eeb00..41204f7 100644 --- a/maibu-netty-server/src/main/java/com/maibu/netty/handler/CommandForwardHandler.java +++ b/maibu-netty-server/src/main/java/com/maibu/netty/handler/CommandForwardHandler.java @@ -1,11 +1,15 @@ package com.maibu.netty.handler; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; import java.util.Set; import com.maibu.memory.DeviceSessionManager; import com.maibu.memory.GlobalMemory; import com.maibu.mqtt.MqttTopic; +import com.maibu.utils.json.JsonUtils; + import org.apache.commons.codec.binary.Hex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,9 +19,13 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import com.maibu.constant.CommandConstant; +import com.maibu.constant.Constant; +import com.maibu.core.business.LawnMoverProtocolEntity; import com.maibu.core.business.device.Connector; import com.maibu.core.business.device.NettyDevice; import com.maibu.core.enums.ConnectorType; +import com.maibu.core.host.DeviceRemoteControlDTO; +import com.maibu.core.host.ParamDetail; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; @@ -29,7 +37,6 @@ import io.netty.channel.SimpleChannelInboundHandler; @ChannelHandler.Sharable public class CommandForwardHandler extends SimpleChannelInboundHandler { - private static final Logger logger = LoggerFactory.getLogger(CommandForwardHandler.class); @Autowired @@ -44,12 +51,11 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler { byte[] bytes = Hex.decodeHex(msg.toCharArray()); if (bytes.length > 3 && (bytes[2] == CommandConstant.remoteControl || bytes[2] == CommandConstant.path - || bytes[2] == CommandConstant.status - )) { + || bytes[2] == CommandConstant.status)) { String senderDeviceId = deviceSessionManager.getDeviceIdByChannel(currentChannel); - NettyDevice senderNettyDevice = - senderDeviceId != null ? deviceSessionManager.getDevice(senderDeviceId) : null; + NettyDevice senderNettyDevice = senderDeviceId != null ? deviceSessionManager.getDevice(senderDeviceId) + : null; if (senderNettyDevice == null) { logger.debug("发送拒绝,设备:{}未发送上线指令", senderDeviceId); @@ -76,22 +82,73 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler { return; } for (Connector target : connectedDevices) { - if (!target.isOnline()) { - logger.debug("发送拒绝master:{},消息到达的salve设备:{},已离线", senderDeviceId, target.getConnectorId()); - continue; - } + if (!target.canReceive()) { logger.debug("发送拒绝master:{},消息到达的slave设备:{},处于禁止接收状态", senderDeviceId, target.getConnectorId()); continue; } - // todo 向上位机发送控制消息 + NettyDevice targetDevice = deviceSessionManager.getDevice(target.getConnectorId()); + if (targetDevice == null) + continue; + // 区分有上位机的还有无上位机的 有上位机的通过上位机下发 没有上位机的按照原来的方式下发 + if (targetDevice.getDevice().getHasHost()) { + if (bytes[2] == CommandConstant.remoteControl) { + // todo 转换 原先的报文重新组装成上位机的报文格式 + DeviceRemoteControlDTO deviceRemoteControlDTO = new DeviceRemoteControlDTO(); + LawnMoverProtocolEntity pEntity = LawnMoverProtocolEntity.parseControlCommand(bytes); + if (pEntity != null) { - GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.MOWER_CONTROL_SET, target.getConnectorId()), msg); -// Channel targetChannel = target.getChannel(); -// if (targetChannel != null && targetChannel.isActive()) { -// targetChannel.writeAndFlush(msg); -// logger.debug("从master:{},向slave:{}, 转发消息:{}", senderDeviceId, target.getConnectorId(), msg); -// } + ParamDetail data = new ParamDetail(); + // data.setLeft_wheel_rpm(pEntity.getLeftWheelSpeed()); + // data.setRight_wheel_rpm(pEntity.getRightWheelSpeed()); + + double angularSpeed = BigDecimal.valueOf(pEntity.getAngularSpeed()) + .setScale(2, RoundingMode.HALF_UP) + .doubleValue(); + + double linearSpeed = BigDecimal.valueOf(pEntity.getLinearSpeed()) + .setScale(2, RoundingMode.HALF_UP) + .doubleValue(); + + data.setLinear_speed(linearSpeed); + data.setAngular_speed(angularSpeed); + + data.setChassis_lift(pEntity.getChassisLiftFlag()); + data.setCutter(pEntity.getMowerSpeedFlag()); + data.setIgnition(pEntity.getIgnitionFlag()); + data.setEmergency_stop(pEntity.getEmergencyStopFlag()); + data.setValid_for_ms(500); + deviceRemoteControlDTO.setData(data); + deviceRemoteControlDTO + .setCommand_id(Constant.remote_control_cmd_prefix + System.currentTimeMillis()); + deviceRemoteControlDTO.setSn(target.getConnectorId()); + deviceRemoteControlDTO.setTimestamp(System.currentTimeMillis()); + deviceRemoteControlDTO + .setMessage_id(Constant.remote_control_msg_prefix + System.currentTimeMillis()); + deviceRemoteControlDTO.setProtocol_version(Constant.protocol_version); + + GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, + String.format(MqttTopic.MOWER_CONTROL_SET, target.getConnectorId()), + JsonUtils.toJsonString(deviceRemoteControlDTO)); + logger.debug("master:{},向slave:{} 有上位机, 转发遥控指令:{}", senderDeviceId, + target.getConnectorId(), + JsonUtils.toJsonString(deviceRemoteControlDTO)); + } + + } + } else { + if (!target.isOnline()) { + logger.debug("发送拒绝master:{},消息到达的salve设备:{},已离线", senderDeviceId, + target.getConnectorId()); + continue; + } + Channel targetChannel = target.getChannel(); + if (targetChannel != null && targetChannel.isActive()) { + targetChannel.writeAndFlush(msg); + logger.debug("从master:{},向slave:{} 无上位机, 转发消息:{}", senderDeviceId, + target.getConnectorId(), msg); + } + } } } else if (ConnectorType.SLAVE.equals(senderNettyDevice.getDeviceType())) { List masters = deviceSessionManager.getMastersBySlaveId(senderDeviceId); diff --git a/maibu-web-middleware/src/main/java/com/maibu/control/DiffSteer.java b/maibu-web-middleware/src/main/java/com/maibu/control/DiffSteer.java index 3838378..9791c96 100644 --- a/maibu-web-middleware/src/main/java/com/maibu/control/DiffSteer.java +++ b/maibu-web-middleware/src/main/java/com/maibu/control/DiffSteer.java @@ -1,9 +1,12 @@ package com.maibu.control; +import lombok.Data; + +@Data public class DiffSteer { - public static final int Polarity_High = 0; //0 - public static final int Polarity_Low = 0; //1 + public static final int Polarity_High = 0; // 0 + public static final int Polarity_Low = 0; // 1 private float turnSpeedScale; private float forwardSpeedScale; @@ -15,6 +18,9 @@ public class DiffSteer { private int leftWheelSpeed; private int rightWheelSpeed; + private double linearSpeed; + private double angularSpeed; + public int getLeftWheelSpeed() { return leftWheelSpeed; } @@ -63,6 +69,14 @@ public class DiffSteer { rightWheelSpeed = clamp(rightWheelSpeed, -speedAmplLimit, speedAmplLimit); } + // 计算线速度和轮速度 + public void calcLinearAngularSpeed(int x, int y, int maxLinear, int maxAngular) { + + this.linearSpeed = y * maxLinear / 1000.0; + this.angularSpeed = x * maxAngular / 1000.0; + + } + // 设置前向速比 public void setTurnSpeedScale(int turnSpeedMax, int xMax) { this.turnSpeedScale = (float) turnSpeedMax / (float) xMax; @@ -88,5 +102,4 @@ public class DiffSteer { return (val < min) ? min : ((val > max) ? max : val); } - } diff --git a/maibu-web-middleware/src/main/java/com/maibu/utils/ControlUtils.java b/maibu-web-middleware/src/main/java/com/maibu/utils/ControlUtils.java index 7134884..b2aee54 100644 --- a/maibu-web-middleware/src/main/java/com/maibu/utils/ControlUtils.java +++ b/maibu-web-middleware/src/main/java/com/maibu/utils/ControlUtils.java @@ -1,9 +1,8 @@ package com.maibu.utils; - import com.maibu.common.MiddleCommandConstant; import com.maibu.control.DiffSteer; -import com.maibu.dto.LawnMoverProtocolEntity; +import com.maibu.core.business.LawnMoverProtocolEntity; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -11,24 +10,29 @@ import java.util.List; public class ControlUtils { - - public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY, List buttons) { + public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY, + List buttons, int maxLinear, int maxAngular) { LawnMoverProtocolEntity state = new LawnMoverProtocolEntity(); diffSteer.calcWheelSpeed(originX, originY); + diffSteer.calcLinearAngularSpeed(originX, originY, maxLinear, maxAngular); state.setCommandType(MiddleCommandConstant.remoteControl); state.setLeftWheelSpeed((short) diffSteer.getLeftWheelSpeed()); state.setRightWheelSpeed((short) diffSteer.getRightWheelSpeed()); - //对应的 button数组 L1 button【4】 R1 button【5】 A对应的button【0】 B对应button【1】 X对应button【2】 Y对应button【3】 button[7]急停 - //A升B降底盘 X割刀加速Y减速 L1点火 R1熄火 + state.setLinearSpeed(diffSteer.getLinearSpeed()); + state.setAngularSpeed(diffSteer.getAngularSpeed()); + + // 对应的 button数组 L1 button【4】 R1 button【5】 A对应的button【0】 B对应button【1】 + // X对应button【2】 Y对应button【3】 button[7]急停 + // A升B降底盘 X割刀加速Y减速 L1点火 R1熄火 Boolean A = buttons.get(0); Boolean B = buttons.get(1); Boolean X = buttons.get(2); Boolean Y = buttons.get(3); Boolean L1 = buttons.get(4); Boolean R1 = buttons.get(5); - Boolean eStop = buttons.get(8); //急停 - //底盘升降 + Boolean eStop = buttons.get(8); // 急停 + // 底盘升降 int chassisLiftFlag = 0; if (A & !B) { chassisLiftFlag = 1; @@ -36,7 +40,7 @@ public class ControlUtils { chassisLiftFlag = 2; } state.setChassisLiftFlag((byte) chassisLiftFlag); - //割刀加减速 + // 割刀加减速 int mowerSpeedFlag = 0; if (X & !Y) { mowerSpeedFlag = 1; @@ -44,7 +48,7 @@ public class ControlUtils { mowerSpeedFlag = 2; } state.setMowerSpeedFlag((byte) mowerSpeedFlag); - //点火熄火 + // 点火熄火 int ignitionFlag = 0; if (L1 & !R1) { ignitionFlag = 1; @@ -55,26 +59,29 @@ public class ControlUtils { int emergencyStopFlag = eStop ? 1 : 0; state.setEmergencyStopFlag((byte) emergencyStopFlag); -// val toBytes = state.toBytes() -// println("toBytes==" + LawnMoverProtocolEntity.printBytesToHex(toBytes)) + // val toBytes = state.toBytes() + // println("toBytes==" + LawnMoverProtocolEntity.printBytesToHex(toBytes)) return state; } public static byte[] buildControlCommand(LawnMoverProtocolEntity entity) { - ByteBuffer buffer = ByteBuffer.allocate(15); + ByteBuffer buffer = ByteBuffer.allocate(27); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.put(entity.getHeader1()); buffer.put(entity.getHeader2()); buffer.put(entity.getCommandType()); - buffer.putShort(entity.getLeftWheelSpeed());//左轮速度 - buffer.putShort(entity.getRightWheelSpeed());//右轮速度 + // buffer.putShort(entity.getLeftWheelSpeed());//左轮速度 + // buffer.putShort(entity.getRightWheelSpeed());//右轮速度 - buffer.put(entity.getChassisLiftFlag());//底盘升降 - buffer.put(entity.getMowerSpeedFlag());//割刀加减速 - buffer.put(entity.getIgnitionFlag());//点火状态 - buffer.put(entity.getEmergencyStopFlag());//急停 + buffer.putDouble(entity.getAngularSpeed());// 左轮速度 + buffer.putDouble(entity.getLinearSpeed());// 右轮速度 + + buffer.put(entity.getChassisLiftFlag());// 底盘升降 + buffer.put(entity.getMowerSpeedFlag());// 割刀加减速 + buffer.put(entity.getIgnitionFlag());// 点火状态 + buffer.put(entity.getEmergencyStopFlag());// 急停 buffer.put((byte) 0x00); buffer.put((byte) 0x00); diff --git a/maibu-web-middleware/src/main/java/com/maibu/websocket/WebsocketHandler.java b/maibu-web-middleware/src/main/java/com/maibu/websocket/WebsocketHandler.java index 3c65b2a..f315836 100644 --- a/maibu-web-middleware/src/main/java/com/maibu/websocket/WebsocketHandler.java +++ b/maibu-web-middleware/src/main/java/com/maibu/websocket/WebsocketHandler.java @@ -2,6 +2,7 @@ package com.maibu.websocket; import com.maibu.constant.CommandConstant; import com.maibu.common.MiddleConstant; +import com.maibu.core.business.LawnMoverProtocolEntity; import com.maibu.core.enums.CommandRequestType; import com.maibu.core.enums.MesType; import com.maibu.dto.*; @@ -36,7 +37,6 @@ import java.util.concurrent.TimeUnit; public class WebsocketHandler extends WebSocketServer { private static final Logger logger = LoggerFactory.getLogger(WebsocketHandler.class); - // 存储客户端连接:key=WebSocket连接对象,value=最后一次活跃时间(毫秒) private final Map clientActiveTimeMap = new ConcurrentHashMap<>(); // 空闲超时时间(10秒):超过10秒无消息则判定为断开 @@ -44,17 +44,17 @@ public class WebsocketHandler extends WebSocketServer { // 定时检测线程池(每隔10秒检测一次空闲连接) private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); - public WebsocketHandler(int port) { super(new InetSocketAddress(port)); // 启动空闲连接检测任务 -// startIdleCheckTask(); + // startIdleCheckTask(); } @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { - logger.info("客户端连接成功: remoteAddress={}, 当前在线数: {}", conn.getRemoteSocketAddress(), MiddleGlobalMemory.onlineSockets.size()); + logger.info("客户端连接成功: remoteAddress={}, 当前在线数: {}", conn.getRemoteSocketAddress(), + MiddleGlobalMemory.onlineSockets.size()); } @Override @@ -62,7 +62,8 @@ public class WebsocketHandler extends WebSocketServer { String key = MiddleGlobalMemory.findBySocket(conn); if (key != null) { releaseResource(key); - logger.info("客户端断开连接: remoteAddress={}, code={}, reason={}, 当前在线数: {}", conn.getRemoteSocketAddress(), code, reason, MiddleGlobalMemory.onlineSockets.size()); + logger.info("客户端断开连接: remoteAddress={}, code={}, reason={}, 当前在线数: {}", conn.getRemoteSocketAddress(), code, + reason, MiddleGlobalMemory.onlineSockets.size()); } MiddleGlobalMemory.removeByWebSocket(conn); } @@ -100,32 +101,34 @@ public class WebsocketHandler extends WebSocketServer { client.initConnect(MiddleConstant.vertxIp, 9001); } } else if (MesType.path.equals(type)) { - //todo下发路径 预留 + // todo下发路径 预留 pathDistribute(); } else if (MesType.remoteControl.equals(type)) { - //遥控 + // 遥控 RemoteData remoteData = webMessageBaseDTO.getRemoteData(); if (remoteData != null) { List axes = remoteData.getAxes(); List buttons = remoteData.getButtons(); - Double y = axes.get(1) * 1000 * -1; //前后值反了 + Double y = axes.get(1) * 1000 * -1; // 前后值反了 Double x = axes.get(2) * 1000; int intX = (int) x.doubleValue(); int intY = (int) y.doubleValue(); + // todo 计算线速度和角速度 还需要根据车型来给线速度 角速度范围最大值 MiddleGlobalMemory.initDiff(); - LawnMoverProtocolEntity entity = ControlUtils.getCarControlMessage(MiddleGlobalMemory.diffSteer, intX, intY, buttons); + LawnMoverProtocolEntity entity = ControlUtils.getCarControlMessage(MiddleGlobalMemory.diffSteer, + intX, intY, buttons, 1, 2); byte[] buf = ControlUtils.buildControlCommand(entity); logger.debug("Netty客户端:{}发送遥控数据: {}", userName, JsonUtils.toJsonString(entity)); NettyClient nettyClient = MiddleGlobalMemory.nettyClientMap.get(key); if (nettyClient != null && nettyClient.isConnected()) { -// if (!nettyClient.isConnected()) nettyClient.connect(); + // if (!nettyClient.isConnected()) nettyClient.connect(); nettyClient.sendData(buf); } } } -// else if(MesType.heartbeat.equals(type)){ -// clientActiveTimeMap.put(conn,System.currentTimeMillis()); -// } + // else if(MesType.heartbeat.equals(type)){ + // clientActiveTimeMap.put(conn,System.currentTimeMillis()); + // } else if (MesType.switchPermission.equals(type)) { DeviceRequestDTO requestDTO = new DeviceRequestDTO(); requestDTO.setRequest(CommandRequestType.switch_control); @@ -138,7 +141,7 @@ public class WebsocketHandler extends WebSocketServer { ByteBuf buf = Unpooled.buffer(); CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction); if (nettyClient != null && nettyClient.isConnected()) { -// if (!nettyClient.isConnected()) nettyClient.connect(); + // if (!nettyClient.isConnected()) nettyClient.connect(); nettyClient.sendData(buf.array()); } } else if (MesType.switchResult.equals(type)) { @@ -156,7 +159,7 @@ public class WebsocketHandler extends WebSocketServer { ByteBuf buf = Unpooled.buffer(); CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction); if (nettyClient != null && nettyClient.isConnected()) { -// if (!nettyClient.isConnected()) nettyClient.connect(); + // if (!nettyClient.isConnected()) nettyClient.connect(); nettyClient.sendData(buf.array()); } } @@ -186,7 +189,8 @@ public class WebsocketHandler extends WebSocketServer { @Override public void onError(WebSocket conn, Exception ex) { String key = MiddleGlobalMemory.findBySocket(conn); - logger.error("WebSocket错误: clientId={}, remoteAddress={}, error={}", key, conn != null ? conn.getRemoteSocketAddress() : null, ex.getMessage(), ex); + logger.error("WebSocket错误: clientId={}, remoteAddress={}, error={}", key, + conn != null ? conn.getRemoteSocketAddress() : null, ex.getMessage(), ex); // 发生错误时清理连接 if (key != null) { releaseResource(key); @@ -222,7 +226,6 @@ public class WebsocketHandler extends WebSocketServer { logger.debug("广播消息给所有客户端: message={}, 客户端数量: {}", message, connections.size()); } - // 核心:定时检测空闲连接(每隔10秒执行一次) private void startIdleCheckTask() { executor.scheduleAtFixedRate(() -> { @@ -261,21 +264,21 @@ public class WebsocketHandler extends WebSocketServer { } } } -// clientActiveTimeMap.clear(); // 清空空闲记录 -// -// // 2. 关闭定时检测线程池(核心:终止非守护线程) -// if (!idleCheckExecutor.isShutdown()) { -// idleCheckExecutor.shutdownNow(); // 立即关闭线程池 -// try { -// // 等待线程池终止,最多等3秒 -// if (!idleCheckExecutor.awaitTermination(3, TimeUnit.SECONDS)) { -// logger.warn("空闲检测线程池未正常终止"); -// } -// } catch (InterruptedException e) { -// idleCheckExecutor.shutdownNow(); -// Thread.currentThread().interrupt(); -// } -// } + // clientActiveTimeMap.clear(); // 清空空闲记录 + // + // // 2. 关闭定时检测线程池(核心:终止非守护线程) + // if (!idleCheckExecutor.isShutdown()) { + // idleCheckExecutor.shutdownNow(); // 立即关闭线程池 + // try { + // // 等待线程池终止,最多等3秒 + // if (!idleCheckExecutor.awaitTermination(3, TimeUnit.SECONDS)) { + // logger.warn("空闲检测线程池未正常终止"); + // } + // } catch (InterruptedException e) { + // idleCheckExecutor.shutdownNow(); + // Thread.currentThread().interrupt(); + // } + // } // 3. 批量关闭所有Netty客户端连接 for (NettyClient client : MiddleGlobalMemory.nettyClientMap.values()) { @@ -300,5 +303,3 @@ public class WebsocketHandler extends WebSocketServer { } } } - -