通用的设备运动同步

通过获取实时采集运动位置,发送到unity程序中,通过比例运算,转换成模型的运动位置,实现虚实同步。

在工业设备中,复杂的运动进行分析、分解,最本质的的运动就是平移和转动,在空间上就是3个维度的平移和旋转,包括:x轴平移,y轴平移,z轴平移,x轴旋转,Y轴旋转,Z轴旋转。

当然根据接收的数据不同,可能有的是一维运动,有的是多个维度合并一起运动。

实现实控虚的主要几个点:

  1. 初始化位置映射,实际设备确定一个零点,在模型需要找到对应零点,记录当前位置
  2. 比例换算,模型显示跟实际尺寸存在非完全一致或者单位换算的问题,对部件进行平移需要换算,旋转角度则不需要
  3. 旋转中心点调整

实现运动控制脚本:

主要实现一个运动控制基类MoveBase和3个维度平移和旋转控制(6个脚本)

基类MoveBase实现

首先实现初始化

InitPosition变量用于存储当前部件模型的初始化位置,虚函数InitLocation()用于根据InitPosition值和不同类型的运动进行不同初始化,具体初始化内容在子类中实现。


    /// <summary>
    /// 初始化位置
    /// </summary>
    public float InitPosition;
    
    /// <summary>
    /// 初始化位置参数
    /// </summary>
    public virtual void InitLocation()
    {

    }

比例换算:

在平移中:

(模型位置 − 模型初始位置) 模型可运动长度 = 实际位置 实际可运动长度 \frac{(模型位置-模型初始位置)}{模型可运动长度}=\frac{实际位置}{实际可运动长度} 模型可运动长度(模型位置模型初始位置)=实际可运动长度实际位置

在旋转:

模型当前角度 = 模型偏转零点 + 转动角度 模型当前角度=模型偏转零点+转动角度 模型当前角度=模型偏转零点+转动角度

设置了四个参数,DataPosition是传过来的位置,就是实际位置;NowPosition是当前位置,就是模型当前位置;MoveLength是模型可运动长度;ActualLength是实际可运动长度;MoveLengthActualLength只有在平移运动式有效,如果是旋转则默认设置为0,不处理。

    /// <summary>
    /// 传过来的位置
    /// </summary>
    protected float DataPosition;
    /// <summary>
    /// 当前位置
    /// </summary>
    public float NowPosition;
    /// <summary>
    /// 模型可移动长度,比例计算
    /// </summary>
    public float MoveLength = 1;
    /// <summary>
    /// 实际可移动长度
    /// </summary>
    public float ActualLength = 1;

运算公式:

模型实时位置 = 模型初始化位置 + 实际位置 ∗ 模型可移动长度 实际可移动长度 模型实时位置=模型初始化位置+\frac{实际位置*模型可移动长度}{实际可移动长度} 模型实时位置=模型初始化位置+实际可移动长度实际位置模型可移动长度

在脚本FixedUpdate()中实时更新模型位置,先使用公式计算当前模型位置,然后调用UpdateModelPosition()更新位置,具体更新在对应子类中转换为坐标更新或者角度旋转。

    private void FixedUpdate()
    {

        if (IsChange())
        {
            NowPosition = InitPosition + DataPosition * MoveLength / ActualLength;
            UpdateModelPosition();
        }

    }
    /// <summary>
    /// 更新位置
    /// </summary>
    public virtual void UpdateModelPosition()
    {

    }

MoveBase基类完整脚本:

/// <summary>
/// 运动控制基类(平移、旋转)
/// </summary>
public class MoveBase : MonoBehaviour
{
    /// <summary>
    /// 运动控制对象
    /// </summary>
    public Transform MoveObject;

    /// <summary>
    /// 传过来的位置
    /// </summary>
    protected float DataPosition;

    /// <summary>
    /// 初始化位置
    /// </summary>
    public float InitPosition;
    /// <summary>
    /// 当前位置
    /// </summary>
    public float NowPosition;

    /// <summary>
    /// 模型移动长度,比例计算
    /// </summary>
    public float MoveLength = 1;
    /// <summary>
    /// 实际移动长度
    /// </summary>
    public float ActualLength = 1;

