水利工程沙盘模型覆盖水利枢纽(大坝、泄洪闸、溢洪道、发电厂房)、防洪调度(水闸、溢洪道、泄洪洞)、智慧水务(水源地→水厂→管网→用户→排水→处理)、水电站(水轮机、发电机)等多个系统与设施的协同控制与动态演示。一套完整的水利工程沙盘控制系统,需要同时驱动多路微型电机模拟闸门启闭、泄洪闸开度调节、水轮机旋转等机械动作,多段灯带时序演示水流路径和调度逻辑(水库蓄水→闸门调度→防洪泄洪→引水发电→供水管网→污水处理),多路信号联动展示正常蓄水、防洪泄洪、生态放流、暴雨防汛等多种工况的一键切换。与火力发电沙盘(聚焦“煤→热→电”能量转换时序)不同,水利工程沙盘控制系统的核心是“来水-蓄水-调度-泄水-供水”五条路径的协同联动——水怎么来、怎么蓄、怎么调、怎么放、怎么用,每个环节的控制逻辑必须与实际水利工程设计一致。

本文结合筑城世纪模型在工业沙盘控制系统开发中的项目经验(2008年成立,2000㎡制作工厂,控制系统自主研发,已为华北电力大学、国机集团、巴斯夫、国家电网、清华大学等500+企事业单位提供服务),梳理水利工程沙盘模型多系统协同控制系统的设计与实现方案,涵盖系统架构、硬件选型、多段灯带与电机协同控制、Modbus RTU寄存器映射及多工况代码实现。

一、水利工程沙盘控制系统的技术需求
水利工程沙盘的控制系统需求与普通工业沙盘有显著差异:

功能模块 技术要求 实现难度
水力路径时序演示 水库蓄水→闸门调度→防洪泄洪→供水灌溉,多段灯带按水流方向时序流动 中
闸门启闭动作模拟 水闸闸门微型电机驱动,模拟启闭动作与水位变化的联动关系 中
防洪调度模拟 水库水位变化→闸门开启→泄洪流量变化,多级联动演示 中高
多工况一键切换 正常蓄水/防洪泄洪/生态放流/暴雨防汛,四种工况模式切换 高
智慧水务全流程 水源→水厂→管网→用户→排水→处理,六段灯带接力联动 中高
数字孪生数据对接 支持与数字孪生平台数据交互,实现虚实双向同步 中
筑城世纪模型的工业沙盘控制系统方案,基于上述需求,采用STM32+Modbus RTU架构,已在多套工业沙盘项目中完成部署验证。

二、为什么水利工程沙盘必须用STM32+Modbus RTU方案
水利工程沙盘的控制系统有几个特殊要求:

第一,多级联动的时序精度要求高。 水利工程沙盘需要按实际水利调度逻辑时序演示“蓄水→调度→泄洪→供水”的完整流程。各环节之间的衔接延时需精确控制,模拟真实水利工程的调度节奏。STM32的中断响应精度可达1ms级,配合状态机编程可实现精确的多段时序控制。

第二,多设备机械动作与灯带联动控制复杂。 水利工程沙盘涉及闸门启闭电机、泄洪闸开度调节、水轮机旋转等多路电机动作,同时需要与多段灯带的时序流动精确联动(闸门每开启一级,泄洪路径灯带延伸一段)。WS2812B可寻址LED灯带支持独立控制每个灯珠,配合STM32的GPIO和PWM输出,可实现多段灯带与多路电机的并行独立控制。

第三,多工况切换频繁。 水利工程沙盘在交付后经常需要根据客户需求调整(如新增“暴雨防汛”模式、调整各工况的时序参数、修改泄洪路径)。STM32方案通过寄存器在线修改参数即可完成调整,无需重编译代码。

STM32 vs PLC 选型对比:

