徐庄矿提升机数字孪生-钢丝绳与提升容器系统控制逻辑说明
1.整体结构

从PLC拿三个值(目前):
(1)开关__主井提升__运行M164
代表系统的运行状态,相当于开车停车信号
(2)模拟__主井提升主画面___提升高度
代表北箕斗的提升高度,范围约为(0 ~ -490),0为停车位置、-490为井下装煤位置
(3)开关__主井提升主画面___提升运行标志4
代表北箕斗的提升方向,true时北箕斗上升,false时北箕斗下降
各脚本功能说明:
(1)MainLogic
负责提升容器与钢丝绳系统的数据接收和转发,负责协调各部件脚本,控制整体逻辑
(2)upDownLogic、reverseUpDown
左(南)箕斗控制脚本与右(北)箕斗控制脚本,负责脚本位置设定
(3)rotateLogic
天轮(导向轮)控制脚本,负责天轮转动逻辑
(4)shengZiLogic、reverseShengZiLogic
左右首绳控制脚本,负责调整绳子伸缩逻辑
(5)leftWeiSheng、rightWeiSheng
左右尾绳控制脚本,负责调整绳子伸缩逻辑
(6)xieShengLogic、wenLiLogic
斜绳(天轮旁边)、纹理控制逻辑
2.主控逻辑(MainLogic)解析
(1)数据获取
添加新值位置
/**************数据接收结构体*************/
[Serializable]
public class GuideWheelData
{
public bool 开关_主井提升_运行M164; // 是否在运行
public float 模拟_主井提升_主画面_提升高度; // 当前高度(0 ~ -490 米)C#
public bool 开关_主井提升_主画面_提升运行标志4; // 运行方向(true=右斗上升)
}
定时刷新,获取新数据
// 每隔 checkInterval 秒检查一次,可以自定义
if (Time.time - lastCheckTime >= checkInterval)
{
lastCheckTime = Time.time;
// 从 guideWheel 队列获取数据,GetQueueData方法在RabbitMQReceiver文件中定义
string guideWheelqueueData = RabbitMQReceiver.Instance.GetQueueData("guideWheel.queue");
使用Unity 内置的 JSON 反序列化方法,会自动把 JSON 字段映射到 GuideWheelData 的同名字段上
JSON 反序列化 = 把一段 JSON 字符串“变回”成程序中的对象(或数据结构)
序列化:对象转数据流 反序列化:数据流转对象
if (guideWheelqueueData != null)
{
Debug.Log("成功获取箕斗系统数据:" + guideWheelqueueData);
// 把 JSON 字符串反序列化为 GuideWheelData 对象
GuideWheelData data = JsonUtility.FromJson<GuideWheelData>(guideWheelqueueData);
// 提取 PLC 值
StartSignal = data.开关_主井提升_运行M164; // 运行信号
plcHeight = data.模拟_主井提升_主画面_提升高度; // 当前高度
beidoudirection = data.开关_主井提升_主画面_提升运行标志4; // 运行方向
}
(2)运动控制:
//判断箕斗系统是否在运行,取自“开关_主井提升_运行M164”
if (StartSignal)
{
//北斗在提升,左降右升 判断箕斗运动方向,取自“开关_主井提升_主画面_提升运行标志4”
if (beidoudirection)
{
Debug.Log("正在执行");
LdownRup(); //控制左降右升方法
}
//北斗在下降,左升右降
else
{
Debug.Log("正在执行");
LupRdown(); //控制左升右降方法
}
}
else
{
//停车,暂停天轮,箕斗,绳子
StopEveryone();
}
北箕斗(右箕斗)提升逻辑,下降的差不多
//左箕斗下降,右箕斗提升
private void LdownRup()
{
float y = PlcToUnityY(plcHeight); //取plc高度的映射值(现实提升高度要映射为数字孪生中的位置)
Debug.Log("当前高度" + y);
for (int i = 0; i < rotateLogic.Length; i++) //控制四个天轮的运动方向
{
rotateLogic[i].DownRotate();
}
for (int i = 0; i < shengZiLogic.Length; i++) //启动左绳子,四根
{
shengZiLogic[i].Move();
}
for (int i = 0; i < reverseShengZiLogic.Length; i++) //启动右绳子,四根
{
reverseShengZiLogic[i].Move();
}
for (int i = 0; i < xieShengLogic.Length; i++) //启动斜绳子,四根
{
xieShengLogic[i].DownMove();
}
for (int i = 0; i < wenLiLogic.Length; i++) //启动纹理,四个
{
wenLiLogic[i].DownMove();
}
for (int i = 0; i < leftWeiSheng.Length; i++) //启动左右尾绳,共四根,每种两根
{
rightWeiSheng[i].Move();
leftWeiSheng[i].Move();
}
// 调用箕斗更新位置方法,在孪生中,位置为负值,取到的数据是正值,要取反。在孪生中,箕斗从顶到底的位置范围是-120 ~ -1350,y的范围是(120 ~ 1350),那么-y与-1470+y的范围都是-120 ~ -1350,南北箕斗的位置和应该等于-1470
upDownLogic.UpdatePosition(-y);
reverseUpDown.UpdatePosition(-1470 + y);
}
(3)位置映射
箕斗位置虚实映射逻辑
// 将 PLC 高度 (0 ~ 490) 映射为 Unity Y 坐标 (—120 ~ -1350)
private float PlcToUnityY(float plcHeightValue)
{
// 限制输入范围(0 ~ 490)
plcHeightValue = Mathf.Clamp(plcHeightValue, 0f, 487f); //这里可以设置为490,实际数据约为486.832
// 映射(0->120, 490->1350)
return Mathf.Lerp(120f, 1350f, plcHeightValue / 487f); //插值映射
}
3.箕斗脚本(UpDownLogic)逻辑解析
改变箕斗位置方法
// 更新箕斗位置
public void UpdatePosition(float height)
{
Vector3 pos = transform.localPosition;
pos.y = height; //改变y
transform.localPosition = pos;
}
4.绳子脚本(ShengZiLogic)逻辑解析
绳子脚本的作用:根据“箕斗系统”的垂直位置变化,动态调整当前绳子的 Y 轴缩放(localScale.y),实现“绳子随箕斗运动而伸长或缩短”的视觉效果
所需变量:
| 变量 | 类型 | 作用 |
|---|---|---|
YScale |
float |
当前绳子的 Y 轴缩放值(控制绳子“长度”) |
rightSystem |
Transform |
核心:右箕斗系统的 Transform,用于监听其 Y 位置变化 |
initialYScale |
float |
初始 Y 缩放值(2.58) |
initialSystemY |
float |
右箕斗系统初始 Y 位置 |
initialLocalPosition |
Vector3 |
绳子自身的初始局部位置(防止跳跃) |
previousSystemY |
float |
上一帧右箕斗系统的 Y 位置(用于计算位移) |
totalDeltaY |
float |
累积总位移,记录从开始到现在右箕斗总共移动了多少 |
isStop |
bool |
控制绳子是否停止更新(暂停动画) |
核心逻辑:
void Update()
{
if (rightSystem != null && !isStop)
{
float currentY = rightSystem.position.y;
float deltaY = previousSystemY - currentY; // 正值:向下移动,计算箕斗位移差
previousSystemY = currentY;
totalDeltaY += deltaY; //计算累计位移,要知道从开始到现在总共移动了多少,才能决定绳子该多长
float temp = YScale;
//核心计算公式
绳子Scale = 绳子初始Scale * (箕斗累计位移 + 绳子模型长度)/ 绳子模型长度
伸缩系数 = (箕斗累计位移 + 绳子模型长度)/ 绳子模型长度
YScale = 2.58f * (totalDeltaY + 154.805f) / 154.805f;
transform.localScale = new Vector3(1.2f, Mathf.Max(0.01f, YScale), 1.2f);
}
}
其它绳子(除了斜绳)的伸缩逻辑同理