Commit ff1c02a2 authored by wanghao's avatar wanghao

1 上料后 机械臂 回零 后 出现了一次 没有上电的操作,涉及到的 机械臂回零判断流程 优化。

2 实时数据 根据 托盘编号排序
3 如果设备号为空,则不设置各种状态信息,防止出现 没有板子的位置也报错,不能解绑的问题。
parent 9dc83746
...@@ -93,6 +93,8 @@ public class CalibrationResultEventHandler { ...@@ -93,6 +93,8 @@ public class CalibrationResultEventHandler {
for (PalletDeviceBinding palletDeviceBinding : palletDeviceBindings) { for (PalletDeviceBinding palletDeviceBinding : palletDeviceBindings) {
MesDeviceDomain mesDeviceDomain = new MesDeviceDomain(); MesDeviceDomain mesDeviceDomain = new MesDeviceDomain();
// 如果设备编号为空 则不处理改设备
if(StringUtils.isBlank(palletDeviceBinding.getDeviceCode())) continue;
// 主板码 // 主板码
mesDeviceDomain.setMotherboardCode(palletDeviceBinding.getDeviceCode()); mesDeviceDomain.setMotherboardCode(palletDeviceBinding.getDeviceCode());
// 浓度 // 浓度
......
...@@ -25,6 +25,7 @@ import java.util.Date; ...@@ -25,6 +25,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/** /**
...@@ -44,10 +45,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -44,10 +45,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd"); private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd");
private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private volatile long lastActivityTime = System.currentTimeMillis(); private volatile long lastActivityTime = System.currentTimeMillis();
/**
* 当前正在处理的指令信息
*/
private final Map<String, CommandExecution> currentCommands = new ConcurrentHashMap<>();
// 线程安全锁,确保文件写入安全 // 线程安全锁,确保文件写入安全
private final ReentrantLock fileLock = new ReentrantLock(); private final ReentrantLock fileLock = new ReentrantLock();
...@@ -59,11 +56,26 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -59,11 +56,26 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
private IRobotArmCommandService robotArmCommandService; private IRobotArmCommandService robotArmCommandService;
@Resource @Resource
private ApplicationEventPublisher eventPublisher; // 新增事件发布器 private ApplicationEventPublisher eventPublisher; // 新增事件发布器
// 使用原子引用,确保状态变更的原子性
private final AtomicReference<CommandState> commandState = new AtomicReference<>(CommandState.IDLE);
// 当前执行的指令ID
private volatile Long currentCommandId = null;
private enum CommandState {
IDLE, // 空闲
EXECUTING, // 执行中
COMPLETING, // 正在完成(防止重复)
ERROR // 错误
}
/** /**
* 接收UDP消息 * 接收UDP消息
*/ */
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
try { try {
// 获取消息内容的字节缓冲区 // 获取消息内容的字节缓冲区
ByteBuf content = packet.content(); ByteBuf content = packet.content();
...@@ -93,9 +105,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -93,9 +105,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
// 保存消息到文件 // 保存消息到文件
//saveMessageToFile(packet.sender().toString(), correctMessage); //saveMessageToFile(packet.sender().toString(), correctMessage);
// 处理消息逻辑
String response = "服务器已收到UDP消息:" + correctMessage;
// 记录最后活动时间 // 记录最后活动时间
lastActivityTime = System.currentTimeMillis(); lastActivityTime = System.currentTimeMillis();
// 判断消息类型并进行相应处理 // 判断消息类型并进行相应处理
...@@ -106,26 +115,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -106,26 +115,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
// 处理普通状态消息(原有逻辑) // 处理普通状态消息(原有逻辑)
handleNormalMessage(ctx, packet, correctMessage); handleNormalMessage(ctx, packet, correctMessage);
} }
// // 解析消息
// RobotArmMessageParser.RobotArmStatus status =
// RobotArmMessageParser.parseMessage(correctMessage);
//
// if (status != null) {
// // 处理状态消息
// processStatusMessage(status);
//
// // 检查是否为完全空闲状态
// if (status.isFullyIdle()) {
// handleFullyIdleState();
// }
// }
//
// // 回复客户端
// byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
// ctx.writeAndFlush(new DatagramPacket(
// io.netty.buffer.Unpooled.copiedBuffer(responseBytes),
// packet.sender()));
} catch (Exception e) { } catch (Exception e) {
log.error("处理UDP消息异常", e); log.error("处理UDP消息异常", e);
// 出现异常时发送故障状态 // 出现异常时发送故障状态
...@@ -144,17 +133,11 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -144,17 +133,11 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
packet.sender())); packet.sender()));
// 解析消息 // 解析消息
RobotArmMessageParser.RobotArmStatus status = RobotArmMessageParser.RobotArmStatus status = RobotArmMessageParser.parseMessage(message);
RobotArmMessageParser.parseMessage(message);
if (status != null) { if (status != null) {
// 处理状态消息 // 处理状态消息
processStatusMessage(status); processStatusMessage(status);
// 检查是否为完全空闲状态
if (status.isFullyIdle()) {
handleFullyIdleState();
}
} }
} }
...@@ -176,25 +159,54 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -176,25 +159,54 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
} }
/** /**
* 仅处理已完成的指令 * 仅处理已完成的指令 - 已修改为使用currentCommandId
*/ */
public void onlyCompleted() { public void onlyCompleted() {
// 每次只能有一个指令正在执行 Long commandId = null;
CommandExecution execution = currentCommands.get("127.0.0.1");
// 如果指令追踪为空,则可能是 刚启动,再去 查一下有没有正在执行的任务 // 优先从currentCommandId获取
if(execution == null) { if (currentCommandId != null) {
commandId = currentCommandId;
} else {
// 如果currentCommandId为空,从数据库查询正在执行的任务
List<RobotArmCommand> robotArmCommands = robotArmCommandService.selectTopRunningRobotArmCommands(); List<RobotArmCommand> robotArmCommands = robotArmCommandService.selectTopRunningRobotArmCommands();
if(robotArmCommands != null && !robotArmCommands.isEmpty()) { if (robotArmCommands != null && !robotArmCommands.isEmpty()) {
// 注册指令跟踪 commandId = robotArmCommands.get(0).getRobotArmCommandId();
execution = new CommandExecution(); // 如果找到了指令ID,更新currentCommandId
execution.commandId = robotArmCommands.get(0).getRobotArmCommandId(); currentCommandId = commandId;
}
}
if (commandId != null) {
// 使用状态机完成指令
completeCommandWithStateMachine(commandId);
} }
} }
if (execution != null) { /**
robotArmCommandService.completeCommand(execution.commandId); * 使用状态机完成指令
currentCommands.remove("127.0.0.1"); */
log.info("指令完成: {}", execution.commandId); private void completeCommandWithStateMachine(Long commandId) {
// 检查当前状态和指令ID是否匹配
if (commandId.equals(currentCommandId) &&
commandState.compareAndSet(CommandState.EXECUTING, CommandState.COMPLETING)) {
try {
robotArmCommandService.completeCommand(commandId);
log.info("指令完成: {}", commandId);
// 清理状态
currentCommandId = null;
commandState.set(CommandState.IDLE);
// 处理待执行指令
handleFullyIdleState();
} catch (Exception e) {
log.error("指令完成失败: {}", commandId, e);
commandState.set(CommandState.ERROR);
}
} else {
log.warn("无法完成指令 {},当前状态: {}, 当前指令ID: {}",
commandId, commandState.get(), currentCommandId);
} }
} }
...@@ -207,45 +219,55 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -207,45 +219,55 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
} else { } else {
sendStatusToWebSocket("error"); sendStatusToWebSocket("error");
} }
// 处理指令完成逻辑 - 使用状态机防止重复
// 处理指令完成
if (status.isFullyIdle()) { if (status.isFullyIdle()) {
// 记录详细状态 handleCompleteState();
log.debug("机械臂状态: code={}, text={}, position=({},{},{},{})", } else {
status.getCode(), status.getText(), log.info("status.isFullyIdle() = false");
status.getX(), status.getY(), status.getZ(), status.getR());
CommandExecution execution = currentCommands.get("127.0.0.1");
// 如果指令追踪为空,则可能是 刚启动,再去 查一下有没有正在执行的任务
if(execution == null) {
List<RobotArmCommand> robotArmCommands = robotArmCommandService.selectTopRunningRobotArmCommands();
if(robotArmCommands != null && !robotArmCommands.isEmpty()) {
// 注册指令跟踪
execution = new CommandExecution();
execution.commandId = robotArmCommands.get(0).getRobotArmCommandId();
} }
} }
if (execution != null) { private void handleCompleteState() {
robotArmCommandService.completeCommand(execution.commandId); // 原子地获取并清空当前指令ID
currentCommands.remove("127.0.0.1"); Long commandIdToComplete = currentCommandId;
log.info("指令完成: {}", execution.commandId);
if (commandIdToComplete != null) {
// 尝试将状态从 EXECUTING 转为 COMPLETING
if (commandState.compareAndSet(CommandState.EXECUTING, CommandState.COMPLETING)) {
try {
// 完成指令
robotArmCommandService.completeCommand(commandIdToComplete);
log.info("指令完成: {}", commandIdToComplete);
// 清空当前指令
currentCommandId = null;
// 状态转为空闲
commandState.set(CommandState.IDLE);
// 处理待执行指令
handleFullyIdleState();
} catch (Exception e) {
log.error("指令完成失败: {}", commandIdToComplete, e);
commandState.set(CommandState.ERROR);
}
} }
} else { } else {
log.info("status.isFullyIdle() = false"); // 没有当前指令,直接处理待执行
handleFullyIdleState();
} }
} }
/** /**
* 记录当前执行的指令 * 记录当前执行的指令
*/ */
public void registerCommandExecution(Long commandId) { public void registerCommandExecution(Long commandId) {
CommandExecution execution = new CommandExecution(); if (commandState.compareAndSet(CommandState.IDLE, CommandState.EXECUTING)) {
execution.commandId = commandId; currentCommandId = commandId;
execution.startTime = System.currentTimeMillis();
// 每次只能有一个正在执行中的,所以先暂时用使用了127.0.0.1
currentCommands.put("127.0.0.1", execution);
log.info("注册指令跟踪: {}", commandId); log.info("注册指令跟踪: {}", commandId);
} else {
throw new IllegalStateException("机械臂当前状态不能执行新指令");
}
} }
...@@ -288,11 +310,8 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -288,11 +310,8 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
IdleStateEvent event = (IdleStateEvent) evt; IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.ALL_IDLE) { if (event.state() == IdleState.ALL_IDLE) {
log.info("UDP服务器超过规定时间未收到数据"); log.info("UDP服务器超过规定时间未收到数据");
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long idleDuration = now - lastActivityTime; long idleDuration = now - lastActivityTime;
// 如果长时间空闲(>2秒)
if (idleDuration > 20000) { if (idleDuration > 20000) {
handleLongIdleState(); handleLongIdleState();
} }
...@@ -301,12 +320,14 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -301,12 +320,14 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
super.userEventTriggered(ctx, evt); super.userEventTriggered(ctx, evt);
} }
} }
private void handleLongIdleState() {
// 检查是否有超时的指令
// 如果当前没有执行中的指令,尝试处理待执行指令
if (currentCommands.isEmpty()) { private void handleLongIdleState() {
// 检查当前是否有执行中的指令(使用currentCommandId)
if (currentCommandId == null) {
handleFullyIdleState(); handleFullyIdleState();
} else {
log.info("当前有指令正在执行中,指令ID: {}", currentCommandId);
} }
} }
/** /**
...@@ -320,13 +341,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP ...@@ -320,13 +341,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
} }
} }
// 添加指令执行状态
private static class CommandExecution {
Long commandId;
long startTime;
}
/** /**
* 将消息保存到本地文件 * 将消息保存到本地文件
* *
......
...@@ -89,6 +89,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -89,6 +89,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
} }
} }
/**
* 机械臂空闲状态下 需要执行的待执行的指令
*/
@Override @Override
@Transactional @Transactional
public void processPendingCommands() { public void processPendingCommands() {
...@@ -336,6 +340,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -336,6 +340,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
return 0; return 0;
} }
/**
* 完成指令
* @param commandId c
*/
@Override @Override
@Transactional @Transactional
public void completeCommand(Long commandId) { public void completeCommand(Long commandId) {
...@@ -346,7 +354,6 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -346,7 +354,6 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
log.info("command != null && \"2\".equals(command.getStatus()"); log.info("command != null && \"2\".equals(command.getStatus()");
// 发送上电指令 // 发送上电指令
try { try {
String storeyCode = command.getStoreyCode(); String storeyCode = command.getStoreyCode();
String equitmentCode; String equitmentCode;
int registerOffset; int registerOffset;
...@@ -361,6 +368,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -361,6 +368,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
log.info("tEquipmentInfo != null"); log.info("tEquipmentInfo != null");
String powerOutageIp = tEquipmentInfo.getfPowerOutageIp(); String powerOutageIp = tEquipmentInfo.getfPowerOutageIp();
Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort(); Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort();
log.info("powerOutageIp: {}, powerOutagePort: {},command.getType:{}", powerOutageIp, powerOutagePort, command.getType());
if(StringUtils.isNotBlank(powerOutageIp) && powerOutagePort != null) { if(StringUtils.isNotBlank(powerOutageIp) && powerOutagePort != null) {
if("0".equals(command.getType())) { if("0".equals(command.getType())) {
eventPublisher.publishEvent(new CheckPowerOnCommandEvent( eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
......
...@@ -114,12 +114,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -114,12 +114,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createTime != null "> and palDeviceBinding.f_create_time = #{createTime}</if> <if test="createTime != null "> and palDeviceBinding.f_create_time = #{createTime}</if>
<if test="status != null and status != '' "> and palDeviceBinding.f_status = #{status}</if> <if test="status != null and status != '' "> and palDeviceBinding.f_status = #{status}</if>
</where> </where>
order by trayInfo.f_tray_code ,palDeviceBinding.f_index asc order by trayInfo.f_tray_code ,palDeviceBinding.f_number asc
</select> </select>
<select id="getAllExcludeUnbindingTimeByTrayId" parameterType="long" resultMap="PalletDeviceBindingResult"> <select id="getAllExcludeUnbindingTimeByTrayId" parameterType="long" resultMap="PalletDeviceBindingResult">
<include refid="selectPalletDeviceBindingVo"/> <include refid="selectPalletDeviceBindingVo"/>
where palDeviceBinding.f_tray_id = #{trayId} where palDeviceBinding.f_tray_id = #{trayId}
order by palDeviceBinding.f_index asc order by palDeviceBinding.f_number asc
</select> </select>
<select id="listByTrayCode" parameterType="string" resultMap="PalletDeviceBindingResult"> <select id="listByTrayCode" parameterType="string" resultMap="PalletDeviceBindingResult">
<include refid="selectPalletDeviceBindingVo"/> <include refid="selectPalletDeviceBindingVo"/>
...@@ -327,7 +327,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -327,7 +327,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="simCardStatus != null">f_sim_card_status = #{simCardStatus},</if> <if test="simCardStatus != null">f_sim_card_status = #{simCardStatus},</if>
<if test="networkStatus != null">f_network_status = #{networkStatus},</if> <if test="networkStatus != null">f_network_status = #{networkStatus},</if>
</trim> </trim>
where f_pallet_device_binding_id = #{palletDeviceBindingId} where f_pallet_device_binding_id = #{palletDeviceBindingId} and f_device_code is not null
</update> </update>
<update id="batchUpdateDeviceCode" parameterType="list"> <update id="batchUpdateDeviceCode" parameterType="list">
<foreach collection="palletDeviceBindingList" item="item" index="index" separator=";"> <foreach collection="palletDeviceBindingList" item="item" index="index" separator=";">
...@@ -350,7 +350,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -350,7 +350,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="item.calibrationConcentration != null">f_calibration_concentration = #{item.calibrationConcentration},</if> <if test="item.calibrationConcentration != null">f_calibration_concentration = #{item.calibrationConcentration},</if>
<if test="item.calibrationConcentrationStatus != null">f_calibration_concentration_status = #{item.calibrationConcentrationStatus},</if> <if test="item.calibrationConcentrationStatus != null">f_calibration_concentration_status = #{item.calibrationConcentrationStatus},</if>
</trim> </trim>
where f_pallet_device_binding_id = #{item.palletDeviceBindingId} where f_pallet_device_binding_id = #{item.palletDeviceBindingId} and f_device_code is not null
</foreach> </foreach>
</update> </update>
<update id="batchUpdateDeviceCodeAndUnbindingTime" parameterType="list"> <update id="batchUpdateDeviceCodeAndUnbindingTime" parameterType="list">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment