Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

19 KiB

PLSR 重构设计书:加减速与多段统一(V1.1)

范围:仅 PULSE/DIR 模式。AB 正交模式维持现状,作为第二阶段另行设计。
V1.1 变更:采纳审查意见,补齐四根承重梁——①多段边界语义解析层;②唯一硬件执行器
(所有权状态机);③STOP/EXT/动态改频统一的 generation 原子重规划;④硬件量化进入
规划闭环。修正脉冲守恒公式表述,修正"预算不足=错误"的文档矛盾。
配套依据:PLSR_Bug报告_2026-08-13_短轮廓与段间延迟.mdPLSR方案设计书_V1.0.md


1. 问题定义

当前固件中"加减速"存在两套并行实现(时间域 ramp 与脉冲域短轮廓),四条输出路径,
接力点由启发式估算决定且不守恒。逻辑分析仪实测(Bug 报告)已证实四类缺陷:

Bug 现象 结构性根因
1 减速预算不足时跳停止速度,尾部慢爬 长 ramp 路径没有"按剩余脉冲重算斜坡”
2 加速 ramp 整体消失,首脉冲即目标频率 ramp 按挂钟计时,与首脉冲等待时间脱节
3 整段以启动/停止速度输出 同上极端版 + 0 脉冲消耗判定缺陷
4 有限路径段间固定 ~2.5ms 低电平间隙 段完成事件跨两个 1ms 周期消费

1.1 无唯一执行所有权(代码事实)

平台层 PSC/ARR 写入散在 5 个点,任务域与中断域两条通道并存,互斥靠临界区 +
写保护 guard + generation 计数拼凑:

写入点 触发场景
PlsrPlatformUpdateFinitePrepared 任务域 有限轮廓运行中调频/ramp 更新
PlsrPlatformUpdateFiniteStep 任务域 有限序列运行中改写旧 step 表
PlsrPlatformQueueFrequency 任务域 时间域 ramp 逐 tick 调频
PlsrPlatformLoadPreparedFromIrq 中断域 profile 队列/handoff 预装载
PlsrFinitePrepareNextStepIrq 中断域 step 表切换预装载

PlsrCutRequested 的消费点只在 PlsrPulseTimerIrq,而有限路径由计数器中断驱动、
不走该函数——有限轮廓运行中触发 EXT 时 cut 语义丢失,要等段自然结束才被当作
普通边界处理。

1.2 重构原则

  1. 不重写硬件层:定时器预装载时序、TIM9/TIM12 计数、掉电保持均为已验证资产。
  2. 单一所有权:任何时刻只有一个执行状态在推进;只有硬件预装载引擎写 PSC/ARR。
  3. 规划与执行分离:规划器是纯函数(流式),执行器只负责在安全边界装载下一项。
  4. 每个阶段可编译、可宿主机测试、可板级波形回归
  5. 第一轮不动 AB 模式(执行状态机预留 AB_STREAM 占位)。

2. 目标架构总览

原始段参数(PLSR_CONFIG + 当前段 + 实际位置)
      │
      ▼
┌───────────────────────────────┐
│ 多段边界语义解析器(新)          │  SEND_COMPLETE / SEND_SUBSEQUENT /
│ 段序列 → MotionBlock 序列        │  WAIT 类型 / 跳转 / 同向连续 / 换向
└───────────────────────────────┘
      │ MotionBlock(entryHz, cruiseHz, exitHz, pulseBudget, boundaryAction)
      ▼
┌───────────────────────────────┐
│ 脉冲域规划器(新,纯函数,流式)   │  相位法:∫f dt = k → t_k → f[k]
│ 量化闭环:以实际定时器周期累计    │  输出 PLSR_STREAM_ITEM(含 repeat 压缩)
└───────────────────────────────┘
      │ 轨迹流
      ▼
┌───────────────────────────────┐
│ 唯一硬件执行器(PLSR_EXEC_MODE) │  STEP_TABLE / STREAM 两种供给方式,
│ 只有它写 PSC/ARR                │  一个执行状态机
└───────────────────────────────┘
      │
      ▼
状态机 / 命令 / Modbus(PlsrPoll1ms 保持 1ms 节拍,不再逐 tick 调频)

3. 多段边界语义解析层(承重梁①)

规划器只管"一个 MotionBlock 内的脉冲域轨迹”。段序列语义在上层解析为块序列,
每次边界推进时用实际位置与方向解析下一块(绝对位置、换向因此天然支持)。

