Files
P4-USB-transfer/main/MOTOR/motor_control.c
T

414 lines
13 KiB
C
Raw Normal View History

2026-10-13 21:54:50 +08:00
#include "motor_control.h"
#include "freertos/projdefs.h"
#include "freertos/queue.h"
#include "step_motor_init.h"
#include "motor_io.h"
#include "foc.h"
#include <limits.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_check.h"
#include "esp_log.h"
#include "BLE/ble.h"
static const char *TAG_MOTOR_CTL = "motor_control";
TaskHandle_t motor_control_handle = NULL;
#define MOTOR_CMD_QUEUE_LEN 16
static QueueHandle_t s_motor_cmd_q = NULL;
typedef enum
{
MOTOR_LAT_UNKNOWN = 0,
MOTOR_LAT_LEFT,
MOTOR_LAT_RIGHT,
MOTOR_LAT_CENTER,
} motor_lateral_t;
/** 仅电机任务写、其它任务读;用于左右切换时是否插 0x0A */
static volatile motor_lateral_t s_motor_last_lateral = MOTOR_LAT_CENTER;
/** 最近一次成功入队的 play_sticker 方向字节;同字节+同侧向则不再重复入队(如已是 0x01 又来 0x01) */
static uint8_t s_last_play_sticker_direction = 0xFF;
// MOTOR_POSITION motor_position ;//记录步进电机的位置
MOTOR_POSITION motor_current_position = MOTOR_POSITION_ZERO;
MOTOR_POSITION motor_target_position = MOTOR_POSITION_ZERO;
MOTOR_DIR motor_dir = MOTOR_CW;
SemaphoreHandle_t motor_action_down_sem = NULL;
static volatile bool s_sentinel_motor_running = false;
static volatile bool s_sentinel_stop_requested = false;
#if MOTOR_WITH_MAGNET_RING
const MOTOR_RUN_TIME motor_run_time =
{
.run_to_left_15 = 250,
.run_to_left_30 = 500,
.run_to_left_90 = 1000,
.run_to_left_180 = 1800,
.run_to_right_15 = 250,
.run_to_right_30 = 500,
.run_to_right_180 = 1800,
};
uint16_t OB_BACK_TIME = 130;
#elif OLD_MOTOR
const MOTOR_RUN_TIME motor_run_time =
{
.run_to_left_15 = 250,
.run_to_left_30 = 500,
.run_to_left_90 = 750,
.run_to_left_180 = 1300,
.run_to_right_15 = 250,
.run_to_right_30 = 500,
.run_to_right_180 = 1300,
};
uint16_t OB_BACK_TIME = 55;
#else
const MOTOR_RUN_TIME motor_run_time =
{
.run_to_left_15 = 250,
.run_to_left_30 = 450,
.run_to_left_90 = 1250,
.run_to_left_180 = 1950,
.run_to_right_15 = 250,
.run_to_right_30 = 450,
.run_to_right_180 = 1950,
};
uint16_t OB_BACK_TIME = 55;
#endif
static void motor_run_steps(uint32_t command);
/** 与上次已在电机任务里执行完的 notify 值相同则忽略,避免 BLE 连发 / completed_cb 重复补发导致同向连转 */
static uint32_t s_last_executed_motor_notify = UINT32_MAX;
static bool motor_cmd_is_left(uint32_t cmd)
{
return cmd == 0x01u || cmd == 0x05u || cmd == 0x07u;
}
static bool motor_cmd_is_right(uint32_t cmd)
{
return cmd == 0x02u || cmd == 0x06u || cmd == 0x08u;
}
static void motor_update_lateral_after_cmd(uint32_t cmd)
{
if (motor_cmd_is_left(cmd))
{
s_motor_last_lateral = MOTOR_LAT_LEFT;
}
else if (motor_cmd_is_right(cmd))
{
s_motor_last_lateral = MOTOR_LAT_RIGHT;
}
else if (cmd == 0x00u || cmd == 0x0Au || cmd == 0x0Bu)
{
s_motor_last_lateral = MOTOR_LAT_CENTER;
}
}
bool motor_post_cmd(uint32_t cmd)
{
if (s_motor_cmd_q == NULL)
{
ESP_LOGW(TAG_MOTOR_CTL, "motor_post_cmd: queue not ready cmd=0x%02lX", (unsigned long)cmd);
return false;
}
if (xQueueSend(s_motor_cmd_q, &cmd, 0) != pdPASS)
{
uint32_t dropped = 0;
(void)xQueueReceive(s_motor_cmd_q, &dropped, 0);
if (xQueueSend(s_motor_cmd_q, &cmd, 0) != pdPASS)
{
ESP_LOGW(TAG_MOTOR_CTL, "motor_post_cmd: enqueue failed cmd=0x%02lX", (unsigned long)cmd);
return false;
}
ESP_LOGW(TAG_MOTOR_CTL, "motor_post_cmd: queue full dropped=0x%02lX enq=0x%02lX",
(unsigned long)dropped, (unsigned long)cmd);
}
return true;
}
bool motor_post_play_sticker_direction(uint8_t direction)
{
const uint32_t cmd = (uint32_t)direction;
/* 0x00:协议表示「本条不追加转向」;若头仍在左/右侧,必须用 0x0A 物理回中,
* 不能发 0x00(openloop stop 与回中语义不同),否则左播途中接 0x10/0x00 会丢回中。 */
if (cmd == 0x00u)
{
const motor_lateral_t last = s_motor_last_lateral;
if (last == MOTOR_LAT_LEFT || last == MOTOR_LAT_RIGHT)
{
if (!motor_post_cmd(0x0Au))
{
return false;
}
s_last_play_sticker_direction = 0xFF;
return true;
}
return true;
}
if (cmd == 0x0Au || cmd == 0x0Bu)
{
if (!motor_post_cmd(cmd))
{
return false;
}
s_last_play_sticker_direction = 0xFF;
return true;
}
if (!motor_cmd_is_left(cmd) && !motor_cmd_is_right(cmd))
{
if (!motor_post_cmd(cmd))
{
return false;
}
s_last_play_sticker_direction = (uint8_t)cmd;
return true;
}
const motor_lateral_t last = s_motor_last_lateral;
/* 侧向未变且与上次下发的方向字节相同:不重复入队(如当前已是 0x01 姿态又来 0x01) */
if ((motor_cmd_is_left(cmd) && last == MOTOR_LAT_LEFT) || (motor_cmd_is_right(cmd) && last == MOTOR_LAT_RIGHT))
{
if ((uint8_t)cmd == s_last_play_sticker_direction)
{
ESP_LOGI(TAG_MOTOR_CTL, "skip redundant play_sticker direction 0x%02lX (same as last)", cmd);
return true;
}
}
const bool need_home =
(last == MOTOR_LAT_LEFT && motor_cmd_is_right(cmd)) || (last == MOTOR_LAT_RIGHT && motor_cmd_is_left(cmd));
if (need_home && !motor_post_cmd(0x0Au))
{
return false;
}
if (!motor_post_cmd(cmd))
{
return false;
}
s_last_play_sticker_direction = (uint8_t)cmd;
return true;
}
void motor_post_cmd_from_isr(uint32_t cmd, BaseType_t *pxHigherPriorityTaskWoken)
{
if (s_motor_cmd_q == NULL)
{
return;
}
if (xQueueSendFromISR(s_motor_cmd_q, &cmd, pxHigherPriorityTaskWoken) != pdPASS)
{
uint32_t dropped = 0;
(void)xQueueReceiveFromISR(s_motor_cmd_q, &dropped, pxHigherPriorityTaskWoken);
(void)xQueueSendFromISR(s_motor_cmd_q, &cmd, pxHigherPriorityTaskWoken);
}
}
void motor_control_init(void)
{
// PWM 初始化 任务创建
//motor_io_init();
stepper_motor_init();
s_motor_cmd_q = xQueueCreate(MOTOR_CMD_QUEUE_LEN, sizeof(uint32_t));
if (s_motor_cmd_q == NULL)
{
ESP_LOGE(TAG_MOTOR_CTL, "motor cmd queue create failed");
}
// 固定到 CPU1,避免与 CPU0 上的 LVGL task 竞争;优先级降为 5
xTaskCreatePinnedToCore(motor_control_task, "motor_control_task", 4096, NULL, 8, &motor_control_handle, 0);
}
void motor_control_task(void *pvParameter)
{
uint32_t bits = 0;
motor_action_down_sem = xSemaphoreCreateBinary();
xSemaphoreGive(motor_action_down_sem);
(void)pvParameter;
s_motor_last_lateral = MOTOR_LAT_CENTER;
motor_current_position =MOTOR_POSITION_ZERO;
motor_run_dir(MOTOR_CW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_left_180));
motor_current_position = MOTOR_POSITION_LEFT_180;
stepper_motor_output_disable();
ESP_LOGW("TAG_MOTOR_CTL", "motor_control_task: TURNED LEFT DONE");
s_motor_last_lateral = MOTOR_LAT_LEFT;
vTaskDelay(pdMS_TO_TICKS(2000));
motor_run_dir(MOTOR_CCW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_right_180));
stepper_motor_output_disable();
s_motor_last_lateral = MOTOR_LAT_CENTER;
motor_current_position = MOTOR_POSITION_ZERO;
ESP_LOGW("TAG_MOTOR_CTL", "motor_control_task: TURNED RIGHT DONE");
while (1)
{
if (s_motor_cmd_q == NULL)
{
vTaskDelay(pdMS_TO_TICKS(20));
continue;
}
if (xQueueReceive(s_motor_cmd_q, &bits, pdMS_TO_TICKS(20)) != pdPASS)
{
continue;
}
if (bits == s_last_executed_motor_notify)
{
ESP_LOGD(TAG_MOTOR_CTL, "skip duplicate motor cmd 0x%02lX", (unsigned long)bits);
continue;
}
motor_run_steps(bits);
s_last_executed_motor_notify = bits;
motor_update_lateral_after_cmd(bits);
}
}
static void motor_run_steps(uint32_t command)
{
uint32_t back_time_ms = 0;
if (command == 0x00)
{
stepper_motor_stop();
motor_current_position = MOTOR_POSITION_ZERO;
}
else if (command == 0x01)
{
motor_run_dir(MOTOR_CW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_left_30));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_LEFT_30;
}
else if (command == 0x02)
{
motor_run_dir(MOTOR_CCW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_right_30));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_RIGHT_30;
}
else if (command == 0x05)
{
// stepper_motor_run_steps(STEPPER_DIR_FORWARD, ANGLE_STEP_15 * 4);
motor_run_dir(MOTOR_CW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_left_15));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_LEFT_15;
}
else if (command == 0x06)
{
// stepper_motor_run_steps(STEPPER_DIR_REVERSE, ANGLE_STEP_15 * 4);
motor_run_dir(MOTOR_CCW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_right_15));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_RIGHT_15;
}
else if (command == 0x07)
{
// stepper_motor_run_steps(STEPPER_DIR_FORWARD, ANGLE_STEP_180 * 4);
motor_run_dir(MOTOR_CW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_left_180));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_LEFT_180;
if(sentinel_mode_is_active == true)
{
vTaskDelay(pdMS_TO_TICKS(2000));
xSemaphoreGive(motor_action_down_sem);
}
}
else if (command == 0x08)
{
// stepper_motor_run_steps(STEPPER_DIR_FORWARD, ANGLE_STEP_180 * 4);
motor_run_dir(MOTOR_CCW);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(motor_run_time.run_to_right_180));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_RIGHT_180;
if(sentinel_mode_is_active == true)
{
vTaskDelay(pdMS_TO_TICKS(2000));
xSemaphoreGive(motor_action_down_sem);
}
}
else if (command == 0x0A)
{
// stepper_motor_run_steps(STEPPER_DIR_FORWARD, ANGLE_STEP_30 * 4);
if(motor_current_position == MOTOR_POSITION_ZERO)back_time_ms = 0;
else if(motor_current_position == MOTOR_POSITION_LEFT_15 || motor_current_position == MOTOR_POSITION_LEFT_30 || motor_current_position == MOTOR_POSITION_LEFT_180)
{
motor_run_dir(MOTOR_CCW);
if(motor_current_position == MOTOR_POSITION_LEFT_15)back_time_ms = motor_run_time.run_to_right_15;
else if(motor_current_position == MOTOR_POSITION_LEFT_30)back_time_ms = motor_run_time.run_to_right_30;
else if(motor_current_position == MOTOR_POSITION_LEFT_180)back_time_ms = motor_run_time.run_to_right_180;
}
else if(motor_current_position == MOTOR_POSITION_RIGHT_15 || motor_current_position == MOTOR_POSITION_RIGHT_30|| motor_current_position == MOTOR_POSITION_RIGHT_180)
{
motor_run_dir(MOTOR_CW);
if(motor_current_position == MOTOR_POSITION_RIGHT_15)back_time_ms = motor_run_time.run_to_left_15;
else if(motor_current_position == MOTOR_POSITION_RIGHT_30)back_time_ms = motor_run_time.run_to_left_30;
else if(motor_current_position == MOTOR_POSITION_RIGHT_180)back_time_ms = motor_run_time.run_to_left_180;
}
if(back_time_ms != 0)
{
ESP_LOGW(TAG_MOTOR_CTL, "0X0A back_time_ms START,motor_current_position=%d,back_time_ms=%d",motor_current_position,back_time_ms);
stepper_motor_output_enable();
vTaskDelay(pdMS_TO_TICKS(back_time_ms));
}
stepper_motor_output_disable();
ESP_LOGW(TAG_MOTOR_CTL, "0X0A back_time_ms END");
if(sentinel_mode_is_active == true)
{
vTaskDelay(pdMS_TO_TICKS(2000));
xSemaphoreGive(motor_action_down_sem);
}
motor_current_position = MOTOR_POSITION_ZERO;
}
else if (command == 0x0B)
{
ESP_LOGE("MOTOR_CONTROL", "MOTOR_CONTROL_STOP");
vTaskDelay(pdMS_TO_TICKS(100));
// motor_run_dir(MOTOR_CW);
// stepper_motor_output_enable();
// vTaskDelay(pdMS_TO_TICKS(35));
stepper_motor_output_disable();
motor_current_position = MOTOR_POSITION_ZERO;
}
}
void motor_run_dir(MOTOR_DIR dir)
{
if(dir == MOTOR_CW)
{
motor_dir = MOTOR_CW;
}
if(dir == MOTOR_CCW)
{
motor_dir = MOTOR_CCW;
}
}