zoukankan      html  css  js  c++  java
  • Unity之串口通信(基于三姿态传感器)

    /*******************************/
    //串口接收,采用多线程+数据池设计模式,使用队列数据结构队列,避免线程阻塞//
    /*******************************/
    using UnityEngine;
    using System.Collections;
    //Other libraries
    using System;
    using System.Threading;
    using System.Collections.Generic;
    using System.ComponentModel;
    //串口命名空间
    using System.IO.Ports;
    using System.Text.RegularExpressions;
    using System.Text;




    public class ComTest : MonoBehaviour {
        /******定义一个串口字段*******/
       private SerialPort sp;
        /*******定义三个外部接口***************/
    public static float FangXiangJiao;
    public static float YangJiao;
    public static float XuanZhuanJiao;
    /*******定义三个角度存储的临时字段***********/
    public static float _FangXiangJiao;
    public static float _YangJiao;
    public static float _XuanZhuanJiao;
        /***********三种角度的循环队列****************/
        private Queue<float> AVEFangXiangJiao = new Queue<float>();
        private Queue<float> AVEYangJiao = new Queue<float>();
        private Queue<float> AVEXuanZhuanJiao = new Queue<float>();
    private byte[] DataBuf;
        
        private bool flag = true;
        private bool showMessage = false;//显示消息
        private bool open = false;


    private int NumberCount=0;
    private Thread SerialPortThread;

    private StringBuilder sbReadline;
        private string strOutPool = string.Empty;
    private Queue<string> queueDataPool;
        private Thread tPort;
        private Thread tPortDeal;
        /***********Unity初始化方法*****************/
    private void Start () {
            sbReadline = new StringBuilder();
            queueDataPool = new Queue<string>();
            //DataBuf = new byte[10];


            sp = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            if (!sp.IsOpen){
                // 开启串口
                sp.Open();
                open = true;
            }


            //开启2个线程分别用于接收数据和处理数据
            tPort = new Thread(DealData);
            tPort.Start();
            tPortDeal = new Thread(ReceiveData);
            tPortDeal.Start();
    //StartCoroutine(DealData()); 

    }


        /***************程序结束的时候,关闭串口**********************/
       void OnApplicationQuit() {
          sp.Close();
    //SerialPortThread.Abort();//终止进程
       }

    /*************Update方法********************/
    //一帧之调用多次
       void FixedUpdate() {
           //定期回收垃圾
           if (Time.frameCount % 120 == 0) System.GC.Collect(); 


           //处理数据的线程停止,那么重启该线程
           if (!tPort.IsAlive) {
               tPort = new Thread(DealData);
               tPort.Start();


           }
           if (!tPortDeal.IsAlive) {
               tPortDeal = new Thread(ReceiveData);
               tPortDeal.Start();
           }
           // StartCoroutine(DealData());
    //Debug.Log( SerialPortThread.ThreadState);
    }


    /// <summary>
    /// 数据接收 进程, 使用队列来存储数据,避免数组的上锁和解锁问题
    /// 设计模式  多线程+数据池
    /// </summary>
    /// <returns>
    /// The data.
    /// </returns>
       /*****************数据接收*************************/
    private void ReceiveData () {
    //读取数据,同时存入数据池中
    //newline结束标记,同时使用readIlne()方法 
    try {

    //从输入缓存区中去读取第一次出现"AA"时的内容
                Byte[] buf=new Byte[120];
              if (open) sp.Read(buf,0,120);
                //如果没有接到到数据,就返回
                if (buf.Length ==0) {
                    return;
                }
               string sbReadline2str = string.Empty;
               if (buf != null)
               {
                   for (int i = 0; i < buf.Length; i++)
                   {
                       sbReadline2str += buf[i].ToString("X2");
                   }
               }         
              //sbReadline2str = System.Text.Encoding.Default.GetString(buf, 0,buf.Length);
           //  Debug.LogError(sbReadline2str.ToString());
            // sbReadline2str = buf.ToString();
               // sbReadline2str = sbReadline.ToString();
                    //提取完整的一个数据包,压入数据池中(队列中)
           if (sbReadline2str.StartsWith("DB90"))
             {       //分组数据包
                 string[] _str = Regex.Split(sbReadline2str, "55AA", RegexOptions.IgnoreCase);
                 foreach (string s in _str)
                 {
                     if (s.Length == 16)
                     {
                         //数据进入队列
                         queueDataPool.Enqueue(s + "55AA");
                         //Debug.LogError(s+"55AA");
                     }
                    
                 }
             }
             else {
                
                sbReadline2str.Remove(0,sbReadline2str.IndexOf("DB90")+1);
                 string[] _str = Regex.Split(sbReadline2str, "55AA", RegexOptions.IgnoreCase);
                 foreach (string s in _str)
                 {
                     if (s.Length == 16)
                     {
                         //数据进入队列
                         queueDataPool.Enqueue(s + "55AA");
                        // Debug.LogError(s+"55AA");
                     }
                    // Convert.ToByte(s,16);
                     
                 }
             }

    }catch (Exception ex) {
    Debug.LogError(ex);
    }
    //yield return null;
    }


        /***************处理出队的数据***********************/
        private void DealData()
        {
            while (queueDataPool.Count != 0)
            {//循环检测队列
                //队列中有数据


                //处理出队的数据
                //循环队列,首先加载第一包数据,只执行一次
                if (flag)
                {    //初始化第一组数据
                    for (int i = 0; i < 7; i++)
                    {   //出队列,同时移除这个数据
                        strOutPool = queueDataPool.Dequeue();
                        float[] jiaodu = DealReceivedDatanow(strOutPool);
                        AVEFangXiangJiao.Enqueue(jiaodu[0]);
                        AVEYangJiao.Enqueue(jiaodu[1]);
                        AVEXuanZhuanJiao.Enqueue(jiaodu[2]);


                    }
                    FangXiangJiao = Caulation(AVEFangXiangJiao);
                    YangJiao = Caulation(AVEYangJiao);
                    XuanZhuanJiao = Caulation(AVEXuanZhuanJiao);
                    flag = false;


                }
                else
                {/*采用7点平滑滤波,消除抖动现象.注意特殊点的处理360到0之间的数据*/
                    
                  
                     //没有存在跳变的现象,那就直接存储数据
                        for (int i = 0; i < 7; i++)
                        {
                            //出队列,同时移除这个数据。
                            //加载7包数据,
                            strOutPool = queueDataPool.Dequeue();
                            //组合加载的数据,低字节在前,高字节在后,return 三个角度值
                            float[] jiaodu = DealReceivedDatanow(strOutPool);
                            //角度循环队列更新最新进入的数据
                            AVEFangXiangJiao.Dequeue();
                            //角度循环队列在队尾插入新的数据
                            AVEFangXiangJiao.Enqueue(jiaodu[0]);
                            //计算更新后的循环队列中的7个数据平均值
                            /*****************处理特殊数据************************/
                            int[] IntPanDuan = CheackDataTuBian(AVEFangXiangJiao);
                            //如果存在着跳变的现象
                            if (IntPanDuan[0] == 1)
                            {//保留队列前面的数据,移除后面的数据
                                float[] FXj = AVEFangXiangJiao.ToArray();
                                float sum = 0f;
                                //获取要移除数据的索引值
                                int indexOfRemovingData = IntPanDuan[2];
                                 for (int j = 0; j < indexOfRemovingData; j++)
                                {
                                    sum += FXj[j];
                                }
                                //计算平均值
                                FangXiangJiao = sum / indexOfRemovingData;
                            }
                            FangXiangJiao = Caulation(AVEFangXiangJiao);
                            /******************处理特殊数据结束*************************/


                            /*******************************************/
                            /*同上*/
                            AVEYangJiao.Dequeue();
                            AVEYangJiao.Enqueue(jiaodu[1]);
                            YangJiao = Caulation(AVEYangJiao);
                            /*同上*/
                            AVEXuanZhuanJiao.Dequeue();
                            AVEXuanZhuanJiao.Enqueue(jiaodu[2]);
                            XuanZhuanJiao = Caulation(AVEXuanZhuanJiao);
                            /******************************************/
                        }
                    
                }


            }


        }


        /************************检验特殊值***************************/
        private int[] CheackDataTuBian(Queue<float> cheackQueue)
        {
            float[] cheackDataArrary = cheackQueue.ToArray();
     
            //flag =0表示false;  flag=1表示true
            int flag = 0; 
            int[] BoolAndIndexOfNext=new int[2];
            for (int count = 0; count < 6; count++ )
            {float Previous =cheackDataArrary[count];
                float Next = cheackDataArrary[count+1];
                if (Mathf.Abs(Previous - Next)>350.0F && Mathf.Abs(Previous -Next)<360.0f) {
                    flag = 1;
                    BoolAndIndexOfNext[0] = flag;
                    BoolAndIndexOfNext[1] = count + 1; break;
                }
            }


            return BoolAndIndexOfNext;
        }




        /*****************计算平均值****************************/
            private float Caulation(Queue<float> AVEf) {
            
            float _f=0.0f;
             foreach (float f in AVEf) {
                 _f+=f;
             }
            return _f/7;
        }
        
        /*****************处理来自数据池的数据**************************/
    private float[] DealReceivedDatanow (string DataBuf) {
    //this is a whole frame data package,then convert the 
    //First convert the Byte type into Char type
    // Debug.Log("--starting");
            //Debug.Log("databuf----"+DataBuf);
            /*把16进制字符串转换成字节数组*/
            byte[] returnBytes = new byte[DataBuf.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(DataBuf.Substring(i * 2, 2), 16);
            /*消除抖动,因为眼镜传感器会不断的发送数据,即使是不动的状态下,也会有这样的现象*/
            float[] jiaoduCollection =new float[3];
            _FangXiangJiao = (float)((byte)returnBytes[2] + ((sbyte)returnBytes[3] << 8)) / 10;
    jiaoduCollection[0] =_FangXiangJiao;
      // Debug.Log("fx-->"+FangXiangJiao);
            _YangJiao = (float)((byte)returnBytes[4] + ((sbyte)returnBytes[5] << 8)) / 10;
    jiaoduCollection[1] =_YangJiao; 
            // Debug.Log("yj-->"+YangJiao);
            _XuanZhuanJiao = -(float)((byte)returnBytes[6] + ((sbyte)returnBytes[7] << 8)) / 10;
    jiaoduCollection[2]=_XuanZhuanJiao;
            //Debug.Log("xz-->"+XuanZhuanJiao);
    //Debug.Log("--ending");




            return jiaoduCollection;
    }


        /********************处理来自数据池的数据**************************/
    private void DealReceivedData (string dataOutPool) 
    {


           //读取串口的数据, 如果没有反应就会出现timeout 异常
    // 数据格式:DB  90  AF  0C  A2  FF  2C  00  55  AA 
    //包头是DB 90  包尾:55 AA 
    //一帧发送一个数据包 总大小10个字节,
                //int DataNumber;  
     
           try { 
    //读取数据

                 byte tempB;
    tempB= (byte)sp.ReadByte();

    //Time.time;
    //Read the header first
    if (tempB ==219)
    {  
    //Debug.Log("i get the 0XDB"+(byte)0xDB);
    DataBuf[0]=tempB;
    tempB= (byte)sp.ReadByte();

    if (tempB ==144)
    DataBuf[1]=tempB;
    int DataNumber=2;
    while(DataNumber<10){
    tempB= (byte) sp.ReadByte();

    DataBuf[DataNumber]=tempB;

    DataNumber++;
      }

    }

    //read out the input data 
    //cheack the header and tail for a data package.


    //this is a whole frame data package,then convert the 
    //First convert the Byte type into Char type
    // Debug.Log("--starting");
        FangXiangJiao=(float)(DataBuf[2]+((sbyte)DataBuf[3]<<8))/10;
    /*while(NumberCount <7) {
    //_FangXiangJiao =
    }*/
     
      // Debug.Log("fx-->"+FangXiangJiao);
    YangJiao = (float)(DataBuf[4]+((sbyte)DataBuf[5]<<8))/10;
     // Debug.Log("yj-->"+YangJiao);
     XuanZhuanJiao = (float)(DataBuf[6]+((sbyte)DataBuf[7]<<8))/10;
      // Debug.Log("xz-->"+XuanZhuanJiao);
    //Debug.Log("--ending");


           } 
           catch (Exception e) {
    Debug.LogError(e);
           }
    //Debug.Log("starting");
    foreach(byte b in DataBuf) {
    //Debug.LogError(Convert.ToString(b,16));
    }
    //Debug.Log("ending");
    //yield return null;

    }


        /*********************************************/
        //在没有开启串口设备电源的时候,显示消息窗口,开启电源之后,点击确定按钮
        private void OnGUI() {
            if (showMessage)
            {
                GUI.BeginGroup(new Rect(Screen.width/2-100,Screen.height-60,400,400));
                GUI.Label(new Rect(Screen.width / 2 - 80, Screen.height - 60,200,150), "请打开串口设备电源!然后点击确定");
                if (GUI.Button(new Rect(Screen.width / 2 -80, Screen.height +95 , 100, 100), "确定"))
                {
                    open = true;
                }
                GUI.EndGroup();
            }


        }




    }

  • 相关阅读:
    由老赵反对青鸟想到的——关于自学编程的讨论
    蛙蛙推荐:《代码大全》第45章读书笔记
    大家来找错自己写个正则引擎(二)构建抽象模式树
    大家来找错自己写个正则引擎(五)检查表及总结
    大家来找错自己写个正则引擎(一)概要介绍
    大家来找错自己写个正则引擎(三)构建正则解析树及分词
    蛙蛙推荐:《代码大全》1至3章读书笔记
    sql for xml path用法(转) dodo
    sql语句总结一 dodo
    System.Management.ManagementException: 访问遭到拒绝的解决方案 dodo
  • 原文地址:https://www.cnblogs.com/alongu3d/p/3054962.html
Copyright © 2011-2022 走看看