Unity开发数字化看板-通用的设备运动同步
通用的设备运动同步
通过获取实时采集运动位置,发送到unity程序中,通过比例运算,转换成模型的运动位置,实现虚实同步。
在工业设备中,复杂的运动进行分析、分解,最本质的的运动就是平移和转动,在空间上就是3个维度的平移和旋转,包括:x轴平移,y轴平移,z轴平移,x轴旋转,Y轴旋转,Z轴旋转。
当然根据接收的数据不同,可能有的是一维运动,有的是多个维度合并一起运动。
实现实控虚的主要几个点:
- 初始化位置映射,实际设备确定一个零点,在模型需要找到对应零点,记录当前位置
- 比例换算,模型显示跟实际尺寸存在非完全一致或者单位换算的问题,对部件进行平移需要换算,旋转角度则不需要
- 旋转中心点调整
实现运动控制脚本:
主要实现一个运动控制基类MoveBase
和3个维度平移和旋转控制(6个脚本)
基类MoveBase
实现
首先实现初始化
InitPosition
变量用于存储当前部件模型的初始化位置,虚函数InitLocation()
用于根据InitPosition
值和不同类型的运动进行不同初始化,具体初始化内容在子类中实现。
/// <summary>/// 初始化位置/// </summary>public float InitPosition;/// <summary>/// 初始化位置参数/// </summary>public virtual void InitLocation(){}
比例换算:
在平移中:
(模型位置−模型初始位置)模型可运动长度=实际位置实际可运动长度\\frac{(模型位置-模型初始位置)}{模型可运动长度}=\\frac{实际位置}{实际可运动长度} 模型可运动长度(模型位置−模型初始位置)=实际可运动长度实际位置
在旋转:
模型当前角度=模型偏转零点+转动角度模型当前角度=模型偏转零点+转动角度 模型当前角度=模型偏转零点+转动角度
设置了四个参数,DataPosition
是传过来的位置,就是实际位置;NowPosition
是当前位置,就是模型当前位置;MoveLength
是模型可运动长度;ActualLength
是实际可运动长度;MoveLength
和ActualLength
只有在平移运动式有效,如果是旋转则默认设置为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物体用于测试
在MoveCube上面挂上Zmove脚本,并且修改脚本参数用于模拟运动
写一个测试的控制脚本,将他挂在随便一个物体上(相机或者Cube),将MoveCube物体复制给Move参数,然后运行,就可以看到物体运动。
public class MoveTest : MonoBehaviour
{public MoveBase Move;int pos = 0;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}private void FixedUpdate(){pos++;Move.SetDataPos(pos);}
}
效果: