|
@@ -671,8 +671,8 @@ void PLSR_PWM_Start(void) |
|
|
switch(g_plsr_route.output_port) |
|
|
switch(g_plsr_route.output_port) |
|
|
{ |
|
|
{ |
|
|
case 0: // TIM10 |
|
|
case 0: // TIM10 |
|
|
__HAL_TIM_SET_COMPARE(&htim10, TIM_CHANNEL_1, htim10.Init.Period / 2); // 设置占空比为50% |
|
|
|
|
|
//HAL_TIM_PWM_Start_IT(&htim10, TIM_CHANNEL_1); |
|
|
|
|
|
|
|
|
//__HAL_TIM_SET_COMPARE(&htim10, TIM_CHANNEL_1, htim10.Init.Period / 2); // 设置占空比为50% |
|
|
|
|
|
HAL_TIM_PWM_Start(&htim10, TIM_CHANNEL_1); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case 1: // TIM11 |
|
|
case 1: // TIM11 |
|
@@ -715,8 +715,8 @@ void PLSR_PWM_Stop(void) |
|
|
switch(g_plsr_route.output_port) |
|
|
switch(g_plsr_route.output_port) |
|
|
{ |
|
|
{ |
|
|
case 0: // TIM10 |
|
|
case 0: // TIM10 |
|
|
__HAL_TIM_SET_COMPARE(&htim10, TIM_CHANNEL_1, htim10.Init.Period); // |
|
|
|
|
|
//HAL_TIM_PWM_Stop(&htim10, TIM_CHANNEL_1); |
|
|
|
|
|
|
|
|
//__HAL_TIM_SET_COMPARE(&htim10, TIM_CHANNEL_1, htim10.Init.Period); // |
|
|
|
|
|
HAL_TIM_PWM_Stop(&htim10, TIM_CHANNEL_1); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case 1: // TIM11 |
|
|
case 1: // TIM11 |
|
@@ -1170,7 +1170,8 @@ void Calculate_PluseNum(PLSR_RouteConfig_t *route) |
|
|
if (route->accel_config.accel_algorithm == PLSR_ACCEL_LINEAR) |
|
|
if (route->accel_config.accel_algorithm == PLSR_ACCEL_LINEAR) |
|
|
{ |
|
|
{ |
|
|
uint32_t v0 = route->current_freq; // 起始频率 |
|
|
uint32_t v0 = route->current_freq; // 起始频率 |
|
|
uint32_t vt = current_section->target_freq; // 期望目标频率 |
|
|
|
|
|
|
|
|
uint32_t vt_desired = current_section->target_freq; // 期望目标频率 |
|
|
|
|
|
uint32_t vt = vt_desired; // 实际目标频率(可能会被调整) |
|
|
uint32_t vf = 0; // 最终频率(必须为0) |
|
|
uint32_t vf = 0; // 最终频率(必须为0) |
|
|
uint32_t a = route->accel_rate; // 加速度 |
|
|
uint32_t a = route->accel_rate; // 加速度 |
|
|
uint32_t d = route->decel_rate; // 减速度 |
|
|
uint32_t d = route->decel_rate; // 减速度 |
|
@@ -1182,186 +1183,152 @@ void Calculate_PluseNum(PLSR_RouteConfig_t *route) |
|
|
if (a == 0) a = 1; |
|
|
if (a == 0) a = 1; |
|
|
if (d == 0) d = 1; |
|
|
if (d == 0) d = 1; |
|
|
|
|
|
|
|
|
// 三部分运动规划: |
|
|
|
|
|
// 第一部分:从v0到vt(加速或减速或保持) |
|
|
|
|
|
// 第二部分:在vt保持匀速 |
|
|
|
|
|
// 第三部分:从vt减速到0 |
|
|
|
|
|
|
|
|
// 初始计算:按理想情况计算各部分脉冲数 |
|
|
|
|
|
PLSR_RunState_t part1_state = PLSR_STATE_CONST; |
|
|
|
|
|
PLSR_RunState_t part2_state = PLSR_STATE_CONST; |
|
|
|
|
|
PLSR_RunState_t part3_state = PLSR_STATE_DECEL; |
|
|
|
|
|
|
|
|
// 计算第一部分:v0 -> vt |
|
|
|
|
|
PLSR_RunState_t part1_state = PLSR_STATE_CONST; // 默认匀速 |
|
|
|
|
|
|
|
|
// 计算理想情况下的第一部分:v0 -> vt |
|
|
if (v0 < vt) |
|
|
if (v0 < vt) |
|
|
{ |
|
|
{ |
|
|
// 需要加速 |
|
|
|
|
|
part1_state = PLSR_STATE_ACCEL; |
|
|
part1_state = PLSR_STATE_ACCEL; |
|
|
part1_time = (vt - v0) / a; |
|
|
part1_time = (vt - v0) / a; |
|
|
if (part1_time == 0) part1_time = 1; |
|
|
if (part1_time == 0) part1_time = 1; |
|
|
|
|
|
|
|
|
uint64_t temp_calc = (uint64_t)(v0 + vt) * part1_time; |
|
|
uint64_t temp_calc = (uint64_t)(v0 + vt) * part1_time; |
|
|
part1_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
part1_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
if(part1_pulse_num == 0) part1_pulse_num = 1; // 防止为0 |
|
|
|
|
|
|
|
|
if(part1_pulse_num == 0) part1_pulse_num = 1; |
|
|
} |
|
|
} |
|
|
else if (v0 > vt) |
|
|
else if (v0 > vt) |
|
|
{ |
|
|
{ |
|
|
// 需要减速 |
|
|
|
|
|
part1_state = PLSR_STATE_DECEL; |
|
|
part1_state = PLSR_STATE_DECEL; |
|
|
part1_time = (v0 - vt) / d; |
|
|
part1_time = (v0 - vt) / d; |
|
|
if (part1_time == 0) part1_time = 1; |
|
|
if (part1_time == 0) part1_time = 1; |
|
|
|
|
|
|
|
|
uint64_t temp_calc = (uint64_t)(v0 + vt) * part1_time; |
|
|
uint64_t temp_calc = (uint64_t)(v0 + vt) * part1_time; |
|
|
part1_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
part1_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
if(part1_pulse_num == 0) part1_pulse_num = 1; // 防止为0 |
|
|
|
|
|
|
|
|
if(part1_pulse_num == 0) part1_pulse_num = 1; |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
// v0 == vt,无需第一部分 |
|
|
|
|
|
part1_state = PLSR_STATE_CONST; |
|
|
|
|
|
part1_pulse_num = 0; |
|
|
part1_pulse_num = 0; |
|
|
part1_time = 0; |
|
|
part1_time = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 计算第三部分:vt -> 0(必须减速到0) |
|
|
|
|
|
PLSR_RunState_t part3_state = PLSR_STATE_DECEL; |
|
|
|
|
|
|
|
|
// 计算理想情况下的第三部分:vt -> 0 |
|
|
if (vt > 0) |
|
|
if (vt > 0) |
|
|
{ |
|
|
{ |
|
|
part3_time = vt / d; |
|
|
part3_time = vt / d; |
|
|
if (part3_time == 0) part3_time = 1; |
|
|
if (part3_time == 0) part3_time = 1; |
|
|
|
|
|
|
|
|
// 从vt减速到0的脉冲数:(vt + 0) * part3_time / 2000 |
|
|
|
|
|
uint64_t temp_calc = (uint64_t)vt * part3_time; |
|
|
uint64_t temp_calc = (uint64_t)vt * part3_time; |
|
|
part3_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
part3_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
if(part3_pulse_num == 0) part3_pulse_num = 1; // 防止为0 |
|
|
|
|
|
|
|
|
if(part3_pulse_num == 0) part3_pulse_num = 1; |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
// 目标频率已经是0,无需第三部分 |
|
|
|
|
|
part3_pulse_num = 0; |
|
|
part3_pulse_num = 0; |
|
|
part3_time = 0; |
|
|
part3_time = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 计算第二部分:匀速部分 |
|
|
|
|
|
PLSR_RunState_t part2_state = PLSR_STATE_CONST; |
|
|
|
|
|
|
|
|
// 检查脉冲数是否足够 |
|
|
int32_t used_pulses = part1_pulse_num + part3_pulse_num; |
|
|
int32_t used_pulses = part1_pulse_num + part3_pulse_num; |
|
|
|
|
|
|
|
|
if (used_pulses < total_pulses) |
|
|
|
|
|
|
|
|
if (used_pulses <= total_pulses) |
|
|
{ |
|
|
{ |
|
|
// 有剩余脉冲用于匀速阶段 |
|
|
|
|
|
|
|
|
// 脉冲数足够,计算匀速部分 |
|
|
part2_pulse_num = total_pulses - used_pulses; |
|
|
part2_pulse_num = total_pulses - used_pulses; |
|
|
|
|
|
|
|
|
// 计算匀速时间 |
|
|
|
|
|
if (vt > 0) { |
|
|
|
|
|
|
|
|
if (vt > 0 && part2_pulse_num > 0) { |
|
|
part2_time = (part2_pulse_num * 1000) / vt; |
|
|
part2_time = (part2_pulse_num * 1000) / vt; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (used_pulses > total_pulses) |
|
|
|
|
|
|
|
|
else |
|
|
{ |
|
|
{ |
|
|
// 脉冲数不足,需要调整运动参数 |
|
|
|
|
|
// 策略:优先保证能减速到0,然后调整第一部分 |
|
|
|
|
|
if (part3_pulse_num <= total_pulses) { |
|
|
|
|
|
// 第三部分可以完成,调整第一部分 |
|
|
|
|
|
int32_t remaining_pulses = total_pulses - part3_pulse_num; |
|
|
|
|
|
|
|
|
|
|
|
if (remaining_pulses > 0) { |
|
|
|
|
|
if (v0 < vt) |
|
|
|
|
|
{ |
|
|
|
|
|
// 加速情况:计算实际能加速到的频率 |
|
|
|
|
|
// vm^2 = v0^2 + remaining_pulses * 2000 * a |
|
|
|
|
|
uint64_t v0_squared = (uint64_t)v0 * v0; |
|
|
|
|
|
uint64_t addition = (uint64_t)remaining_pulses * 2000ULL * a; |
|
|
|
|
|
uint64_t vm_squared = v0_squared + addition; |
|
|
|
|
|
|
|
|
|
|
|
if (vm_squared <= 0xFFFFFFFFULL) { |
|
|
|
|
|
uint32_t vm = integer_sqrt((uint32_t)vm_squared); |
|
|
|
|
|
if (vm > vt) vm = vt; // 不超过期望目标频率 |
|
|
|
|
|
|
|
|
|
|
|
// 重新计算第一部分和第三部分 |
|
|
|
|
|
vt = vm; // 更新实际目标频率 |
|
|
|
|
|
part1_time = (vt - v0) / a; |
|
|
|
|
|
if (part1_time == 0) part1_time = 1; |
|
|
|
|
|
part1_pulse_num = remaining_pulses; |
|
|
|
|
|
|
|
|
|
|
|
// 重新计算第三部分 |
|
|
|
|
|
part3_time = vt / d; |
|
|
|
|
|
if (part3_time == 0) part3_time = 1; |
|
|
|
|
|
uint64_t temp_calc = (uint64_t)vt * part3_time; |
|
|
|
|
|
part3_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (v0 > vt) { |
|
|
|
|
|
// 减速情况:计算实际能减速到的频率 |
|
|
|
|
|
// vm^2 = v0^2 - remaining_pulses * 2000 * d |
|
|
|
|
|
uint64_t v0_squared = (uint64_t)v0 * v0; |
|
|
|
|
|
uint64_t reduction = (uint64_t)remaining_pulses * 2000ULL * d; |
|
|
|
|
|
|
|
|
|
|
|
if (v0_squared > reduction) { |
|
|
|
|
|
uint32_t vm_squared = (uint32_t)(v0_squared - reduction); |
|
|
|
|
|
uint32_t vm = integer_sqrt(vm_squared); |
|
|
|
|
|
if (vm < vt) vm = vt; // 不低于期望目标频率 |
|
|
|
|
|
|
|
|
|
|
|
// 更新实际目标频率 |
|
|
|
|
|
vt = vm; |
|
|
|
|
|
part1_time = (v0 - vt) / d; |
|
|
|
|
|
if (part1_time == 0) part1_time = 1; |
|
|
|
|
|
part1_pulse_num = remaining_pulses; |
|
|
|
|
|
|
|
|
|
|
|
// 重新计算第三部分 |
|
|
|
|
|
part3_time = vt / d; |
|
|
|
|
|
if (part3_time == 0) part3_time = 1; |
|
|
|
|
|
uint64_t temp_calc = (uint64_t)vt * part3_time; |
|
|
|
|
|
part3_pulse_num = (uint32_t)(temp_calc / 2000); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// v0 == vt,直接分配给第一部分作为匀速 |
|
|
|
|
|
part1_pulse_num = remaining_pulses; |
|
|
|
|
|
part1_state = PLSR_STATE_CONST; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// remaining_pulses == 0,只有第三部分 |
|
|
|
|
|
part1_pulse_num = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
part2_pulse_num = 0; // 无匀速阶段 |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// 连第三部分都无法完成,重新规划整个运动 |
|
|
|
|
|
// 计算在total_pulses内能实现的运动 |
|
|
|
|
|
|
|
|
|
|
|
// 简化处理:直接从v0减速,看能减速到什么频率 |
|
|
|
|
|
// vf^2 = v0^2 - total_pulses * 2000 * d |
|
|
|
|
|
uint64_t v0_squared = (uint64_t)v0 * v0; |
|
|
|
|
|
uint64_t reduction = (uint64_t)total_pulses * 2000ULL * d; |
|
|
|
|
|
|
|
|
// 脉冲数不足,需要重新规划运动 |
|
|
|
|
|
part2_pulse_num = 0; // 没有匀速阶段 |
|
|
|
|
|
|
|
|
|
|
|
// 优化策略:寻找最优的中间频率vm,使得总脉冲数刚好等于available_pulses |
|
|
|
|
|
uint32_t vm = OptimalIntermediateFrequency(v0, vt_desired, total_pulses, a, d); |
|
|
|
|
|
|
|
|
|
|
|
if (vm != v0) // 找到了有效的中间频率 |
|
|
|
|
|
{ |
|
|
|
|
|
vt = vm; // 更新实际目标频率 |
|
|
|
|
|
|
|
|
if (v0_squared > reduction) { |
|
|
|
|
|
uint32_t vf_squared = (uint32_t)(v0_squared - reduction); |
|
|
|
|
|
uint32_t actual_vf = integer_sqrt(vf_squared); |
|
|
|
|
|
|
|
|
// 重新计算第一部分 |
|
|
|
|
|
if (v0 < vm) |
|
|
|
|
|
{ |
|
|
|
|
|
part1_state = PLSR_STATE_ACCEL; |
|
|
|
|
|
// 使用运动学公式:s = (v0 + vm) * t / 2,其中 t = (vm - v0) / a |
|
|
|
|
|
// 所以:s = (v0 + vm) * (vm - v0) / (2 * a) = (vm^2 - v0^2) / (2 * a) |
|
|
|
|
|
uint64_t numerator = (uint64_t)vm * vm - (uint64_t)v0 * v0; |
|
|
|
|
|
part1_pulse_num = (uint32_t)(numerator / (2000ULL * a)); |
|
|
|
|
|
if (part1_pulse_num == 0) part1_pulse_num = 1; |
|
|
|
|
|
|
|
|
// 设置为单一减速阶段 |
|
|
|
|
|
part1_state = PLSR_STATE_DECEL; |
|
|
|
|
|
part1_pulse_num = total_pulses; |
|
|
|
|
|
part1_time = (v0 - actual_vf) / d; |
|
|
|
|
|
|
|
|
part1_time = (vm - v0) / a; |
|
|
if (part1_time == 0) part1_time = 1; |
|
|
if (part1_time == 0) part1_time = 1; |
|
|
|
|
|
} |
|
|
|
|
|
else if (v0 > vm) |
|
|
|
|
|
{ |
|
|
|
|
|
part1_state = PLSR_STATE_DECEL; |
|
|
|
|
|
// 减速情况:s = (v0^2 - vm^2) / (2 * d) |
|
|
|
|
|
uint64_t numerator = (uint64_t)v0 * v0 - (uint64_t)vm * vm; |
|
|
|
|
|
part1_pulse_num = (uint32_t)(numerator / (2000ULL * d)); |
|
|
|
|
|
if (part1_pulse_num == 0) part1_pulse_num = 1; |
|
|
|
|
|
|
|
|
vt = actual_vf; // 更新目标频率 |
|
|
|
|
|
part2_pulse_num = 0; |
|
|
|
|
|
part3_pulse_num = 0; |
|
|
|
|
|
|
|
|
part1_time = (v0 - vm) / d; |
|
|
|
|
|
if (part1_time == 0) part1_time = 1; |
|
|
} |
|
|
} |
|
|
else { |
|
|
|
|
|
// 数学上不可行,保持当前频率 |
|
|
|
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
part1_state = PLSR_STATE_CONST; |
|
|
part1_state = PLSR_STATE_CONST; |
|
|
part1_pulse_num = total_pulses; |
|
|
|
|
|
part2_pulse_num = 0; |
|
|
|
|
|
|
|
|
part1_pulse_num = 0; |
|
|
|
|
|
part1_time = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重新计算第三部分:vm -> 0 |
|
|
|
|
|
if (vm > 0) |
|
|
|
|
|
{ |
|
|
|
|
|
part3_state = PLSR_STATE_DECEL; |
|
|
|
|
|
// s = vm^2 / (2 * d) |
|
|
|
|
|
uint64_t numerator = (uint64_t)vm * vm; |
|
|
|
|
|
part3_pulse_num = (uint32_t)(numerator / (2000ULL * d)); |
|
|
|
|
|
if (part3_pulse_num == 0) part3_pulse_num = 1; |
|
|
|
|
|
|
|
|
|
|
|
part3_time = vm / d; |
|
|
|
|
|
if (part3_time == 0) part3_time = 1; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
part3_pulse_num = 0; |
|
|
part3_pulse_num = 0; |
|
|
vt = v0; |
|
|
|
|
|
|
|
|
part3_time = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 确保总脉冲数不超过限制 |
|
|
|
|
|
int32_t calculated_total = part1_pulse_num + part3_pulse_num; |
|
|
|
|
|
if (calculated_total > total_pulses) |
|
|
|
|
|
{ |
|
|
|
|
|
// 按比例调整 |
|
|
|
|
|
if (part1_pulse_num > 0) { |
|
|
|
|
|
part1_pulse_num = (part1_pulse_num * total_pulses) / calculated_total; |
|
|
|
|
|
} |
|
|
|
|
|
if (part3_pulse_num > 0) { |
|
|
|
|
|
part3_pulse_num = total_pulses - part1_pulse_num; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
// 无法找到有效的运动规划,保持当前频率 |
|
|
|
|
|
part1_state = PLSR_STATE_CONST; |
|
|
|
|
|
part1_pulse_num = total_pulses; |
|
|
|
|
|
part1_time = (total_pulses * 1000) / v0; |
|
|
|
|
|
part3_pulse_num = 0; |
|
|
|
|
|
part3_time = 0; |
|
|
|
|
|
vt = v0; // 实际目标频率等于起始频率 |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
part2_pulse_num = 0; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 保存三个部分的状态和脉冲计数到结构体 |
|
|
|
|
|
// 使用现有的字段来存储三个部分的信息 |
|
|
|
|
|
|
|
|
|
|
|
// 第一部分 |
|
|
|
|
|
|
|
|
// 保存计算结果到结构体 |
|
|
if (part1_state == PLSR_STATE_ACCEL) |
|
|
if (part1_state == PLSR_STATE_ACCEL) |
|
|
{ |
|
|
{ |
|
|
route->accel_pulse_count = part1_pulse_num; |
|
|
route->accel_pulse_count = part1_pulse_num; |
|
@@ -1370,41 +1337,181 @@ void Calculate_PluseNum(PLSR_RouteConfig_t *route) |
|
|
{ |
|
|
{ |
|
|
route->accel_pulse_count = (part1_state == PLSR_STATE_DECEL) ? part1_pulse_num : 0; |
|
|
route->accel_pulse_count = (part1_state == PLSR_STATE_DECEL) ? part1_pulse_num : 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// if(route->accel_pulse_count > 1) |
|
|
|
|
|
// { |
|
|
|
|
|
// route->accel_pulse_count -= 1; // 减1防止过冲 |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
// 第二部分(匀速) |
|
|
|
|
|
route->const_pulse_count = part2_pulse_num; |
|
|
route->const_pulse_count = part2_pulse_num; |
|
|
|
|
|
|
|
|
// 第三部分(减速到0) |
|
|
|
|
|
route->decel_pulse_count = part3_pulse_num; |
|
|
route->decel_pulse_count = part3_pulse_num; |
|
|
|
|
|
|
|
|
route->part1_state = part1_state; // 保存第一部分状态 |
|
|
|
|
|
route->part2_state = part2_state; // 保存第二部分状态 |
|
|
|
|
|
route->part3_state = part3_state; // 保存第三部分状态 |
|
|
|
|
|
route->part1_target_freq = vt; // 第一部分结束频率 |
|
|
|
|
|
route->part2_target_freq = vt; // 第二部分结束频率 |
|
|
|
|
|
route->part3_target_freq = 0; // 第三部分结束频率必须为0 |
|
|
|
|
|
|
|
|
route->part1_state = part1_state; |
|
|
|
|
|
route->part2_state = part2_state; |
|
|
|
|
|
route->part3_state = part3_state; |
|
|
|
|
|
route->part1_target_freq = vt; |
|
|
|
|
|
route->part2_target_freq = vt; |
|
|
|
|
|
route->part3_target_freq = 0; |
|
|
|
|
|
|
|
|
// 设置初始运行状态 |
|
|
// 设置初始运行状态 |
|
|
if (part1_pulse_num > 0) { |
|
|
|
|
|
|
|
|
if (part1_pulse_num > 0) |
|
|
|
|
|
{ |
|
|
route->run_state = part1_state; |
|
|
route->run_state = part1_state; |
|
|
route->target_freq = vt; |
|
|
route->target_freq = vt; |
|
|
} else if (part2_pulse_num > 0) { |
|
|
|
|
|
|
|
|
} else if (part2_pulse_num > 0) |
|
|
|
|
|
{ |
|
|
route->run_state = PLSR_STATE_CONST; |
|
|
route->run_state = PLSR_STATE_CONST; |
|
|
route->target_freq = vt; |
|
|
route->target_freq = vt; |
|
|
} else if (part3_pulse_num > 0) { |
|
|
|
|
|
|
|
|
} else if (part3_pulse_num > 0) |
|
|
|
|
|
{ |
|
|
route->run_state = PLSR_STATE_DECEL; |
|
|
route->run_state = PLSR_STATE_DECEL; |
|
|
route->target_freq = 0; |
|
|
route->target_freq = 0; |
|
|
} else { |
|
|
|
|
|
|
|
|
} else |
|
|
|
|
|
{ |
|
|
route->run_state = PLSR_STATE_CONST; |
|
|
route->run_state = PLSR_STATE_CONST; |
|
|
route->target_freq = v0; |
|
|
route->target_freq = v0; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @brief 计算最优中间频率 |
|
|
|
|
|
* @param v0 起始频率 |
|
|
|
|
|
* @param vt_desired 期望目标频率 |
|
|
|
|
|
* @param total_pulses 可用总脉冲数 |
|
|
|
|
|
* @param a 加速度 |
|
|
|
|
|
* @param d 减速度 |
|
|
|
|
|
* @return 最优中间频率vm |
|
|
|
|
|
*/ |
|
|
|
|
|
uint32_t OptimalIntermediateFrequency(uint32_t v0, uint32_t vt_desired, |
|
|
|
|
|
int32_t total_pulses, uint32_t a, uint32_t d) |
|
|
|
|
|
{ |
|
|
|
|
|
// 数学推导: |
|
|
|
|
|
// 设中间频率为vm |
|
|
|
|
|
// 第一阶段脉冲数:s1 = |vm^2 - v0^2| / (2000 * rate1) |
|
|
|
|
|
// 第三阶段脉冲数:s3 = vm^2 / (2000 * d) |
|
|
|
|
|
// 约束条件:s1 + s3 = total_pulses |
|
|
|
|
|
|
|
|
|
|
|
uint32_t vm = v0; // 默认返回起始频率 |
|
|
|
|
|
|
|
|
|
|
|
if (total_pulses <= 0) return vm; |
|
|
|
|
|
|
|
|
|
|
|
// 情况1:需要加速 (v0 < vt_desired) |
|
|
|
|
|
if (v0 < vt_desired) |
|
|
|
|
|
{ |
|
|
|
|
|
// s1 = (vm^2 - v0^2) / (2000 * a) |
|
|
|
|
|
// s3 = vm^2 / (2000 * d) |
|
|
|
|
|
// s1 + s3 = total_pulses |
|
|
|
|
|
// (vm^2 - v0^2) / (2000 * a) + vm^2 / (2000 * d) = total_pulses |
|
|
|
|
|
// vm^2 * (1/(2000*a) + 1/(2000*d)) - v0^2/(2000*a) = total_pulses |
|
|
|
|
|
// vm^2 * (d + a)/(2000*a*d) = total_pulses + v0^2/(2000*a) |
|
|
|
|
|
|
|
|
|
|
|
uint64_t coefficient = (uint64_t)(a + d) * 1000ULL; // 分母:2000*a*d,这里先乘1000 |
|
|
|
|
|
uint64_t constant_term = ((uint64_t)v0 * v0) / (2ULL * a); // v0^2/(2*a),单位是脉冲*1000 |
|
|
|
|
|
uint64_t rhs = (uint64_t)total_pulses * 1000ULL + constant_term; // 右边,单位是脉冲*1000 |
|
|
|
|
|
|
|
|
|
|
|
// vm^2 = rhs * 2000 * a * d / (a + d) / 1000 |
|
|
|
|
|
uint64_t vm_squared = (rhs * 2000ULL * a * d) / coefficient; |
|
|
|
|
|
|
|
|
|
|
|
if (vm_squared > 0 && vm_squared <= 0xFFFFFFFFULL) |
|
|
|
|
|
{ |
|
|
|
|
|
vm = integer_sqrt((uint32_t)vm_squared); |
|
|
|
|
|
|
|
|
|
|
|
// 限制vm不能超过期望目标频率太多 |
|
|
|
|
|
if (vm > vt_desired * 2) vm = vt_desired * 2; |
|
|
|
|
|
|
|
|
|
|
|
// 验证计算结果 |
|
|
|
|
|
uint32_t s1_calc = ((uint64_t)vm * vm - (uint64_t)v0 * v0) / (2000ULL * a); |
|
|
|
|
|
uint32_t s3_calc = ((uint64_t)vm * vm) / (2000ULL * d); |
|
|
|
|
|
|
|
|
|
|
|
if ((int32_t)(s1_calc + s3_calc) > total_pulses) { |
|
|
|
|
|
// 结果超出限制,进行二分搜索优化 |
|
|
|
|
|
vm = BinarySearchOptimalFreq(v0, vt_desired, total_pulses, a, d, 1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 情况2:需要减速 (v0 > vt_desired) |
|
|
|
|
|
else if (v0 > vt_desired) |
|
|
|
|
|
{ |
|
|
|
|
|
// s1 = (v0^2 - vm^2) / (2000 * d) |
|
|
|
|
|
// s3 = vm^2 / (2000 * d) |
|
|
|
|
|
// s1 + s3 = (v0^2 - vm^2) / (2000 * d) + vm^2 / (2000 * d) = v0^2 / (2000 * d) |
|
|
|
|
|
// 这种情况下总脉冲数固定为 v0^2 / (2000 * d) |
|
|
|
|
|
|
|
|
|
|
|
uint32_t required_pulses = ((uint64_t)v0 * v0) / (2000ULL * d); |
|
|
|
|
|
|
|
|
|
|
|
if (required_pulses <= (uint32_t)total_pulses) |
|
|
|
|
|
{ |
|
|
|
|
|
// 脉冲数足够,可以减速到任意频率 |
|
|
|
|
|
// 选择一个合理的中间频率,优先选择期望频率 |
|
|
|
|
|
if (vt_desired < v0) { |
|
|
|
|
|
vm = vt_desired; |
|
|
|
|
|
} else { |
|
|
|
|
|
vm = v0 / 2; // 选择一个中间值 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
// 脉冲数不足,计算能减速到的最低频率 |
|
|
|
|
|
// vm^2 = v0^2 - total_pulses * 2000 * d |
|
|
|
|
|
uint64_t v0_squared = (uint64_t)v0 * v0; |
|
|
|
|
|
uint64_t reduction = (uint64_t)total_pulses * 2000ULL * d; |
|
|
|
|
|
|
|
|
|
|
|
if (v0_squared > reduction) { |
|
|
|
|
|
uint32_t vm_squared = (uint32_t)(v0_squared - reduction); |
|
|
|
|
|
vm = integer_sqrt(vm_squared); |
|
|
|
|
|
} else { |
|
|
|
|
|
vm = 0; // 理论上可以减速到0 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return vm; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @brief 二分搜索寻找最优频率 |
|
|
|
|
|
* @param v0 起始频率 |
|
|
|
|
|
* @param vt_desired 期望目标频率 |
|
|
|
|
|
* @param total_pulses 可用总脉冲数 |
|
|
|
|
|
* @param a 加速度 |
|
|
|
|
|
* @param d 减速度 |
|
|
|
|
|
* @param is_accel 是否为加速情况 |
|
|
|
|
|
* @return 最优频率 |
|
|
|
|
|
*/ |
|
|
|
|
|
uint32_t BinarySearchOptimalFreq(uint32_t v0, uint32_t vt_desired, |
|
|
|
|
|
int32_t total_pulses, uint32_t a, uint32_t d, |
|
|
|
|
|
uint8_t is_accel) |
|
|
|
|
|
{ |
|
|
|
|
|
uint32_t low = is_accel ? v0 : 0; |
|
|
|
|
|
uint32_t high = is_accel ? (vt_desired * 2) : v0; |
|
|
|
|
|
uint32_t best_vm = v0; |
|
|
|
|
|
|
|
|
|
|
|
for (int iterations = 0; iterations < 20; iterations++) // 限制迭代次数 |
|
|
|
|
|
{ |
|
|
|
|
|
uint32_t mid = low + (high - low) / 2; |
|
|
|
|
|
|
|
|
|
|
|
// 计算当前频率下的脉冲数 |
|
|
|
|
|
uint32_t s1, s3; |
|
|
|
|
|
if (is_accel) { |
|
|
|
|
|
s1 = ((uint64_t)mid * mid - (uint64_t)v0 * v0) / (2000ULL * a); |
|
|
|
|
|
} else { |
|
|
|
|
|
s1 = ((uint64_t)v0 * v0 - (uint64_t)mid * mid) / (2000ULL * d); |
|
|
|
|
|
} |
|
|
|
|
|
s3 = ((uint64_t)mid * mid) / (2000ULL * d); |
|
|
|
|
|
|
|
|
|
|
|
int32_t total_calc = s1 + s3; |
|
|
|
|
|
|
|
|
|
|
|
if (total_calc == total_pulses) { |
|
|
|
|
|
return mid; // 找到精确解 |
|
|
|
|
|
} else if (total_calc < total_pulses) { |
|
|
|
|
|
best_vm = mid; |
|
|
|
|
|
low = mid + 1; |
|
|
|
|
|
} else { |
|
|
|
|
|
high = mid - 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (low > high) break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return best_vm; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void PLSR_HandleSectionEnd(void) |
|
|
void PLSR_HandleSectionEnd(void) |
|
|
{ |
|
|
{ |
|
|
// 清零所有部分的脉冲计数 |
|
|
// 清零所有部分的脉冲计数 |
|
@@ -1466,7 +1573,6 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) |
|
|
|
|
|
|
|
|
PLSR_PWM_SetFrequency(g_plsr_route.target_freq); |
|
|
PLSR_PWM_SetFrequency(g_plsr_route.target_freq); |
|
|
__HAL_TIM_SetAutoreload(&htim2, g_plsr_route.const_pulse_count); |
|
|
__HAL_TIM_SetAutoreload(&htim2, g_plsr_route.const_pulse_count); |
|
|
|
|
|
|
|
|
__HAL_TIM_SET_COUNTER(&htim2, 0); |
|
|
__HAL_TIM_SET_COUNTER(&htim2, 0); |
|
|
PLSR_PWM_Start(); |
|
|
PLSR_PWM_Start(); |
|
|
break; |
|
|
break; |
|
@@ -1637,7 +1743,7 @@ void PLSR_Route_Init(PLSR_RouteConfig_t* route) |
|
|
// 初始化全局变量 |
|
|
// 初始化全局变量 |
|
|
g_last_freq = 0; // 清零上一次计算的频率 |
|
|
g_last_freq = 0; // 清零上一次计算的频率 |
|
|
|
|
|
|
|
|
PLSR_TIM6_SetUpdateFreq(10); //初始化TIM6更新频率为1000us(1ms) |
|
|
|
|
|
|
|
|
PLSR_TIM6_SetUpdateFreq(100); //初始化TIM6更新频率为1000us(1ms) |
|
|
PLSR_PWM_Stop(); // 确保PWM停止,避免意外输出 |
|
|
PLSR_PWM_Stop(); // 确保PWM停止,避免意外输出 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -2135,21 +2241,21 @@ void PLSR_Section_SwitchNext(PLSR_RouteConfig_t* route, uint8_t is_pulse_complet |
|
|
route->prevPulseCount = g_plsr_location; |
|
|
route->prevPulseCount = g_plsr_location; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// 检查下一段是否有效 |
|
|
|
|
|
if(next_section_num == 0 && current_section->section_num == route->section_num) |
|
|
|
|
|
{ |
|
|
|
|
|
// 如果是最后一段且下一段为0,结束路径 |
|
|
|
|
|
route->route_state = PLSR_ROUTE_COMPLETED; |
|
|
|
|
|
PLSR_Route_Stop(route); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (next_section_num > PLSR_MAX_SECTIONS) |
|
|
|
|
|
{ |
|
|
|
|
|
// 路径结束 |
|
|
|
|
|
route->route_state = PLSR_ROUTE_COMPLETED; |
|
|
|
|
|
PLSR_Route_Stop(route); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// // 检查下一段是否有效 |
|
|
|
|
|
// if(next_section_num == 0 && current_section->section_num == route->section_num) |
|
|
|
|
|
// { |
|
|
|
|
|
// // 如果是最后一段且下一段为0,结束路径 |
|
|
|
|
|
// route->route_state = PLSR_ROUTE_COMPLETED; |
|
|
|
|
|
// PLSR_Route_Stop(route); |
|
|
|
|
|
// return; |
|
|
|
|
|
// } |
|
|
|
|
|
// if (next_section_num > PLSR_MAX_SECTIONS) |
|
|
|
|
|
// { |
|
|
|
|
|
// // 路径结束 |
|
|
|
|
|
// route->route_state = PLSR_ROUTE_COMPLETED; |
|
|
|
|
|
// PLSR_Route_Stop(route); |
|
|
|
|
|
// return; |
|
|
|
|
|
// } |
|
|
if(next_section_num == 0) |
|
|
if(next_section_num == 0) |
|
|
{ |
|
|
{ |
|
|
route->current_section_num = current_section->section_num + 1; |
|
|
route->current_section_num = current_section->section_num + 1; |
|
|