diff --git a/Core/Bsp/bsp_uart.c b/Core/Bsp/bsp_uart.c index b3ab987..5cc0746 100644 --- a/Core/Bsp/bsp_uart.c +++ b/Core/Bsp/bsp_uart.c @@ -21,8 +21,11 @@ HAL_StatusTypeDef ESP12F_TCP_SendMessage(const char *data) { return HAL_ERROR; // 数据为空 } - // 启动 DMA 传输 - return HAL_UART_Transmit_DMA(&huart1, (uint8_t *)data, size); + /* + * 这里使用阻塞发送而不是 DMA:协议帧很短,且发送缓冲区通常来自局部变量。 + * 使用 DMA 会引入发送缓冲区生命周期问题,容易导致反馈丢失或数据不稳定。 + */ + return HAL_UART_Transmit(&huart1, (uint8_t *)data, size, 50U); } /* External DMA handle */ diff --git a/Core/Bsp/protocol.c b/Core/Bsp/protocol.c index 939f56e..f964b1c 100644 --- a/Core/Bsp/protocol.c +++ b/Core/Bsp/protocol.c @@ -40,6 +40,9 @@ #define OBSTACLE_STOP_DISTANCE_CM 18.0f #define OBSTACLE_RECOVER_DISTANCE_CM 22.0f +/* 手动控制方向斜向速度缩放,避免斜向合速度过大 */ +#define MANUAL_DIAG_SCALE 0.7071f + /* 电机位置定义 (基于用户规定) */ #define MOTOR_LR MOTOR_1 // 左后 (Left Rear) #define MOTOR_LF MOTOR_2 // 左前 (Left Front) @@ -59,12 +62,75 @@ static uint8_t obstacle_locked = 0; // 避障锁(1=有障碍锁定) static track_ir_ctrl_output_t track_output = {0}; static uint8_t track_line_mask = 0; +static void CarCtrl_StopAll(void); + +typedef enum { + CTRL_MODE_AUTO = 0, + CTRL_MODE_MANUAL +} ctrl_mode_t; + +typedef enum { + MAN_DIR_STOP = 0, + MAN_DIR_FWD, + MAN_DIR_BWD, + MAN_DIR_LEFT, + MAN_DIR_RIGHT, + MAN_DIR_LF, + MAN_DIR_RF, + MAN_DIR_LB, + MAN_DIR_RB, + MAN_DIR_CW, + MAN_DIR_CCW +} manual_dir_t; + +static ctrl_mode_t car_ctrl_mode = CTRL_MODE_AUTO; +static manual_dir_t manual_dir = MAN_DIR_STOP; + #define CAR_STATION_MIN ((uint16_t)STATION_1) #define CAR_STATION_MAX ((uint16_t)STATION_2) /* 4个电机的 PID 控制器 */ static PID_TypeDef motor_pid[MOTOR_COUNT]; +static const char *CarCtrl_ModeToString(ctrl_mode_t mode) +{ + return (mode == CTRL_MODE_MANUAL) ? "MAN" : "AUTO"; +} + +static const char *CarCtrl_ManualDirToString(manual_dir_t dir) +{ + switch (dir) { + case MAN_DIR_FWD: return "FWD"; + case MAN_DIR_BWD: return "BWD"; + case MAN_DIR_LEFT: return "LEFT"; + case MAN_DIR_RIGHT:return "RIGHT"; + case MAN_DIR_LF: return "LF"; + case MAN_DIR_RF: return "RF"; + case MAN_DIR_LB: return "LB"; + case MAN_DIR_RB: return "RB"; + case MAN_DIR_CW: return "CW"; + case MAN_DIR_CCW: return "CCW"; + case MAN_DIR_STOP: + default: + return "STOP"; + } +} + +static void CarCtrl_SetManualDirection(manual_dir_t dir) +{ + manual_dir = dir; + if (dir == MAN_DIR_STOP) { + car_running = 0U; + target_v_x = 0.0f; + target_v_y = 0.0f; + target_v_w = 0.0f; + CarCtrl_StopAll(); + } else { + car_running = 1U; + car_target_reached = 0U; + } +} + /** * @brief 初始化闭环控制系统 */ @@ -77,6 +143,8 @@ void CarCtrl_InitClosedLoop(void) track_ir_algo_init(); obstacle_locked = 0U; + car_ctrl_mode = CTRL_MODE_AUTO; + manual_dir = MAN_DIR_STOP; BEEP_Off(); } @@ -113,6 +181,10 @@ static void CarCtrl_CheckTargetStation(void) rc522_card_info_t card; station_id_t station; + if (car_ctrl_mode != CTRL_MODE_AUTO) { + return; + } + if (car_running == 0U || car_target_reached != 0U || car_target_station == 0U) { return; } @@ -168,8 +240,66 @@ void CarCtrl_UpdateClosedLoop(void) BEEP_Off(); - track_line_mask = track_ir_get_line_mask_filtered(); - track_ir_algo_step(track_line_mask, &track_output); + if (car_ctrl_mode == CTRL_MODE_AUTO) { + track_line_mask = track_ir_get_line_mask_filtered(); + track_ir_algo_step(track_line_mask, &track_output); + + // 从前进速度分量计算基础速度(自动循迹) + target_v_x = (float)car_speed_percent * TARGET_MAX_RPM / 100.0f; + target_v_x = target_v_x * (float)track_output.speed_scale_percent / 100.0f; + target_v_y = 0.0f; + target_v_w = track_output.yaw_correction_rpm; + } else { + float base_rpm = (float)car_speed_percent * TARGET_MAX_RPM / 100.0f; + track_line_mask = 0U; + memset(&track_output, 0, sizeof(track_output)); + + /* 手动模式下,依据上位机方向指令生成 Vx/Vy/Vw */ + switch (manual_dir) { + case MAN_DIR_FWD: + target_v_x = base_rpm; target_v_y = 0.0f; target_v_w = 0.0f; + break; + case MAN_DIR_BWD: + target_v_x = -base_rpm; target_v_y = 0.0f; target_v_w = 0.0f; + break; + case MAN_DIR_LEFT: + target_v_x = 0.0f; target_v_y = base_rpm; target_v_w = 0.0f; // 修正:左移Vy为正 + break; + case MAN_DIR_RIGHT: + target_v_x = 0.0f; target_v_y = -base_rpm; target_v_w = 0.0f; // 修正:右移Vy为负 + break; + case MAN_DIR_LF: + target_v_x = base_rpm * MANUAL_DIAG_SCALE; + target_v_y = -base_rpm * MANUAL_DIAG_SCALE; + target_v_w = 0.0f; + break; + case MAN_DIR_RF: + target_v_x = base_rpm * MANUAL_DIAG_SCALE; + target_v_y = base_rpm * MANUAL_DIAG_SCALE; + target_v_w = 0.0f; + break; + case MAN_DIR_LB: + target_v_x = -base_rpm * MANUAL_DIAG_SCALE; + target_v_y = -base_rpm * MANUAL_DIAG_SCALE; + target_v_w = 0.0f; + break; + case MAN_DIR_RB: + target_v_x = -base_rpm * MANUAL_DIAG_SCALE; + target_v_y = base_rpm * MANUAL_DIAG_SCALE; + target_v_w = 0.0f; + break; + case MAN_DIR_CW: + target_v_x = 0.0f; target_v_y = 0.0f; target_v_w = base_rpm; + break; + case MAN_DIR_CCW: + target_v_x = 0.0f; target_v_y = 0.0f; target_v_w = -base_rpm; + break; + case MAN_DIR_STOP: + default: + target_v_x = 0.0f; target_v_y = 0.0f; target_v_w = 0.0f; + break; + } + } /* 麦克纳姆轮运动解算 (RPM单位) * 根据你的电机位置规定: @@ -177,12 +307,6 @@ void CarCtrl_UpdateClosedLoop(void) */ float target_rpms[MOTOR_COUNT]; - // 从前进速度分量计算基础速度 - target_v_x = (float)car_speed_percent * TARGET_MAX_RPM / 100.0f; - target_v_x = target_v_x * (float)track_output.speed_scale_percent / 100.0f; - target_v_y = 0.0f; - target_v_w = track_output.yaw_correction_rpm; - // 麦轮全向解算公式: // LF = Vx + Vy - Vw // RF = Vx - Vy + Vw @@ -332,6 +456,72 @@ static void CarCtrl_HandleCommand(const char *cmd_payload) return; } + // 控制模式切换:MD:AUTO / MD:MAN + if (strncmp(cmd_payload, "MD", 2) == 0) { + if (strcmp(arg + 1, "AUTO") == 0) { + car_ctrl_mode = CTRL_MODE_AUTO; + manual_dir = MAN_DIR_STOP; + car_running = 0U; + obstacle_locked = 0U; + track_ir_algo_reset(); + CarCtrl_StopAll(); + elog_i(Protocol_TAG, "已切换为自动循迹模式(AUTO)"); + Protocol_SendFeedback("MD", 1); + } else if (strcmp(arg + 1, "MAN") == 0) { + car_ctrl_mode = CTRL_MODE_MANUAL; + obstacle_locked = 0U; + CarCtrl_SetManualDirection(MAN_DIR_STOP); + elog_i(Protocol_TAG, "已切换为手动麦轮模式(MAN)"); + Protocol_SendFeedback("MD", 1); + } else { + elog_w(Protocol_TAG, "未知模式命令: %s", cmd_payload); + Protocol_SendFeedback("MD", 0); + } + return; + } + + // 手动运动方向命令:MV:FWD/BWD/LEFT/RIGHT/LF/RF/LB/RB/CW/CCW/STOP + if (strncmp(cmd_payload, "MV", 2) == 0) { + if (car_ctrl_mode != CTRL_MODE_MANUAL) { + elog_w(Protocol_TAG, "当前非手动模式,拒绝执行MV。请先下发 MD:MAN"); + Protocol_SendFeedback("MV", 0); + return; + } + + if (strcmp(arg + 1, "FWD") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_FWD); + } else if (strcmp(arg + 1, "BWD") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_BWD); + } else if (strcmp(arg + 1, "LEFT") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_LEFT); + } else if (strcmp(arg + 1, "RIGHT") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_RIGHT); + } else if (strcmp(arg + 1, "LF") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_LF); + } else if (strcmp(arg + 1, "RF") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_RF); + } else if (strcmp(arg + 1, "LB") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_LB); + } else if (strcmp(arg + 1, "RB") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_RB); + } else if (strcmp(arg + 1, "CW") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_CW); + } else if (strcmp(arg + 1, "CCW") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_CCW); + } else if (strcmp(arg + 1, "STOP") == 0) { + CarCtrl_SetManualDirection(MAN_DIR_STOP); + } else { + elog_w(Protocol_TAG, "未知手动方向命令: %s", cmd_payload); + Protocol_SendFeedback("MV", 0); + return; + } + + elog_i(Protocol_TAG, "手动方向=%s, speed=%u%%", CarCtrl_ManualDirToString(manual_dir), + car_speed_percent); + Protocol_SendFeedback("MV", 1); + return; + } + // 未知命令类型 elog_w(Protocol_TAG, "未支持的控制命令: %s", cmd_payload); } @@ -354,7 +544,7 @@ static void Protocol_SendPacket(const char *payload) { size_t current_len = strlen(packet); snprintf(packet + current_len, sizeof(packet) - current_len, ":%02X#", cs); - // 4. 发送 + // 4. 直接发送 ESP12F_TCP_SendMessage(packet); } @@ -363,7 +553,7 @@ static void Protocol_SendPacket(const char *payload) { * 格式示例: STAT:SP:080,STA:001,RUN:1,DIS:12.5,TRK:0010,RPM:25:25:25:25 */ void Protocol_SendStatusReport(void) { - char payload[128] = {0}; + char payload[160] = {0}; float dist = sr04_get_distance(); uint8_t trk_mask = track_line_mask; @@ -371,8 +561,11 @@ void Protocol_SendStatusReport(void) { // TRK 此时上报 4 位二进制掩码 (H4 H3 H2 H1) // RPM 为各个电机的实际 RPM,保留整数 snprintf(payload, sizeof(payload), - "STAT:SP:%03u,STA:%03u,RUN:%u,DIS:%.1f,TRK:%u%u%u%u,DEV:%d,OBS:%u,RPM:%d:%d:%d:%d", - car_speed_percent, car_target_station, car_running, dist, + "STAT:SP:%03u,STA:%03u,RUN:%u,MODE:%s,MAN:%s,DIS:%.1f,TRK:%u%u%u%u,DEV:%d,OBS:%u,RPM:%d:%d:%d:%d", + car_speed_percent, car_target_station, car_running, + CarCtrl_ModeToString(car_ctrl_mode), + CarCtrl_ManualDirToString(manual_dir), + dist, (trk_mask & TRACK_IR_H4_BIT) ? 1 : 0, (trk_mask & TRACK_IR_H3_BIT) ? 1 : 0, (trk_mask & TRACK_IR_H2_BIT) ? 1 : 0, diff --git a/Core/Inc/FreeRTOSConfig.h b/Core/Inc/FreeRTOSConfig.h index f0c28ab..66c3675 100644 --- a/Core/Inc/FreeRTOSConfig.h +++ b/Core/Inc/FreeRTOSConfig.h @@ -64,7 +64,7 @@ #define configTICK_RATE_HZ ((TickType_t)1000) #define configMAX_PRIORITIES ( 56 ) #define configMINIMAL_STACK_SIZE ((uint16_t)128) -#define configTOTAL_HEAP_SIZE ((size_t)10000) +#define configTOTAL_HEAP_SIZE ((size_t)18000) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index 3348c8f..d069929 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -60,35 +60,35 @@ osThreadId_t initTaskHandle; const osThreadAttr_t initTask_attributes = { .name = "initTask", - .stack_size = 128 * 4, + .stack_size = 256 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for CarCtrlTask */ osThreadId_t CarCtrlTaskHandle; const osThreadAttr_t CarCtrlTask_attributes = { .name = "CarCtrlTask", - .stack_size = 256 * 4, + .stack_size = 1024 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for timerTask */ osThreadId_t timerTaskHandle; const osThreadAttr_t timerTask_attributes = { .name = "timerTask", - .stack_size = 512 * 4, + .stack_size = 1024 * 4, .priority = (osPriority_t) osPriorityBelowNormal, }; /* Definitions for sr04Task */ osThreadId_t sr04TaskHandle; const osThreadAttr_t sr04Task_attributes = { .name = "sr04Task", - .stack_size = 128 * 4, + .stack_size = 512 * 4, .priority = (osPriority_t) osPriorityLow, }; /* Definitions for rc522Task */ osThreadId_t rc522TaskHandle; const osThreadAttr_t rc522Task_attributes = { .name = "rc522Task", - .stack_size = 128 * 4, + .stack_size = 512 * 4, .priority = (osPriority_t) osPriorityBelowNormal, }; /* Definitions for CmdQueue */ diff --git a/docs/upper_computer_ai_guide.md b/docs/upper_computer_ai_guide.md new file mode 100644 index 0000000..3534c19 --- /dev/null +++ b/docs/upper_computer_ai_guide.md @@ -0,0 +1,331 @@ +# Logistics Car Upper Computer AI Guide + +## 1. Purpose +This document is written for an AI agent that will implement the upper computer application. +Goal: build a stable TCP client for the logistics car, with both auto mode and manual mecanum mode, based on the embedded protocol implemented in this repository. + +Target users: +- AI coding agents (Copilot-like, AutoGen-like, etc.) +- Human developers who review AI-generated upper computer code + +Out of scope: +- Modifying embedded firmware behavior +- Replacing transport protocol + +--- + +## 2. Must-Follow Protocol Contract + +### 2.1 Frame format +All commands and telemetry use ASCII text: + +LOGI::# + +Fields: +- LOGI: fixed header +- : command or telemetry body +- : 2-digit uppercase hex checksum +- #: fixed frame tail + +### 2.2 Checksum algorithm +Checksum is the low 8 bits of ASCII sum of all bytes from L in LOGI to the byte before the final colon before CS. + +Pseudo: +1. base = "LOGI:" + payload +2. cs = sum(base bytes as ASCII) & 0xFF +3. frame = base + ":" + toHex2Upper(cs) + "#" + +Python reference: + +```python +def build_frame(payload: str) -> str: + base = f"LOGI:{payload}" + cs = sum(base.encode("ascii")) & 0xFF + return f"{base}:{cs:02X}#" +``` + +C# reference: + +```csharp +static string BuildFrame(string payload) +{ + string baseStr = $"LOGI:{payload}"; + int sum = 0; + foreach (byte b in System.Text.Encoding.ASCII.GetBytes(baseStr)) + sum = (sum + b) & 0xFF; + return $"{baseStr}:{sum:X2}#"; +} +``` + +Important: +- Must use uppercase hex (for consistency) +- Do not append CRLF unless your socket tool requires it +- One frame can be sent as raw ASCII bytes directly + +--- + +## 3. Command Set (PC -> Car) + +### 3.1 Common control +- SP:xxx set speed 000..100 +- ST:RUN start auto run +- ST:STOP stop run +- GS:xxx set target station (current firmware supports 001, 002) + +### 3.2 Mode switch (new) +- MD:MAN switch to manual mecanum mode +- MD:AUTO switch to auto tracking mode + +### 3.3 Manual movement (new, only valid in MAN mode) +- MV:FWD forward +- MV:BWD backward +- MV:LEFT strafe left +- MV:RIGHT strafe right +- MV:LF forward-left diagonal +- MV:RF forward-right diagonal +- MV:LB backward-left diagonal +- MV:RB backward-right diagonal +- MV:CW rotate clockwise +- MV:CCW rotate counterclockwise +- MV:STOP stop motion + +If current mode is AUTO and you send MV:*: +- car returns FB:MV:0 (rejected) +- upper computer must first send MD:MAN + +--- + +## 4. Telemetry and Feedback (Car -> PC) + +### 4.1 Periodic status (every ~500ms) +Payload format: + +STAT:SP:xxx,STA:xxx,RUN:x,MODE:mode,MAN:dir,DIS:d,TRK:b4b3b2b1,DEV:n,OBS:x,RPM:m1:m2:m3:m4 + +Fields: +- SP: speed percent +- STA: target station +- RUN: 1 running, 0 stopped +- MODE: AUTO or MAN +- MAN: STOP/FWD/BWD/LEFT/RIGHT/LF/RF/LB/RB/CW/CCW +- DIS: ultrasonic distance in cm +- TRK: 4-channel line mask, order H4 H3 H2 H1 +- DEV: track deviation (auto mode meaningful) +- OBS: obstacle lock (1 blocked, 0 clear) +- RPM: 4 motor RPM, order M1:M2:M3:M4 (LR:LF:RF:RR) + +### 4.2 Command feedback (immediate) +Payload format: + +FB::<0|1> + +Examples: +- FB:SP:1 speed accepted +- FB:GS:0 station invalid or parse fail +- FB:MV:0 movement rejected (for example mode mismatch) + +Upper computer rule: +- Every button operation should wait for feedback timeout window +- If no feedback in timeout, mark command uncertain and retry policy applies + +--- + +## 5. Upper Computer Architecture Requirements + +AI must implement the upper computer with these modules. + +### 5.1 Network module +Responsibilities: +- Maintain TCP connection lifecycle +- Auto reconnect with backoff +- Byte stream receive and frame extraction + +Required behavior: +- Reconnect delay: 1s, 2s, 3s, then fixed 3s +- On reconnect success, UI state set to Connected +- On disconnect, all movement buttons should be disabled + +### 5.2 Protocol module +Responsibilities: +- Build frames from payload +- Parse incoming frames +- Verify checksum before dispatch + +Required behavior: +- Drop frame if checksum invalid +- Log invalid frame raw text for diagnostics +- Expose strongly typed events: StatusEvent, FeedbackEvent + +### 5.3 Command dispatcher +Responsibilities: +- Serialize outbound commands (single queue) +- Attach request id locally (not in protocol) for UI correlation +- Wait feedback with timeout + +Recommended defaults: +- Feedback timeout: 800 ms +- Max retries for idempotent commands (SP, MD, MV:STOP): 2 +- No auto-retry for ST:RUN and GS:xxx unless user confirms + +### 5.4 UI module +Required controls: +- Connection: IP, port, connect/disconnect +- Mode: AUTO / MAN toggle +- Speed: slider 0..100 with send button +- Auto controls: station selector (001/002), RUN, STOP +- Manual controls: directional keypad + rotation + STOP +- Status panel: parsed telemetry fields +- Logs panel: TX/RX raw frames + parsed result + +### 5.5 Safety guard module +Required safety logic: +- If UI in MAN mode and mouse/touch release on direction button, auto send MV:STOP +- If no fresh status for >2s, show stale warning +- Emergency stop hotkey sends MV:STOP first; if in AUTO also send ST:STOP + +--- + +## 6. Exact Button-to-Command Mapping + +All below are complete frames with checksum, directly sendable. + +### 6.1 Mode +- Switch to manual: LOGI:MD:MAN:0C# +- Switch to auto: LOGI:MD:AUTO:69# + +### 6.2 Speed presets +- 30%: LOGI:SP:030:D5# +- 50%: LOGI:SP:050:D7# +- 80%: LOGI:SP:080:DA# + +### 6.3 Auto mode +- Station 001: LOGI:GS:001:CA# +- Station 002: LOGI:GS:002:CB# +- Auto run: LOGI:ST:RUN:3B# +- Auto stop: LOGI:ST:STOP:8C# + +### 6.4 Manual movement +- Forward: LOGI:MV:FWD:23# +- Backward: LOGI:MV:BWD:1F# +- Left strafe: LOGI:MV:LEFT:6D# +- Right strafe: LOGI:MV:RIGHT:C0# +- Forward-left: LOGI:MV:LF:D4# +- Forward-right: LOGI:MV:RF:DA# +- Backward-left: LOGI:MV:LB:D0# +- Backward-right: LOGI:MV:RB:D6# +- Rotate CW: LOGI:MV:CW:DC# +- Rotate CCW: LOGI:MV:CCW:1F# +- Stop: LOGI:MV:STOP:88# + +--- + +## 7. Recommended Operation Sequences + +### 7.1 Manual driving flow +1. Connect TCP +2. Send SP:xxx +3. Send MD:MAN +4. Hold direction button -> send MV:* repeatedly or once per state change +5. Release button -> send MV:STOP + +Recommended send style for manual: +- Edge-triggered (on press send once, on release send stop) is preferred +- If network jitter is high, add keepalive send of same MV every 300 ms + +### 7.2 Auto transport flow +1. Connect TCP +2. Send SP:xxx +3. Send MD:AUTO +4. Send GS:001 or GS:002 +5. Send ST:RUN +6. Observe RUN and feedback/status until arrival + +Arrival behavior in firmware: +- Car auto-stops on target RFID +- RUN becomes 0 +- Next run requires sending GS again, then ST:RUN + +--- + +## 8. Frame Parsing Strategy (Stream-safe) + +TCP is stream-based, not message-based. AI must implement frame extraction correctly. + +Required parser behavior: +- Keep a receive buffer string/byte array +- Search for header "LOGI:" +- Search for tail '#' +- Extract candidate frame from first valid header to first following '#' +- Validate checksum +- Dispatch valid frame; remove consumed bytes +- If garbage before header, discard garbage + +Do not assume one recv equals one frame. + +--- + +## 9. Error Handling and Recovery + +### 9.1 Feedback timeout +If command has no FB within timeout: +- Mark as timeout in UI +- For safe idempotent commands, retry once or twice +- For movement commands, prefer fail-safe by sending STOP + +### 9.2 Checksum mismatch in received data +- Drop frame +- Log as warning with raw text +- Keep connection alive (do not disconnect directly) + +### 9.3 Mode conflict +If receiving FB:MV:0 after sending MV command: +- UI should hint: "Not in manual mode, switching to MAN" +- Auto-send MD:MAN then retry once + +### 9.4 Connection loss during motion +On disconnect event: +- UI enters safe state +- disable movement controls +- after reconnect, require operator to re-confirm mode and speed + +--- + +## 10. AI Implementation Checklist (Definition of Done) + +Functional: +- Can connect/disconnect TCP manually +- Can parse status and feedback reliably +- All buttons send correct command frames +- Manual control works in all listed directions +- Auto mode flow works (GS + RUN + STOP) + +Robustness: +- Stream parser handles sticky packets and split packets +- Reconnect works automatically +- Command timeout/retry policy implemented +- Logs include TX/RX and parse errors + +Usability: +- Telemetry fields visible and updating +- Mode and direction state clearly shown +- Emergency stop is always accessible + +Testing: +- Unit test for checksum build/verify +- Unit test for parser with mixed/fragmented frames +- Integration test with mock TCP server replaying status/feedback + +--- + +## 11. Suggested Prompt for Coding AI +Use this prompt when asking another coding AI to generate the upper computer: + +"Implement a production-ready TCP upper computer client for an STM32 logistics car protocol. Use ASCII frame format LOGI::# with checksum as sum(base bytes) & 0xFF where base is LOGI:. Support commands SP, ST, GS, MD, MV. Parse status payload STAT with fields SP, STA, RUN, MODE, MAN, DIS, TRK, DEV, OBS, RPM. Parse feedback payload FB::<0|1>. Build a stream-safe parser for sticky/fragmented TCP packets. Include reconnect, timeout/retry, and a UI with manual mecanum directional controls and auto mode controls." + +--- + +## 12. Notes for Future Extension +If firmware adds fields later: +- Keep parser tolerant: unknown key-value pairs should not crash parser +- Preserve raw payload in logs for forward compatibility +- Version your app-side parser module (for example v1_2) diff --git a/docs/upper_computer_ai_guide_python_web_zh.md b/docs/upper_computer_ai_guide_python_web_zh.md new file mode 100644 index 0000000..94b2dfd --- /dev/null +++ b/docs/upper_computer_ai_guide_python_web_zh.md @@ -0,0 +1,392 @@ +# Python Web 上位机实施文档(给开发AI直接执行) + +## 1. 目标与技术选型 + +目标:实现一个可运行、可联调、可扩展的上位机系统,满足以下要求: +- 与小车通过 TCP 协议通信 +- 浏览器可视化控制(自动模式 + 手动麦轮模式) +- 实时状态显示(500ms级) +- 日志、重连、超时、错误恢复完整 + +推荐技术栈: +- 后端:Python 3.11+ +- Web框架:FastAPI +- 实时推送:WebSocket +- 异步:asyncio +- 前端:Vue3 或 React(都可以,本文给中立接口规范) +- 部署:Windows 本地运行(开发阶段) + +建议架构: +- Browser UI <-> WebSocket/HTTP <-> Python Backend <-> TCP Socket <-> Car + +--- + +## 2. 协议契约(必须严格一致) + +帧格式: +LOGI::# + +校验和: +- 对字符串 LOGI: 做 ASCII 累加 +- 取低8位 +- 转 2位大写十六进制 + +Python函数(必须实现并复用): + +```python +def build_frame(payload: str) -> str: + base = f"LOGI:{payload}" + cs = sum(base.encode("ascii")) & 0xFF + return f"{base}:{cs:02X}#" +``` + +已验证可直接发送的关键命令: +- LOGI:MD:MAN:0C# +- LOGI:MD:AUTO:69# +- LOGI:MV:FWD:23# +- LOGI:MV:BWD:1F# +- LOGI:MV:LEFT:6D# +- LOGI:MV:RIGHT:C0# +- LOGI:MV:LF:D4# +- LOGI:MV:RF:DA# +- LOGI:MV:LB:D0# +- LOGI:MV:RB:D6# +- LOGI:MV:CW:DC# +- LOGI:MV:CCW:1F# +- LOGI:MV:STOP:88# +- LOGI:SP:030:D5# +- LOGI:SP:050:D7# +- LOGI:SP:080:DA# +- LOGI:GS:001:CA# +- LOGI:GS:002:CB# +- LOGI:ST:RUN:3B# +- LOGI:ST:STOP:8C# + +--- + +## 3. 项目目录(AI生成代码必须遵循) + +```text +upper-computer-python-web/ + backend/ + app/ + main.py + config.py + models.py + protocol.py + tcp_client.py + command_service.py + state_store.py + ws_hub.py + parser.py + logger.py + api/ + http_routes.py + ws_routes.py + requirements.txt + frontend/ + src/ + main.ts + api.ts + ws.ts + store.ts + components/ + ConnectionPanel.vue + ModePanel.vue + SpeedPanel.vue + AutoPanel.vue + ManualPad.vue + StatusPanel.vue + LogPanel.vue + package.json + README.md +``` + +--- + +## 4. 后端职责与实现要求 + +### 4.1 TCP客户端(tcp_client.py) + +必须实现: +- connect(host, port) +- disconnect() +- send_frame(frame) +- background_read_loop() +- auto_reconnect_loop() + +重连策略: +- 1s -> 2s -> 3s -> 3s循环 + +连接状态事件: +- connected +- disconnected +- reconnecting +- connect_failed + +### 4.2 流式解析器(parser.py) + +TCP是流,必须做粘包拆包。 + +规则: +1. 维护 bytearray 缓冲区 +2. 找 LOGI: 起点 +3. 找 # 终点 +4. 抽取候选帧 +5. 校验和正确才分发 +6. 错帧丢弃并记录日志 + +必须支持: +- 一次收多帧 +- 一帧分多次收 +- 帧前垃圾字节 + +### 4.3 协议服务(protocol.py) + +必须提供: +- build_frame(payload) +- parse_frame(frame) -> dict +- verify_checksum(frame) -> bool + +parse_frame 输出建议: +- type: status / feedback / unknown +- payload_raw +- fields: dict + +### 4.4 命令服务(command_service.py) + +必须实现命令队列与反馈匹配: +- send_command(payload, wait_feedback=True) +- 超时默认 800ms +- 可重试命令:SP、MD、MV:STOP(最多2次) +- 非幂等命令 ST:RUN、GS 不自动重试 + +反馈格式: +- FB::<0|1> + +### 4.5 状态存储(state_store.py) + +维护全局状态对象: +- connection +- speed +- station +- run +- mode +- manual_dir +- distance +- trk +- dev +- obs +- rpm[4] +- last_status_ts + +超过2秒无状态包: +- 标记 stale = true +- 推送前端告警 + +### 4.6 WebSocket中枢(ws_hub.py) + +前端订阅以下事件: +- conn_update +- status_update +- feedback_update +- tx_log +- rx_log +- warn +- error + +--- + +## 5. HTTP 与 WebSocket 接口规范 + +### 5.1 HTTP + +1) POST /api/connect +- body: {"host":"192.168.1.50","port":3456} +- resp: {"ok":true} + +2) POST /api/disconnect +- resp: {"ok":true} + +3) POST /api/cmd +- body: {"payload":"MV:FWD","waitFeedback":true} +- resp: {"ok":true,"feedback":{"cmd":"MV","status":1}} + +4) GET /api/state +- resp: 全量状态JSON + +5) GET /api/health +- resp: {"ok":true} + +### 5.2 WebSocket + +- ws://host:port/ws + +消息统一格式: +- {"event":"status_update","data":{...}} +- {"event":"feedback_update","data":{...}} +- {"event":"tx_log","data":{"frame":"..."}} +- {"event":"rx_log","data":{"frame":"..."}} + +--- + +## 6. 前端页面与按钮行为 + +页面最少包含: +- 连接面板:IP、端口、连接/断开 +- 模式面板:AUTO / MAN +- 速度面板:0-100滑条 + 发送按钮 +- 自动面板:站点001/002、RUN、STOP +- 手动面板:8方向 + CW/CCW + STOP +- 状态面板:SP/STA/RUN/MODE/MAN/DIS/TRK/DEV/OBS/RPM +- 日志面板:TX/RX + +按钮映射要求: + +1) 切手动 +- 发送 payload: MD:MAN + +2) 切自动 +- 发送 payload: MD:AUTO + +3) 速度 +- 发送 payload: SP:xxx(补零3位) + +4) 自动站点 +- 001 -> GS:001 +- 002 -> GS:002 + +5) 自动运行控制 +- RUN -> ST:RUN +- STOP -> ST:STOP + +6) 手动方向 +- 前进 MV:FWD +- 后退 MV:BWD +- 左移 MV:LEFT +- 右移 MV:RIGHT +- 左前 MV:LF +- 右前 MV:RF +- 左后 MV:LB +- 右后 MV:RB +- 顺时针 MV:CW +- 逆时针 MV:CCW +- 停止 MV:STOP + +手动安全行为(必须): +- 按下方向键:发对应MV +- 松开方向键:立即发 MV:STOP + +--- + +## 7. 关键业务逻辑(必须实现) + +### 7.1 模式冲突恢复 +如果发送 MV:* 收到 FB:MV:0: +1. 自动提示“当前不在手动模式” +2. 自动发送 MD:MAN +3. 重试一次原MV命令 + +### 7.2 断线保护 +断线时: +- 禁用全部运动按钮 +- UI状态置灰 +- 重连成功后,不自动恢复运动,必须人工再次点方向 + +### 7.3 急停策略 +急停按钮逻辑: +1. 先发 MV:STOP +2. 若当前模式是AUTO,再发 ST:STOP + +### 7.4 自动流程约束 +自动流程推荐顺序: +- SP -> MD:AUTO -> GS -> ST:RUN + +到站后固件会锁存,下一次运行前应: +- 重发 GS +- 再发 ST:RUN + +--- + +## 8. 后端参考代码骨架(最小可运行) + +main.py 示例: + +```python +from fastapi import FastAPI, WebSocket +from app.api.http_routes import router as http_router +from app.api.ws_routes import router as ws_router + +app = FastAPI(title="Car Upper Computer") +app.include_router(http_router, prefix="/api") +app.include_router(ws_router) + +@app.get("/api/health") +async def health(): + return {"ok": True} +``` + +command_service.py 的命令发送入口示例: + +```python +async def send_payload(payload: str, wait_feedback: bool = True): + frame = build_frame(payload) + await tcp_client.send_frame(frame) + await ws_hub.broadcast("tx_log", {"frame": frame}) + if not wait_feedback: + return {"ok": True} + fb = await feedback_waiter.wait(payload.split(":", 1)[0], timeout=0.8) + return {"ok": fb is not None, "feedback": fb} +``` + +--- + +## 9. 联调步骤(按此执行) + +1. 启动后端 +- uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload + +2. 启动前端 +- npm install +- npm run dev + +3. 页面连接到小车TCP +- 输入IP和端口 +- 点击连接 + +4. 先测基础命令 +- SP:050 +- MD:MAN +- MV:FWD +- MV:STOP + +5. 再测自动流程 +- MD:AUTO +- GS:001 +- ST:RUN + +6. 检查状态面板字段是否持续刷新 + +--- + +## 10. 测试清单(必须通过) + +单元测试: +- build_frame校验值正确 +- verify_checksum正确拦截坏包 +- parser支持粘包拆包 + +集成测试: +- 命令发送后能收到FB +- 状态包断流时 stale 告警出现 +- 断线后自动重连并恢复状态展示 + +交互测试: +- 手动按钮按下/松开逻辑正确 +- 急停在任意状态都可触发 + +--- + +## 11. 给开发AI的最终任务提示词 + +请实现一个 Python Web 上位机系统,后端用 FastAPI + asyncio TCP + WebSocket,前端用 Vue3 或 React。协议为 LOGI::#,CS 为 LOGI: 的 ASCII 累加低8位。实现 SP/ST/GS/MD/MV 命令,解析 STAT 与 FB。支持手动麦轮方向控制(8方向+旋转+STOP)和自动模式控制。必须实现 TCP 粘包拆包解析、命令反馈超时处理、自动重连、状态实时推送、日志面板与安全急停逻辑。 diff --git a/docs/upper_computer_ai_guide_zh.md b/docs/upper_computer_ai_guide_zh.md new file mode 100644 index 0000000..2103817 --- /dev/null +++ b/docs/upper_computer_ai_guide_zh.md @@ -0,0 +1,311 @@ +# 上位机开发AI执行文档(物流小车 TCP 协议) + +## 1. 文档目标 +这份文档是写给“负责开发上位机的AI”的,不是普通说明书。 +目标是让AI按本文档直接产出可运行的上位机程序(TCP客户端),并且与当前固件协议完全兼容。 + +适用范围: +- Windows上位机(Python / C# / C++ / Electron均可) +- 控制模式:自动循迹 + 手动麦克纳姆 +- 通信方式:TCP,ASCII协议 + +不做的事情: +- 不修改单片机固件协议 +- 不更换通信栈 + +--- + +## 2. 协议总规范(必须严格遵守) + +### 2.1 帧格式 +所有收发数据都使用: + +LOGI::# + +字段说明: +- LOGI: 固定帧头 +- : 有效载荷 +- : 2位大写十六进制校验和 +- #: 固定帧尾 + +### 2.2 校验和算法 +计算范围是 LOGI:PAYLOAD 这一段(不含最后 :CS#)。 +算法:ASCII逐字节累加,取低8位。 + +示例代码(Python): + +```python +def build_frame(payload: str) -> str: + base = f"LOGI:{payload}" + cs = sum(base.encode("ascii")) & 0xFF + return f"{base}:{cs:02X}#" +``` + +示例代码(C#): + +```csharp +static string BuildFrame(string payload) +{ + string baseStr = $"LOGI:{payload}"; + int sum = 0; + foreach (byte b in System.Text.Encoding.ASCII.GetBytes(baseStr)) + sum = (sum + b) & 0xFF; + return $"{baseStr}:{sum:X2}#"; +} +``` + +硬性要求: +- 十六进制统一大写 +- 不要额外拼接换行(除非你的网络调试工具强制) + +--- + +## 3. 下行指令(上位机 -> 小车) + +### 3.1 通用控制 +- SP:xxx 设置速度(000~100) +- ST:RUN 自动启动 +- ST:STOP 自动停止 +- GS:xxx 设置目标站点(当前固件支持001/002) + +### 3.2 模式切换(新增) +- MD:MAN 切换手动麦轮模式 +- MD:AUTO 切换自动循迹模式 + +### 3.3 手动方向(新增,仅MAN模式有效) +- MV:FWD 前进 +- MV:BWD 后退 +- MV:LEFT 左平移 +- MV:RIGHT 右平移 +- MV:LF 左前 +- MV:RF 右前 +- MV:LB 左后 +- MV:RB 右后 +- MV:CW 原地顺时针 +- MV:CCW 原地逆时针 +- MV:STOP 停止 + +注意: +- 若处于AUTO模式直接发MV:*,固件会返回 FB:MV:0 +- 上位机应先发 MD:MAN 再发 MV:* + +--- + +## 4. 上行数据(小车 -> 上位机) + +### 4.1 状态上报(约500ms) +PAYLOAD格式: + +STAT:SP:xxx,STA:xxx,RUN:x,MODE:mode,MAN:dir,DIS:d,TRK:b4b3b2b1,DEV:n,OBS:x,RPM:m1:m2:m3:m4 + +字段含义: +- SP: 当前速度百分比 +- STA: 当前目标站点 +- RUN: 1运行,0停止 +- MODE: AUTO 或 MAN +- MAN: STOP/FWD/BWD/LEFT/RIGHT/LF/RF/LB/RB/CW/CCW +- DIS: 超声距离(cm) +- TRK: 循迹4位掩码(H4 H3 H2 H1) +- DEV: 偏差值(自动模式更有意义) +- OBS: 避障锁(1有障碍,0无) +- RPM: 4路电机转速,顺序 M1:M2:M3:M4(LR:LF:RF:RR) + +### 4.2 命令反馈(即时) +PAYLOAD格式: + +FB::<0|1> + +示例: +- FB:SP:1 表示设置速度成功 +- FB:MV:0 表示手动命令被拒绝(如模式不对) + +上位机处理规则: +- 每个按钮操作都要等待反馈超时窗口 +- 无反馈应标记为超时,按策略重试或提示用户 + +--- + +## 5. 上位机程序架构要求(AI必须实现) + +### 5.1 网络层 +功能: +- TCP连接/断开 +- 自动重连 +- 接收字节流 + +要求: +- 重连退避:1s -> 2s -> 3s -> 3s... +- 断线后禁用运动按钮 +- 重连成功后状态切到已连接 + +### 5.2 协议层 +功能: +- 组帧(payload -> frame) +- 解帧(frame -> typed message) +- 校验和验证 + +要求: +- 校验失败帧丢弃并记录日志 +- 提供结构化事件:StatusEvent / FeedbackEvent + +### 5.3 命令调度层 +功能: +- 发送队列串行化 +- 等待反馈 +- 超时重试 + +建议默认: +- 反馈超时 800ms +- 可重试命令:SP、MD、MV:STOP(最多2次) +- ST:RUN、GS:xxx不自动重试,避免误动作 + +### 5.4 UI层 +必须具备控件: +- 网络连接区:IP、端口、连接/断开 +- 模式区:AUTO/MAN +- 速度区:滑条+发送 +- 自动区:站点选择、RUN、STOP +- 手动区:方向盘(8方向)+旋转+STOP +- 状态区:实时显示SP/STA/RUN/MODE/MAN/DIS/TRK/DEV/OBS/RPM +- 日志区:TX/RX原始帧 + 解析结果 + +### 5.5 安全保护 +必须实现: +- 手动方向按钮松开时自动发送 MV:STOP +- 2秒无状态包,UI提示“状态超时” +- 急停键:优先发 MV:STOP;若在AUTO,再发 ST:STOP + +--- + +## 6. 按钮与命令映射(可直接发送,含校验) + +### 6.1 模式 +- 手动模式:LOGI:MD:MAN:0C# +- 自动模式:LOGI:MD:AUTO:69# + +### 6.2 速度快捷键 +- 30%:LOGI:SP:030:D5# +- 50%:LOGI:SP:050:D7# +- 80%:LOGI:SP:080:DA# + +### 6.3 自动流程按钮 +- 站点001:LOGI:GS:001:CA# +- 站点002:LOGI:GS:002:CB# +- 启动:LOGI:ST:RUN:3B# +- 停止:LOGI:ST:STOP:8C# + +### 6.4 手动方向按钮 +- 前进:LOGI:MV:FWD:23# +- 后退:LOGI:MV:BWD:1F# +- 左移:LOGI:MV:LEFT:6D# +- 右移:LOGI:MV:RIGHT:C0# +- 左前:LOGI:MV:LF:D4# +- 右前:LOGI:MV:RF:DA# +- 左后:LOGI:MV:LB:D0# +- 右后:LOGI:MV:RB:D6# +- 顺时针:LOGI:MV:CW:DC# +- 逆时针:LOGI:MV:CCW:1F# +- 停止:LOGI:MV:STOP:88# + +--- + +## 7. 操作时序(AI实现时必须按此流程) + +### 7.1 手动控制时序 +1. 连接TCP +2. 发速度 SP:xxx +3. 发 MD:MAN +4. 按下方向键发 MV:* +5. 松开方向键发 MV:STOP + +建议: +- 优先“边沿发送”(按下发一次,松开发STOP) +- 若网络抖动明显,可每300ms补发一次当前MV,松开必发STOP + +### 7.2 自动运输时序 +1. 连接TCP +2. 发速度 SP:xxx +3. 发 MD:AUTO +4. 发 GS:001 或 GS:002 +5. 发 ST:RUN +6. 监控状态包直到到站 + +固件行为: +- 到站会自动停 +- RUN变0 +- 再次启动前需先重发GS,再发ST:RUN + +--- + +## 8. TCP粘包/拆包解析要求 + +TCP是流,不能假设一次recv就是一帧。 + +必须实现: +- 维护接收缓存 +- 搜索帧头 LOGI: +- 搜索帧尾 # +- 从有效头到尾提取候选帧 +- 校验通过才分发 +- 头前垃圾数据丢弃 + +如果不做这一层,上位机会出现随机解析错误。 + +--- + +## 9. 错误处理策略 + +### 9.1 超时 +- 指令超时无反馈:UI标红并记录日志 +- 安全指令可重试 +- 运动指令超时优先补发STOP + +### 9.2 校验失败 +- 丢弃该帧 +- 记录原始帧日志 +- 不要直接断线 + +### 9.3 模式冲突 +收到 FB:MV:0 时: +1. 自动提示“当前非手动模式” +2. 自动发 MD:MAN +3. 重试一次原MV命令 + +### 9.4 断线 +- 立刻禁用控制按钮 +- 显示离线 +- 重连成功后要求用户确认模式和速度后再控车 + +--- + +## 10. AI交付验收清单(Definition of Done) + +功能通过: +- 能连接/断开TCP +- 能正确收发并解析状态和反馈 +- 全部按钮命令可用 +- 手动10方向可控 +- 自动流程可用(GS+RUN+STOP) + +稳定性通过: +- 粘包拆包处理正确 +- 自动重连生效 +- 超时重试策略生效 +- 日志可追溯 + +可用性通过: +- 状态字段实时刷新 +- 当前模式和方向显示清晰 +- 急停入口明显且可用 + +测试通过: +- 校验和单元测试 +- 解析器单元测试(粘包/拆包/坏包) +- 联调测试(与真实小车或Mock服务) + +--- + +## 11. 给“上位机开发AI”的可直接任务描述 +请将下面这段作为任务输入给编码AI: + +实现一个可发布的物流小车TCP上位机客户端。协议是ASCII帧 LOGI::#,校验算法为 sum(LOGI:的ASCII字节) & 0xFF。实现命令 SP/ST/GS/MD/MV,解析状态STAT和反馈FB。支持自动模式和手动麦克纳姆模式(8方向+旋转+停止)。必须实现TCP流式粘包拆包解析、自动重连、命令超时重试、原始日志和结构化状态显示。UI必须包含连接区、模式区、速度区、自动区、手动方向区、状态区和日志区。 diff --git a/f103_car.ioc b/f103_car.ioc index 4566575..34a2a72 100644 --- a/f103_car.ioc +++ b/f103_car.ioc @@ -33,11 +33,11 @@ Dma.USART2_TX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE Dma.USART2_TX.2.PeriphInc=DMA_PINC_DISABLE Dma.USART2_TX.2.Priority=DMA_PRIORITY_LOW Dma.USART2_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority -FREERTOS.FootprintOK=true +FREERTOS.FootprintOK=false FREERTOS.IPParameters=Tasks01,FootprintOK,Queues01,configTOTAL_HEAP_SIZE FREERTOS.Queues01=CmdQueue,16,16,1,Dynamic,NULL,NULL -FREERTOS.Tasks01=initTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;CarCtrlTask,24,256,CarCtrl_Task,As weak,NULL,Dynamic,NULL,NULL;timerTask,16,512,speed_get,As weak,NULL,Dynamic,NULL,NULL;sr04Task,8,128,sr04_task,Default,NULL,Dynamic,NULL,NULL;rc522Task,16,128,rc522_task,Default,NULL,Dynamic,NULL,NULL -FREERTOS.configTOTAL_HEAP_SIZE=10000 +FREERTOS.Tasks01=initTask,24,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;CarCtrlTask,24,1024,CarCtrl_Task,As weak,NULL,Dynamic,NULL,NULL;timerTask,16,1024,speed_get,As weak,NULL,Dynamic,NULL,NULL;sr04Task,8,512,sr04_task,Default,NULL,Dynamic,NULL,NULL;rc522Task,16,512,rc522_task,Default,NULL,Dynamic,NULL,NULL +FREERTOS.configTOTAL_HEAP_SIZE=18000 File.Version=6 GPIO.groupedBy=Group By Peripherals KeepUserPlacement=false diff --git a/物流小车/esp_12f/AiThinker_Serial_Tool_V1.2.3/aithinker_serial_tool.cfg b/物流小车/esp_12f/AiThinker_Serial_Tool_V1.2.3/aithinker_serial_tool.cfg index b52e628..fab40ed 100644 --- a/物流小车/esp_12f/AiThinker_Serial_Tool_V1.2.3/aithinker_serial_tool.cfg +++ b/物流小车/esp_12f/AiThinker_Serial_Tool_V1.2.3/aithinker_serial_tool.cfg @@ -32,7 +32,7 @@ - + @@ -60,7 +60,7 @@ - + diff --git a/物流小车/esp_12f/TCPUDPDbg/config/config.ini b/物流小车/esp_12f/TCPUDPDbg/config/config.ini index abafa64..f5762cd 100644 --- a/物流小车/esp_12f/TCPUDPDbg/config/config.ini +++ b/物流小车/esp_12f/TCPUDPDbg/config/config.ini @@ -10,7 +10,7 @@ SendHex=0 [DlgCreateServer] DlgServerPort=3456 [Update] -Time=1775660879 +Time=1776317344 [SysOptions] SendBlSZforFile=10240 SendBlITforFile=1 diff --git a/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/hspi_download.conf b/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/hspi_download.conf index 964f856..1ab60fd 100644 --- a/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/hspi_download.conf +++ b/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/hspi_download.conf @@ -62,7 +62,7 @@ file_sel13 = 0 file_path13 = file_flag13 = False file_offset13 = -default_path = E:\My_Workpace\С\esp_12f\flash_download_tool_3.9.7 +default_path = E:\My_Workpace\f103_car\С\esp_12f\flash_download_tool_3.9.7 [FLASH_CRYSTAL] spicfgdis = 1 diff --git a/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/spi_download.conf b/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/spi_download.conf index f574595..2d8adce 100644 --- a/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/spi_download.conf +++ b/物流小车/esp_12f/flash_download_tool_3.9.7/configure/esp8266/spi_download.conf @@ -7,7 +7,7 @@ multi_col = 2 [DOWNLOAD PATH] file_sel0 = 1 -file_path0 = E:\My_Workpace\С\esp_12f\flash_download_tool_3.9.7\1112ESP8266-4M.bin +file_path0 = E:\My_Workpace\f103_car\С\esp_12f\1112ESP8266-4M.bin file_flag0 = False file_offset0 = 0 file_sel1 = 0 @@ -62,7 +62,7 @@ file_sel13 = 0 file_path13 = file_flag13 = False file_offset13 = -default_path = E:\My_Workpace\С\esp_12f\flash_download_tool_3.9.7 +default_path = E:\My_Workpace\f103_car\С\esp_12f [FLASH_CRYSTAL] spicfgdis = 1 diff --git a/物流小车/esp_12f/flash_download_tool_3.9.7/(1112)ESP8266-4M.bin b/物流小车/esp_12f/(1112)ESP8266-4M.bin similarity index 100% rename from 物流小车/esp_12f/flash_download_tool_3.9.7/(1112)ESP8266-4M.bin rename to 物流小车/esp_12f/(1112)ESP8266-4M.bin diff --git a/物流小车/web/app.exe b/物流小车/web/app.exe index 4885dc5..355caf5 100644 Binary files a/物流小车/web/app.exe and b/物流小车/web/app.exe differ