feat: 添加状态报告和反馈功能,更新协议文档

This commit is contained in:
2026-04-15 00:54:14 +08:00
parent 9313675630
commit e5b2ad20a3
4 changed files with 210 additions and 0 deletions

View File

@@ -14,6 +14,8 @@
#include "bsp_uart.h"
#include "bsp_rc522.h"
#include "bsp_beep.h"
#include "bsp_sr04.h"
#include "bsp_track_ir.h"
#include "checksum.h"
#include "cmsis_os.h"
#include "elog.h"
@@ -235,6 +237,7 @@ static void CarCtrl_HandleCommand(const char *cmd_payload)
CarCtrl_StopAll();
elog_w(Protocol_TAG, "已到达站点,请先重新设置目标站点 (GS:xxx) 之后再启动");
CarCtrl_BeepTimes(2U);
Protocol_SendFeedback("ST", 0);
return;
}
@@ -243,6 +246,7 @@ static void CarCtrl_HandleCommand(const char *cmd_payload)
CarCtrl_StopAll();
elog_w(Protocol_TAG, "未设置有效站点,拒绝启动。请先下发 GS:001 或 GS:002");
CarCtrl_BeepTimes(2U);
Protocol_SendFeedback("ST", 0);
return;
}
@@ -250,13 +254,16 @@ static void CarCtrl_HandleCommand(const char *cmd_payload)
car_target_reached = 0;
elog_i(Protocol_TAG, "小车自动循迹启动, speed=%u%%, station=%u", car_speed_percent,
car_target_station);
Protocol_SendFeedback("ST", 1);
} else if (strcmp(arg + 1, "STOP") == 0) {
car_running = 0;
car_target_reached = 0;
CarCtrl_StopAll();
elog_i(Protocol_TAG, "小车自动循迹暂停");
Protocol_SendFeedback("ST", 1);
} else {
elog_w(Protocol_TAG, "未知启动/停止命令: %s", cmd_payload);
Protocol_SendFeedback("ST", 0);
}
return;
}
@@ -278,8 +285,10 @@ static void CarCtrl_HandleCommand(const char *cmd_payload)
if (car_running != 0U) {
CarCtrl_ApplySpeed();
}
Protocol_SendFeedback("SP", 1);
} else {
elog_w(Protocol_TAG, "速度参数解析失败: %s", cmd_payload);
Protocol_SendFeedback("SP", 0);
}
return;
}
@@ -301,8 +310,10 @@ static void CarCtrl_HandleCommand(const char *cmd_payload)
car_target_reached = 0;
elog_i(Protocol_TAG, "设置目标站点: %03u", car_target_station);
CarCtrl_BeepTimes(1U);
Protocol_SendFeedback("GS", 1);
} else {
elog_w(Protocol_TAG, "站点参数解析失败: %s", cmd_payload);
Protocol_SendFeedback("GS", 0);
}
return;
}
@@ -311,6 +322,65 @@ static void CarCtrl_HandleCommand(const char *cmd_payload)
elog_w(Protocol_TAG, "未支持的控制命令: %s", cmd_payload);
}
/**
* @brief 打包并发送协议帧到上位机 (TCP)
* @param payload 有效载荷文本 (不含帧头 LOGI:, 分隔符 :, 校验位 CS 和 帧尾 #)
*/
static void Protocol_SendPacket(const char *payload) {
char packet[64] = {0};
uint8_t cs = 0;
// 1. 组装基础段: LOGI:PAYLOAD
snprintf(packet, sizeof(packet), "LOGI:%s", payload);
// 2. 计算校验和 (从 LOGI 开始到 payload 结束的累加和)
cs = Calculate_CheckSum((uint8_t *)packet, 0, (uint16_t)strlen(packet));
// 3. 拼接校验位和帧尾
size_t current_len = strlen(packet);
snprintf(packet + current_len, sizeof(packet) - current_len, ":%02X#", cs);
// 4. 发送
ESP12F_TCP_SendMessage(packet);
}
/**
* @brief 发送状态报告
* 格式示例: 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};
float dist = sr04_get_distance();
uint8_t trk_mask = track_ir_get_line_mask();
// STAT:SP:xxx,STA:xxx,RUN:x,DIS:xxx.x,TRK:xxxx,RPM:m1:m2:m3:m4
// 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,RPM:%d:%d:%d:%d",
car_speed_percent, car_target_station, car_running, 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,
(trk_mask & TRACK_IR_H1_BIT) ? 1 : 0,
(int)hall_get_speed(MOTOR_1),
(int)hall_get_speed(MOTOR_2),
(int)hall_get_speed(MOTOR_3),
(int)hall_get_speed(MOTOR_4));
Protocol_SendPacket(payload);
}
/**
* @brief 发送反馈
* 格式示例: FB:ST:1 (ST成功), FB:GS:0 (GS失败)
*/
void Protocol_SendFeedback(const char *cmd_type, uint8_t status) {
char payload[16] = {0};
snprintf(payload, sizeof(payload), "FB:%s:%u", cmd_type, status);
Protocol_SendPacket(payload);
}
/* 引用在 freertos.c 中定义的消息队列句柄 */
extern osMessageQueueId_t CmdQueueHandle;
/**
@@ -403,12 +473,15 @@ void Protocol_HandleMessage(uint8_t *data, uint16_t len) {
void CarCtrl_Task(void *argument) {
/* USER CODE BEGIN CarCtrl_Task */
char cmd_payload[16] = {0};
uint32_t last_report_tick = 0;
/* 初始化闭环 PID 控制器 */
CarCtrl_InitClosedLoop();
/* Infinite loop */
for (;;) {
uint32_t now = HAL_GetTick();
/* 1. 处理控制指令 (非阻塞获取,如果没有指令则继续执行闭环) */
if (osMessageQueueGet(CmdQueueHandle, cmd_payload, NULL, 0) == osOK) {
elog_d(CarCtrlTask_TAG, "CarCtrl: Command %s", cmd_payload);
@@ -421,6 +494,12 @@ void CarCtrl_Task(void *argument) {
/* 2. 执行 PID 闭环控制更新 */
CarCtrl_UpdateClosedLoop();
/* 3. 定期向应用层/上位机发送状态报告 (每 500ms) */
if (now - last_report_tick >= 500) {
Protocol_SendStatusReport();
last_report_tick = now;
}
/*
* 与 hall_update_speed() 的 100ms 采样周期对齐,避免 PID 使用过期速度反复修正。
* 如果后续把测速周期改成 20ms这里也要同步改回 20ms。