141 lines
14 KiB
Markdown
141 lines
14 KiB
Markdown
# RS485 → Pharos LPC 灯光控制项目总结
|
||
|
||
日期:2026-10-09(2026-10-10 更新:**LPC 自治架构**——照度采集+闭环移入 LPC Lua,Ubuntu 只做监控/记录)
|
||
状态:✅ 全部验证通过(LPC 自治闭环实测收敛 484 Lux≈目标 500;网页控制台 v3 回归全过:FX/SC/BRT 经 HTTP 触发器下发、联动开关切换 lux_link_on、历史曲线含 LPC lux)
|
||
|
||
## LPC 自治架构(2026-10-10)
|
||
|
||
- 传感器、LPC 串口、Ubuntu USB-485 同一条 RS485 总线;LPC 串口改 **RS485/4800/8N1** 后由 LPC 独占主机轮询,Ubuntu 串口命令链路废弃
|
||
- 新增触发器:**#14 LuxPoll**(Real Time 高级掩码每秒)→ Output Serial hex `02030002000265F8`(Modbus 读地址 2 输入寄存器 0x0002,32 位 lux);**#15 LuxIn**(Serial Input,Hex 匹配 `020304<4c><2c>`,`<4c>` 捕获 32 位 lux 到变量 1,`<2c>` 吞 CRC)→ `lpc_modbus_lux.lua`(`lux_value=lux` 全局暴露 + `lux_link_on` 开关 + `lux_poll_s` 调节间隔闸门 + `lux_fade` 渐变 + **自适应模型闭环**:在线辨识 k=Δlux/Δlevel(EMA、限 100~10000、限幅时不采样),步长 `err/k` 一步到位、上限 20%,误差变号减半防震荡,基准亮度 `lux_cur_level` 累加避免硬件量化吞小步长、偏差>5% 重同步;替代旧 P 调节 GAIN 0.3/最小步长 2% 的死区极限环);**#16/#17 LuxLinkOn/Off**(ASCII `LLON`/`LLOFF`);**#18 LuxFadeSet**(`FAD=<4d>`,0.1s 单位→`lux_fade`)/ **#19 LuxPeriodSet**(`PER=<4d>` 1~60→`lux_poll_s`)/ **#20 LuxDeadbandSet**(`DBD=<4d>` 1~1000→`lux_deadband`,默认 1 Lux),均可 HTTP `?num=N&var=V` 触发
|
||
- **注意**:LPC Lua 直接调 `os.time()` 会中断脚本(无报错日志),须 `pcall(function() return os.time() end)` 兜底(失败退化为计数分频)
|
||
- lux 对外暴露用 **Lua 全局变量 + `GET /api/lua?variables=lux_value`**(`set_text_slot` 在 Lua 不可用;text slot 仅 HTTP PUT/GET)
|
||
- HTTP 触发器带参:`POST /api/trigger?num=N&var=V`(实测 #9 var=600→lux_target=600)
|
||
- 网页控制台 v3:`/send` 改 `POST /api/trigger`(BRT→#2、LUX→#8、LXT→#9、LX2→#10、FX→#11、SC→#12),`/luxlink` 改 #16/#17 + 读 `lux_link_on`/`lux_value`,采样器不再碰串口;`lux_sync.py`/`poll_lux.py` 停用(避免双主机抢总线)
|
||
- 实测:上传后 T1 重启,lux 0→(升光)→饱和回落→收敛 484 Lux(死区内),level 稳定 100%;LLON/LLOFF HTTP 切换正常
|
||
|
||
## 系统架构
|
||
|
||
```
|
||
照度传感器(地址2) ─┐
|
||
发送方(PC/ESP32)─┼─ RS485 总线(4800 8N1,2026-10-10 起)──> Pharos LPC 0140650 (192.168.58.109)
|
||
Ubuntu USB-485 ────┘ (LPC 为主机每秒轮询传感器;ASCII 命令帧仍可用)
|
||
│ Serial Input 触发器 + Quick Script (Lua)
|
||
├─> get_group(0):set_master_intensity() → "All Fixtures" 组
|
||
└─> 32 × Generic Conventional 8 bit 灯具 → DMX universe 1 通道 1~32
|
||
```
|
||
|
||
## Patch(2026-10-09 新增)
|
||
|
||
- Layout 1:32 个 `Generic > Conventional 8 bit` 灯具(8 列 × 4 行),自动归入组 `All Conventional 8 bit`
|
||
- Patch:灯具 1~32 → DMX universe 1 通道 1~32(`dmx:1:N`),Controller 2 占用 32/512
|
||
- 调光粒度:Group 0 `All Fixtures` 的 master_intensity 作为总调光作用于全部 32 通道(现有 BRT/LUX/LX2 脚本无需修改)
|
||
- **eDMX Pass-Through 已改为 None**(本地模式):实测直通优先级高于本地输出(外部源发黑场时本地 255 也出不来,通道显示 `=0`),二者无法叠加,只能二选一;如需恢复直通:Patch 视图 → DMX universe 1 → eDMX Pass-Through 下拉选 `1: ArtNet In`
|
||
- **灯具强度来源**:组 master_intensity 只是缩放系数,灯具自身 intensity 须由 Timeline/Override 提供;当前用 `PUT /api/override {"target":"group","num":0,"intensity":255}` 拉满。注意 **Upload 会清空 Override**,上传后需重新下发
|
||
- 输出回读:`GET /api/output?universe=dmx:1`(`"0"`=已patch,`"=0"`=外部直通,`"!255"`=override)
|
||
- `/api/fixtures` 现返回 32 个灯具;`/api/group` 返回 `All Fixtures`(num 0) + `All Conventional 8 bit`
|
||
- GUI 操作要点:Patch 视图从左侧灯具树**拖拽**灯具到通道网格格子即完成 Patch(点击/双击格子无效)
|
||
|
||
## 通信协议(ASCII 帧,`\n` 结尾)
|
||
|
||
| 帧格式 | 含义 | LPC 触发器 |
|
||
|--------|------|-----------|
|
||
| `BRT=NNN` | 手动亮度 0~100%(3 位补零) | #2 |
|
||
| `LUX=NNNNNN` | 实测照度 0~200000 Lux(6 位补零)→ 闭环自动调光 | #8 Lux Auto Dim |
|
||
| `LXT=NNNNNN` | 设定目标照度(默认 500 Lux,全局变量 `lux_target`) | #9 Lux Target Set |
|
||
| `LX2=NNNNNN` | 照度→亮度对数映射(指示模式,灯=照度计):`level=log(lux+1)/log(200001)`,0.5s 渐变 | #10 Lux Display Map |
|
||
| `FX=NN` | 灯光效果 01~04 → 启动 Timeline N(2 位数字) | #11 FXSelect |
|
||
| `SC=NN` | 场景 01~04 → 释放全部 Timeline + 组 Override 静态亮度(2 位数字) | #12 SC Select |
|
||
|
||
## FX/SC 效果与场景(2026-10-09 新增)
|
||
|
||
- **Timeline(FX)**:T1 常亮(White 0-30s 直出 255);T2 呼吸(4 个 White 块 0-8/8-16/16-24/24-30s,Fade 4/Release 4,末块 3/3);T3 闪烁(White 0-30s,Shape=Square,Base 0 / Size 255 / Period 1s);T4 缓变(White 0-30s,Fade 15/Release 15)
|
||
- **场景(SC)**:SC=01 全亮 255 / 02 半亮 128 / 03 微亮 26 / 04 全灭 0,由 `get_group_override(0):set_intensity(level, 1.0)` 实现(0-255 整数)
|
||
- **互斥逻辑**:FX 脚本先 `get_group_override(0):clear(1.0)` 再 `get_timeline(n):start_release_others()`;SC 脚本先 `release()` 全部 4 条 Timeline 再设 Override,避免互相遮蔽
|
||
- **循环播放(2026-10-10 修复)**:Timeline 播完 Length 默认 released(灯灭)。工具栏 Loop 按钮(x=358,标尺末端出循环标记)已开启但实测对控制器不生效;实际靠触发器 **#13 FXLoop**(Timeline Ended, Any → `get_timeline(tv.integer):start()`)重启实现无限循环。SC 的 release() 属 Timeline Released,不会触发 FXLoop 误重启。实测 FX=01 两次跨过 30s 边界 pos 回绕、state 恒 running、onstage 恒 true
|
||
- **照度叠加不变**:BRT/LUX/LX2 仍写 Group 0 master_intensity,作为总调光系数乘在 Timeline/Override 基础亮度之上
|
||
- Timeline GUI 操作要点:**双击右侧 Built-in 面板效果进入放置模式(画布蓝框),再单击画布空白处提交**(拖拽不可靠;落在已有块上会被拒绝);块只在选中时渲染;后块紧邻时前块 Release 字段锁定置灰(需在放置后块之前设好 Release);Ctrl+C/V 复制块无效
|
||
|
||
LX2 映射对照:1 Lux→6% / 10→19% / 100→38% / 500→51% / 1k→57% / 10k→75% / 100k→94% / 200k→100%(与 LUX 闭环相互独立,后到的帧生效)
|
||
|
||
闭环调光参数:死区 ±50 Lux,步进 = |误差|/目标 × 0.3(限幅 2%~20%),亮度限幅 5%~100%,1 秒渐变。
|
||
|
||
## 成果文件清单
|
||
|
||
### Windows 侧 `C:\Users\tonycao\work\lpc-rs485\`
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `rs485_verification_plan.md` | 设计/验证文档(含实测结论、通配符语法、API 要点) |
|
||
| `SETUP.md` | 搭建步骤说明(硬件接线 / Designer 项目 / Timeline / 触发器 / Ubuntu 部署) |
|
||
| `USAGE.md` | 使用说明(协议命令表 / 发送方式 / API 查询 / 常见问题) |
|
||
| `TEST_REPORT.md` | 功能测试报告(50 项全部通过,含 FX/SC 现场回归取证) |
|
||
| `SUMMARY.md` | 本文档 |
|
||
| `lpc_serial_brt.lua` | LPC 触发器 #2 脚本:BRT 手动亮度 |
|
||
| `lpc_serial_lux.lua` | LPC 触发器 #8 脚本:LUX 闭环自动调光 |
|
||
| `lpc_serial_lxt.lua` | LPC 触发器 #9 脚本:LXT 设目标照度 |
|
||
| `lpc_serial_lx2.lua` | LPC 触发器 #10 脚本:LX2 照度→亮度对数映射 |
|
||
| `lpc_serial_fx.lua` | LPC 触发器 #11 脚本:FX 效果选择(清 Override + 启 Timeline N) |
|
||
| `lpc_serial_sc.lua` | LPC 触发器 #12 脚本:SC 场景选择(释放 Timeline + Override 亮度预设) |
|
||
| `lpc_fxloop.lua` | LPC 触发器 #13 脚本:Timeline Ended → 重启该时间线(FX 循环播放) |
|
||
| `lpc_modbus_lux.lua` | LPC 触发器 #15 脚本:Modbus 照度闭环(复用 #8 逻辑 + `lux_value` 全局暴露 + `lux_link_on` 开关) |
|
||
| `lpc_web.py` | 网页控制台 v3(部署于 Ubuntu `~/rs485-lpc/`,http://192.168.58.7:8090):实时状态 + FX/SC/BRT(HTTP 触发器)+ 联动开关(#16/#17)+ 48h 历史曲线(30s 采样 LPC API,存 `history.jsonl`) |
|
||
| `lx2_test.sh` | LX2 映射回归(8 档照度→亮度对照,PASS=8) |
|
||
| `loop_test.sh` | BRT 闭环回归(5 项,PASS=5) |
|
||
| `lux_test.sh` | 照度闭环回归(7 项:死区/降光/升光/上下限幅,PASS=7) |
|
||
| `api_smoke.sh` | LPC HTTP API 冒烟测试 |
|
||
| `test_rs485.py` | Ubuntu 串口收发工具(`-l/-p/-b/-s/-w/-i`) |
|
||
| `Test-Rs485.ps1` | Windows 串口自收发测试 |
|
||
| `Verify-Rs485.ps1` | 离线 S1~S4 验证脚本(16/16 PASS,需 UTF-8 BOM) |
|
||
| `ui.ps1` | Designer 2 GUI 自动化(点击/双击/右键/拖拽/SendKeys/截图/窗口最大化) |
|
||
| `Run-Remote.ps1` | Posh-SSH 远程执行(Ubuntu 192.168.58.7) |
|
||
| `Get-Remote.ps1` | Posh-SSH SFTP 下载 |
|
||
|
||
### Designer 2 项目
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `0140650.pd2`(本目录) | 项目文件(触发器 #1/#2/#8-#20 含 LuxPoll/LuxIn/LuxLinkOn/Off/LuxFadeSet/LuxPeriodSet/LuxDeadbandSet + 4 条 Loop Timeline,串口 RS485 4800 8N1),已上传 LPC(2026-10-10 19:56 归档) |
|
||
|
||
### 参考文档 `docs\`
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `renke-illuminance-485-200k-manual.pdf` | 仁科光照度变送器(485 型 20w)使用说明书 |
|
||
| `modbus-illuminance-packet-formats.md` | 仁科/耘农 Modbus 帧格式实测笔记 |
|
||
|
||
### Ubuntu 侧(192.168.58.7,USB-485 = `/dev/ttyUSB0`)
|
||
|
||
| 路径 | 说明 |
|
||
|------|------|
|
||
| `~/rs485-lpc/loop_test.sh` | BRT 回归(与 Windows 侧同步) |
|
||
| `~/rs485-lpc/lux_test.sh` | 照度闭环回归(已部署,7/7 PASS) |
|
||
| `~/rs485-lpc/api_smoke.sh` | LPC HTTP API 冒烟测试 |
|
||
| `~/rs485-lpc_test_rs485.py` | 串口发送工具 |
|
||
|
||
## 验证记录
|
||
|
||
- 2026-10-09 离线 S1~S4:16/16 PASS
|
||
- 2026-10-09 BRT 闭环:5/5 PASS(100/0/50/80/25)
|
||
- 2026-10-09 LUX 闭环回归:死区 / 超目标降光 / 欠目标升光 / 上下限限幅 全部通过(lux_test.sh 7/7 PASS)
|
||
- 2026-10-09 LX2 照度指示映射:8 档对数映射全过(lx2_test.sh 8/8 PASS)
|
||
- 2026-10-09 Patch 32 通道(DMX 1~32)并 Upload;回归抽测 BRT=050→level 50、BRT=000→level 0 通过
|
||
- 2026-10-09 FX/SC:FX=01 常亮 255(T1 running)/ FX=02 呼吸(255→202 渐变)/ FX=03 闪烁(255/0 交替)/ FX=04 缓变(39→75→110 缓升);SC=02→128 / SC=04→0(Override 生效、Timeline 释放);FX 与 SC 互斥切换正常
|
||
- 2026-10-10 FX 循环修复:发现 FX 播完 30s 即 released 灯灭;Loop 工具栏按钮单独开启无效,加触发器 #13 FXLoop(Timeline Ended 重启)后实测 FX=01 连续 2 个循环 pos 回绕(29500→1550→…→27980→20)输出不掉 0;FX=02 跨 30s 仍 running;SC=04 释放后 35s 保持 released 无误重启
|
||
- 2026-10-10 照度功能验证:传感器在线(Modbus 地址 2 @4800,实测 26 Lux);手动 LUX 闭环升/降/死区正常(LUX=10→level 50→70,LUX=10000→50,LUX=500 死区不动);LX2=10→level≈20;lux_sync.py 端到端 26 Lux → BRT=73 → group level=73 → 输出随动
|
||
- 2026-10-10 LPC 自治改造:触发器 #14(每秒 Modbus 轮询)+#15(hex 通配符捕获+Lua 闭环)+#16/#17(联动开关)建成并上传;LPC 日志确认 #14 Matched 207 次 / #15 Captured 2 variables 244 次;闭环实测 lux 0→饱和→收敛 484(目标 500±50 死区),`/api/lua?variables=lux_value` 实时可读;HTTP 带参触发(`?num=9&var=600`)验证通过;网页控制台 v3 回归:FX=02→T2 running、BRT=060→level 60、luxlink off/on→lux_link_on false/true、history 采样含 LPC lux=479
|
||
|
||
## 关键技术结论(官方文档未载)
|
||
|
||
1. **串行通配符语法**:`<3d>` = 恰好 3 位数字(数字在前,类型 `[cCdDxXsS]`);`?` `*` `#` `%` 均为普通字符
|
||
2. **Designer 2 触发变量**:`get_trigger_variable(1)`(v1 的 `variable[1]` 已废弃)
|
||
3. **组亮度 API**:`get_group(n):set_master_intensity(level[, fade])`,读当前值用 `grp.master_intensity_level.integer / .range`
|
||
4. **LPC HTTP API 免认证**:`GET /api/group`(`level` 字段回读)、`/api/trigger`、`/api/log`
|
||
5. **LPC 自治照度闭环(2026-10-10)**:Serial Input hex 匹配串支持通配符 `<4c>`(捕获 32 位)/`<2c>`(吞 16 位 CRC);Real Time 触发器高级掩码秒级分辨率可每秒触发 Output Serial 静态 hex 帧(Modbus 轮询);lux 经 Lua 全局变量 + `GET /api/lua?variables=` 暴露(`set_text_slot` 非 Lua 函数);HTTP 触发器带参 `POST /api/trigger?num=N&var=V`。**GUI 自动化**:Serial Input/Output 的 String 框逐键输 `<` 不进(中文布局/过滤),须 Set-Clipboard + ^v 粘贴;Upload 对话框须先点选设备行再点 Upload All
|
||
6. **Timeline 循环(2026-10-10)**:工具栏三个易混按钮——Hold At End(→|)、Loop(↻ 单环,运行时循环)、Enable Looping(↻ 两点,仅编辑器仿真,不上传)。实测 Loop 按钮开启(标尺末端有循环标记、保存、上传)后控制器仍在 Length 处 released;可靠方案是 **Timeline Ended 触发器 + `tl:start()`**(Timeline Ended/Started/Released 在 Timeline=Any 时把时间线号捕获到变量 1;Ended 不在 Hold 时触发,Released 是独立类型,SC 释放不会误触发)。本地帮助:`C:\Program Files\Pharos Controls\Designer 2\help\content\help\reference\timeline\working with timelines.htm`
|
||
|
||
## 仁科照度计参考(esp32-voice 项目)
|
||
|
||
- 大量程 0~200000 Lux 型:32 位寄存器对 0x0002(hi)/0x0003(lo),单位 1 Lux
|
||
- ESP32 侧实现:`src/config.rs`(MODBUS_ILLUMINANCE_REG=0x0002, COUNT=2)、`src/modbus/master.rs` `poll_illuminance()`
|
||
- 文档:esp32-voice `docs/` 原件;本项目 `docs/` 已归档副本(20w 说明书 PDF + 帧格式笔记)
|