新增复合管控器(pCCU) + 惯导数据解析 + 设备控制页增强 + 0824协议文档归档
- 新增 pCCU 复合管控器程序(src/pCCU):FC/PM 双链路(UDP)、协议编解码器 (FcProtocol/PmProtocol/Frame/Message/MessageRegistry)、快照与落库(DbStore)、 内置 WebServer;挂入 src/CMakeLists.txt 与板卡 mission(h100.moos) - 惯导/深度数据:新增 uDevice_insData 消息解析,接入 UpperCommManager, pPowerMangerHost 注册监视,UpmsgTest 覆盖 - pPowerMangerHost 设备控制页增强(web/index.html) - 部署/运维脚本改为 4 个 systemd 服务(moosdb/pPowerManger/pPowerMangerHost/pCCU): deploy/clean-data/fetch-data 同步适配 - 协议文档:归档 0824 控制主机与复合管控器通信协议 xlsx 及关联 docx,移除旧 md - 测试:新增 pccu 单元/集成测试与 disSysTest Python 配电仿真 - 清理:移除未使用的 CCU 状态调试打印 coutMsg;.gitignore 补充编译产物/临时文件忽略
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
"""内置模拟器:产生四路母线反馈,支持配电指令回显。
|
||||
|
||||
设计:模拟器状态(反馈消息 + 最近指令)独立维护;周期性调用 update()
|
||||
返回需要注入解析管线的反馈消息列表。配电指令通过 apply_command()
|
||||
回写对应断路器状态,从而与真实设备的收发链路完全一致。
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
from . import protocol
|
||||
from .protocol import (MsgDisHighVolBusFb, MsgDisHighAVolBusFb,
|
||||
MsgDisLowMainBusFb, MsgDisLowBusFb,
|
||||
BREAKER_ON)
|
||||
|
||||
|
||||
class Simulator:
|
||||
# 指令消息 ID -> 对应反馈消息 ID
|
||||
CMD_TO_FB = {0x0001: 0x0005, 0x0002: 0x0006,
|
||||
0x0003: 0x0007, 0x0004: 0x0008}
|
||||
|
||||
def __init__(self):
|
||||
self.fb = {
|
||||
0x0005: MsgDisHighVolBusFb(),
|
||||
0x0006: MsgDisHighAVolBusFb(),
|
||||
0x0007: MsgDisLowMainBusFb(),
|
||||
0x0008: MsgDisLowBusFb(),
|
||||
}
|
||||
# 最近一次配电指令(用于回显)
|
||||
self.last_cmd = {
|
||||
0x0001: protocol.MsgDisHVBCmd(),
|
||||
0x0002: protocol.MsgDisHVBACmd(),
|
||||
0x0003: protocol.MsgDisLVMBCmd(),
|
||||
0x0004: protocol.MsgDisLVBCmd(),
|
||||
}
|
||||
self.fault_animation = True
|
||||
self.noise = True
|
||||
self._fault_counter = 0
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self._init_high_vol()
|
||||
self._init_high_a_vol()
|
||||
self._init_low_main()
|
||||
self._init_low_bus()
|
||||
# 复位指令状态
|
||||
for cmd in self.last_cmd.values():
|
||||
for name in cmd.field_names():
|
||||
setattr(cmd, name, 0)
|
||||
|
||||
# ---- 初始值(与 test.py 一致) ---------------------------------
|
||||
def _init_high_vol(self):
|
||||
m = self.fb[0x0005]
|
||||
for name in m.field_names():
|
||||
setattr(m, name, 0)
|
||||
for name in ("fuelCellCircuitBreaker", "powerLithiumBatteryCircuitBreaker",
|
||||
"propulsionMotorCircuitBreaker", "lithiumBatteryGroupInstrumentCircuitBreaker",
|
||||
"dcDc5ModuleCircuitBreaker", "bowHighVoltageDistributionBoxCircuitBreaker",
|
||||
"sternFTDevice45CircuitBreaker", "sternRudderSwitch1CircuitBreaker",
|
||||
"sternRudderSwitch2CircuitBreaker", "fbReservedCircuitBreaker",
|
||||
"tyzReservedCircuitBreaker", "reservedCircuitBreaker"):
|
||||
setattr(m, name, BREAKER_ON)
|
||||
m.dcDcFaultWord1 = 0x01
|
||||
m.dcDcFaultWord2 = 0x01
|
||||
m.powerBusInsulationStatus = BREAKER_ON
|
||||
m.aBusInsulationStatus = BREAKER_ON
|
||||
m.meterPowerLossSignal = BREAKER_ON
|
||||
m.emergencyPowerLossSignal = BREAKER_ON
|
||||
m.dcdcTemperature = 0x08
|
||||
m.powerBusVoltage = 6000
|
||||
m.dcDc5ModuleCurrent = 500
|
||||
m.powerBusCurrent = 1000
|
||||
m.busbarAVoltage = 6000
|
||||
m.propulsionMotorControlBoxCurrent = 800
|
||||
m.busbarACurrent = 500
|
||||
m.lithiumBatteryGroupMeterCurrent = 300
|
||||
m.bowHighVoltageDistributionBoxCurrent = 200
|
||||
m.sternFTDevice45Current = 150
|
||||
m.tyzReservedSwitchCurrent = 0
|
||||
m.sternRudderSwitch1Current = 100
|
||||
m.reservedCurrent1 = 1000
|
||||
m.sternRudderSwitch2Current = 100
|
||||
m.reservedCurrent2 = 1000
|
||||
m.fbReservedSwitchCurrent = 10000
|
||||
m.reservedCurrent3 = 1000
|
||||
m.coolWaterPressure = 1000
|
||||
|
||||
def _init_high_a_vol(self):
|
||||
m = self.fb[0x0006]
|
||||
for name in m.field_names():
|
||||
setattr(m, name, 0)
|
||||
for name in ("bowFTDevice123CircuitBreaker", "actuatorCircuitBreaker",
|
||||
"mastSteeringGearControlBoxCircuitBreaker", "xczCircuitBreaker",
|
||||
"bowRudderControlBoxCircuitBreaker", "openWaterCoverStartCylinderCircuitBreaker"):
|
||||
setattr(m, name, BREAKER_ON)
|
||||
m.instrumentPowerFailureSignal = BREAKER_ON
|
||||
m.emergencyPowerFailureSignal = BREAKER_ON
|
||||
m.waterIngressionAlarm = BREAKER_ON
|
||||
m.busbarBVoltage = 6000
|
||||
m.busbarBCurrent = 300
|
||||
m.bowFTDevice123Current = 200
|
||||
m.actuatorCurrent = 150
|
||||
m.mastSteeringGearControlBoxCurrent = 100
|
||||
m.xczCurrent = 50
|
||||
m.bowRudderControlBoxCurrent = 80
|
||||
m.openWaterCoverStartCylinderCurrent = 0
|
||||
|
||||
def _init_low_main(self):
|
||||
m = self.fb[0x0007]
|
||||
for name in m.field_names():
|
||||
setattr(m, name, 0)
|
||||
m.lithiumBatteryGroupInstrumentCircuitBreaker = BREAKER_ON
|
||||
m.bowLowVoltageDistributionBoxCircuitBreaker = BREAKER_ON
|
||||
m.unit4InstrumentDC48VCircuitBreaker = BREAKER_ON
|
||||
m.dcC1DCDistributionPanelCircuitBreaker = BREAKER_ON
|
||||
m.reservedCircuitBreaker1 = BREAKER_ON
|
||||
m.reservedCircuitBreaker2 = BREAKER_ON
|
||||
m.emergencyLithiumBatteryGroup2CircuitBreaker = BREAKER_ON
|
||||
m.instrumentPowerFailureSignal = BREAKER_ON
|
||||
m.emergencyPowerFailureSignal = BREAKER_ON
|
||||
m.instrumentBusbarInsulationLow = BREAKER_ON
|
||||
m.instrumentBusbarVoltage = 480
|
||||
m.bowLowVoltageDistributionBoxCurrent = 100
|
||||
m.dcC1InstrumentDC48VCurrent = 50
|
||||
m.reservedCurrent1 = 1100
|
||||
m.emergencyLithiumBatteryGroup2Current = 1000
|
||||
m.lithiumBatteryGroupInstrumentCurrent = 200
|
||||
m.unit4InstrumentDC48VCurrent = 50
|
||||
m.reservedCurrent2 = 1000
|
||||
m.emergency2BusbarVoltage = 480
|
||||
m.compositeEnergyManagementSystemEmergencyDC48VCurrent = 20
|
||||
m.fuelCellSecuritySystemEmergencyDC48VCurrent = 20
|
||||
m.plcControlPowerCurrent = 10
|
||||
|
||||
def _init_low_bus(self):
|
||||
m = self.fb[0x0008]
|
||||
for name in m.field_names():
|
||||
setattr(m, name, 0)
|
||||
for name in ("unit1CircuitBreaker", "unit2CircuitBreaker",
|
||||
"unit3CircuitBreaker", "unit5CircuitBreaker",
|
||||
"bowPZDeviceCircuitBreaker", "reservedCircuitBreaker1",
|
||||
"reservedCircuitBreaker2", "emergencyLithiumBatteryGroup1CircuitBreaker"):
|
||||
setattr(m, name, BREAKER_ON)
|
||||
m.instrumentPowerFailureSignal = BREAKER_ON
|
||||
m.emergencyPowerFailureSignal = BREAKER_ON
|
||||
m.waterIngressionAlarm = BREAKER_ON
|
||||
m.instrumentBusbarVoltage = 480
|
||||
m.instrumentBusbarCurrent = 5000
|
||||
m.unit1Current = 1000
|
||||
m.unit2Current = 1000
|
||||
m.unit3Current = 1000
|
||||
m.unit5Current = 1000
|
||||
m.bowPZDeviceCurrent = 500
|
||||
m.emergencyLithiumBatteryGroup1Current = 1000
|
||||
m.emergency1BusbarVoltage = 480
|
||||
|
||||
# ---- 对外接口 ------------------------------------------------
|
||||
def apply_command(self, cmd):
|
||||
"""收到配电指令后回写对应母线反馈的断路器状态。"""
|
||||
fb = self.fb.get(self.CMD_TO_FB.get(cmd.MSG_ID))
|
||||
if fb is None:
|
||||
return
|
||||
self.last_cmd[cmd.MSG_ID] = cmd
|
||||
for name in cmd.field_names():
|
||||
if hasattr(fb, name):
|
||||
setattr(fb, name, getattr(cmd, name))
|
||||
|
||||
def _jitter(self, fb):
|
||||
"""给电流/电压叠加轻微随机波动,模拟真实读数。"""
|
||||
for name in fb.field_names():
|
||||
if name.endswith("Current") or name.endswith("Voltage") or name.endswith("Pressure"):
|
||||
v = getattr(fb, name)
|
||||
if v > 0:
|
||||
setattr(fb, name, max(0, v + random.randint(-int(v * 0.05), int(v * 0.05))))
|
||||
|
||||
def _step_fault(self):
|
||||
m = self.fb[0x0005]
|
||||
w1 = ((m.dcDcFaultWord1 << 1) | (m.dcDcFaultWord1 >> 7)) & 0xFF
|
||||
w2 = ((m.dcDcFaultWord2 >> 1) | (m.dcDcFaultWord2 << 7)) & 0xFF
|
||||
m.dcDcFaultWord1 = w1
|
||||
m.dcDcFaultWord2 = w2
|
||||
|
||||
def update(self, interval=1.0):
|
||||
"""推进一帧模拟。返回需要注入解析管线的反馈消息列表。"""
|
||||
if self.fault_animation:
|
||||
self._step_fault()
|
||||
if self.noise:
|
||||
for fb in self.fb.values():
|
||||
self._jitter(fb)
|
||||
return list(self.fb.values())
|
||||
Reference in New Issue
Block a user