    /// <summary>
    /// 设置实时数据
    /// </summary>
    /// <param name="pos"></param>
    public virtual void SetDataPos(float pos)
    {
        DataPosition = pos;
    }

    public bool IsChange()
    {

        if (NowPosition != DataPosition)
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    void Start()
    {
        MoveObject = gameObject.transform;
    }
    /// <summary>
    /// 初始化位置参数
    /// </summary>
    public virtual void InitLocation()
    {

    }

    private void FixedUpdate()
    {
        if (IsChange())
        {
            NowPosition = InitPosition + DataPosition * MoveLength / ActualLength;
            UpdateModelPosition();
        }
    }
    /// <summary>
    /// 更新位置
    /// </summary>
    public virtual void UpdateModelPosition()
    {

    }
}


各个维度控制脚本:

X轴平移:

public class XMove : MoveBase
{
    public override void InitLocation()
    {
        MoveObject.localPosition = new Vector3(InitPosition, MoveObject.localPosition.y, MoveObject.localPosition.z);
    }

    public override void UpdateModelPosition()
    {
            MoveObject.localPosition = new Vector3(NowPosition, MoveObject.localPosition.y, MoveObject.localPosition.z);
    }
}

Y轴平移:

public class YMove : MoveBase
{
    public override void InitLocation()
    {
        MoveObject.localPosition = new Vector3(MoveObject.localPosition.x, InitPosition, MoveObject.localPosition.z);
    }

    public override void UpdateModelPosition()
    {
        MoveObject.localPosition = new Vector3(MoveObject.localPosition.x, NowPosition, MoveObject.localPosition.z);

    }
}

Z轴平移:

public class ZMove : MoveBase
{
    public override void InitLocation()
    {
        MoveObject.localPosition = new Vector3(MoveObject.localPosition.x, MoveObject.localPosition.y, InitPosition);
    }

    public override void UpdateModelPosition()
    {
        MoveObject.localPosition = new Vector3(MoveObject.localPosition.x, MoveObject.localPosition.y, NowPosition);
    }
}

X轴旋转:

public class XRotate : MoveBase
{
    public override void InitLocation()
    {
        MoveObject.localRotation = Quaternion.Euler(InitPosition, MoveObject.localPosition.y, MoveObject.localPosition.z);
    }

    public override void UpdateModelPosition()
    {
        MoveObject.localRotation = Quaternion.Euler(NowPosition, MoveObject.localPosition.y, MoveObject.localPosition.z);
    }
}

Y轴旋转:

public class YRotate : MoveBase
{
    public override void InitLocation()
    {
        MoveObject.localRotation = Quaternion.Euler(MoveObject.localPosition.x, InitPosition, MoveObject.localPosition.z);
    }
    public override void UpdateModelPosition()
    {
        MoveObject.localRotation = Quaternion.Euler(MoveObject.localPosition.x, NowPosition, MoveObject.localPosition.z);
    }
}

Z轴旋转:

public class ZRotate : MoveBase
{
    public override void InitLocation()
    {
        MoveObject.localRotation = Quaternion.Euler(MoveObject.localPosition.x, MoveObject.localPosition.y, InitPosition);
    }
    public override void UpdateModelPosition()
    {
        MoveObject.localRotation = Quaternion.Euler(MoveObject.localPosition.x, MoveObject.localPosition.y, NowPosition);
    }
}

测试:

创建两个Cube物体用于测试

Unity开发数字化看板-通用的设备运动同步-LMLPHP

在MoveCube上面挂上Zmove脚本,并且修改脚本参数用于模拟运动

Unity开发数字化看板-通用的设备运动同步-LMLPHP

写一个测试的控制脚本,将他挂在随便一个物体上(相机或者Cube),将MoveCube物体复制给Move参数,然后运行,就可以看到物体运动。

Unity开发数字化看板-通用的设备运动同步-LMLPHP

public class MoveTest : MonoBehaviour
{
    public MoveBase Move;
    int pos = 0;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
    private void FixedUpdate()
    {
        pos++;
        Move.SetDataPos(pos);
    }
}

效果:

Unity开发数字化看板-通用的设备运动同步-LMLPHP

04-16 23:29