feat: add direction controller component

This commit is contained in:
2026-01-30 16:10:51 +08:00
parent 917f42d7ab
commit e437cbf8d2
5 changed files with 449 additions and 137 deletions

View File

@@ -1,2 +1,4 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS "."
REQUIRES "direction_controller"
PRIV_REQUIRES "driver")

View File

@@ -4,14 +4,14 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "stepper_motor.h"
#include "direction_controller.h"
static const char *TAG = "Direction Controller";
@@ -22,103 +22,6 @@ static const char *TAG = "Direction Controller";
#define UART_BUF_SIZE 256
#define INPUT_BUF_SIZE 64
/* Current angle tracking (relative to South = 0°) */
static float s_current_angle = 0.0f;
/* Direction definitions (angles relative to South = 0°) */
typedef struct {
const char *name_cn; /* Chinese name */
const char *name_en; /* English abbreviation */
float angle; /* Angle relative to South */
} direction_t;
/*
* Direction angle mapping (South = 0°, clockwise positive)
*
* 北 (180°)
* |
* 西北(135°) | 东北(-135°/225°)
* |
* 西(90°) ------+------ 东(-90°/270°)
* |
* 西南(45°) | 东南(-45°/315°)
* |
* 南 (0°) [HOME]
*/
static const direction_t directions[] = {
{"", "S", 0.0f}, /* South - Home position */
{"西南", "SW", 45.0f}, /* Southwest */
{"西", "W", 90.0f}, /* West */
{"西北", "NW", 135.0f}, /* Northwest */
{"", "N", 180.0f}, /* North */
{"东北", "NE", -135.0f}, /* Northeast */
{"", "E", -90.0f}, /* East */
{"东南", "SE", -45.0f}, /* Southeast */
};
#define NUM_DIRECTIONS (sizeof(directions) / sizeof(directions[0]))
/**
* @brief Calculate shortest rotation angle to target
*
* @param current Current angle
* @param target Target angle
* @return Shortest rotation angle (positive = clockwise, negative = counter-clockwise)
*/
static float calculate_shortest_rotation(float current, float target)
{
float diff = target - current;
/* Normalize to -180 ~ 180 range */
while (diff > 180.0f) {
diff -= 360.0f;
}
while (diff < -180.0f) {
diff += 360.0f;
}
return diff;
}
/**
* @brief Rotate to specified direction
*
* @param target_angle Target angle (relative to South)
*/
static void rotate_to_angle(float target_angle)
{
float rotation = calculate_shortest_rotation(s_current_angle, target_angle);
if (rotation == 0.0f) {
ESP_LOGI(TAG, "Already at target position");
return;
}
ESP_LOGI(TAG, "Rotating from %.1f° to %.1f° (rotation: %.1f°)",
s_current_angle, target_angle, rotation);
stepper_rotate_angle_with_accel(rotation, STEPPER_SPEED_FAST);
s_current_angle = target_angle;
stepper_motor_power_off();
ESP_LOGI(TAG, "Rotation complete, current position: %.1f°", s_current_angle);
}
/**
* @brief Find direction by name
*
* @param input User input string
* @return Pointer to direction_t if found, NULL otherwise
*/
static const direction_t* find_direction(const char *input)
{
for (int i = 0; i < NUM_DIRECTIONS; i++) {
if (strcmp(input, directions[i].name_cn) == 0 ||
strcasecmp(input, directions[i].name_en) == 0) {
return &directions[i];
}
}
return NULL;
}
/**
* @brief Print help message with available directions
@@ -129,14 +32,18 @@ static void print_help(void)
printf(" 方向控制系统 (Direction Control)\n");
printf("========================================\n");
printf("可用方向 (Available directions):\n");
printf(" 南/S - South (0°) [默认位置]\n");
printf(" 西南/SW - Southwest (45°)\n");
printf(" 西/W - West (90°)\n");
printf(" 西北/NW - Northwest (135°)\n");
printf(" 北/N - North (180°)\n");
printf(" 东北/NE - Northeast (-135°)\n");
printf(" 东/E - East (-90°)\n");
printf(" 东南/SE - Southeast (-45°)\n");
size_t direction_count = direction_controller_get_direction_count();
for (size_t i = 0; i < direction_count; i++) {
const direction_controller_direction_t *dir = direction_controller_get_direction(i);
if (dir == NULL) {
continue;
}
if (dir->angle == 0.0f) {
printf(" %s/%s - %.1f° [默认位置]\n", dir->name_cn, dir->name_en, dir->angle);
} else {
printf(" %s/%s - %.1f°\n", dir->name_cn, dir->name_en, dir->angle);
}
}
printf("----------------------------------------\n");
printf("命令 (Commands):\n");
printf(" help - 显示帮助信息\n");
@@ -149,14 +56,13 @@ static void print_help(void)
*/
static void print_current_position(void)
{
const char *dir_name = "未知";
for (int i = 0; i < NUM_DIRECTIONS; i++) {
if (directions[i].angle == s_current_angle) {
dir_name = directions[i].name_cn;
break;
}
const direction_controller_direction_t *dir = direction_controller_get_current_direction();
float angle = direction_controller_get_current_angle();
if (dir != NULL) {
printf("当前位置: %s (%.1f°)\n", dir->name_cn, angle);
} else {
printf("当前位置: 未知 (%.1f°)\n", angle);
}
printf("当前位置: %s (%.1f°)\n", dir_name, s_current_angle);
}
/**
@@ -189,27 +95,43 @@ static void direction_control_task(void *arg)
if (input_idx > 0) {
input_buf[input_idx] = '\0';
/* Trim leading/trailing whitespace */
char *cmd = input_buf;
while (*cmd == ' ') cmd++;
char *end = cmd + strlen(cmd) - 1;
while (end > cmd && *end == ' ') *end-- = '\0';
/* Process command */
if (strcmp(cmd, "help") == 0 || strcmp(cmd, "?") == 0) {
print_help();
} else if (strcmp(cmd, "pos") == 0) {
print_current_position();
} else {
const direction_t *dir = find_direction(cmd);
if (dir != NULL) {
printf("目标方向: %s (%s, %.1f°)\n",
dir->name_cn, dir->name_en, dir->angle);
rotate_to_angle(dir->angle);
} else {
while (*cmd != '\0' && isspace((unsigned char)*cmd)) {
cmd++;
}
char *end = cmd + strlen(cmd);
while (end > cmd && isspace((unsigned char)*(end - 1))) {
end--;
}
*end = '\0';
if (*cmd != '\0') {
const direction_controller_direction_t *dir = NULL;
direction_controller_cmd_t cmd_type =
direction_controller_parse_command(cmd, &dir);
switch (cmd_type) {
case DIRECTION_CONTROLLER_CMD_HELP:
print_help();
break;
case DIRECTION_CONTROLLER_CMD_POSITION:
print_current_position();
break;
case DIRECTION_CONTROLLER_CMD_DIRECTION:
if (dir != NULL) {
printf("目标方向: %s (%s, %.1f°)\n",
dir->name_cn, dir->name_en, dir->angle);
if (direction_controller_rotate_to_angle(dir->angle) != ESP_OK) {
printf("旋转失败\n");
}
}
break;
default:
printf("未知方向: '%s'\n", cmd);
printf("输入 'help' 查看可用方向\n");
break;
}
}
}
@@ -259,13 +181,9 @@ void app_main(void)
ESP_LOGI(TAG, "========================================");
/* Initialize peripherals */
stepper_motor_gpio_init();
direction_controller_init(NULL);
uart_init();
/* Set initial position to South (0°) */
s_current_angle = 0.0f;
stepper_motor_power_off();
ESP_LOGI(TAG, "Initial position: South (0°)");
/* Start direction control task */