typedef enum
{
    PLSR_BOUNDARY_STOP,        /* 运动结束 */
    PLSR_BOUNDARY_NEXT_FRESH,  /* 完成发送:减速到停止速度,下一块从启动速度起 */
    PLSR_BOUNDARY_NEXT_CARRY,  /* 后续发送同向连续:exitHz = 下一块 cruiseHz */
    PLSR_BOUNDARY_WAIT_TIME,   /* WAIT 时间 → 状态机等待,不属执行器 */
    PLSR_BOUNDARY_WAIT_SIGNAL, /* WAIT 信号 → 同上 */
    PLSR_BOUNDARY_WAIT_EXT,    /* EXT 信号 → 同上 */
    PLSR_BOUNDARY_JUMP,        /* 跳转段 */
    PLSR_BOUNDARY_EXT_CUT      /* EXT 提前截断(立即切断语义) */
} PLSR_BOUNDARY_ACTION;

typedef struct
{
    uint32_t entryHz;          /* 块起点:启动速度 或 上一块 carry */
    uint32_t cruiseHz;         /* 段目标频率 */
    uint32_t exitHz;           /* 块终点:停止速度 或 下一块 cruiseHz */
    uint32_t pulseBudget;      /* 本块脉冲预算(uint32_t) */
    PLSR_BOUNDARY_ACTION boundary;
} PLSR_MOTION_BLOCK;

