unity串口通信

来源:互联网 发布:知乎达芬奇的恶魔 编辑:程序博客网 时间:2024/06/06 20:57

1  偏向硬件方向的详细介绍

http://blog.csdn.net/kasama1953/article/details/51434295

2 偏向软件方向的,使用软件跟硬件交互,显示的屋里数据通过发送串口数据,控制虚拟的运动,自行车项目等等。如何发串口数据,这不是unity关心的,我们只要关心如何接受,并且如何使用它们

首先接受串口数据 using System.IO.Ports; 使用这个命名空间的方法

SerialPort 类

using System;using System.Collections.Generic;using System.IO.Ports;using System.Runtime.InteropServices;using UnityEngine;public class SerialPortData : MonoBehaviour{    public bool Ismulti;    public int interval_ms = 30;    public string com = "COM2";    private List<byte> buffer = new List<byte>();    public int dataHead = 0xff;        private SerialPort MainPort;    private bool mainPortIsOpen;    //public GUIStyle mygui;      private byte[] ReceiveBytes = new byte[5];    private bool showstr;    public int speed_locate = 1;    public int btn_locate = 2;    public int rotation_locate = 3;    public float port_speedvalue;    public int port_rotationvalue;    public int port_btnvalue;    private string strport;    private float t1;    public static byte speed;    public static byte doorClose;    public int port_yugua;    [DllImport("user32")]    public static extern int MessageBox(int Hwnd, string text, string Caption, int iType);    private void OnApplicationQuit()    {        this.mainPortIsOpen = false;        this.MainPort.Close();    }    private void OnGU1I()    {        //float x = Camera.mainCamera.ViewportToScreenPoint(new Vector3(0f, 0f, 0f)).x;        //if (this.showstr)        //{        //    GUI.Label(new Rect(x, (float)(Screen.height - 50), 700f, 50f), "Port: " + this.com + " Data: " + this.strport, this.mygui);        //}        GUIStyle bb = new GUIStyle();        bb.normal.background = null;    //这是设置背景填充的        bb.normal.textColor = new Color(1, 0, 0);   //设置字体颜色的        bb.fontSize = 30;       //当然,这是字体颜色        GUI.Label(new Rect(30, 20, 800, 400), "data:"+this.strport, bb);    }    private void ProcessMsg()    {        this.strport = this.ReceiveBytes[0].ToString() + "  " + this.ReceiveBytes[1].ToString() + "  " + this.ReceiveBytes[2].ToString() + "  " + this.ReceiveBytes[3].ToString();        this.port_speedvalue = this.ReceiveBytes[this.speed_locate]; // 速度        //Debug.Log("");        this.port_rotationvalue = this.ReceiveBytes[this.rotation_locate]; // 播放        this.port_btnvalue = this.ReceiveBytes[this.btn_locate]; //  开关车门        this.port_yugua = this.ReceiveBytes[4];// 获取第五位        Debug.Log(this.port_yugua);        Array.Clear(this.ReceiveBytes, 0, this.ReceiveBytes.Length);    }    private void Start()    {                try        {            this.MainPort = new SerialPort(this.com, 0x2580, Parity.None, 8, StopBits.One);            this.MainPort.Open();        }        catch (Exception exception)        {            MessageBox(0, exception.Message + "  I'm open" + this.com, null, 0x40);            this.MainPort = null;            Application.Quit();        }        if ((this.MainPort != null) && this.MainPort.IsOpen)        {            this.mainPortIsOpen = true;        }        else        {            this.mainPortIsOpen = false;        }    }    public void WritePortData(string dataStr)    {        if (this.mainPortIsOpen)        {            this.MainPort.Write(dataStr);        }    }    private void Update()    {        if (this.mainPortIsOpen)        {            this.t1 += Time.deltaTime;            // 30ms 算一次            if ((this.t1 * 1000f) >= this.interval_ms)            {                this.t1 = 0f;                byte[] buffer1 = new byte[20];                int length = 0;                try                {                    length = this.MainPort.Read(buffer1, 0, 20); // read  放到buf1中,然后将buf1拷贝到destinationArray中,                                                        //然后在buf追加destinationArray。当buf长度超过5,解析给ReceiveBytes,清空buf,重新读取                       Debug.Log("Length  " + buffer1.Length+" "+buffer1[2]);                }                catch (Exception)                {                    MessageBox(0, "Port breaked! Plaese reconnect!!!  I'm " + this.com, null, 0x40);                    this.MainPort = null;                    Application.Quit();                }                byte[] destinationArray = new byte[length];                Array.Copy(buffer1, destinationArray, length);                           this.buffer.AddRange(destinationArray);                if (this.buffer.Count >= 5)                {                   // Debug.Log("count is out 5");                    if (this.buffer[0] == this.dataHead)                    {                        this.buffer.CopyTo(0, this.ReceiveBytes, 0, 5);                        this.ProcessMsg();                        this.buffer.Clear();                    }                    this.buffer.Clear();                }               // this.MainPort.Write(new byte[] { 0xff, speed, doorClose }, 0, 3);            }            if (Input.GetKeyDown(KeyCode.F5))            {                this.showstr = !this.showstr;            }        }    }}
获取数据,然后控制物体运动,一般运动使用第三人称脚本

using UnityEngine;using System.Collections; /** *  @Author : www.xuanyusong.com  */ [RequireComponent(typeof(CharacterMotor))][AddComponentMenu("Character/FPS Input Controller")] public class FPSInputController : MonoBehaviour { private CharacterMotor motor ; // Use this for initializationvoid Awake () {motor = GetComponent<CharacterMotor>();} // Update is called once per framevoid Update () {// Get the input vector from kayboard or analog stickVector3 directionVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); if (directionVector != Vector3.zero) {// Get the length of the directon vector and then normalize it// Dividing by the length is cheaper than normalizing when we already have the length anywayvar directionLength = directionVector.magnitude;directionVector = directionVector / directionLength; // Make sure the length is no bigger than 1directionLength = Mathf.Min(1, directionLength); // Make the input vector more sensitive towards the extremes and less sensitive in the middle// This makes it easier to control slow speeds when using analog sticksdirectionLength = directionLength * directionLength; // Multiply the normalized direction vector by the modified lengthdirectionVector = directionVector * directionLength;} // Apply the direction to the CharacterMotor
//  此处加入旋转的代码   motor.inputMoveDirection = transform.rotation * directionVector;motor.inputJump = Input.GetButton("Jump");} }
如果通过串口数据,加入旋转代码:

  spdata = GameObject.Find("myfirst").GetComponent<SerialPortData>();


float RotationValue = ClampFloat(spdata.port_rotationvalue, vrCenter) * vrDir;


transform.Rotate(new Vector3(0, RotationValue * vrRotateSpeed * 0.01f, 0));               //旋转轴是Y轴(向上)


 motor.inputMoveDirection = transform.rotation * directionVector * vrMoveSpeed * Time.deltaTime * 12;


 float ClampFloat(float value, float center)
    {
        return value - center;
    }

这是一种情况,根据串口旋转,还有就是根据路径点旋转,读取每个路径点,旋转注视

private Transform[] Road_T;            保存所有路径点


  Road_T = GameObject.FindGameObjectWithTag(name).GetComponentsInChildren<Transform>();    获取所有路径点,保存

 private void RotateG() {             if(Vector3.Distance(this.transfrom.position,Road_T[count].position)<5f){            canMove = true;        }        if (canMove) {            canMove = false;            if (count == Road_T.Length - 1) {                count = Road_T.Length - 1;                return;            }            count++;        }        this.transform.rotation = Quaternion.Lerp(this.transform.rotation,Quaternion.LookRotation(Road_T[count].position-this.transform.position),5*Time.deltaTime);        }

是起到平滑过渡的效果  
但你要去控制时间 tim.time 或 time。
datetime  才能看出平滑过渡效果来

LookRotation  旋转插值

此函数作用是生成一个四元数表示的三维朝向,然后可以直接把这个朝向赋给游戏对象来变更其朝向,也可以通过线性插值(Quaternion.Slerp 和 Quaternion.Lerp)来实现游戏对象从当前朝向转到这个新生成的朝向上来

static function LookRotation (forward : Vector3, upwards : Vector3 = Vector3.up) : Quaternion


现在来看 LookRotation 的两个参数,第一个参数 forward,是一个三元组,也就是三个浮点数的组合,这个三元组可以确定世界坐标系下的一个点,从世界坐标系的坐标原点到这个定点就构成了一个三维空间矢量,当我们忽略这个矢量的长度时,它就退化为一个纯粹的方向指示,换句话说,这第一个参数 forward 确定了一个世界坐标系下的方向,而这个方向就是物体转动后 +z 轴所要指向的方向;第二个参数 upwards,也是个三元组(之前没看懂就是没看懂在这个参数上,一致闹不明白这个三元组是干啥用的),这个三元组同样可以确定一个世界坐标系下的方向,物体转动后 x 轴必须与这个方向垂直(如果转动前物体的x轴不满足此条件,那么物体除了改变朝向外还会绕 z 轴旋转以确保转动结束后 x 轴与此方向垂直)。

示例代码:

using UnityEngine;using System.Collections;public class LookAtRotation : MonoBehaviour {    public Transform cube;    public Transform  target;    public Vector3 v;    // Use this for initialization    public enum Direc {       UP= 1,       Forwad=2,    }   public Direc direc;void Start () {}// Update is called once per framevoid Update () {        if (direc == Direc.Forwad) v = Vector3.forward;        else v = Vector3.up;        cube.rotation = Quaternion.LookRotation(target.position-cube.position,v);        Debug.DrawLine(Vector3.zero,cube.forward,Color.blue);        Debug.DrawLine(Vector3.zero,cube.right,Color.red);        Debug.DrawLine(Vector3.zero,cube.up,Color.green);}}



补充:

运行一段时间发现,串口通信会卡死。。。就是当接受不到数据的时候会卡死! 目测是线程堵死了,看了Read半天也没有发现这个API是否是堵塞,不管了,直接放到子线程处理





over