rs485-lpc/SUMMARY.md

14 KiB
Raw Permalink Blame History

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 + 帧格式笔记)