Update FreeRTOS configuration and enhance upper computer AI documentation
- Increased total heap size in FreeRTOSConfig.h from 10000 to 18000. - Modified stack sizes for various tasks in freertos.c to improve performance: - initTask: 128 to 256 - CarCtrlTask: 256 to 1024 - timerTask: 512 to 1024 - sr04Task: 128 to 512 - rc522Task: 128 to 512 - Added comprehensive upper computer AI guide for TCP client implementation, detailing protocol contracts, command sets, telemetry, architecture requirements, and error handling strategies. - Introduced a Python web upper computer AI guide with a recommended tech stack and project structure. - Created a Chinese version of the upper computer AI guide for local developers. - Updated STM32 project configuration to reflect new task stack sizes and heap settings. - Adjusted configuration files for various tools to ensure compatibility with the new project structure.
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user