解析规则(落实 SEND 模式与边界语义,避免"完成发送/后续发送被当成同一结果”):

  1. SEND_COMPLETEexitHz = stopSpeedHz(decelerationTimeMs>0 时),
    boundary = NEXT_FRESH;下一块 entryHz = startSpeedHz
  2. SEND_SUBSEQUENT + 同向 + waitType==EXT_OR_COMPLETE + 无跳转
    exitHz = 下一段 cruiseHzboundary = NEXT_CARRY;下一块 entryHz = carry
  3. 换向:强制 NEXT_FRESH 语义(exitHz = stopSpeedHz),方向延时在块间由状态机
    处理,不属于执行器。
  4. 绝对位置模式:段位移 = pulses − 实际位置,方向在解析时确定;解析器在每个
    边界用 PlsrPosition 的最新值解析下一块,不允许跨段预缓存方向。
  5. WAIT_TIME / WAIT_SIGNAL / WAIT_EXT:块在脉冲完成处结束,边界转入状态机
    等待,重入运动时从解析器重新取块。
  6. EXT_OR_COMPLETE:正常运行语义 = NEXT_FRESH 或 NEXT_CARRY(同 1/2);
    EXT 边沿事件 = BOUNDARY_EXT_CUT,走 §6 原子重规划(立即切断)。

4. 脉冲域规划器(承重梁④)

4.1 守恒定义(修正 V1.0 公式错误)

  • 脉冲数守恒N = ∫ f(t) dt
  • 第 k 个脉冲边界 t_k 满足 ∫[0,t_k] f(t) dt = k(k = 1..N)。
  • 第 k 个脉冲周期Δt_k = t_k − t_{k−1},目标频率 f[k] = 1/Δt_k
  • 量化闭环f_timer[k] = BuildTimerSetting(f[k]) 的 actualHz(PSC/ARR 量化
    结果),并以量化后的真实周期反推相位推进,后续边界在此基础上继续求解——
    量化误差不累积。BuildTimerSetting 必须无副作用、可在宿主机纯运行。

现有实现对照:PlsrRampAreaQ32 即 ∫f dt 的 Q32 积分、PlsrExactRampBoundaryQ32
即相位边界求解,二者原样迁入;新增量化反馈环。

4.2 流式接口(不再有 1000 脉冲算法边界)

typedef struct
{
    uint16_t psc;             /* 量化后定时器设定 */
    uint16_t pairPsc;         /* PULSE/DIR 恒 0(AB 复用) */
    uint32_t arr;
    uint32_t compare;
    uint32_t actualHz;
} PLSR_TIMER_STEP;

typedef struct
{
    PLSR_TIMER_STEP step;
    uint32_t repeatCount;     /* 匀速区压缩:连续同频脉冲合并 */
} PLSR_STREAM_ITEM;

typedef struct
{
    PLSR_MOTION_BLOCK block;
    uint32_t appliedHz;       /* 起点:实际生效频率(见 §6.3) */
    uint64_t phasePulses;     /* 起点相位:已实际输出脉冲数 */
    /* 内部:曲线积分表索引、Q32 相位累计、量化误差累计 */
    uint8_t curveMode;
    /* ... */
} PLSR_PLANNER_CONTEXT;

typedef enum
{
    PLSR_PLANNER_OK = 0,      /* 正常生成(含完整梯形稳态段) */
    PLSR_PLANNER_CLIPPED,     /* 预算不足,结果为可执行的截断形态(三角/纯加减速) */
    PLSR_PLANNER_DONE,        /* 全部脉冲已生成 */
    PLSR_PLANNER_INVALID      /* 参数非法 */
} PLSR_PLANNER_STATUS;

PLSR_PLANNER_STATUS PlsrPlannerBegin(PLSR_PLANNER_CONTEXT *ctx,
                                     const PLSR_MOTION_BLOCK *block,
                                     uint32_t appliedHz,
                                     uint64_t phasePulses);
uint16_t PlsrPlannerGenerate(PLSR_PLANNER_CONTEXT *ctx,
                             PLSR_STREAM_ITEM *out,
                             uint16_t capacity);

要点:

  • pulseBudgetuint32_tphasePulsesuint64_t(长运动相位累计)。
  • 匀速区以 {step, repeatCount} 压缩;ramp 区逐脉冲(或按可合并步长)输出。
  • 环形执行队列只保存未来几十到几百项;1000 仅是执行缓存上限,不再是算法边界。
  • CLIPPED 不是错误:三角、纯加速/减速、可达终速轨迹都是短距离运动的正常结果。

4.3 宿主机单测(并入 tests/plsr_host

  • 相位守恒:随机 (from, cruise, exit, N, curveMode),对每个生成脉冲验证
    |Σ 1/f_timer[k] − ∫dt| 误差有界且不随 N 增长(量化闭环验收)。
  • 脉冲数精确:Σ repeatCount = N(含 CLIPPED 形态)。
  • 单调性:加速序列非降、减速序列非升。
  • 边界:N=1、N=2、预算恰等于完整梯形所需(稳态段恰为 0~1)。
  • Bug 1/2/3 配置重演:无 100Hz 尾巴;首脉冲后规划;10Hz 启动重规划。
  • 峰值对照:f_peak² ≈ 2·N·defaultSpeedHz·1000/(t1+t2) + 端点加权(补推导注释)。

5. 唯一硬件执行器(承重梁②)

5.1 执行状态机

typedef enum
{
    PLSR_EXEC_IDLE = 0,      /* 无运动 */
    PLSR_EXEC_STEP_TABLE,    /* 供给方式一:整体预展开 step 表(有限序列) */
    PLSR_EXEC_STREAM,        /* 供给方式二:队列续块流式(长段/方向切换/CLIPPED) */
    PLSR_EXEC_AB_STREAM,     /* AB 模式占位(第二阶段迁入) */
    PLSR_EXEC_REPLANNING,    /* 原子重规划过渡态(STOP/EXT/改频统一入口) */
    PLSR_EXEC_STOPPING       /* 受控停止排空 */
} PLSR_EXEC_MODE;

所有权规则(写死)

  1. STEP_TABLE 与 STREAM 只是两种数据供给方式,不是两个执行器;二者共享同一个
    执行状态机、同一套计数器/预装载推进逻辑。
  2. 只有执行器内部的 PlsrExecLoadNext() 写 PSC/ARR(写保护 guard、UIF 提交、
    generation 校验全部集中在这一个函数里)。
  3. PlsrPoll1ms、Modbus 写寄存器、STOP/EXT/动态改频、规划器:均不得直接写
    定时器寄存器
    ,只能向执行器提交请求(进入 REPLANNING)。
  4. AB 模式第一轮仍走旧路径,但必须经 PlsrExecLoadNext() 兼容出口(或加
    PLSR_RAMP_LEGACY 隔离段),保证"写 PSC/ARR 的通道唯一"这一约束自 Phase 1
    起全局成立。

5.2 供给方式选择(决策点收敛)

status = PlsrPlannerBegin(&ctx, &block, appliedHz, phase);
if (status == PLSR_PLANNER_OK || status == PLSR_PLANNER_CLIPPED) {
    /* 可整体预展开(总步数≤上限、无运行时变数)→ STEP_TABLE
       否则                                    → STREAM
       两种方式都由同一执行器消费,禁止第四条路径 */
} else {
    fault();
}
  • STEP_TABLE 限制(同向、完成模式、相对位置)放松为"规划器可整体预计算即可”;
    其余一律 STREAM。
  • STREAM 的队列生产者从"逐项二分求解"改为"从规划器输出缓冲复制”,ISR 侧不再跑
    数学。

5.3 保留的硬件语义

预装载时序(ARPE/OC1PE、UI 提交、写保护窗口)、计数器块式执行(
PLSR_COUNTER_BLOCK_PULSES、CC1 提前一脉冲准备、UI 块完成)、下降沿安全停止
PlsrFiniteStopAtFallingEdge)、停止重定向(PlsrPlatformRetargetFiniteStop
全部保留;只是这些函数变成执行器内部实现,外部不再直接调用。


6. 原子重规划协议(承重梁③)

STOP、EXT、动态改频统一走同一套过程,不再分别散落在
PlsrExecuteStop / PlsrRequestCut / PlsrFrequencyUpdatePending

6.1 统一协议

事件源:STOP 命令 | EXT 边沿(CUT 或受控) | 动态改频
   ↓
① 冻结:临界区内读三件事:
     countedPulses   = 硬件已计数脉冲(含未发布块)
     appliedHz       = 正在实际输出的频率(PlsrTimerActiveSetting)
     committed       = 已预装载、不可撤销的下一脉冲数(1~2,现
                       PlsrStopDrainPulseCount 概念的推广)
   ↓
② 失效:planGeneration++(旧 step 表 / profile 队列 / handoff 计划全部原子失效)
   ↓
③ 重规划:pulseBudget = targetPulses − countedPulses − committed
          PlsrPlannerBegin(appliedHz, phase = countedPulses)
          (STOP 必须从 appliedHz 起,不能从 commanded/preloaded 起)
   ↓
④ 切换:在下一个安全脉冲边界(UI 提交点 / 写保护窗口)由 PlsrExecLoadNext 装载
          新计划;committed 项按原计划排空后生效
   ↓
状态迁移:任意态 → REPLANNING → (STEP_TABLE | STREAM | STOPPING | IDLE)

6.2 EXT 两种语义(明确闭环)

语义 触发 行为
立即切断 EXT_OR_COMPLETE 段中 EXT 边沿 重规划为空计划,最近安全下降沿停止(与信捷 PLSR"提前结束"对齐)
受控停止 (若需求扩展配置位) 从 appliedHz 按剩余预算重规划减速,走 STOP 同一条协议

两者都必须经 REPLANNING,不允许只设一个逻辑标志等普通脉冲 IRQ 消费——这正是
当前 PlsrCutRequested 在有限路径无消费点的缺陷。

6.3 三种频率的明确区分

commandedHz    /* 逻辑层已命令(规划器请求值) */
preloadedHz    /* 已写 PSC/ARR 预装载、尚未经 UI 提交 */
appliedHz      /* 正在实际输出(PlsrTimerActiveSetting) */

重规划的起点只能是 appliedHz,预算必须扣掉 committed(已预装载不可撤销项),
否则产生一脉冲错位或 STOP 初始频率跳变。

6.4 动态改频

PlsrFrequencyUpdatePending 路径替换为:REPLANNING(新目标 Hz + 剩余预算)→
生成新轨迹 → 安全边界切换。不再局部修改旧 step 表
PlsrPlatformUpdateFiniteStep 退役),保证已预计算的后续减速段同步更新。
有限序列运行中的段频率改写亦走同一协议。


7. 失败测试先行(最高优先级动作)

在动架构之前,先把三组失败测试落在宿主机框架里(当前代码预期失败,记录失败模式):

# 用例 预期行为 当前代码失败模式
T1 有限轮廓运行中触发 EXT 最近安全边界切断,位置=已输出脉冲 CutRequested 无消费点,段跑完,cut 丢失
T2 有限加速过程中触发 STOP 从 appliedHz 受控减速,总脉冲精确,无频率跳变 时间域 ramp 与脉冲域 retarget 混用,预算不含 committed
T3 有限加减速过程中动态修改目标频率 从 appliedHz 重规划到新目标,后续减速同步更新 局部改旧 step 表 + 时间域 ramp,旧减速段残留

补充用例(Phase 2 后追加):T4 stream 模式运行中 EXT/STOP;T5 段边界 NEXT_CARRY
与 NEXT_FRESH 的 exitHz 正确性(宿主机断言规划器输入块)。

三组失败测试在 Phase 1/2 的通过情况即为验收闸门。


8. 迁移路线(优先级:所有权 → 重规划 → 统一规划器 → 曲线校准)

Phase 内容 验收闸门
0 基线锁定(bug 报告 4 配置波形存档)+ 三组失败测试落地(预期红) 基线入库;失败测试红且失败模式与 §7 表一致
1 执行状态机 PLSR_EXEC_MODE + 单一所有权:PSC/ARR 写入收敛到 PlsrExecLoadNext,AB 加 LEGACY 隔离 编译干净;旧功能全量回归;T1 失败模式变为"协议未实现”(不再是静默丢 cut)
2 原子重规划:STOP/EXT/动态改频统一入口(REPLANNING),appliedHz 起点 + committed 扣减 T1/T2/T3 转绿;板级 EXT/STOP 波形验收
3 流式规划器 + 边界语义解析器落地;时间域 PlsrRamp/PlsrMaybePlanBoundaryRamp/PlsrRampPulseEstimate 退役;量化闭环生效 宿主机全绿;Bug 1/2/3/4 配置回归通过
4 曲线校准:正弦/S 曲线与信捷对标数据(PLSR信捷对标追踪矩阵.md)逐点校准 对标矩阵通过;波形时频曲线容差达标
5 AB 第二阶段:AB 迁入 STREAM(规划器支持 pairPsc) AB 验收用例全量回归

每 Phase 的板级对比容差:总脉冲数精确、时频曲线形状一致、无速度跳变;逐 tick
频率值不作为对比基准(脉冲域规划无 1ms 台阶,理论上优于时间域)。


9. 验收标准汇总

  1. 宿主机测试:现有 test_plsr_host.c 全绿 + 新增规划器/执行器/重规划单测全绿。
  2. 失败测试:T1/T2/T3 转绿(Phase 2 后),T4/T5 转绿(Phase 3 后)。
  3. Bug 报告回归表:
配置 预期
bug1:100000/100/100/100/100/1000 三角平滑到 100Hz,总时长 ~64ms,无 100Hz 尾巴
bug2:加速 10ms/启动 100Hz/1000 脉冲 首脉冲后完整加速可见,总时长 ~20ms
bug3:启动 10Hz/1000 脉冲 首脉冲等待 100ms 后按剩余脉冲重新规划
TC-PD-011:10 段恒速 1000Hz 段间间隙 <1ms
  1. 波形验收:wave_viewer.py / bin_to_time_freq.py 时频曲线 vs 理论曲线。
  2. 诊断寄存器:COUNT_PASS / FREQUENCY_PASS / CURVE_PASS 全置位。

10. 风险与回退

  1. 量化闭环的定点取舍:相位累计用 Q32 整数(沿用 PlsrRampAreaQ32),量化
    反馈用 actualHz 反推真实周期,宿主机单测必须覆盖"长期累计误差有界”。
  2. REPLANNING 与中断竞态:冻结读三件事与 generation 失效必须在同一临界区;
    宿主机测试覆盖"重规划瞬间恰好产生脉冲"用例(现有 PlsrTestEmitPulseOnCriticalEntry
    等桩已具备此能力)。
  3. STREAM 队列生产者耗时:改纯复制后 PLSR_DEBUG_TIMING 对比改前改后
    PlsrProfileProducerMaxItemCycles 应显著下降)。
  4. AB 隔离:Phase 1 起 PlsrExecLoadNext 是唯一写通道;AB 旧路径经 LEGACY
    出口兼容,防止出现第二写通道。
  5. 回退:Phase 2 之前不改平台层;Phase 3 是唯一大删除点,要求 Phase 2 的
    T1~T3 全绿 + 板级波形对比通过后才合并。

版本历史

  • V1.0(2026-08-15):审查初版。规划器接口、Phase 路线;存在四缺:无多段语义层、
    无唯一执行器所有权、重规划不统一、量化不进闭环;脉冲守恒公式表述错误。
  • V1.1(2026-08-15):采纳审查意见修订。新增 §3 边界语义解析层、§5 执行状态机与
    所有权规则、§6 原子重规划协议、§7 失败测试先行;修正 §4 守恒公式与 CLIPPED
    语义;迁移路线按"所有权 → 重规划 → 统一规划器 → 曲线校准"重排。