11 KiB
11 KiB
变更日志
YYYY-MM-DD
- 初始化项目变更日志。
- 确认采用 Gitea Webhook + Shell 脚本的 CI/CD 方案。
- 部署脚本 (
deploy.sh) 和相关配置已准备。
YYYY-MM-DD (请替换为实际日期)
- 详细分析了项目整体结构,特别是单片机 (
mqtt_esp32_client.ino) 与后端 (springboot-init-main) 之间基于README.md的 MQTT 通信流程和协议。 - 核心理解:
- 主题:
- 上行 (设备 -> 后端):
yupi_mqtt_power_project/robot/status/{spotUid}(状态/心跳/ACK) - 下行 (后端 -> 设备):
yupi_mqtt_power_project/robot/command/{spotUid}(指令)
- 上行 (设备 -> 后端):
- 消息格式: JSON。上行消息结构对应后端
com.yupi.project.model.dto.mqtt.RobotStatusMessage。 - 关键上行消息字段:
robotUid,actualRobotStatus,taskId(for ACK),status(for ACK),activeTaskId(通常为sessionId)。 - 关键下行消息字段:
commandType("START_CHARGE", "STOP_CHARGE", 等),taskId,sessionId(for "START_CHARGE")。 - 通信流程: 设备连接后订阅指令主题并上报初始状态。周期性上报状态和心跳。后端下发指令,设备执行后通过ACK响应,并更新状态。
activeTaskId的作用: 该字段在单片机的状态上报和ACK中被用来传递当前有效的sessionId,对于后端跟踪会话状态至关重要。- 单片机代码中包含对
MOVE_TO_SPOT指令的处理,README.md未明确列出,后端可能需同步支持。
- 主题:
- 后续 Debug 将基于此理解进行。
YYYY-MM-DD (请替换为今天的实际日期)
- 核心逻辑变更:"到达即充电"
- 移除了原先设想的由后端发送
START_CHARGEMQTT 指令来启动充电的流程。 - 新流程:机器人(单片机)在执行
MOVE_TO_SPOT指令并成功到达车位后,立即将自身状态更新为CHARGING并上报。后端在收到MOVE_TO_SPOT任务的 ACK (其中应包含机器人已是CHARGING状态) 后,将机器人DB状态更新为CHARGING,并将充电会话状态更新为CHARGING_STARTED。
- 移除了原先设想的由后端发送
- 代码修改:
mqtt_esp32_client.ino:MOVE_TO_SPOT指令处理逻辑修改:- 收到指令后,状态变为
MOVING并上报。 - 模拟移动到达后,状态变为
CHARGING。 - 发送的 ACK 消息中
actualRobotStatus反映为CHARGING。 - 再次上报
CHARGING状态。
- 收到指令后,状态变为
ChargingSessionServiceImpl.java:handleRobotArrival方法修改:- 当
MOVE_TO_SPOT任务完成后,将充电会话状态 (ChargingSession.status) 直接更新为CHARGING_STARTED。 - 记录
robotArrivalTime和chargeStartTime。 - 将数据库中机器人状态 (
ChargingRobot.status) 更新为CHARGING。 - 确保关联的
RobotTask(移动任务) 被正确处理和完成。
- 当
README.md:- 更新了MQTT通信约定、消息示例、单片机开发关键逻辑以及示例充电流程,以反映"到达即充电"的新业务规则。
- 待考虑/后续:
ChargingSessionServiceImpl.handleChargingStart方法目前因START_CHARGE指令不再由后端主动发送而可能不再被主要流程调用,其定位和用途需要进一步明确或在未来重构中调整。- 前端界面和用户交互流程可能需要相应调整,以匹配后端"到达即充电"的逻辑(例如,可能不再需要用户在机器人到达后点击"开始充电"按钮)。
YYYY-MM-DD (自动填充日期)
ESP32 固件与后端通信逻辑校准与文档更新
主要变更点:
-
MQTT ACK 消息格式校准 (关键):
- 问题分析: 通过深入分析后端代码 (
MqttMessageHandlerImpl.java和CommandTypeEnum.java),发现后端期望的MQTT ACK消息格式与之前README.md及单片机固件发送的格式存在显著差异。- 后端期望ACK中包含
command_ack字段,其值为指令的中文描述 (例如 "移动到指定点"),用于CommandTypeEnum.fromAck()方法匹配。 - 后端期望任务ID字段为
task_id(数字类型)。 - 后端期望成功状态字段为
success(布尔类型)。
- 后端期望ACK中包含
README.md更新: 已更新README.md(4.2.1节) 中的ACK消息示例,以准确反映后端期望的格式。包括添加了command_ack,并将taskId改为task_id,status(String) 改为success(Boolean)。- 行动项 (开发者): 开发者需要修改
esp32_robot_firmware/mqtt_handler.cpp中的mqtt_publish_ack函数,使其发送的ACK JSON符合后端MqttMessageHandlerImpl.java的实际解析逻辑 (即包含中文描述的command_ack,数字类型的task_id,和布尔类型的success)。
- 问题分析: 通过深入分析后端代码 (
-
MQTT 下行
MOVE_TO_SPOT指令校准:- 问题分析: 后端
ChargingSessionServiceImpl.java在发送移动指令时,实际使用的payload是{"command":"MOVE", ...},而README.md先前示例为{"commandType":"MOVE_TO_SPOT", ...}。 README.md更新: 已更新README.md(4.2.2节) 中移动指令的示例,以反映后端实际发送的command: "MOVE"格式,并添加了说明指出单片机固件已做兼容处理。- 行动项 (开发者, 可选): 为保持一致性,可考虑更新后端
ChargingSessionServiceImpl.java,使其发送移动指令时使用commandType: "MOVE_TO_SPOT"。
- 问题分析: 后端
-
文档整体一致性提升:
README.md中关于单片机处理逻辑 (4.3节) 和示例流程 (4.4节) 的部分也相应作了调整,以强调新的ACK格式要求和指令细节。
代码分析涉及文件:
springboot-init-main/src/main/java/com/yupi/project/service/impl/ChargingSessionServiceImpl.java(下行指令发送)springboot-init-main/src/main/java/com/yupi/project/service/impl/MqttServiceImpl.java(下行指令封装与taskId注入)springboot-init-main/src/main/java/com/yupi/project/mqtt/handler/MqttMessageHandlerImpl.java(上行消息及ACK处理核心逻辑)springboot-init-main/src/main/java/com/yupi/project/model/enums/CommandTypeEnum.java(ACK中command_ack的解析方式)esp32_robot_firmware/mqtt_handler.cpp(单片机ACK发送逻辑 - 需修改)esp32_robot_firmware/esp32_robot_firmware.ino(单片机指令回调处理)
后续影响与建议:
- 首要任务是修正单片机固件的ACK发送逻辑,确保与后端正确对接。
- 在完成固件修改后,建议进行完整的MQTT通信测试,覆盖所有指令类型及其ACK流程。
2025-05-24: 后端会话管理核心逻辑强化
主要变更与决策:
-
明确用户充电请求流程与并发处理:
- 用户请求充电时 (
ChargingSessionController.requestCharging->ChargingSessionServiceImpl.requestCharging->assignRobotToSession),系统会检查车位可用性、用户状态,并尝试分配空闲机器人。 - 机器人分配机制:
ChargingRobotServiceImpl.assignIdleRobot()负责查找空闲机器人并将其状态更新为MOVING(或类似表示已分配的状态)。此操作与会话创建、车位预定、任务创建均在一个事务内。 - 机器人繁忙处理: 如果没有空闲机器人,
assignRobotToSession将返回null,随后requestCharging方法会将此会话标记为CANCELLED_BY_SYSTEM并向用户抛出明确的"无可用机器人"或"机器人繁忙"的错误。系统不会为此类请求创建等待执行的RobotTask,用户需稍后重试。这简化了后端的任务管理和状态维护。
- 用户请求充电时 (
-
MQTT 指令发送与任务状态同步 (
MqttServiceImpl.sendCommand):- 任务预创建:
sendCommand方法要求调用者 (如ChargingSessionServiceImpl) 必须预先创建状态为PENDING的RobotTask,并将任务ID (associatedTaskId) 传递给sendCommand。 - 机器人繁忙校验: 在发送指令前,
sendCommand会调用RobotTaskServiceImpl.hasOtherPendingOrSentTask()检查目标机器人是否已有其他PENDING或SENT状态的任务(排除当前associatedTaskId)。若是,则通常中止发送(STOP_CHARGE指令除外,它具有优先权)。 - Payload 增强:
sendCommand会自动向发送的MQTT JSON payload 中添加taskId字段,其值为associatedTaskId。这有助于机器人端将ACK消息与特定任务关联。 - 事务与数据一致性:
sendCommand标记为@Transactional。- MQTT消息成功发布后,会调用
RobotTaskServiceImpl.markTaskAsSent()将对应任务状态从PENDING更新为SENT。 - 为确保数据一致性(避免MQTT已发送但任务状态更新失败),
RobotTaskServiceImpl.markTaskAsSent()方法已被修改:在其无法成功将任务标记为 SENT(如任务不存在、原状态非PENDING、数据库更新失败)时,会抛出BusinessException。此异常会触发sendCommand所在事务的回滚,从而撤销MQTT发送(如果尚未实际完成网络传输)或至少确保数据库层面的一致性。
- MQTT消息成功发布后,会调用
- 任务预创建:
-
会话状态流转与MQTT消息处理 (初步对齐):
- "到达即充电"逻辑: 当前遵循此简化逻辑。当
MOVE_TO_SPOT任务成功被机器人ACK后,ChargingSessionServiceImpl.handleRobotArrival()会直接将会话状态更新为CHARGING_STARTED。 MqttMessageHandler在收到机器人的状态回报(特别是包含taskId的ACK)后,会首先调用RobotTaskService更新任务状态,然后基于任务结果调用ChargingSessionService的相应方法来驱动会话状态的变更。
- "到达即充电"逻辑: 当前遵循此简化逻辑。当
-
兼容性考虑:
- 当前的修改重点在于增强后端逻辑的健壮性和数据一致性,同时尽量维持现有的MQTT消息JSON结构 (仅在payload中增加
taskId,这是一个向后兼容的增强) 和主要的业务流程,以避免对前端和单片机代码产生破坏性变更。 - MQTT指令名称 (如
MOVEvsMOVE_TO_SPOT) 与CommandTypeEnum的映射关系需要在后端处理,以适应单片机固件的期望。
- 当前的修改重点在于增强后端逻辑的健壮性和数据一致性,同时尽量维持现有的MQTT消息JSON结构 (仅在payload中增加
后续关注点:
- 详细实现
ChargingSessionService中处理充电结束、取消、错误、超时的逻辑。 - 设计和实现计费服务。
- 确保
MqttMessageHandler中对所有预期机器人回报的完整处理和对ChargingSessionService的正确调用。 - 审阅并完善所有相关的
@Transactional注解,确保事务边界和传播行为的正确性。
YYYY-MM-DD (请替换为今天的实际日期)
- 新建 Arduino Nano 循迹避障项目
arduino_nano_tracker。- 目标:实现单片机控制的循迹和避障功能。
- 硬件配置:
- TT 电机 x2 (PWM控制转速): 左电机引脚 9, 右电机引脚 10。
- TRCT5000 循迹传感器 x2: 左传感器引脚 7, 右传感器引脚 8。
- 超声波传感器 (HC-SR04): Trig 引脚 12, Echo 引脚 11。
- 180度舵机 (SG90): 引脚 3。
- 在
arduino_nano_tracker/目录下创建了arduino_nano_tracker.ino文件,并包含基础的引脚定义和setup()/loop()结构。