煤矿单体设备模型多电机协同控制系统设计:基于STM32与Modbus RTU的采煤机/液压支架/刮板输送机控制方案
煤矿单体设备模型覆盖采煤机模型(截割部、牵引部、液压系统)、液压支架模型(顶梁、掩护梁、四连杆机构、立柱、推移千斤顶)、刮板输送机模型(机头传动部、中部槽、刮板链)等单体设备的精细还原与动态演示。一套完整的煤矿单体设备模型控制系统,需要同时驱动多台微型电机模拟滚筒旋转、摇臂升降、支架移架循环、刮板链运行等动作——采煤机滚筒旋转与摇臂升降、液压支架“降-移-升-推”四步循环、刮板输送机链轮驱动刮板链运行,每个设备的动作逻辑必须与实际设备操作规程一致。
本文结合筑城世纪模型在工业模型控制系统开发中的项目经验(2008年成立,2000㎡制作工厂,控制系统自主研发,已为华北电力大学、国机集团、巴斯夫、国家电网、清华大学等500+企事业单位提供服务),梳理煤矿单体设备模型多电机协同控制系统的设计与实现方案,涵盖系统架构、Modbus RTU寄存器映射、多路PWM电机控制代码实现及现场调试要点。
一、为什么煤矿单体设备模型必须用STM32+Modbus RTU方案
煤矿单体设备模型的控制系统有几个特殊要求:
第一,多电机独立驱动要求高。 采煤机模型需要同时控制滚筒旋转电机、摇臂升降电机、牵引行走电机;液压支架模型需要控制立柱升降、推移千斤顶伸缩等多个动作;刮板输送机模型需要控制链轮驱动电机。各电机需独立PWM调速、独立启停,动作时序需精确配合。
第二,动作逻辑复杂且需可调。 采煤机滚筒旋转速度、摇臂升降角度、液压支架“降-移-升-推”四步循环的时序间隔、刮板链运行速度,均需支持现场调节。STM32方案通过寄存器在线修改参数即可调整,无需重编译代码。
第三,控制点数多但成本敏感。 煤矿单体设备模型的控制点数通常在16-48路之间(多路电机+限位传感器+灯带)。PLC方案同等IO点数约5000-10000元,STM32方案硬件成本约500-1200元。
PLC vs STM32 选型对比
对比项 PLC方案 STM32方案
硬件成本 5000-10000元 500-1200元
电机控制精度 依赖专用运动模块 PWM直接驱动,精度1%
开发灵活度 梯形图编程,复杂动作逻辑实现困难 C语言状态机,灵活可控
体积 模块化结构,占用空间大 单板集成,可嵌入模型底座
后期修改 需编程软件授权+工程师到场 寄存器在线修改,无需重编译
扩展性 依赖专用模块 开放GPIO/USART,灵活扩展
为什么用RS485/Modbus RTU?
煤矿设备模型内部金属结构多,WiFi信号衰减严重。RS485是工业现场总线标准,抗干扰能力强。Modbus RTU是工业标准协议,支持接入触摸屏、上位机等第三方设备。
二、系统架构设计
2.1 总体架构
text
┌─────────────────────────────────────────────────────────┐
│ 中控平板/触摸屏(Modbus RTU 主站) │
│ 设备选择 动作指令下发 速度调节 模式切换 │
└─────────────────────┬───────────────────────────────────┘
│ RS485(9600,8N1,120Ω终端电阻)
┌─────────────────────▼───────────────────────────────────┐
│ STM32F103RCT6 从站 │
│ 指令解析 → 设备状态机调度 → GPIO/PWM输出 │
└───────┬─────────┬─────────┬─────────┬───────────────────┘
│ │ │ │
┌───▼───┐ ┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│采煤机 │ │液压支 │ │刮板输 │ │限位/ │
│电机群 │ │架电机 │ │送机电机│ │传感器 │
└───────┘ └───────┘ └───────┘ └───────┘
2.2 硬件选型
组件 选型 数量 选型理由
主控MCU STM32F103RCT6 1 256KB Flash,51个GPIO,3个USART
通讯接口 MAX485ESA 1 RS485收发器,工业级抗干扰
电机驱动 DRV8833(双路H桥) 依电机数 驱动微型直流电机,支持PWM调速
限位传感器 微型微动开关/霍尔传感器 依动作数 检测机械动作极限位置
电源 24V→5V/3.3V隔离模块 1 隔离供电,降低电机对控制器的干扰
2.3 GPIO分配表(以采煤机模型为例)
端口 功能 信号类型 说明
PA9/PA10 USART1 通讯 与中控屏RS485通讯
PA2/PA3 USART2 通讯 预留调试串口
PA0 滚筒旋转电机 PWM输出 调速,控制截割动作
PA1 摇臂升降电机 PWM输出 调速,控制升降动作
PA4 牵引行走电机 PWM输出 调速,控制行走动作
PA5 滚筒旋转限位 数字量输入 位置反馈(霍尔/光电)
PA6 摇臂升降限位 数字量输入 上下极限(微动开关)
PB0 设备状态指示灯带 单总线输出 WS2812B数据线
三、Modbus寄存器映射设计
以下为采煤机模型控制系统的寄存器定义(共20个保持寄存器):
3.1 系统控制寄存器(40001-40008)
寄存器地址 偏移地址 功能 数据类型 读写 取值范围 说明
40001 0x0000 设备选择 uint16 R/W 1-3 1=采煤机,2=液压支架,3=刮板输送机
40002 0x0001 系统启停 bit R/W 0/1 0=停止,1=启动
40003 0x0002 当前动作 uint16 R 0-5 0=停止,1-5=当前执行动作
40004 0x0003 循环模式 uint16 R/W 0/1 0=单次,1=无限循环
40005 0x0004 单步触发 bit R/W 0/1 写1执行下一步,自动归0
40006 0x0005 速度档位 uint16 R/W 1-5 档位越高,动作越快
40007 0x0006 系统状态 uint16 R 0-3 0=停止,1=运行中,2=暂停,3=故障
40008 0x0007 故障代码 uint16 R 0-99 0=无故障
3.2 采煤机动作控制寄存器(40009-40014)
寄存器地址 偏移地址 功能 数据类型 读写 说明
40009 0x0008 滚筒旋转启停 bit R/W 1=运行
40010 0x0009 滚筒旋转速度 uint16 R/W 0-100,PWM占空比
40011 0x000A 摇臂升降启停 bit R/W 1=上升,0=停止,-1=下降
40012 0x000B 摇臂升降速度 uint16 R/W 0-100,PWM占空比
40013 0x000C 牵引行走启停 bit R/W 1=前进,0=停止,-1=后退
40014 0x000D 牵引行走速度 uint16 R/W 0-100,PWM占空比
3.3 运行参数寄存器(40015-40020)
寄存器地址 偏移地址 功能 数据类型 读写 说明
40015-40017 0x000E-0x0010 各动作运行时间 uint16 R 秒,返回当前动作已运行时间
40018-40020 0x0011-0x0013 各动作延时参数 uint16 R/W ms,动作间延时
四、核心代码实现
4.1 Modbus从站初始化
cpp
#include “ModbusRTU.h”
#define SLAVE_ID 1
#define BAUD_RATE 9600
// 采煤机电机GPIO定义
#define MOTOR_DRUM PA0 // 滚筒旋转电机(PWM)
#define MOTOR_ARM PA1 // 摇臂升降电机(PWM)
#define MOTOR_TRACTION PA4 // 牵引行走电机(PWM)
// 限位传感器GPIO定义
#define SENSOR_ARM_UP PA5 // 摇臂上限位
#define SENSOR_ARM_DOWN PA6 // 摇臂下限位
#define ACTION_NUM 5
ModbusRTU mb;
uint16_t holdingRegs[20] = {0};
uint16_t actionDurations[ACTION_NUM] = {3000, 2000, 2000, 3000, 2000};
uint16_t baseDurations[ACTION_NUM] = {3000, 2000, 2000, 3000, 2000};
enum SystemState { STOPPED, RUNNING, PAUSED, FAULT };
SystemState currentState = STOPPED;
volatile uint8_t currentAction = 0;
volatile unsigned long actionStartTime = 0;
volatile uint16_t actionElapsedMs = 0;
void setup() {
SystemClock_Config(); // 72MHz
Serial1.begin(BAUD_RATE);
mb.begin(&Serial1);
mb.slave(SLAVE_ID);
mb.addHreg(0, holdingRegs, 20);
mb.onGet(handleRead);
mb.onSet(handleWrite);
pinMode(MOTOR_DRUM, OUTPUT);
pinMode(MOTOR_ARM, OUTPUT);
pinMode(MOTOR_TRACTION, OUTPUT);
pinMode(SENSOR_ARM_UP, INPUT_PULLUP);
pinMode(SENSOR_ARM_DOWN, INPUT_PULLUP);
Timer1.initialize(1000);
Timer1.attachInterrupt(stateMachineTick);
}
void loop() {
mb.task();
}
4.2 寄存器读写回调
cpp
uint16_t handleRead(uint16_t offset, uint8_t index) {
if (offset >= 14 && offset <= 16) {
if (currentState == RUNNING && currentAction == (offset - 14)) {
return (uint16_t)(millis() - actionStartTime) / 1000;
}
return 0;
}
return holdingRegs[offset];
}
void handleWrite(uint16_t offset, uint8_t index, uint16_t value) {
switch(offset) {
case 0: // 设备选择
holdingRegs[0] = value;
currentState = STOPPED;
allMotorsStop();
break;
case 1: // 系统启停
if (value == 1 && currentState != RUNNING) {
currentState = RUNNING;
currentAction = 0;
actionElapsedMs = 0;
actionStartTime = millis();
switchAction(currentAction);
holdingRegs[6] = 1;
} else if (value == 0) {
currentState = STOPPED;
allMotorsStop();
holdingRegs[2] = 0;
holdingRegs[6] = 0;
}
break;
case 4: // 速度档位
if (value >= 1 && value <= 5) {
for (int i = 0; i < ACTION_NUM; i++) {
actionDurations[i] = baseDurations[i] / value;
}
}
break;
case 8: // 滚筒旋转启停
if (value == 1) analogWrite(MOTOR_DRUM, holdingRegs[9]);
else analogWrite(MOTOR_DRUM, 0);
break;
case 9: // 滚筒旋转速度
if (holdingRegs[8] == 1) analogWrite(MOTOR_DRUM, value);
break;
case 10: // 摇臂升降
if (value == 1 && digitalRead(SENSOR_ARM_UP) == HIGH) {
analogWrite(MOTOR_ARM, holdingRegs[11]);
} else if (value == 2 && digitalRead(SENSOR_ARM_DOWN) == HIGH) {
analogWrite(MOTOR_ARM, -holdingRegs[11]);
} else {
analogWrite(MOTOR_ARM, 0);
}
break;
}
holdingRegs[offset] = value;
}
4.3 状态机调度核心(采煤机5动作时序)
cpp
void stateMachineTick() {
if (currentState != RUNNING) return;
actionElapsedMs++;
if (actionElapsedMs >= actionDurations[currentAction]) {
actionElapsedMs = 0;
currentAction++;
if (currentAction >= ACTION_NUM) {
if (holdingRegs[3] == 1) {
currentAction = 0;
} else {
currentState = STOPPED;
holdingRegs[1] = 0;
allMotorsStop();
return;
}
}
switchAction(currentAction);
holdingRegs[2] = currentAction + 1;
}
}
void switchAction(uint8_t action) {
allMotorsStop();
switch(action) {
case 0: // 滚筒旋转
analogWrite(MOTOR_DRUM, 180);
break;
case 1: // 摇臂上升
if (digitalRead(SENSOR_ARM_UP) == HIGH)
analogWrite(MOTOR_ARM, 150);
break;
case 2: // 摇臂下降
if (digitalRead(SENSOR_ARM_DOWN) == HIGH)
analogWrite(MOTOR_ARM, -150);
break;
case 3: // 牵引前进
analogWrite(MOTOR_TRACTION, 120);
break;
case 4: // 牵引后退
analogWrite(MOTOR_TRACTION, -120);
break;
}
}
void allMotorsStop() {
analogWrite(MOTOR_DRUM, 0);
analogWrite(MOTOR_ARM, 0);
analogWrite(MOTOR_TRACTION, 0);
}
五、关键技术细节
5.1 多电机独立PWM调速
STM32F103RCT6的通用定时器可同时输出多路独立PWM信号,分别控制采煤机滚筒转速(PA0)、摇臂升降速度(PA1)、牵引速度(PA4)。通过修改定时器的捕获比较寄存器值即可独立调节各电机占空比,互不干扰。
5.2 限位传感器防抖动处理
摇臂升降需要检测上下极限位置。机械限位开关触点存在5-20ms抖动,建议在软件中做20ms去抖动延时,或使用带施密特触发的数字输入,避免误触发导致电机堵转。
5.3 液压支架四步循环的状态机实现
液压支架“降-移-升-推”四步循环可定义为4个独立状态,通过状态机依次切换:
text
状态0: 降架(立柱收缩,电机反转)
状态1: 移架(推移千斤顶伸出,电机正转)
状态2: 升架(立柱伸出,电机正转)
状态3: 推溜(推移千斤顶收缩,电机反转)
每步的持续时间和电机速度均可通过寄存器(40018-40020)在线调节。
5.4 通讯异常处理
策略 实现方式
保持当前状态 不改变输出,等待通讯恢复
自动停止 超时后自动停止所有动作
状态上报 向上位机发送故障码
六、现场调试要点
6.1 电机动作异常排查
现象 排查方向 解决方案
电机不转 电源/驱动 检查DRV8833供电,确认EN引脚电平
电机转速不稳 PWM频率 确认PWM频率≥1kHz
电机方向错误 驱动逻辑 检查IN1/IN2逻辑电平
多电机互相干扰 电源 各电机电源独立走线,增加滤波电容
6.2 限位传感器异常排查
现象 排查方向 解决方案
限位不触发 安装位置 调整传感器与机械触动件的相对位置
误触发 抖动 增加软件去抖动延时20-50ms
信号不稳定 接线 使用屏蔽线,增加上拉电阻
6.3 调试工具推荐
调试阶段推荐使用Modbus Poll(Windows)作为主站调试工具,配合USB转RS485转换器连接目标板。通讯正常后,依次测试各寄存器的读写功能,确认单路控制正常后再进行联调。
七、工程实践能力
基于STM32平台的多电机协同控制方案,已在筑城世纪多个工业模型项目中完成部署验证:
华北电力大学火电原理教学沙盘:涉及锅炉、汽轮机、发电机等多系统协同
国机集团柬埔寨燃机联合循环电站沙盘:6级灯光联动、65米灯带
上述项目验证的核心能力(多路电机独立PWM调速、限位传感器状态读取、复杂动作时序编程),与煤矿单体设备模型的控制需求一致。控制系统支持多路电机独立控制、限位传感器检测、动作时序在线调节。2000㎡制作工厂,全流程自主完成,有图纸就能做。
八、总结
煤矿单体设备模型控制系统的设计,核心在于三个层面:
-
多电机独立驱动是基础。 各设备需要独立的PWM调速和动作时序控制。采用状态机编程,将每个动作定义为独立状态,各状态之间通过时序计数器触发切换。
-
限位反馈与安全保护是关键。 摇臂升降、支架移架等动作需要检测极限位置,限位传感器的可靠性和防抖动处理直接影响系统稳定性。
-
控制系统的自主可控是保障。 自主研发的控制系统才能做到后期随时修改动作逻辑、新增演示模式。
更多推荐

所有评论(0)