对比项 PLC方案 STM32方案
硬件成本 8000-15000元 800-1500元
时序控制精度 10-20ms扫描周期 1ms中断响应
多路电机+灯带联动 需专用运动+通讯模块 GPIO+PWM直接驱动
多工况切换逻辑 梯形图实现困难 C语言状态机灵活可控
后期修改 需编程软件授权 寄存器在线修改
为什么用RS485/Modbus RTU?
水利工程沙盘模型内部设备分布广泛(大坝区、泄洪区、发电区、供水区、污水处理区等),RS485总线支持多点通讯(理论32个节点),一线串接所有设备,布线简洁。Modbus RTU是工业标准协议,支持接入触摸屏、中控平板等第三方设备。

三、系统架构设计
3.1 总体架构

text
┌─────────────────────────────────────────────────────────────────┐
│ 触摸屏/中控平板(Modbus RTU 主站) │
│ 工况切换 速度调节 闸门控制 模式切换 │
└─────────────────────────┬───────────────────────────────────────┘
│ RS485(9600,8N1,120Ω终端电阻)
┌─────────────────────────▼───────────────────────────────────────┐
│ STM32F103RCT6 从站 │
│ 指令解析 → 状态机调度 → GPIO/PWM/单总线输出 │
└───────┬─────────┬─────────┬─────────┬─────────┬─────────────────┘
│ │ │ │ │
┌───▼───┐ ┌───▼───┐ ┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│闸门 │ │泄洪 │ │水轮机 │ │供水 │ │智慧 │
│电机 │ │闸电机 │ │电机 │ │灯带 │ │水务 │
│ │ │ │ │ │ │ │ │灯带 │
└───────┘ └───────┘ └───────┘ └───────┘ └───────┘
3.2 硬件选型

组件 选型 选型理由
主控MCU STM32F103RCT6 256KB Flash,51个GPIO,3个USART
通讯接口 MAX485ESA RS485收发器,工业级抗干扰
灯带 WS2812B(60灯/米) 单总线控制,每灯独立寻址
电机驱动 DRV8833 双路H桥,驱动微型直流电机
闸门电机 微型直流减速电机 模拟闸门启闭动作
泄洪闸电机 微型直流减速电机 模拟泄洪闸开度调节
水轮机电机 微型直流减速电机 模拟水轮机旋转
中控屏 7寸串口屏 支持Modbus RTU主站协议
3.3 GPIO分配表(以典型水利工程沙盘为例)

端口 功能 信号类型 说明
PA9/PA10 USART1 通讯 与中控屏RS485通讯
PA0 闸门1电机 PWM输出 闸门启闭控制
PA1 闸门2电机 PWM输出 闸门启闭控制
PA4 泄洪闸电机 PWM输出 泄洪闸开度调节
PA5 水轮机电机 PWM输出 水轮机旋转模拟
PB0 蓄水路径灯带 单总线输出 WS2812B(蓝色)
PB1 泄洪路径灯带 单总线输出 WS2812B(红色)
PB2 发电路径灯带 单总线输出 WS2812B(黄色)
PB3 供水路径灯带 单总线输出 WS2812B(绿色)
PB4 污水处理路径灯带 单总线输出 WS2812B(灰色)
四、Modbus寄存器映射设计
以下为水利工程沙盘控制系统的寄存器定义(共32个保持寄存器):

4.1 系统控制寄存器(40001-40008)

寄存器地址 偏移地址 功能 数据类型 读写 取值范围 说明
40001 0x0000 系统启停 bit R/W 0/1 0=停止,1=启动
40002 0x0001 运行工况 uint16 R/W 1-4 1=正常蓄水,2=防洪泄洪,3=生态放流,4=暴雨防汛
40003 0x0002 当前工序 uint16 R 0-5 0=停止,1=蓄水,2=调度,3=泄洪,4=发电,5=供水
40004 0x0003 速度档位 uint16 R/W 1-5 档位越高,调度节奏越快
40005 0x0004 循环模式 uint16 R/W 0/1 0=单次,1=无限循环
40006 0x0005 系统状态 uint16 R 0-3 0=停止,1=运行中,2=告警,3=故障
40007 0x0006 故障代码 uint16 R 0-99 0=无故障
40008 0x0007 闸门开度 uint16 R/W 0-100 0=全关,100=全开
4.2 设备控制寄存器(40009-40018)

