pCCU新增锂电池通信/协调操作 + 电源协调状态机骨架(惰性)
锂电池通信(docs/锂电池协议20230324.docx): - 协议层 BatProtocol:自检0x0000(2B)/设备控制0x0001(17B)/电池组状态0x0003(80B)/ 电池包报警0x0004(68B),uint32字节和校验、小端 - 链路层 BatLinkManager:动力/仪表锂电池独立UDP链路,本机监听与远端IP端口 均由.moos配置(dyn_bat_*/ins_bat_*/bat_work_condition) - SystemData/SnapshotBuilder/网页:电池数据按动力/仪表归类展示(运行状态/接触器 电气量/电池包电压温度/报警),收发帧落库SQLite,网页新增电池标签页 操作->指令下发(PowerCoordinator): - 操作接口:自检/上下电(母线接触器55H接通77H断开,含预充)/功率设定(0~500kW)/ 电池切换(低压->高压6步、高压->低压5步,按协议时序) - 步骤引擎:每电池独立步骤队列,下发->状态反馈确认->超时兜底;周期1s心跳控制帧 - PM操控指令insBatCmd/dynBatCmd/dynBatPower自动映射为电池操作 电源协调状态机骨架(CoordFsm, TinyFSM): - 事件Tick/PmControl/StepDone + 状态Normal/Switching/Fault,react均为TODO占位 - 当前未接线(无start/dispatch调用,运行行为与接入前一致),CoordFsm.hpp头部附接线指南 测试与部署: - pccuTest新增电池协议编解码/帧长/链路分发用例(175项通过);集成测试覆盖电池 心跳、启停映射(0x10->0x55/0x20->0x77)、状态落库;同步pccu_it.moos与ws_check - h100.moos与pCCU.moos增加锂电池链路配置;归档锂电池协议文档
This commit is contained in:
+111
-3
@@ -14,8 +14,11 @@ CCU::CCU() {}
|
||||
|
||||
CCU::~CCU() {
|
||||
if (m_web) { m_web->stop(); delete m_web; m_web = nullptr; }
|
||||
if (m_coord) { delete m_coord; m_coord = nullptr; }
|
||||
if (m_fcLink) { m_fcLink->stop(); delete m_fcLink; m_fcLink = nullptr; }
|
||||
if (m_pmLink) { m_pmLink->stop(); delete m_pmLink; m_pmLink = nullptr; }
|
||||
if (m_dynBatLink) { m_dynBatLink->stop(); delete m_dynBatLink; m_dynBatLink = nullptr; }
|
||||
if (m_insBatLink) { m_insBatLink->stop(); delete m_insBatLink; m_insBatLink = nullptr; }
|
||||
if (m_db) { delete m_db; m_db = nullptr; }
|
||||
if (m_snap) { delete m_snap; m_snap = nullptr; }
|
||||
if (m_sysData) { delete m_sysData; m_sysData = nullptr; }
|
||||
@@ -46,6 +49,13 @@ bool CCU::OnStartUp() {
|
||||
else if (param == "pm_local_port") m_pmLocalPort = atol(value.c_str());
|
||||
else if (param == "pm_remote_ip") m_pmHost = value;
|
||||
else if (param == "pm_remote_port") m_pmPort = atol(value.c_str());
|
||||
else if (param == "dyn_bat_local_port") m_dynBatLocalPort = atol(value.c_str());
|
||||
else if (param == "dyn_bat_remote_ip") m_dynBatHost = value;
|
||||
else if (param == "dyn_bat_remote_port") m_dynBatPort = atol(value.c_str());
|
||||
else if (param == "ins_bat_local_port") m_insBatLocalPort = atol(value.c_str());
|
||||
else if (param == "ins_bat_remote_ip") m_insBatHost = value;
|
||||
else if (param == "ins_bat_remote_port") m_insBatPort = atol(value.c_str());
|
||||
else if (param == "bat_work_condition") m_batWorkCondition = atol(value.c_str());
|
||||
else if (param == "dbpath") m_dbPath = value;
|
||||
else if (param == "logpath") m_logPath = value;
|
||||
else if (param == "web_port") m_webPort = atoi(value.c_str());
|
||||
@@ -101,8 +111,33 @@ bool CCU::OnStartUp() {
|
||||
if (!m_pmLink->start())
|
||||
LOG_F(ERROR, "PM link start failed");
|
||||
|
||||
// 锂电池链路(动力 / 仪表)
|
||||
m_dynBatLink = new BatLinkManager(BatRole::Dyn, m_dynBatLocalPort, m_dynBatHost, m_dynBatPort);
|
||||
m_dynBatLink->setLogSink(m_db);
|
||||
m_dynBatLink->setOnMessage([this](Message* msg, const std::vector<uint8_t>& frame) {
|
||||
handleBatMessage(BatRole::Dyn, msg, frame);
|
||||
});
|
||||
m_dynBatLink->setOnRawFrame([](int, const std::vector<uint8_t>&, bool) {});
|
||||
if (!m_dynBatLink->start())
|
||||
LOG_F(ERROR, "Dyn battery link start failed");
|
||||
|
||||
m_insBatLink = new BatLinkManager(BatRole::Ins, m_insBatLocalPort, m_insBatHost, m_insBatPort);
|
||||
m_insBatLink->setLogSink(m_db);
|
||||
m_insBatLink->setOnMessage([this](Message* msg, const std::vector<uint8_t>& frame) {
|
||||
handleBatMessage(BatRole::Ins, msg, frame);
|
||||
});
|
||||
m_insBatLink->setOnRawFrame([](int, const std::vector<uint8_t>&, bool) {});
|
||||
if (!m_insBatLink->start())
|
||||
LOG_F(ERROR, "Ins battery link start failed");
|
||||
|
||||
// 电源协调器(操作->指令下发 + 锂电池/燃料电池协调占位)
|
||||
m_coord = new PowerCoordinator();
|
||||
m_coord->setup(m_sysData, m_fcLink, m_pmLink, m_dynBatLink, m_insBatLink);
|
||||
m_coord->setWorkCondition(static_cast<uint8_t>(m_batWorkCondition));
|
||||
|
||||
// 快照构建器(链路就绪后创建)
|
||||
m_snap = new SnapshotBuilder(m_sysData, m_fcLink, m_pmLink, m_db);
|
||||
m_snap = new SnapshotBuilder(m_sysData, m_fcLink, m_pmLink,
|
||||
m_dynBatLink, m_insBatLink, m_db);
|
||||
|
||||
// 网页
|
||||
if (m_webEnable) {
|
||||
@@ -118,9 +153,12 @@ bool CCU::OnStartUp() {
|
||||
}
|
||||
}
|
||||
|
||||
LOG_F(INFO, "pCCU started: fc_link local=%ld -> %s:%ld, pm_link local=%ld -> %s:%ld",
|
||||
LOG_F(INFO, "pCCU started: fc_link local=%ld -> %s:%ld, pm_link local=%ld -> %s:%ld, "
|
||||
"bat_dyn local=%ld -> %s:%ld, bat_ins local=%ld -> %s:%ld",
|
||||
m_fcLocalPort, m_fcHost.c_str(), m_fcPort,
|
||||
m_pmLocalPort, m_pmHost.c_str(), m_pmPort);
|
||||
m_pmLocalPort, m_pmHost.c_str(), m_pmPort,
|
||||
m_dynBatLocalPort, m_dynBatHost.c_str(), m_dynBatPort,
|
||||
m_insBatLocalPort, m_insBatHost.c_str(), m_insBatPort);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -140,6 +178,8 @@ void CCU::registerVariables() {
|
||||
// pCCU 数据交换主要走 UDP;MOOSDB 仅登记运行状态变量
|
||||
Register("CCU_FC_LINK_STATE", 0);
|
||||
Register("CCU_PM_LINK_STATE", 0);
|
||||
Register("CCU_DYN_BAT_LINK_STATE", 0);
|
||||
Register("CCU_INS_BAT_LINK_STATE", 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
@@ -169,6 +209,10 @@ bool CCU::Iterate() {
|
||||
m_lastStatusTx = now;
|
||||
}
|
||||
|
||||
// 电源协调器:操作步骤推进 + 锂电池心跳指令(1s) + 协调算法占位
|
||||
if (m_coord)
|
||||
m_coord->tick(now);
|
||||
|
||||
// 周期(1Hz)推送网页快照
|
||||
if (m_web) {
|
||||
static double lastWebPush = 0;
|
||||
@@ -234,6 +278,16 @@ void CCU::handlePmMessage(Message* msg, const std::vector<uint8_t>& frame) {
|
||||
m_sysData->updateFcControl(f);
|
||||
m_fcLink->sendMessage(0x0001, &f);
|
||||
LOG_F(INFO, "[FC] forward control cmd=%d power=%d", f.cmd, f.outputPower);
|
||||
|
||||
// 锂电池启停/功率指令 -> 生成电池操作序列(协调器按步骤下发)
|
||||
// 启停指令:00无效 / 10启动 / 20关闭
|
||||
if (m_coord) {
|
||||
if (c.insBatCmd == 0x10) m_coord->submitPowerOn(BatRole::Ins);
|
||||
else if (c.insBatCmd == 0x20) m_coord->submitPowerOff(BatRole::Ins);
|
||||
if (c.dynBatCmd == 0x10) m_coord->submitPowerOn(BatRole::Dyn);
|
||||
else if (c.dynBatCmd == 0x20) m_coord->submitPowerOff(BatRole::Dyn);
|
||||
if (c.dynBatPower > 0) m_coord->submitSetPower(BatRole::Dyn, c.dynBatPower);
|
||||
}
|
||||
} else {
|
||||
LOG_F(ERROR, "[PM] control decode failed");
|
||||
}
|
||||
@@ -262,6 +316,43 @@ void CCU::handlePmMessage(Message* msg, const std::vector<uint8_t>& frame) {
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// handleBatMessage:处理锂电池链路收到的消息(动力/仪表共用协议)
|
||||
|
||||
void CCU::handleBatMessage(BatRole role, Message* msg, const std::vector<uint8_t>& frame) {
|
||||
if (!msg) return;
|
||||
const char* tag = (role == BatRole::Dyn) ? "BAT_DYN" : "BAT_INS";
|
||||
switch (msg->id()) {
|
||||
case 0x0003: { // 电池组状态反馈
|
||||
BatStatusValue v;
|
||||
if (msg->decode(frame, static_cast<void*>(&v))) {
|
||||
m_sysData->updateBatStatus(static_cast<int>(role), v);
|
||||
LOG_F(INFO, "[%s] status: wc=0x%02X selfCheck=0x%02X bus=0x%02X "
|
||||
"soc=%.1f%% pwr_out=%.1fkW hb=%d",
|
||||
tag, v.workCondition, v.selfCheckState, v.busContactorState,
|
||||
v.soc * 0.1, v.currentAccessPower * 0.1, v.heartbeat);
|
||||
} else {
|
||||
LOG_F(ERROR, "[%s] status decode failed", tag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0004: { // 电池包报警信息
|
||||
BatPackAlarmValue v;
|
||||
if (msg->decode(frame, static_cast<void*>(&v))) {
|
||||
m_sysData->updateBatAlarm(static_cast<int>(role), v);
|
||||
LOG_F(INFO, "[%s] pack alarm: packNo=%d alarm1=0x%02X alarm2=0x%02X",
|
||||
tag, v.packNo, v.alarmFlag[0], v.alarmFlag[1]);
|
||||
} else {
|
||||
LOG_F(ERROR, "[%s] pack alarm decode failed", tag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_F(WARNING, "[%s] unhandled msg id 0x%04X", tag, msg->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// sendPmStatus:整合最新 FC 状态,编码 PM 状态报文发送
|
||||
|
||||
@@ -398,9 +489,26 @@ bool CCU::buildReport() {
|
||||
<< " tx:" << m_pmLink->txCount()
|
||||
<< " err:" << m_pmLink->errorCount() << "\n";
|
||||
}
|
||||
if (m_dynBatLink) {
|
||||
m_msgs << "动力锂电池链路 local:" << m_dynBatLink->localPort()
|
||||
<< " rx:" << m_dynBatLink->rxCount()
|
||||
<< " tx:" << m_dynBatLink->txCount()
|
||||
<< " err:" << m_dynBatLink->errorCount() << "\n";
|
||||
}
|
||||
if (m_insBatLink) {
|
||||
m_msgs << "仪表锂电池链路 local:" << m_insBatLink->localPort()
|
||||
<< " rx:" << m_insBatLink->rxCount()
|
||||
<< " tx:" << m_insBatLink->txCount()
|
||||
<< " err:" << m_insBatLink->errorCount() << "\n";
|
||||
}
|
||||
if (m_coord) {
|
||||
m_msgs << "协调器待执行步骤:" << m_coord->pendingSteps() << "\n";
|
||||
}
|
||||
if (m_sysData) {
|
||||
m_msgs << "FC 状态接收次数:" << m_sysData->fcStatusCount() << "\n";
|
||||
m_msgs << "PM 指令接收次数:" << m_sysData->pmControlCount() << "\n";
|
||||
m_msgs << "动力电池状态接收次数:" << m_sysData->batStatusCount(0) << "\n";
|
||||
m_msgs << "仪表电池状态接收次数:" << m_sysData->batStatusCount(1) << "\n";
|
||||
}
|
||||
if (m_db) {
|
||||
m_msgs << "数据库记录数:" << m_db->count() << "\n";
|
||||
|
||||
Reference in New Issue
Block a user