Commit ff1c02a2 authored by wanghao's avatar wanghao

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

2 实时数据 根据 托盘编号排序
3 如果设备号为空,则不设置各种状态信息,防止出现 没有板子的位置也报错,不能解绑的问题。
parent 9dc83746
......@@ -93,6 +93,8 @@ public class CalibrationResultEventHandler {
for (PalletDeviceBinding palletDeviceBinding : palletDeviceBindings) {
MesDeviceDomain mesDeviceDomain = new MesDeviceDomain();
// 如果设备编号为空 则不处理改设备
if(StringUtils.isBlank(palletDeviceBinding.getDeviceCode())) continue;
// 主板码
mesDeviceDomain.setMotherboardCode(palletDeviceBinding.getDeviceCode());
// 浓度
......@@ -499,4 +501,4 @@ public class CalibrationResultEventHandler {
this.calibrationValue = calibrationValue;
}
}
}
\ No newline at end of file
}
......@@ -25,6 +25,7 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
/**
......@@ -44,10 +45,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd");
private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private volatile long lastActivityTime = System.currentTimeMillis();
/**
* 当前正在处理的指令信息
*/
private final Map<String, CommandExecution> currentCommands = new ConcurrentHashMap<>();
// 线程安全锁,确保文件写入安全
private final ReentrantLock fileLock = new ReentrantLock();
......@@ -59,11 +56,26 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
private IRobotArmCommandService robotArmCommandService;
@Resource
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消息
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
try {
// 获取消息内容的字节缓冲区
ByteBuf content = packet.content();
......@@ -93,9 +105,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
// 保存消息到文件
//saveMessageToFile(packet.sender().toString(), correctMessage);
// 处理消息逻辑
String response = "服务器已收到UDP消息:" + correctMessage;
// 记录最后活动时间
lastActivityTime = System.currentTimeMillis();
// 判断消息类型并进行相应处理
......@@ -106,26 +115,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
// 处理普通状态消息(原有逻辑)
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) {
log.error("处理UDP消息异常", e);
// 出现异常时发送故障状态
......@@ -144,17 +133,11 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
packet.sender()));
// 解析消息
RobotArmMessageParser.RobotArmStatus status =
RobotArmMessageParser.parseMessage(message);
RobotArmMessageParser.RobotArmStatus status = RobotArmMessageParser.parseMessage(message);
if (status != null) {
// 处理状态消息
processStatusMessage(status);
// 检查是否为完全空闲状态
if (status.isFullyIdle()) {
handleFullyIdleState();
}
}
}
......@@ -176,25 +159,54 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
}
/**
* 仅处理已完成的指令
* 仅处理已完成的指令 - 已修改为使用currentCommandId
*/
public void onlyCompleted() {
// 每次只能有一个指令正在执行
CommandExecution execution = currentCommands.get("127.0.0.1");
// 如果指令追踪为空,则可能是 刚启动,再去 查一下有没有正在执行的任务
if(execution == null) {
Long commandId = null;
// 优先从currentCommandId获取
if (currentCommandId != null) {
commandId = currentCommandId;
} else {
// 如果currentCommandId为空,从数据库查询正在执行的任务
List<RobotArmCommand> robotArmCommands = robotArmCommandService.selectTopRunningRobotArmCommands();
if(robotArmCommands != null && !robotArmCommands.isEmpty()) {
// 注册指令跟踪
execution = new CommandExecution();
execution.commandId = robotArmCommands.get(0).getRobotArmCommandId();
if (robotArmCommands != null && !robotArmCommands.isEmpty()) {
commandId = robotArmCommands.get(0).getRobotArmCommandId();
// 如果找到了指令ID,更新currentCommandId
currentCommandId = commandId;
}
}
if (execution != null) {
robotArmCommandService.completeCommand(execution.commandId);
currentCommands.remove("127.0.0.1");
log.info("指令完成: {}", execution.commandId);
if (commandId != null) {
// 使用状态机完成指令
completeCommandWithStateMachine(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
} else {
sendStatusToWebSocket("error");
}
// 处理指令完成
// 处理指令完成逻辑 - 使用状态机防止重复
if (status.isFullyIdle()) {
// 记录详细状态
log.debug("机械臂状态: code={}, text={}, position=({},{},{},{})",
status.getCode(), status.getText(),
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) {
robotArmCommandService.completeCommand(execution.commandId);
currentCommands.remove("127.0.0.1");
log.info("指令完成: {}", execution.commandId);
}
handleCompleteState();
} else {
log.info("status.isFullyIdle() = false");
}
}
private void handleCompleteState() {
// 原子地获取并清空当前指令ID
Long commandIdToComplete = currentCommandId;
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 {
// 没有当前指令,直接处理待执行
handleFullyIdleState();
}
}
/**
* 记录当前执行的指令
*/
public void registerCommandExecution(Long commandId) {
CommandExecution execution = new CommandExecution();
execution.commandId = commandId;
execution.startTime = System.currentTimeMillis();
// 每次只能有一个正在执行中的,所以先暂时用使用了127.0.0.1
currentCommands.put("127.0.0.1", execution);
log.info("注册指令跟踪: {}", commandId);
if (commandState.compareAndSet(CommandState.IDLE, CommandState.EXECUTING)) {
currentCommandId = commandId;
log.info("注册指令跟踪: {}", commandId);
} else {
throw new IllegalStateException("机械臂当前状态不能执行新指令");
}
}
......@@ -288,11 +310,8 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.ALL_IDLE) {
log.info("UDP服务器超过规定时间未收到数据");
long now = System.currentTimeMillis();
long idleDuration = now - lastActivityTime;
// 如果长时间空闲(>2秒)
if (idleDuration > 20000) {
handleLongIdleState();
}
......@@ -301,12 +320,14 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
super.userEventTriggered(ctx, evt);
}
}
private void handleLongIdleState() {
// 检查是否有超时的指令
// 如果当前没有执行中的指令,尝试处理待执行指令
if (currentCommands.isEmpty()) {
private void handleLongIdleState() {
// 检查当前是否有执行中的指令(使用currentCommandId)
if (currentCommandId == null) {
handleFullyIdleState();
} else {
log.info("当前有指令正在执行中,指令ID: {}", currentCommandId);
}
}
/**
......@@ -320,13 +341,6 @@ public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramP
}
}
// 添加指令执行状态
private static class CommandExecution {
Long commandId;
long startTime;
}
/**
* 将消息保存到本地文件
*
......
......@@ -36,12 +36,12 @@ import javax.annotation.Resource;
/**
* 机械臂指令Service业务层处理
*
*
* @author zehong
* @date 2025-08-04
*/
@Service
public class RobotArmCommandServiceImpl implements IRobotArmCommandService
public class RobotArmCommandServiceImpl implements IRobotArmCommandService
{
private static final Logger log = LoggerFactory.getLogger(RobotArmCommandServiceImpl.class);
......@@ -89,6 +89,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
}
}
/**
* 机械臂空闲状态下 需要执行的待执行的指令
*/
@Override
@Transactional
public void processPendingCommands() {
......@@ -336,6 +340,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
return 0;
}
/**
* 完成指令
* @param commandId c
*/
@Override
@Transactional
public void completeCommand(Long commandId) {
......@@ -346,7 +354,6 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
log.info("command != null && \"2\".equals(command.getStatus()");
// 发送上电指令
try {
String storeyCode = command.getStoreyCode();
String equitmentCode;
int registerOffset;
......@@ -361,6 +368,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
log.info("tEquipmentInfo != null");
String powerOutageIp = tEquipmentInfo.getfPowerOutageIp();
Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort();
log.info("powerOutageIp: {}, powerOutagePort: {},command.getType:{}", powerOutageIp, powerOutagePort, command.getType());
if(StringUtils.isNotBlank(powerOutageIp) && powerOutagePort != null) {
if("0".equals(command.getType())) {
eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
......@@ -415,7 +423,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
/**
* 查询机械臂指令
*
*
* @param robotArmCommandId 机械臂指令ID
* @return 机械臂指令
*/
......@@ -427,7 +435,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
/**
* 查询机械臂指令列表
*
*
* @param robotArmCommand 机械臂指令
* @return 机械臂指令
*/
......@@ -475,7 +483,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
/**
* 新增机械臂指令
*
*
* @param robotArmCommand 机械臂指令
* @return 结果
*/
......@@ -578,7 +586,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
/**
* 修改机械臂指令
*
*
* @param robotArmCommand 机械臂指令
* @return 结果
*/
......@@ -606,7 +614,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
/**
* 批量删除机械臂指令
*
*
* @param robotArmCommandIds 需要删除的机械臂指令ID
* @return 结果
*/
......@@ -620,7 +628,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
/**
* 删除机械臂指令信息
*
*
* @param robotArmCommandId 机械臂指令ID
* @return 结果
*/
......
......@@ -3,7 +3,7 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zehong.system.mapper.PalletDeviceBindingMapper">
<resultMap type="PalletDeviceBinding" id="PalletDeviceBindingResult">
<result property="palletDeviceBindingId" column="f_pallet_device_binding_id" />
<result property="trayId" column="f_tray_id" />
......@@ -101,7 +101,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectPalletDeviceBindingList" parameterType="PalletDeviceBinding" resultMap="PalletDeviceBindingResult">
<include refid="selectPalletDeviceBindingVo"/>
<where>
<where>
<if test="trayId != null "> and palDeviceBinding.f_tray_id = #{trayId}</if>
<if test="deviceCode != null and deviceCode != ''"> and palDeviceBinding.f_device_code like concat('%',#{deviceCode},'%') </if>
<if test="fTrayCode != null and fTrayCode != ''"> and trayInfo.f_tray_code like concat('%',#{fTrayCode},'%')</if>
......@@ -114,18 +114,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createTime != null "> and palDeviceBinding.f_create_time = #{createTime}</if>
<if test="status != null and status != '' "> and palDeviceBinding.f_status = #{status}</if>
</where>
order by trayInfo.f_tray_code ,palDeviceBinding.f_index asc
order by trayInfo.f_tray_code ,palDeviceBinding.f_number asc
</select>
<select id="getAllExcludeUnbindingTimeByTrayId" parameterType="long" resultMap="PalletDeviceBindingResult">
<include refid="selectPalletDeviceBindingVo"/>
where palDeviceBinding.f_tray_id = #{trayId}
order by palDeviceBinding.f_index asc
order by palDeviceBinding.f_number asc
</select>
<select id="listByTrayCode" parameterType="string" resultMap="PalletDeviceBindingResult">
<include refid="selectPalletDeviceBindingVo"/>
where trayInfo.f_tray_code = #{trayCode}
</select>
<select id="selectPalletDeviceBindingById" parameterType="Long" resultMap="PalletDeviceBindingResult">
<include refid="selectPalletDeviceBindingVo"/>
where palDeviceBinding.f_pallet_device_binding_id = #{palletDeviceBindingId}
......@@ -327,7 +327,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="simCardStatus != null">f_sim_card_status = #{simCardStatus},</if>
<if test="networkStatus != null">f_network_status = #{networkStatus},</if>
</trim>
where f_pallet_device_binding_id = #{palletDeviceBindingId}
where f_pallet_device_binding_id = #{palletDeviceBindingId} and f_device_code is not null
</update>
<update id="batchUpdateDeviceCode" parameterType="list">
<foreach collection="palletDeviceBindingList" item="item" index="index" separator=";">
......@@ -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.calibrationConcentrationStatus != null">f_calibration_concentration_status = #{item.calibrationConcentrationStatus},</if>
</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>
</update>
<update id="batchUpdateDeviceCodeAndUnbindingTime" parameterType="list">
......@@ -430,9 +430,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<delete id="deletePalletDeviceBindingByIds" parameterType="String">
delete from t_pallet_device_binding where f_pallet_device_binding_id in
delete from t_pallet_device_binding where f_pallet_device_binding_id in
<foreach item="palletDeviceBindingId" collection="array" open="(" separator="," close=")">
#{palletDeviceBindingId}
</foreach>
</delete>
</mapper>
\ No newline at end of file
</mapper>
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