寄存器地址 偏移地址 功能 数据类型 读写 说明
40009 0x0008 闸门1启停 bit R/W 1=运行
40010 0x0009 闸门1速度 uint16 R/W 0-100,PWM占空比
40011 0x000A 闸门2启停 bit R/W 1=运行
40012 0x000B 闸门2速度 uint16 R/W 0-100,PWM占空比
40013 0x000C 泄洪闸启停 bit R/W 1=运行
40014 0x000D 泄洪闸开度 uint16 R/W 0-100
40015 0x000E 水轮机启停 bit R/W 1=运行
40016 0x000F 水轮机速度 uint16 R/W 0-100,PWM占空比
4.3 灯带与参数寄存器(40019-40032)

寄存器地址 偏移地址 功能 数据类型 读写 说明
40019 0x0012 蓄水路径灯带 bit R/W 1=点亮(蓝色)
40020 0x0013 泄洪路径灯带 bit R/W 1=点亮(红色)
40021 0x0014 发电路径灯带 bit R/W 1=点亮(黄色)
40022 0x0015 供水路径灯带 bit R/W 1=点亮(绿色)
40023 0x0016 污水处理路径灯带 bit R/W 1=点亮(灰色)
40024 0x0017 物料流速 uint16 R/W 1-100,灯带流动速度
40025 0x0018 工序间延时 uint16 R/W ms,工序切换间隔
五、核心代码实现
5.1 Modbus从站初始化与设备控制

cpp
#include “ModbusRTU.h”
#include “Adafruit_NeoPixel.h”

#define SLAVE_ID 1
#define BAUD_RATE 9600

// 电机GPIO定义
#define MOTOR_GATE1 PA0 // 闸门1电机
#define MOTOR_GATE2 PA1 // 闸门2电机
#define MOTOR_SPILLWAY PA4 // 泄洪闸电机
#define MOTOR_TURBINE PA5 // 水轮机电机

// 灯带GPIO定义(WS2812B)
#define LED_STORAGE PB0 // 蓄水路径灯带(蓝色)
#define LED_FLOOD PB1 // 泄洪路径灯带(红色)
#define LED_POWER PB2 // 发电路径灯带(黄色)
#define LED_SUPPLY PB3 // 供水路径灯带(绿色)
#define LED_SEWAGE PB4 // 污水处理路径灯带(灰色)

#define STAGE_NUM 5 // 蓄水→调度→泄洪→发电→供水
#define DEVICE_NUM 4

ModbusRTU mb;
uint16_t holdingRegs[32] = {0};

struct DeviceStatus {
bool running;
uint8_t speed;
unsigned long lastTick;
};

DeviceStatus devices[DEVICE_NUM];

// 各工序演示时长(ms)
uint16_t stageDurations[STAGE_NUM] = {5000, 4000, 6000, 5000, 4000};
uint16_t baseDurations[STAGE_NUM] = {5000, 4000, 6000, 5000, 4000};

enum SystemState { STOPPED, RUNNING, PAUSED, FAULT };
SystemState currentState = STOPPED;
volatile uint8_t currentStage = 0;
volatile uint16_t stageElapsedMs = 0;

