智慧交通沙盘模型控制系统设计:基于STM32与Modbus RTU的车路协同-智能信号-数字孪生全场景联动方案
智慧交通沙盘模型控制系统,是城市交通数字化转型的“神经中枢”。一套完整的智慧交通沙盘控制系统,需要同时驱动多路口信号灯联动模拟交通调度,多辆智能微缩车辆模拟自动驾驶、信号灯识别与车路协同通信,多段灯带时序演示交通流路径和拥堵传播,多路信号联动展示正常通行、高峰拥堵、应急调度、车路协同等多种交通场景的一键切换。与港口物流沙盘(聚焦“海陆空铁”四网联动的货物运输路径)不同,智慧交通沙盘控制系统的核心是“聪明的车、智慧的路、智能的云、安全的网”四层架构的协同运行——车辆怎么感知、信号怎么控制、数据怎么传输、系统怎么决策,每个环节的控制逻辑必须与实际智慧交通系统的运行逻辑一致。
本文结合筑城世纪模型在工业沙盘控制系统开发中的项目经验(2008年成立,2000㎡制作工厂,控制系统自主研发,已为中国物流集团、华北电力大学、国机集团、国家电网、清华大学等500+企事业单位提供服务),梳理智慧交通沙盘模型控制系统的设计与实现方案,涵盖系统架构、硬件选型、多路信号灯与智能车辆协同控制、Modbus RTU寄存器映射及多场景代码实现。文中案例基于已落地的多式联运智慧沙盘模型项目(集成动态高铁、动态航运、动态飞机、港口物流沙盘、智能交通沙盘及物联网数据联动),该沙盘完整呈现“海陆空铁”四网联动的现代交通枢纽。
一、智慧交通沙盘控制系统的技术需求
智慧交通沙盘的控制系统需求与普通工业沙盘有显著差异:
功能模块 技术要求 实现难度
车路协同V2X模拟 智能微缩车辆识别信号灯状态、障碍物识别、自动避障,与路侧单元实时通信 高
多路口信号灯联动控制 多路口信号灯独立控制,支持公交优先、绿波带等交通管控策略模拟 中高
多场景一键切换 正常通行/高峰拥堵/应急调度/车路协同,四种交通场景模式切换 高
交通流路径灯带演示 多段LED灯带按交通流方向时序流动,模拟车流、拥堵传播路径 中
数字孪生数据对接 支持与交通数字孪生平台数据交互,实现物理沙盘与虚拟数据联动 中
中控平板分区讲解 支持逐区独立讲解,速度可调 中
基于上述需求,采用STM32+Modbus RTU架构。
二、为什么智慧交通沙盘采用STM32+Modbus RTU方案
智慧交通沙盘的控制系统有几个特殊要求:
第一,多场景切换的逻辑复杂度高。 智慧交通沙盘需要支持正常通行、高峰拥堵、应急调度、车路协同四种交通场景的一键切换,每种场景的信号灯状态、车辆运行逻辑、灯带时序参数完全不同。STM32配合状态机编程可实现灵活的场景切换逻辑。
第二,多设备协同控制的复杂度高。 智慧交通沙盘涉及多路口信号灯(红/黄/绿三色LED独立控制)、多辆智能微缩车辆(路径规划、速度控制、信号灯识别)、多段LED灯带(交通流路径)的并行协同控制,每种设备的控制逻辑和时序参数各不相同。STM32配合GPIO和PWM输出可实现多设备的并行独立控制。
第三,后期修改频繁。 智慧交通沙盘在交付后经常需要根据教学或展示需求调整(如新增“潮汐车道”模式、调整各路口的信号配时参数、修改车辆行驶路径)。STM32方案通过寄存器在线修改参数即可完成调整,无需重编译代码。
STM32 vs PLC 选型对比:
对比项 PLC方案 STM32方案
硬件成本 8000-15000元 800-1500元
时序控制精度 10-20ms扫描周期 1ms中断响应
多设备并行控制 需多个PLC或专用模块 GPIO+PWM直接驱动
多场景切换逻辑 梯形图实现困难 C语言状态机灵活可控
后期修改 需编程软件授权 寄存器在线修改
为什么用RS485/Modbus RTU:
智慧交通沙盘模型内部设备分布广泛(各路口区、车辆行驶区、路侧单元区等),RS485总线支持多点通讯(理论32个节点),一线串接所有设备,布线简洁。Modbus RTU是工业标准协议,支持接入触摸屏、中控平板等第三方设备。
三、系统架构设计
3.1 总体架构
text
┌─────────────────────────────────────────────────────────────────┐
│ 触摸屏/中控平板(Modbus RTU 主站) │
│ 场景切换 速度调节 车辆调度 模式切换 │
└─────────────────────────┬───────────────────────────────────────┘
│ RS485(9600,8N1,120Ω终端电阻)
┌─────────────────────────▼───────────────────────────────────────┐
│ STM32F103RCT6 从站 │
│ 指令解析 → 状态机调度 → GPIO/PWM/单总线输出 │
└───────┬─────────┬─────────┬─────────┬─────────┬─────────────────┘
│ │ │ │ │
┌───▼───┐ ┌───▼───┐ ┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│路口1 │ │路口2 │ │路口3 │ │车辆 │ │交通 │
│信号灯 │ │信号灯 │ │信号灯 │ │控制 │ │流灯带 │
└───────┘ └───────┘ └───────┘ └───────┘ └───────┘
3.2 硬件选型
组件 选型 选型理由
主控MCU STM32F103RCT6 256KB Flash,51个GPIO,3个USART
通讯接口 MAX485ESA RS485收发器,工业级抗干扰
信号灯 红/黄/绿三色LED模块(I2C/GPIO控制) 模拟真实交通信号灯
智能微缩车辆 微型直流电机+红外/超声波传感器 模拟自动驾驶、避障、信号灯识别
灯带 WS2812B(60灯/米) 单总线控制,每灯独立寻址
中控屏 7寸串口屏 支持Modbus RTU主站协议
3.3 GPIO分配表(以典型智慧交通沙盘为例)
端口 功能 信号类型 说明
PA9/PA10 USART1 通讯 与中控屏RS485通讯
PA0 路口1红灯 GPIO输出 红/黄/绿三色独立控制
PA1 路口1黄灯 GPIO输出
PA2 路口1绿灯 GPIO输出
PA3 路口2红灯 GPIO输出
PA4 路口2黄灯 GPIO输出
PA5 路口2绿灯 GPIO输出
PA6 路口3红灯 GPIO输出
PA7 路口3黄灯 GPIO输出
PA8 路口3绿灯 GPIO输出
PB0 车辆1电机 PWM输出 智能微缩车辆速度控制
PB1 车辆2电机 PWM输出
PB2 车辆3电机 PWM输出
PB3 交通流灯带1 单总线输出 WS2812B(南北向车流)
PB4 交通流灯带2 单总线输出 WS2812B(东西向车流)
PB5 路侧单元灯带 单总线输出 WS2812B(V2X通信指示)
四、Modbus寄存器映射设计
以下为智慧交通沙盘控制系统的寄存器定义(共32个保持寄存器):
4.1 系统控制寄存器(40001-40007)
寄存器地址 偏移地址 功能 数据类型 读写 取值范围 说明
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-3 0=停止,1=南北直行,2=东西直行,3=左转
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=故障
4.2 灯带与参数寄存器(40007-40016)
寄存器地址 偏移地址 功能 数据类型 读写 说明
40007 0x0006 南北向交通流灯带 bit R/W 1=点亮
40008 0x0007 东西向交通流灯带 bit R/W 1=点亮
40009 0x0008 路侧单元灯带 bit R/W 1=点亮(V2X通信指示)
40010 0x0009 交通流速 uint16 R/W 1-100,灯带流动速度
40011 0x000A 信号周期 uint16 R/W ms,信号灯切换周期
40012 0x000B 绿信比 uint16 R/W 0-100,绿灯时间占比
五、核心代码实现
5.1 Modbus从站初始化
cpp
#include “ModbusRTU.h”
#include “Adafruit_NeoPixel.h”
#define SLAVE_ID 1
#define BAUD_RATE 9600
// 信号灯GPIO定义
#define TRAFFIC_R1 PA0
#define TRAFFIC_Y1 PA1
#define TRAFFIC_G1 PA2
#define TRAFFIC_R2 PA3
#define TRAFFIC_Y2 PA4
#define TRAFFIC_G2 PA5
#define TRAFFIC_R3 PA6
#define TRAFFIC_Y3 PA7
#define TRAFFIC_G3 PA8
// 电机GPIO定义
#define MOTOR_CAR1 PB0
#define MOTOR_CAR2 PB1
#define MOTOR_CAR3 PB2
// 灯带GPIO定义(WS2812B)
#define LED_NORTH PB3
#define LED_EAST PB4
#define LED_V2X PB5
#define SCENE_NUM 4
#define INTERSECT_NUM 3
ModbusRTU mb;
uint16_t holdingRegs[32] = {0};
uint16_t signalCycle[INTERSECT_NUM] = {4000, 4000, 4000};
uint16_t baseCycle[INTERSECT_NUM] = {4000, 4000, 4000};
enum SystemState { STOPPED, RUNNING, PAUSED, FAULT };
SystemState currentState = STOPPED;
volatile uint8_t currentScene = 0;
volatile uint8_t currentPhase[INTERSECT_NUM] = {1, 1, 1};
volatile unsigned long lastTick[INTERSECT_NUM] = {0, 0, 0};
Adafruit_NeoPixel strips[3] = {
Adafruit_NeoPixel(60, LED_NORTH, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(60, LED_EAST, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(30, LED_V2X, NEO_GRB + NEO_KHZ800)
};
void setup() {
SystemClock_Config();
Serial1.begin(BAUD_RATE);
mb.begin(&Serial1);
mb.slave(SLAVE_ID);
mb.addHreg(0, holdingRegs, 32);
mb.onGet(handleRead);
mb.onSet(handleWrite);
// 初始化信号灯GPIO
pinMode(TRAFFIC_R1, OUTPUT);
pinMode(TRAFFIC_Y1, OUTPUT);
pinMode(TRAFFIC_G1, OUTPUT);
pinMode(TRAFFIC_R2, OUTPUT);
pinMode(TRAFFIC_Y2, OUTPUT);
pinMode(TRAFFIC_G2, OUTPUT);
pinMode(TRAFFIC_R3, OUTPUT);
pinMode(TRAFFIC_Y3, OUTPUT);
pinMode(TRAFFIC_G3, OUTPUT);
pinMode(MOTOR_CAR1, OUTPUT);
pinMode(MOTOR_CAR2, OUTPUT);
pinMode(MOTOR_CAR3, OUTPUT);
for (int i = 0; i < 3; i++) {
strips[i].begin();
strips[i].show();
}
Timer1.initialize(1000);
Timer1.attachInterrupt(stateMachineTick);
}
void loop() {
mb.task();
}
5.2 交通信号灯控制与多场景切换
cpp
// 路口相位切换
void setIntersectionPhase(int intersect, uint8_t phase) {
int rPin, yPin, gPin;
switch(intersect) {
case 0: rPin=TRAFFIC_R1; yPin=TRAFFIC_Y1; gPin=TRAFFIC_G1; break;
case 1: rPin=TRAFFIC_R2; yPin=TRAFFIC_Y2; gPin=TRAFFIC_G2; break;
case 2: rPin=TRAFFIC_R3; yPin=TRAFFIC_Y3; gPin=TRAFFIC_G3; break;
}
digitalWrite(rPin, LOW);
digitalWrite(yPin, LOW);
digitalWrite(gPin, LOW);
switch(phase) {
case 1: digitalWrite(gPin, HIGH); break;
case 2: digitalWrite(yPin, HIGH); break;
case 3: digitalWrite(gPin, HIGH); break;
case 4: digitalWrite(yPin, HIGH); break;
}
currentPhase[intersect] = phase;
}
// 交通信号灯时序控制
void trafficLightTick() {
for (int i = 0; i < INTERSECT_NUM; i++) {
unsigned long now = millis();
if (now - lastTick[i] >= signalCycle[i] / 4) {
lastTick[i] = now;
uint8_t phase = currentPhase[i];
phase = (phase % 4) + 1;
setIntersectionPhase(i, phase);
}
}
}
// 场景切换
void switchScene(uint16_t scene) {
allLightsOff();
allMotorsStop();
allSignalsOff();
switch(scene) {
case 1: // 正常通行
for (int i = 0; i < INTERSECT_NUM; i++) {
signalCycle[i] = 4000;
setIntersectionPhase(i, 1);
}
flowLight(strips[0], 0x00FF66, 800);
flowLight(strips[1], 0x0066FF, 800);
analogWrite(MOTOR_CAR1, 120);
analogWrite(MOTOR_CAR2, 120);
holdingRegs[5] = 1;
break;
case 2: // 高峰拥堵
for (int i = 0; i < INTERSECT_NUM; i++) {
signalCycle[i] = 2000;
}
flowLight(strips[0], 0xFF6600, 400);
flowLight(strips[1], 0xFF6600, 400);
analogWrite(MOTOR_CAR1, 80);
analogWrite(MOTOR_CAR2, 80);
for (int i = 0; i < 3; 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) ? 0xFF0000 : 0x000000);
}
strips[0].show(); strips[1].show();
delay(300);
}
holdingRegs[5] = 2;
break;
case 3: // 应急调度
setIntersectionPhase(0, 1);
setIntersectionPhase(1, 1);
setIntersectionPhase(2, 1);
flowLight(strips[0], 0x00FF00, 300);
flowLight(strips[2], 0xFFFF00, 300);
analogWrite(MOTOR_CAR1, 200);
holdingRegs[5] = 3;
break;
case 4: // 车路协同
flowLight(strips[0], 0x00FF66, 500);
flowLight(strips[1], 0x0066FF, 500);
flowLight(strips[2], 0x00CCFF, 300);
analogWrite(MOTOR_CAR1, 150);
analogWrite(MOTOR_CAR2, 150);
for (int i = 0; i < 5; i++) {
strips[2].clear();
for (int p = 0; p < strips[2].numPixels(); p++) {
strips[2].setPixelColor(p, (i % 2 == 0) ? 0x00CCFF : 0x000000);
}
strips[2].show();
delay(200);
}
holdingRegs[5] = 4;
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 allSignalsOff() {
digitalWrite(TRAFFIC_R1, LOW); digitalWrite(TRAFFIC_Y1, LOW); digitalWrite(TRAFFIC_G1, LOW);
digitalWrite(TRAFFIC_R2, LOW); digitalWrite(TRAFFIC_Y2, LOW); digitalWrite(TRAFFIC_G2, LOW);
digitalWrite(TRAFFIC_R3, LOW); digitalWrite(TRAFFIC_Y3, LOW); digitalWrite(TRAFFIC_G3, LOW);
}
void allLightsOff() {
for (int i = 0; i < 3; i++) {
strips[i].clear();
strips[i].show();
}
}
void allMotorsStop() {
analogWrite(MOTOR_CAR1, 0);
analogWrite(MOTOR_CAR2, 0);
analogWrite(MOTOR_CAR3, 0);
}
5.3 寄存器读写回调
cpp
void stateMachineTick() {
if (currentState != RUNNING) return;
trafficLightTick();
}
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) {
switchScene(holdingRegs[1]);
currentState = RUNNING;
} else if (value == 0) {
currentState = STOPPED;
allMotorsStop();
allSignalsOff();
allLightsOff();
holdingRegs[2] = 0;
holdingRegs[5] = 0;
}
break;
case 1:
holdingRegs[1] = value;
if (holdingRegs[0] == 1) {
switchScene(value);
currentState = RUNNING;
}
break;
case 3:
if (value >= 1 && value <= 5) {
for (int i = 0; i < INTERSECT_NUM; i++) {
signalCycle[i] = baseCycle[i] / value;
}
}
break;
default:
holdingRegs[offset] = value;
break;
}
holdingRegs[offset] = value;
}
六、关键技术细节
6.1 四场景状态机设计
智慧交通沙盘的核心价值在于“正常通行→高峰拥堵→应急调度→车路协同”四种交通场景的一键切换:
正常通行:三个路口四相位信号灯正常切换,车流平稳流动
高峰拥堵:信号周期缩短、车流灯带快速流动且呈红色拥堵指示、车辆减速
应急调度:南北向优先通行,应急车辆加速,黄闪警示
车路协同:路侧单元灯带闪烁模拟V2X通信,车辆与信号灯协同
各场景之间通过寄存器40002一键切换,场景切换时自动重置所有设备状态。
6.2 多路口信号灯独立控制
每个路口有独立的相位控制和信号周期:
路口 相位1 相位2 相位3 相位4
路口1 南北直行 南北左转 东西直行 东西左转
路口2 南北直行 南北左转 东西直行 东西左转
路口3 南北直行 南北左转 东西直行 东西左转
每个路口的信号周期和相位可通过寄存器独立调节。
6.3 通讯异常处理
策略 实现方式 适用场景
保持当前状态 不改变输出,等待通讯恢复 展厅演示
自动切换安全模式 切换至停止状态(所有信号灯黄闪) 安全要求较高
状态上报 向上位机发送故障码 远程监控
七、现场调试要点
7.1 信号灯异常排查
现象 排查方向 解决方案
信号灯不亮 电源/GPIO 检查三色LED供电,确认GPIO电平
相位切换错乱 控制逻辑 检查相位切换时序
多路口不同步 时序配置 确认各路口信号周期一致性
7.2 灯带异常排查
现象 排查方向 解决方案
灯带全亮白光 数据线虚接 重新焊接,确认GPIO输出电平
颜色偏色 电源电压不足 测量末端电压,<4.8V需增加供电点
首灯正常后续不亮 MCU主频配置不当 确认系统时钟72MHz,WS2812B时序正确
八、总结
智慧交通沙盘模型控制系统的设计,核心在于三个层面:
-
四场景差异化控制是核心。 智慧交通沙盘的价值在于“正常通行→高峰拥堵→应急调度→车路协同”四种交通场景的差异化还原——每种场景的信号灯状态、车辆逻辑、灯带时序、交通流参数完全不同。采用状态机编程,将各场景定义为独立状态,通过寄存器一键切换。
-
多设备协同控制是基础。 多路口信号灯、智能微缩车辆、多段灯带等多路设备,需要精确协同运行,实现“信号控、车流动、灯带亮”的完整交通演示效果。
-
控制系统自主可控是保障。 智慧交通沙盘在交付后经常需要根据教学或展示需求调整控制逻辑(如新增潮汐车道模式、调整各路口的信号配时参数、修改车辆行驶路径)。自主研发的控制系统通过Modbus寄存器在线修改参数即可完成调整,无需依赖外部支持。
更多推荐


所有评论(0)