feat: 添加状态报告和反馈功能,更新协议文档
This commit is contained in:
@@ -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。
|
||||
|
||||
Reference in New Issue
Block a user