#修改远程遥控控制方式 将左右轮速改成线速度和角速度
This commit is contained in:
@@ -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<String> ATT_DEVICE_ID = AttributeKey.valueOf("deviceId");
|
||||
|
||||
public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY =
|
||||
AttributeKey.valueOf("READ_CONFIG");
|
||||
public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY = AttributeKey
|
||||
.valueOf("READ_CONFIG");
|
||||
|
||||
public static final AttributeKey<ConnectionCloseReason> 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";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
// 割刀速度标志位
|
||||
@@ -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())) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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; // 指令有效时间,单位毫秒
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<String> {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CommandForwardHandler.class);
|
||||
|
||||
@Autowired
|
||||
@@ -44,12 +51,11 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
|
||||
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<String> {
|
||||
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<NettyDevice> masters = deviceSessionManager.getMastersBySlaveId(senderDeviceId);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Boolean> buttons) {
|
||||
public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY,
|
||||
List<Boolean> 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);
|
||||
|
||||
@@ -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<WebSocket, Long> 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<Double> axes = remoteData.getAxes();
|
||||
List<Boolean> 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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user