unity与usb串口通信(web版)

一、本文介绍在web环境下unity与usb串口进行通信的代码

本篇使用本地服务器作为unity与串口的中介,unity发送数据到服务器,服务器发送给串口收到响应并解析返回给uinty。

使用websocket协议。

注:

1.我的硬件是检测磁阻液位,用到四字节十六进制浮点数,所以这里会直接转换到十进制。

2.我的硬件会返回9字节响应,所以我会限制响应长度,可以进行适当更改

重要:

1.再开始前一定要改为.NET 4.x,或者.NET Framework,因为.NET standard 2.0或者2.1不包括需要用到的using System.IO.Ports;更换路径为File/Build Setting/Player Settings.../Other Settings/Api Compatibility Level

二、准备文件:

1.使用c#写服务端,需要打开nuget包进行安装websocket,路径:工具/NuGet包管理器/管理解决方案的NuGet程序包/浏览

2.unity端:下载NativeWebSocket,地址:https://github.com/endel/NativeWebSocket

注意:下载了.unitypackage包后拖入到unity中,他会存放到与Assets同级的目录下,打开文件夹将他全部拖到Assets目录就可以了(我不知道不拖行不行,反正我这么做的可以正常使用)

三、服务端代码:

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using WebSocketSharp.Server;
using System.Threading;
using WebSocketSharp;

namespace webforeverusb
{
    class Program
    {
        static void Main(string[] args)
        {
            var wss = new WebSocketServer("ws://localhost:8080");
            wss.AddWebSocketService<SerialService>("/serial");
            wss.Start();
            Console.WriteLine("WebSocket 服务器正在运行...");
            Console.ReadLine(); // 保持控制台运行
            wss.Stop(); // 优雅关闭服务器
        }
    }
    class SerialService : WebSocketBehavior
    {
        private SerialPort sp = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
        private bool isRunning = false;

        protected override void OnOpen()
        {
            try
            {
                sp.Open();
                Console.WriteLine("串口已打开");
                // StartReading(); // 移除持续读取,仅通过命令触发
            }
            catch (Exception ex)
            {
                Console.WriteLine($"串口打开失败: {ex.Message}");
            }
            Console.WriteLine("客户端已连接");
        }

        protected override void OnMessage(MessageEventArgs e)
        {
            string command = e.Data;
            Console.WriteLine($"收到客户端命令: {command}");

            try
            {
                if (sp.IsOpen)
                {
                    // 将命令转换为字节数组并写入串口
                    byte[] commandBytes = HexStringToBytes(command);
                    sp.Write(commandBytes, 0, commandBytes.Length);
                    Console.WriteLine("命令已写入串口");

                    // 等待并读取串口响应(9 字节)
                    byte[] response = new byte[9];
                    int bytesRead = 0;
                    int timeoutMs = 1000; // 超时时间 1 秒
                    DateTime startTime = DateTime.Now;

                    while (bytesRead < 9 && sp.IsOpen)
                    {
                        if (sp.BytesToRead > 0)
                        {
                            bytesRead += sp.Read(response, bytesRead, 9 - bytesRead);
                            Console.WriteLine($"已读取 {bytesRead}/9 字节");
                        }

                        if ((DateTime.Now - startTime).TotalMilliseconds > timeoutMs)
                        {
                            Console.WriteLine("读取响应超时");
                            Send("错误: 读取响应超时");
                            return;
                        }

                        Thread.Sleep(10);
                    }

                    // 验证响应格式
                    string responseHex = BitConverter.ToString(response).Replace("-", " ");
                    Console.WriteLine($"串口响应: {responseHex}");

                    if (response.Length == 9 && response[0] == 0x01 && response[1] == 0x04)
                    {
                        // 提取第 3 到第 6 字节(4 字节数据)
                        byte[] floatBytes = new byte[4];
                        Array.Copy(response, 3, floatBytes, 0, 4);

                        // 转换为浮点数
                        float floatValue = ConvertHexToFloat(floatBytes);
                        Console.WriteLine($"解析得到的浮点数: {floatValue}");

                        // 将浮点数值发送给客户端
                        Send(floatValue.ToString());
                    }
                    else
                    {
                        Console.WriteLine("响应格式错误");
                        Send("错误: 响应格式错误");
                    }
                }
                else
                {
                    Console.WriteLine("串口未打开");
                    Send("错误: 串口未打开");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"串口通信失败: {ex.Message}");
                Send($"错误: {ex.Message}");
            }
        }

