三维姿态显⽰上位机C#+WPF+HID+Unity3D技术
三维姿态显⽰上位机 C#+WPF+HID+Unity3D技术
在毕业设计中做了⼀个基于AHRS的设计,涉及了姿态融合算法,为了调试算法参数性能,需要⽤到姿态显⽰上位机⽤来显⽰验证算法的效果。在收集了很多资料后,决定⾃⼰做⼀个三维姿态显⽰上位机。由于本⼈学识浅薄,程序中可能有很多⽬前没有发现的BUG,如有纰漏,敬请指正。
下⾯介绍⼀下我开发的⼤致⽅法:
1、HID数据传输,在开发的过程中,采⽤⽆线传输的⽅式将单⽚机的数据传输到电脑的USB端,再采⽤HID协议将USB端点的数据上传到电脑。
2、在电脑上位机中检测上传到电脑的数据,当检测到数据后,通过TCP协议与Unity3D通讯,Unity3D作为服务器,根据通信内容执⾏相关操作。
3、上位机UI采⽤开源的PanuonUI进⾏开发。
该上位机的优劣:
优点:开发简单,不⽤使⽤OpenGL开发,仅使⽤C#语⾔就可以完成开发;界⾯美观,贴图和背景相⽐OpenGL开发效果好很多;运⾏中Unity3D使⽤了GPU渲染,相⽐软渲染流畅度更好。
缺点:Unity3D的EXE⽂件较⼤,⽐采⽤C++开发的上位机体量⼤很多;可以作为学习和实验使⽤,距离商⽤还有很⼤差距。
由于整个上位机的开发过程叙述起来⽐较⿇烦,这⾥直接放出源码供需要的⼈下载使⽤。
关键代码:
HID对接收数据进⾏转换:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Windows.Interop;
using System.Windows.Threading;
using HID;
using System.Runtime.InteropServices;
using Panuon.UI.Silver;
namespace CubeAttitudeShow
{
public partial class MainWindow : WindowX
{
#region HID_协议定义与实现
/*定义HID数传的内容*/
public Hid myHid =new Hid();
public IntPtr myHidPtr =new IntPtr();
string IMUKeyNum;
int temp;
public bool BiaoDingFlag =false;
public bool BiaoDingFlag2 =false;
double MagX,MagY,MagZ;
string SmagX, SmagY, SmagZ;
string SmagX, SmagY, SmagZ;
public string Dis1;
public string Dis2;
public string Yaw;
public string Pitch;
public string Roll;
/***************************************************************************/
/// <summary>
///  数据到达事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void myhid_DataReceived(object sender, report e)
{
if(lianjieflag)
{
RecDataBuffer = e.reportBuff;
for(int a =0; a <6; a++)
TransformData[a]= RecDataBuffer[a +5];
WpfServer.SendMessage(TransformData);
/*把数据显⽰到列表框*/
IMUKeyNum = RecDataBuffer[0].ToString();//按键信息
temp =0;
if(RecDataBuffer[1]>=0x80)//判定是否是负数
temp =0-((RecDataBuffer[1]&0x7f)*256+ RecDataBuffer[2]);
else
temp =(RecDataBuffer[1])*256+ RecDataBuffer[2];
Dis1 = temp.ToString();// 1 距离
temp =0;
if(RecDataBuffer[3]>=0x80)//判定是否是负数
temp =0-((RecDataBuffer[3]&0x7f)*256+ RecDataBuffer[4]);
else
temp =(RecDataBuffer[3])*256+ RecDataBuffer[4];
Dis2 = temp.ToString();// 2 距离
temp =0;
if(RecDataBuffer[5]>=0x80)
temp =0-((RecDataBuffer[5]&0x7f)*256+ RecDataBuffer[6])/10;
else
temp =((RecDataBuffer[5])*256+(RecDataBuffer[6]))/10;
Yaw = temp.ToString();//偏航⾓
MagX = temp *0.00256;
SmagX = MagX.ToString();
temp =0;
if(RecDataBuffer[7]>=0x80)
temp =0-((RecDataBuffer[7]&0x7f)*256+ RecDataBuffer[8])/10;
else
temp =((RecDataBuffer[7])*256+(RecDataBuffer[8]))/10;
Pitch = temp.ToString();//俯仰⾓
MagY = temp *0.00256;
SmagY = MagY.ToString();
temp =0;
if(RecDataBuffer[9]>=0x80)
temp =0-((RecDataBuffer[9]&0x7f)*256+ RecDataBuffer[10])/10;
else
else
temp =((RecDataBuffer[9])*256+(RecDataBuffer[10]))/10;
Roll = temp.ToString();//滚转⾓
MagZ = temp *0.00256;
SmagZ = MagZ.ToString();
this.Dispatcher.Invoke(new Action(delegate{ KeyCommand.Text = IMUKeyNum;}));
this.Dispatcher.Invoke(new Action(delegate{ Station1.Text = Dis1;}));
this.Dispatcher.Invoke(new Action(delegate{ Station2.Text = Dis2;}));
this.Dispatcher.Invoke(new Action(delegate{ PitchAngle.Text = Pitch;}));
this.Dispatcher.Invoke(new Action(delegate{ YawAngle.Text = Yaw;}));
this.Dispatcher.Invoke(new Action(delegate{ RollAngle.Text = Roll;}));
}
}
/// <summary>
/// 设备移除事件
/// </summary>
/
// <param name="sender"></param>
/// <param name="e"></param>
protected void myhid_DeviceRemoved(object sender, EventArgs e)
{
CloseDevice();
this.Dispatcher.Invoke(new Action(delegate{ LianJie.Content = tubiao +" 失去连接 ";}));
lianjieflag =false;
}
/***************************************************************************/
Byte[] RecDataBuffer =new byte[90];
/// <summary>
/
// 打开设备
/// </summary>
protected bool OpenDevice()
{
if(myHid.Opened ==false)
{
UInt16 myVendorID =0x3333;
UInt16 myProductID =0x4444;
if((int)(myHidPtr = myHid.OpenDevice(myVendorID, myProductID))!=-1)//调⽤开启HID函数来开启HID⼝{
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
/// <summary>
/
// 设备关闭
/// </summary>
protected void CloseDevice()
{
myHid.CloseDevice(myHidPtr);
}
/// <summary>
/// 窗⼝加载时完成事件说明
/// </summary>
protected void HID_Loaded()
{
{
myHid.DataReceived +=new EventHandler&port>(myhid_DataReceived);//订阅DataRec事件            myHid.DeviceRemoved +=new EventHandler(myhid_DeviceRemoved);
}
#endregion
}
}
TCP客户端:
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.Text;
using System;
namespace CubeAttitudeShow
{
class TcpServer
{
//私有成员
private static byte[] result =new byte[1024];
private int myProt =500;//端⼝
static Socket serverSocket;//服务器接⼝
static Socket clientSocket;//客户接⼝
Thread myThread;
static Thread receiveThread;
//属性
public int port {get;set;}
//⽅法
internal void StartServer()
{
//服务器IP地址
IPAddress ip = IPAddress.Parse("127.0.0.1");thread技术
serverSocket =new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);            serverSocket.Bind(new IPEndPoint(ip, myProt));//绑定IP地址:端⼝
serverSocket.Listen(10);//设定最多10个排队连接请求
myThread =new Thread(ListenClientConnect);
myThread.Start();
}
internal void QuitServer()
{
serverSocket.Close();
clientSocket.Close();
myThread.Abort();
receiveThread.Abort();
}
internal void SendMessage(byte[] msg)
{
clientSocket.Send(msg);
}
/// <summary>
/// 监听客户端连接
/// </summary>
private static void ListenClientConnect()
{
while(true)
while(true)
{
try
{
clientSocket = serverSocket.Accept();
//clientSocket.Send(Encoding.ASCII.GetBytes("Server Say Hello"));
receiveThread =new Thread(ReceiveMessage);
receiveThread.Start(clientSocket);
}
catch(Exception)
{
}
}
}
/// <summary>
/// 接收消息
/// </summary>
/// <param name="clientSocket"></param>
private static void ReceiveMessage(object clientSocket)
{
Socket myClientSocket =(Socket)clientSocket;
while(true)
{
try
{
//通过clientSocket接收数据
int receiveNumber = myClientSocket.Receive(result);
//Debug.WriteLine("接收客户端{0}消息{1}", myClientSocket.RemoteEndPoint.ToString(), Encoding.ASCII.GetString(result, 0, receiveNumber));
}
catch(Exception ex)
{
try
{
Debug.WriteLine(ex.Message);
myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
break;
}
catch(Exception)
{
}
}
}
}
}
}
Unity嵌套:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
namespace CubeAttitudeShow
{
public partial class UnityControl : UserControl
{
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle,int x,int y,int width,int height,bool redraw);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。