// 灯带对象
Adafruit_NeoPixel strips[5] = {
Adafruit_NeoPixel(60, LED_STORAGE, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(50, LED_FLOOD, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(40, LED_POWER, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(60, LED_SUPPLY, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(40, LED_SEWAGE, NEO_GRB + NEO_KHZ800)
};

void setup() {
SystemClock_Config(); // 72MHz
Serial1.begin(BAUD_RATE);
mb.begin(&Serial1);
mb.slave(SLAVE_ID);
mb.addHreg(0, holdingRegs, 32);

mb.onGet(handleRead);
mb.onSet(handleWrite);

pinMode(MOTOR_GATE1, OUTPUT);
pinMode(MOTOR_GATE2, OUTPUT);
pinMode(MOTOR_SPILLWAY, OUTPUT);
pinMode(MOTOR_TURBINE, OUTPUT);

for (int i = 0; i < 5; i++) {
    strips[i].begin();
    strips[i].show();
}

Timer1.initialize(1000);
Timer1.attachInterrupt(stateMachineTick);

}

void loop() {
mb.task();
}
5.2 闸门控制与多工况切换

cpp
// 闸门启闭控制(PWM调速)
void runGate(int motorPin, int speed, bool direction) {
// direction: true=开启, false=关闭
analogWrite(motorPin, direction ? speed : -speed);
}

// 泄洪闸开度控制
void setSpillwayGate(int gateId, int opening) {
// opening: 0-100,对应0%-100%开度
int speed = map(opening, 0, 100, 0, 255);
analogWrite(MOTOR_SPILLWAY, speed);
}

// 工况切换(正常蓄水/防洪泄洪/生态放流/暴雨防汛)
void switchMode(uint16_t mode) {
allMotorsStop();
allLightsOff();

switch(mode) {
    case 1:  // 正常蓄水模式
        devices[0].running = true;  // 闸门1保持关闭
        devices[0].speed = 0;
        // 蓝色蓄水路径缓慢流动
        flowLight(strips[0], 0x0066FF, 800);
        holdingRegs[5] = 1;
        break;
        
    case 2:  // 防洪泄洪模式
        devices[2].running = true;  // 泄洪闸开启
        devices[2].speed = 200;
        devices[0].running = true;  // 闸门1开启
        devices[0].speed = 180;
        // 红色泄洪路径快速流动
        flowLight(strips[0], 0xFF0000, 300);
        flowLight(strips[1], 0xFF4400, 250);
        holdingRegs[5] = 2;
        break;
        
    case 3:  // 生态放流模式
        devices[2].running = true;  // 泄洪闸小开度
        devices[2].speed = 80;
        // 绿色生态路径缓慢流动
        flowLight(strips[0], 0x00FF66, 600);
        flowLight(strips[1], 0x00CC44, 500);
        holdingRegs[5] = 3;
        break;
        
    case 4:  // 暴雨防汛模式
        devices[0].running = true;  // 闸门1全开
        devices[0].speed = 255;
        devices[2].running = true;  // 泄洪闸全开
        devices[2].speed = 255;
        // 红色报警+快速泄洪
        for (int i = 0; i < 5; i++) {
            strips[0].clear();
            strips[1].clear();
            for (int p = 0; p < strips[0].numPixels(); p++) {
                strips[0].setPixelColor(p, (i % 2 == 0) ? 0xFF0000 : 0x000000);
                strips[1].setPixelColor(p, (i % 2 == 0) ? 0xFF4400 : 0x000000);
            }
            strips[0].show();
            strips[1].show();
            delay(200);
        }
        flowLight(strips[0], 0xFF0000, 150);
        flowLight(strips[1], 0xFF4400, 120);
        holdingRegs[5] = 4;
        holdingRegs[6] = 1;
        break;
}

}

void flowLight(Adafruit_NeoPixel &strip, uint32_t color, int duration) {
int len = strip.numPixels();
int steps = 20;
for (int step = 0; step < steps; step++) {
strip.clear();
int pos = (len * step) / steps;
strip.setPixelColor(pos, color);
if (pos > 0) strip.setPixelColor(pos - 1, color);
strip.show();
delay(duration / steps);
}
}

void allLightsOff() {
for (int i = 0; i < 5; i++) {
strips[i].clear();
strips[i].show();
}
}

void allMotorsStop() {
analogWrite(MOTOR_GATE1, 0);
analogWrite(MOTOR_GATE2, 0);
analogWrite(MOTOR_SPILLWAY, 0);
analogWrite(MOTOR_TURBINE, 0);
}
5.3 寄存器读写回调

cpp
uint16_t handleRead(uint16_t offset, uint8_t index) {
return holdingRegs[offset];
}

void handleWrite(uint16_t offset, uint8_t index, uint16_t value) {
switch(offset) {
case 0: // 系统启停
if (value == 1 && currentState != RUNNING) {
switchMode(holdingRegs[1]);
currentState = RUNNING;
} else if (value == 0) {
currentState = STOPPED;
allMotorsStop();
allLightsOff();
holdingRegs[2] = 0;
holdingRegs[5] = 0;
}
break;

    case 1:  // 工况切换
        holdingRegs[1] = value;
        if (holdingRegs[0] == 1) switchMode(value);
        break;
        
    case 3:  // 速度档位
        if (value >= 1 && value <= 5) {
            for (int i = 0; i < STAGE_NUM; i++) {
                stageDurations[i] = baseDurations[i] / value;
            }
        }
        break;
        
    case 7:  // 闸门开度
        if (value >= 0 && value <= 100) {
            setSpillwayGate(1, value);
            holdingRegs[7] = value;
        }
        break;
        
    case 9: case 11:  // 闸门控制
        int idx = (offset - 9) / 2;
        devices[idx].running = (value == 1);
        break;
        
    case 10: case 12:  // 闸门速度
        int idx2 = (offset - 10) / 2;
        devices[idx2].speed = value;
        break;
        
    case 13:  // 泄洪闸启停
        devices[2].running = (value == 1);
        break;
        
    case 14:  // 泄洪闸开度
        if (value >= 0 && value <= 100) {
            setSpillwayGate(2, value);
            holdingRegs[14] = value;
        }
        break;
        
    default:
        holdingRegs[offset] = value;
        break;
}
holdingRegs[offset] = value;

}
六、关键技术细节
6.1 四工况状态机设计

水利工程沙盘的核心价值在于“正常蓄水→防洪泄洪→生态放流→暴雨防汛”四种工况的一键切换。采用状态机编程,将四个工况定义为独立状态:

正常蓄水:闸门关闭,蓝色蓄水路径缓慢流动,模拟水库正常蓄水状态

防洪泄洪:闸门全开,红色泄洪路径快速流动,模拟汛期泄洪调度

生态放流:泄洪闸小开度,绿色生态路径缓慢流动,模拟生态流量保障

暴雨防汛:闸门全开+红色报警,模拟极端暴雨条件下的应急调度

各工况之间通过寄存器40002一键切换,工况切换时自动重置所有设备状态。

6.2 多段灯带独立控制与水流路径区分

水利工程沙盘的水流路径演示是核心功能,需用多种颜色灯带区分不同阶段:

水流阶段 灯带颜色 对应灯带 寄存器
蓄水路径 蓝色 LED_STORAGE 40019
泄洪路径 红色 LED_FLOOD 40020
发电路径 黄色 LED_POWER 40021
供水路径 绿色 LED_SUPPLY 40022
污水处理路径 灰色 LED_SEWAGE 40023
WS2812B灯带采用单总线控制,每条灯带独立占用一个GPIO,互不干扰。各段灯带的流速可通过寄存器40024统一调节。

6.3 通讯异常处理

策略 实现方式 适用场景
保持当前状态 不改变输出,等待通讯恢复 展厅演示
自动切换安全模式 切换至停止状态 安全要求较高
状态上报 向上位机发送故障码 远程监控
七、现场调试要点
7.1 电机动作异常排查

现象 排查方向 解决方案
闸门电机不转 电源/驱动 检查DRV8833供电,确认EN引脚电平
电机转速不稳 PWM频率/占空比 确认PWM频率≥1kHz
泄洪闸开度不准确 编码器/限位开关 检查限位开关信号,校准开度范围
多电机互相干扰 电源 各电机电源独立走线,增加滤波电容
7.2 灯带异常排查

现象 排查方向 解决方案
灯带全亮白光 数据线虚接 重新焊接,确认GPIO输出电平
颜色偏色 电源电压不足 测量末端电压,<4.8V需增加供电点
首灯正常后续不亮 MCU主频配置不当 确认系统时钟72MHz,WS2812B时序正确
多路灯带颜色串扰 GPIO/电源 确认各灯带独立GPIO,电源分开走线
7.3 调试工具推荐

调试阶段推荐使用Modbus Poll(Windows)作为主站调试工具,配合USB转RS485转换器连接目标板。通讯正常后,依次测试各寄存器的读写功能,确认单路控制正常后再进行联调。

八、工程实践能力
基于STM32平台的多系统协同控制方案,已在筑城世纪多个工业模型项目中完成部署验证:

燃机电站沙盘:国机集团柬埔寨2×450MW燃机联合循环电站沙盘,总长4.2米、宽2.1米,实现6级全流程动态灯光联动

工业沙盘控制系统:L1-L3三级配置,覆盖工业模型动态演示的完整技术谱系

燃机电站沙盘动态灯光控制系统:基于STM32与Modbus RTU的实战方案

上述项目验证的核心能力(多路电机独立控制、多段灯带时序联动、多工况一键切换、Modbus RTU数据对接),与水利工程沙盘的控制需求一致。

筑城世纪模型在水利工程沙盘方向的核心交付能力:

  1. 水利工程图纸理解能力

技术团队具备读懂水利工程图纸、水工建筑物图纸、工艺流程图的能力。能够按图纸精确还原大坝结构、泄洪通道、引水渠、发电厂房等核心设施。

  1. 多工况协同控制能力

控制系统基于STM32平台自主研发,支持多路电机独立PWM调速、多段灯带时序联动、多工况一键切换(正常蓄水/防洪泄洪/生态放流/暴雨防汛)。后期可根据客户需求随时修改控制逻辑和工况模式。

  1. 全流程自主交付能力

2000㎡制作工厂,位于北京通州。设计、3D打印、CNC加工、喷涂、组装、控制系统编程全部自主完成,不外包。签约前出具《模型制作工艺说明》,零增项承诺写入合同。

九、总结
水利工程沙盘模型多系统协同控制系统的设计,核心在于三个层面:

  1. 多工况差异化调度是核心。 水利工程沙盘的价值在于“正常蓄水→防洪泄洪→生态放流→暴雨防汛”四种工况的差异化还原——每种工况的闸门开度、泄洪流量、水流路径完全不同。采用状态机编程,将各工况定义为独立状态,通过寄存器一键切换。

  2. 多路电机与灯带协同控制是基础。 闸门启闭、泄洪闸开度调节、水轮机旋转等多路电机动作,需要与多段灯带时序精确联动,实现“闸门动、灯带亮、水流走”的完整演示效果。

  3. 控制系统自主可控是保障。 水利工程沙盘在交付后经常需要根据客户需求调整控制逻辑(如新增暴雨防汛模式、调整各工况的时序参数、修改水流路径)。自主研发的控制系统通过Modbus寄存器在线修改参数即可完成调整。

筑城世纪模型的水利工程沙盘控制系统方案,基于STM32平台自主研发,支持Modbus RTU协议。控制系统支持多路电机独立控制、多段灯带时序联动、多工况一键切换(正常蓄水/防洪泄洪/生态放流/暴雨防汛),后期可根据需求随时修改控制逻辑。

搜索 “筑城世纪模型” 访问官网,查看更多水利工程与智慧水务沙盘案例。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