Files
linear-Slide/Application/app_motor.c

329 lines
8.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "app_motor.h"
/* 当前位置相关用于CiA402位置反馈 */
float current_absolute_pos_mm = 0.0f;
float last_move_start_pos_mm = 0.0f;
/* 电机内部状态机 */
Motor_State_t internal_state = STATE_SWITCH_ON_DISABLED;
Homing_State_t homing_state = HOMING_IDLE;
/* 兼容旧调试变量值由StepLossMonitor同步更新 */
float error = 0.0f;
float distance = 0.0f;
float encoder_distance = 0.0f;
uint32_t steps = 0;
#define STEPLOSS_SETTLE_MS 200U
#define STEPLOSS_THRESHOLD_MM_DEFAULT 0.1f
/* 丢步检测运行态:集中管理,避免状态分散在多个全局变量 */
typedef struct
{
/* 实时观测量 */
float abs_error_mm;
float cmd_distance_mm;
float enc_distance_mm;
uint32_t cmd_steps;
/* 编码器16位计数扩展 */
int32_t accum_pulses;
uint16_t prev_raw_cnt;
uint8_t prev_raw_valid;
uint8_t motion_active;
uint32_t prev_cmd_steps;
/* 停止后延时上报 */
uint8_t wait_stop_settle;
uint32_t stop_tick_ms;
uint8_t report_ready;
float report_error_mm;
float threshold_mm;
Stepper_state_t prev_state;
} StepLossMonitor_t;
static StepLossMonitor_t s_step_loss = {
.threshold_mm = STEPLOSS_THRESHOLD_MM_DEFAULT,
.prev_state = STOP,
.prev_cmd_steps = 0U,
};
static float Normalize_FollowingErrorThreshold(float threshold_mm, float fallback_mm)
{
if (!(threshold_mm == threshold_mm))
{
return fallback_mm;
}
if (threshold_mm <= 0.0f)
{
return fallback_mm;
}
if (threshold_mm > SOFT_LIMIT_MAX_MM)
{
return SOFT_LIMIT_MAX_MM;
}
return threshold_mm;
}
static void Sync_FollowingErrorThreshold_From_OD(void)
{
OD_entry_t *entry_ferr = OD_find(OD, CIA402_INDEX_FOLLOWING_ERROR_WINDOW);
if (entry_ferr == NULL)
{
return;
}
float32_t threshold_mm = 0.0f;
if (OD_get_f32(entry_ferr, 0, &threshold_mm, true) == ODR_OK)
{
s_step_loss.threshold_mm =
Normalize_FollowingErrorThreshold((float)threshold_mm, s_step_loss.threshold_mm);
}
}
static void Update_PP_FollowingError_StatusBit(float stop_error_mm)
{
OD_entry_t *entry_mode = OD_find(OD, CIA402_INDEX_OP_MODE);
OD_entry_t *entry_sw = OD_find(OD, CIA402_INDEX_STATUSWORD);
if (entry_mode == NULL || entry_sw == NULL)
{
return;
}
int8_t mode = 0;
OD_get_i8(entry_mode, 0, &mode, true);
if (mode != 1)
{
return;
}
CO_LOCK_OD(CO->CANmodule);
uint16_t sw = 0;
OD_get_u16(entry_sw, 0, &sw, true);
if (stop_error_mm > s_step_loss.threshold_mm)
{
sw |= CIA402_STATUS_OMS_13;
}
else
{
sw &= (uint16_t)(~CIA402_STATUS_OMS_13);
}
OD_set_u16(entry_sw, 0, sw, true);
CO_UNLOCK_OD(CO->CANmodule);
}
static void Update_FollowingErrorActual_To_OD(float abs_error_mm)
{
OD_entry_t *entry_ferr_actual = OD_find(OD, CIA402_INDEX_FOLLOWING_ERROR_ACTUAL);
float32_t ferr_mm = (float32_t)abs_error_mm;
if (entry_ferr_actual == NULL)
{
return;
}
if (CO != NULL)
{
CO_LOCK_OD(CO->CANmodule);
(void)OD_set_f32(entry_ferr_actual, 0, ferr_mm, true);
CO_UNLOCK_OD(CO->CANmodule);
}
else
{
(void)OD_set_f32(entry_ferr_actual, 0, ferr_mm, true);
}
}
/* 核心运动分发:先做安全判断,再按模式进入回零/位置模式处理 */
static void Process_Motion_Logic(void)
{
/* 未使能运行时,强制停机并维持状态反馈 */
if ((internal_state != STATE_OPERATION_ENABLED) && (stepper_1.run_flag == 0u))
{
if (stepper_1.state != STOP)
{
Int_TMC2209_stop();
stepper_1.state = STOP;
}
homing_state = HOMING_IDLE;
Update_Motion_State_To_OD();
return;
}
Update_Motion_State_To_OD();
OD_entry_t *entry_mode = OD_find(OD, CIA402_INDEX_OP_MODE);
OD_entry_t *entry_mode_disp = OD_find(OD, CIA402_INDEX_OP_MODE_DISPLAY);
if (entry_mode != NULL)
{
int8_t mode = 0;
OD_get_i8(entry_mode, 0, &mode, true);
if (entry_mode_disp != NULL)
{
OD_set_i8(entry_mode_disp, 0, mode, true);
}
switch (mode)
{
case 6:
Handle_Homing_Mode();
break;
case 1:
Handle_Position_Mode();
break;
default:
break;
}
}
}
void App_Motor_Init(void)
{
/* 统一初始化运行态与位置基准 */
current_absolute_pos_mm = 0.0f;
last_move_start_pos_mm = 0.0f;
homing_state = HOMING_IDLE;
internal_state = STATE_SWITCH_ON_DISABLED;
Int_Encoder_Init();
debug_printf("App Motor Initialized.");
}
void App_Motor_Process(void)
{
Sync_FollowingErrorThreshold_From_OD();
Update_FollowingErrorActual_To_OD(s_step_loss.abs_error_mm);
/* 先跑CiA402状态机再执行业务运动逻辑 */
Process_StateMachine();
Process_Motion_Logic();
float stop_error_mm = 0.0f;
if (App_Motor_TryGetStopError(&stop_error_mm))
{
Update_PP_FollowingError_StatusBit(stop_error_mm);
/* 回零流程不输出StepLoss误差日志避免与“回零成功/失败”语义混淆 */
if (homing_state == HOMING_IDLE)
{
debug_printf("[StepLoss] stop+200ms error = %.6f mm", stop_error_mm);
}
}
}
void App_Motor_StepLossCheck(void)
{
/* 周期读取硬件计数与已发步数TIM12中断调用 */
uint16_t raw_cnt = (uint16_t)__HAL_TIM_GET_COUNTER(&htim1);
uint8_t rebase_now = 0U;
s_step_loss.cmd_steps = stepper_1.step_count;
/* 新动作开始时重置累计基准,避免跨动作串扰 */
if (stepper_1.state != STOP)
{
if ((!s_step_loss.motion_active) || (s_step_loss.cmd_steps < s_step_loss.prev_cmd_steps))
{
s_step_loss.motion_active = 1U;
s_step_loss.accum_pulses = 0;
s_step_loss.prev_raw_cnt = raw_cnt;
s_step_loss.prev_raw_valid = 1U;
rebase_now = 1U;
}
}
else if (s_step_loss.motion_active)
{
s_step_loss.motion_active = 0U;
}
/* 首次采样仅建立基准,不计算位移增量 */
if (!s_step_loss.prev_raw_valid)
{
s_step_loss.prev_raw_cnt = raw_cnt;
s_step_loss.prev_raw_valid = 1U;
}
/* int16差分可自然处理16位计数器回绕溢出/下溢) */
int16_t delta = 0;
if (rebase_now)
{
/* New move baseline: skip one diff sample to avoid counter-reset jump. */
}
else
{
delta = (int16_t)(raw_cnt - s_step_loss.prev_raw_cnt);
s_step_loss.accum_pulses += (int32_t)delta;
s_step_loss.prev_raw_cnt = raw_cnt;
}
s_step_loss.prev_cmd_steps = s_step_loss.cmd_steps;
/* 输出扩展后的总脉冲给上层使用 */
encoder_1.pulses = s_step_loss.accum_pulses;
encoder_1.overflow = (uint16_t)(abs(encoder_1.pulses) / 65536);
/* 统一换算为mm并计算绝对误差 */
s_step_loss.cmd_distance_mm = (float)s_step_loss.cmd_steps / STEPS_PER_MM;
s_step_loss.enc_distance_mm = (float)abs(encoder_1.pulses) * STICK_LEAD / (float)ENCODER_PULSES_PER_CIRCLE;
s_step_loss.abs_error_mm = s_step_loss.enc_distance_mm - s_step_loss.cmd_distance_mm;
if (s_step_loss.abs_error_mm < 0.0f)
{
s_step_loss.abs_error_mm = -s_step_loss.abs_error_mm;
}
/* 同步旧调试变量,便于观察窗口/旧日志继续使用 */
steps = s_step_loss.cmd_steps;
distance = s_step_loss.cmd_distance_mm;
encoder_distance = s_step_loss.enc_distance_mm;
error = s_step_loss.abs_error_mm;
/* 运动中不出最终结论,仅标记“停稳后需要上报一次” */
if (stepper_1.state != STOP)
{
s_step_loss.wait_stop_settle = 1U;
s_step_loss.report_ready = 0U;
s_step_loss.prev_state = stepper_1.state;
return;
}
/* 从运动态切换到STOP时开始计时稳定窗口 */
if (s_step_loss.prev_state != STOP)
{
s_step_loss.prev_state = STOP;
s_step_loss.stop_tick_ms = HAL_GetTick();
return;
}
/* STOP持续到阈值后锁存一次最终误差 */
if (s_step_loss.wait_stop_settle &&
((uint32_t)(HAL_GetTick() - s_step_loss.stop_tick_ms) >= STEPLOSS_SETTLE_MS))
{
s_step_loss.report_error_mm = s_step_loss.abs_error_mm;
s_step_loss.report_ready = 1U;
s_step_loss.wait_stop_settle = 0U;
}
}
/* 一次性读取“停止后最终误差”读取成功后自动清ready标志 */
bool App_Motor_TryGetStopError(float *err_mm)
{
if (!s_step_loss.report_ready)
{
return false;
}
if (err_mm != NULL)
{
*err_mm = s_step_loss.report_error_mm;
}
s_step_loss.report_ready = 0U;
return true;
}