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

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);
    }
}

其它绳子(除了斜绳)的伸缩逻辑同理