feat: 新增单路流入口 SensorStream(T08a)
SensorStream 串起 Sensor/SensorContext、ImagePipeline 与 ForceStreamSession:实时模式只保留最新候选并计数覆盖;StreamPipeline 负责线程与原子复位版本,力侧只在 HHD 线程的 on_frame 中运行;reset_and_zero 原子领取目标版本,在力线程帧边界发起同版本空载归零,每次调用只等待自己的命令结果;借用的 Sensor 不被关闭,stop 后恢复原来的 measurement session 状态,拥有的 Sensor 在 stop 时关闭。回归 402 项、lint 通过。
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# 新力侧会话(T06a/T06b、T07 输出滤波)
|
||||
# 新力侧会话与单路入口(T06a/T06b、T07 输出滤波、T08a)
|
||||
|
||||
本文件是单路 SensorStream 计划 T06a/T06b/T07 的 SDK 合同:新的力侧会话直接消费 T05 的
|
||||
`ImageMeasurement`(T03 `MeasurementFrame` 头 + 同帧 raw/field),参考版本取帧上的
|
||||
@@ -73,6 +73,52 @@ assert session.output_settings.median_window == 3, "switch waits for a frame bou
|
||||
assert session.design_sample_rate_hz == 30.0
|
||||
```
|
||||
|
||||
## SensorStream 入口(T08a)
|
||||
|
||||
`SensorStream` 把 T04–T07 串成一个运行中的单路入口:
|
||||
|
||||
- **所有权。** `SensorStream.open(source, ...)` 自己打开 Sensor 并在 `stop()` 关闭;调用方传入
|
||||
已打开的 Sensor 或外部喂帧时只借用,`stop()` 不关闭借用源。运行中只有一个采集所有者;
|
||||
流在 `start()` 启用 measurement session,`stop()`/启动失败时恢复借用 Sensor 原来的模式
|
||||
(原本已启用的保持启用)。
|
||||
- **实时 latest。** `push_frame(...)` 的未领取候选帧会被最新输入覆盖并计入
|
||||
`overwritten_frames`;已经交给流水线的帧照常完成。`wait_output()` 是 latest-wins 结果流,
|
||||
`drain_events()` 取会话事件。
|
||||
- **线程/版本。** 复用 `StreamPipeline` 的线程与原子 `request_reset()` 版本;力侧只在 HHD
|
||||
线程的 `on_frame` 中调用 `ForceStreamSession`,因此 T07 的 `drain_events` 线程约束由门面满足,
|
||||
没有第二套版本或复位记账。
|
||||
- **组合归零。** `reset_and_zero(reference_id=...)` 执行“图像复位确认 → 同版本 30 帧无载基线 →
|
||||
力 ready”;用户不管理版本号。在途旧版本帧不会进入新基线(T06a 的规则)。每次调用只等待
|
||||
本条命令的结果:力线程把该命令的 `ZeroProgress`/错误写回命令对象并通知,调用方线程不读取
|
||||
`session.zero`,因此连续两次调用时第二次不会复用第一次的零点。
|
||||
- **T08a 边界。** 实时模式、无标定/标量会话、逐帧结果最新视图已实现;field/contact 的
|
||||
`include`、文件/debug 完整逐帧、有界背压、时间来源与 PTS 标注、`source_dt_s`/长间隔诊断和
|
||||
完整生命周期诊断属于 **T08b**。
|
||||
- **时间基准(T08b 实现约定)。** 实时相机 `capture_monotonic`;Orisys 自己录像(文件内保存
|
||||
信号时间)`recorded_signal`;外部调用方提供可证明的容器 PTS 才 `video_pts`;内置 OpenCV
|
||||
读取普通视频文件用 `estimated_source`,`capture_time_ns` 按 `source_frame_id ÷ 名义帧率` 推算,
|
||||
POS_MSEC 只进 diagnostics。T08a 的外部帧默认 `capture_monotonic`。
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from orisys.sensor import Sensor
|
||||
from orisys.sensor_stream import SensorStream
|
||||
|
||||
sensor = Sensor("external", config_name="box", verbose=False, backend="cpu")
|
||||
stream = SensorStream(sensor, sensor_id="BOX-001", session_id="run-1")
|
||||
stream.start()
|
||||
try:
|
||||
stream.push_frame(
|
||||
np.full((365, 365), 100, dtype=np.uint8),
|
||||
source_frame_id=0,
|
||||
capture_time_ns=1_000_000_000,
|
||||
)
|
||||
output = stream.wait_output(timeout=5.0)
|
||||
assert output is not None and output.frame.stamp.sensor_id == "BOX-001"
|
||||
finally:
|
||||
stream.stop()
|
||||
```
|
||||
|
||||
## 示例
|
||||
|
||||
```python
|
||||
@@ -98,8 +144,8 @@ assert row.zero.phase in ("resetting", "collecting")
|
||||
## 后续
|
||||
|
||||
T06b 已交付标量/field/FN-only 三类标定与旧 ForceSession 的完整数值等价;T07 已交付固定
|
||||
设计帧率、显式切换事件与历史/直通合同。spatial_gain/接触映射模型不在 T06/T07 验收范围,
|
||||
需要时另立任务。
|
||||
T08 接单路流入口;T09/T10 迁移 App 后删除旧 `ForceSession`。
|
||||
设计帧率、显式切换事件与历史/直通合同;T08a 已交付 SensorStream 实时入口、所有权与组合归零。
|
||||
spatial_gain/接触映射模型不在 T06/T07 验收范围,需要时另立任务。
|
||||
T08b 补齐文件/debug 完整逐帧、有界背压、时间来源/PTS 标注与完整诊断后再进入 T09/T10(App 迁移)。
|
||||
另一项后续任务:删除旧 `ForceSession` 之前,先把零点、标定、读数引擎从旧类中抽出来,
|
||||
避免新会话依赖待删除的类型(T09 之前)。
|
||||
|
||||
Reference in New Issue
Block a user