Unity之串口通信(基于三姿态传感器)
原地址:http://www.cnblogs.com/alongu3d/archive/2013/05/02/3054962.html
/*******************************/
//串口接收,采用多线程+数据池设计模式,使用队列数据结构队列,避免线程阻塞//
/*******************************/
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();
}
}
}
Unity之串口通信(基于三姿态传感器)的更多相关文章
- Java串口通信--------基于RXTX (附带资源地址)
最近帮老师做了一个小项目,一个牧场公司想用传感器收集一些环境信息,记录到数据库里去,然后加以分析查看.这里面和传感器通信用到了串口通信,我也是接触了一下,把用到的东西分享出来. 准备工作: RXTX: ...
- 基于FPGA的红外遥控解码与PC串口通信
基于FPGA的红外遥控解码与PC串口通信 zouxy09@qq.com http://blog.csdn.net/zouxy09 这是我的<电子设计EDA>的课程设计作业(呵呵,这个月都拿 ...
- C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序
C#中缓存的使用 缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可: <%@ Outp ...
- Unity串口通信
一.串口简介 串行接口(串口)通常指COM接口,是采用串行通信方式的扩展接口.串口按位(bit)发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接 ...
- VS2008基于对话框的MFC上位机串口通信(C++实现)简单例程
首先,在 vs2008 环境下创建 MFC 运用程序 设置项目名称为 ComTest(这个地方随意命名,根据个人习惯),点击确定后,点击下一步 出现如下界面 选择"基于对话框"模式 ...
- [stm32][ucos] 1、基于ucos操作系统的LED闪烁、串口通信简单例程
* 内容简述: 本例程操作系统采用ucos2.86a版本, 建立了5个任务 任务名 优先级 ...
- 电赛菜鸟营培训(三)——STM32F103CB之串口通信
一.串口通信概念 1.缩写 USART:Universal Synchronous/Asynchronous Receiver/Transmitter 通用同步/异步接收和发送器 2.用处 (1)同步 ...
- (三)stm32之串口通信DMA传输完成中断
一.DMA功能简介 首先唠叨一下DMA的基本概念,DMA的出现大大减轻了CPU的工作量.在硬件系统中,主要由CPU(内核).外设.内存(SRAM).总线等结构组成,数据经常要在内存和外设之间,外设和外 ...
- [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)
星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...
随机推荐
- Centos 7安装gvim
sudo yum install vim-X11 download vimrc from github
- JavaScript高级程序设计(第三版)学习笔记20、21、23章
第20章,JSON JSON(JavaScript Object Notation,JavaScript对象表示法),是JavaScript的一个严格的子集. JSON可表示一下三种类型值: 简单值: ...
- php 首页定时生成静态页面
往往首页的js,商务通代码加的太多,导致页面访问速度变慢,可以把首页有动态变为静态进行访问,访问速度会有所提升,不过如果更新首页数据,并不能及时更新,而是你规定的时间内固定更新一次 代码如下: < ...
- 支持BLOB操作的Jena框架扩展——JenaBLOB
与研究语义网的同行们分享一下上半年做的一个东西,它是支持BLOB操作的Jena框架扩展--JenaBLOB,已在GitHub上开源,欢迎提出宝贵意见! 众所周知,Jena是不支持BLOB类型的Lite ...
- PL/SQL在Oracle服务器上连接出错
今天在Oracle服务器上使用PL/SQL连接Oracle软件的时候出现了错误,错误如下: 具体的解决办法如下: 需要下载32位的Oracle Client,具体的步骤如下:登录Oracle官方网站 ...
- SSRS和SSAS是支持VB的
SSRS和SSAS是支持VB的,而且自定义Code其实也是只支持VB,或者其他语言可以编码成DLL再用咯.下面是官方VB函数库,基本上都能用,保存起来妥妥的. https://msdn.microso ...
- SQLSERVER2012用户登录error40
昨天晚上公司停电了,电脑非正常关闭,今早回来之后,用sa登录sqlserver,一直报error40这个错,以前没碰到过,所以很紧张,问东问西,在网上也搜了好多,也跟着配置了好多,都不行,快被逼疯的时 ...
- 关于数据导出到Excel科学计数法的处理
SELECT '=T("'+字段+'")' from table 在这里在显示的字段内容前加了 '=T("',在后面也加了'")'.在这这里T()是Exc ...
- Sql Server通过BCP数据导出Excel
1.1. bcp的主要参数介绍 bcp共有四个动作可以选择. (1) 导入. 这个动作使用in命令完成,后面跟需要导入的文件名. (2) 导出. 这个动作使用out命令完成,后面跟需要导出的文件名. ...
- 九度OJ1198 a+b 【高精度整数】
题目地址:http://ac.jobdu.com/problem.php?pid=1198 题目描述: 实现一个加法器,使其能够输出a+b的值. 输入: 输入包括两个数a和b,其中a和b的位数不超过1 ...