        // 将十六进制字符串转换为字节数组
        private byte[] HexStringToBytes(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            byte[] bytes = new byte[hexString.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return bytes;
        }

        // 将 4 个字节转换为 IEEE 754 单精度浮点数
        private float ConvertHexToFloat(byte[] bytes)
        {
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes); // 翻转字节顺序(大端转小端)
            }
            return BitConverter.ToSingle(bytes, 0);
        }

        protected override void OnClose(CloseEventArgs e)
        {
            isRunning = false;
            if (sp != null && sp.IsOpen)
            {
                sp.Close();
                sp.Dispose();
                Console.WriteLine("串口已关闭");
            }
            Console.WriteLine("客户端断开连接");
        }

        protected override void OnError(WebSocketSharp.ErrorEventArgs e)
        {
            Console.WriteLine($"WebSocket 错误: {e.Message}");
        }
    }
}

四、unity端:

cs 复制代码
using UnityEngine;
using NativeWebSocket;
using System.Threading.Tasks;

public class WebSocketClient : MonoBehaviour
{
    private WebSocket websocket;
    public float pavalue; // 存储解析后的浮点数值

    async void Start()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        websocket = new WebSocket("ws://localhost:8080/serial");

        websocket.OnOpen += () =>
        {
            Debug.Log("连接成功,状态: " + websocket.State);
            SendCommand("01 04 00 02 00 02 D0 0B"); // 发送新命令
        };

        websocket.OnMessage += (bytes) =>
        {
            string message = System.Text.Encoding.UTF8.GetString(bytes);
            Debug.Log($"收到数据: {message}");

            // 尝试解析为浮点数
            if (float.TryParse(message, out float value))
            {
                pavalue = value;
                Debug.Log($"解析得到的浮点数: {pavalue}");
            }
            else
            {
                Debug.LogWarning("无法解析为浮点数: " + message);
            }
        };

        websocket.OnError += (e) =>
        {
            Debug.LogError($"错误: {e}");
        };

        websocket.OnClose += (e) =>
        {
            Debug.Log("连接关闭");
        };

        await websocket.Connect();
#else
        Debug.LogWarning("WebSocket 仅在 WebGL 构建中运行");
#endif
    }

    public void SendCommand(string command)
    {
        if (websocket != null && websocket.State == WebSocketState.Open)
        {
            websocket.SendText(command);
            Debug.Log($"发送命令: {command}");
        }
        else
        {
            Debug.LogError("WebSocket 未连接,无法发送命令");
        }
    }

    float timer = 0f;
    void Update()
    {
        timer += Time.deltaTime;
        if (timer >= 1f)
        {
            SendCommand("01 04 00 02 00 02 D0 0B");
            timer = 0f;
        }
    }

    async void OnDestroy()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        if (websocket != null)
        {
            await websocket.Close();
        }
#endif
    }
}

五、结尾:

有任何错误请指出,补充请评论,看到会第一时间回复,谢谢。
相关推荐
专注VB编程开发20年10 分钟前
C#.NET模拟用户点击按钮button1.PerformClick自动化测试
开发语言·自动化测试·c#·vb.net
一个程序员(●—●)2 小时前
C#调用Lua方法1+C#调用Lua方法2,3
开发语言·c#·lua
头发掉光的程序员2 小时前
Raymarching Textures In Depth
ue5·游戏引擎·图形渲染
虾球xz4 小时前
游戏引擎学习第219天
c++·学习·游戏引擎
佟格湾7 小时前
聊透多线程编程-线程池-7.C# 三个Timer类
开发语言·后端·c#·多线程编程·多线程
浅陌sss8 小时前
C#容器源码分析 --- Queue<T>
c#
观无10 小时前
JWT认证服务与授权 .netCore
c#
虾球xz10 小时前
游戏引擎学习第213天
c++·windows·学习·游戏引擎
FAREWELL0007510 小时前
C#核心学习(十五)面向对象--关联知识点(1)命名空间
学习·c#·命名空间
宝桥南山11 小时前
Model Context Protocol (MCP) - 尝试创建和测试一下MCP Server
microsoft·ai·微软·c#·.net·.net core