You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派WebGL版Unity项目与串口双向通信的实现方案咨询

方案:Unity WebGL ↔ Node.js Express ↔ Python串口脚本 ↔ Arduino 双向通信

核心架构逻辑

Unity WebGL跑在浏览器沙箱里,没法直接访问本地串口或原生套接字,所以必须搭三层中转链路:

  1. Unity WebGL 用 WebSocket 和本地Express服务器双向通信(浏览器原生支持WebSocket,Unity也有对应API)
  2. Express服务器 通过 子进程管道 和Python串口脚本做数据交互(子进程模式轻量,适配树莓派性能)
  3. Python脚本 直接操作树莓派串口,和Arduino做双向收发

第一步:Unity WebGL 端实现WebSocket通信

用Unity 2020+原生的ClientWebSocket(避免第三方库兼容问题),实现和Express服务器的消息收发:

Unity核心代码示例

using UnityEngine;
using System.Net.WebSockets;
using System.Threading;
using System.Text;
using System.Threading.Tasks;

public class WebGLSerialLink : MonoBehaviour
{
    private ClientWebSocket _webSocket;
    private CancellationTokenSource _cts;

    async void Start()
    {
        _webSocket = new ClientWebSocket();
        _cts = new CancellationTokenSource();
        // 连接本地Express的WebSocket端点
        await _webSocket.ConnectAsync(new System.Uri("ws://localhost:3000/serial"), _cts.Token);
        // 后台启动接收线程,不阻塞渲染
        _ = ReceiveSerialMessages();
    }

    // 给Arduino发数据(调用这个方法即可从Unity传数据)
    public async void SendToArduino(string data)
    {
        if (_webSocket.State != WebSocketState.Open) return;
        byte[] buffer = Encoding.UTF8.GetBytes(data);
        await _webSocket.SendAsync(
            new ArraySegment<byte>(buffer), 
            WebSocketMessageType.Text, 
            true, 
            _cts.Token
        );
    }

    // 接收从Arduino传来的数据
    private async Task ReceiveSerialMessages()
    {
        byte[] buffer = new byte[1024];
        while (_webSocket.State == WebSocketState.Open)
        {
            var result = await _webSocket.ReceiveAsync(
                new ArraySegment<byte>(buffer), 
                _cts.Token
            );
            string message = Encoding.UTF8.GetString(buffer, 0, result.Count).Trim();
            // 这里把数据传给你的游戏逻辑
            Debug.Log($"Received from Arduino: {message}");
        }
    }

    void OnDestroy()
    {
        _cts.Cancel();
        _webSocket?.CloseAsync(
            WebSocketCloseStatus.NormalClosure, 
            "App closed", 
            CancellationToken.None
        );
    }
}

第二步:Node.js Express 服务器搭建

用Express托管Unity WebGL文件,同时结合ws库实现WebSocket服务,中转WebGL和Python的数据:

1. 安装依赖

npm install express ws

2. Express核心代码示例(server.js)

const express = require('express');
const WebSocket = require('ws');
const { spawn } = require('child_process');
const path = require('path');

const app = express();
const port = 3000;

// 托管Unity WebGL构建文件(把WebGL导出的Build、TemplateData、index.html放到public目录)
app.use(express.static(path.join(__dirname, 'public')));

// 创建WebSocket服务器
const wss = new WebSocket.Server({ server: app.listen(port) });

// 启动Python串口处理脚本
const pythonSerial = spawn('python3', [path.join(__dirname, 'serial_handler.py')]);

// 处理WebGL客户端连接
wss.on('connection', (ws) => {
    console.log('WebGL client connected');

    // 把WebGL传来的数据转发给Python
    ws.on('message', (data) => {
        pythonSerial.stdin.write(data.toString() + '\n'); // 加换行让Python识别行输入
    });

    // 把Python传来的串口数据转发给WebGL
    pythonSerial.stdout.on('data', (data) => {
        ws.send(data.toString().trim());
    });

    // 打印Python的错误日志
    pythonSerial.stderr.on('data', (data) => {
        console.error('Python Error:', data.toString());
        ws.send(`ERROR: ${data.toString().trim()}`);
    });

    ws.on('close', () => {
        console.log('WebGL client disconnected');
    });
});

console.log(`Server running at http://localhost:${port}`);

第三步:Python 串口处理脚本

用pyserial库操作树莓派串口,实现和Arduino的双向通信:

1. 安装依赖

pip install pyserial

2. Python核心代码示例(serial_handler.py)

import serial
import sys

# 配置串口(树莓派上Arduino通常是/dev/ttyUSB0或/dev/ttyACM0,用ls /dev/tty*确认)
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)

def main():
    while True:
        # 读取Node.js传来的数据,发给Arduino
        input_msg = sys.stdin.readline().strip()
        if input_msg:
            ser.write(f"{input_msg}\n".encode('utf-8'))
        
        # 读取Arduino发来的数据,传给Node.js
        arduino_msg = ser.readline().strip().decode('utf-8')
        if arduino_msg:
            print(arduino_msg)
            sys.stdout.flush()  # 强制立即输出,避免缓存

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        ser.close()
        sys.exit(0)

部署与测试步骤

  1. 将Unity WebGL构建的所有文件(index.html、Build、TemplateData)放到Express项目的public目录下。
  2. 给树莓派用户串口权限:sudo usermod -a -G dialout pi,重启生效。
  3. 连接Arduino到树莓派USB口,确认串口路径正确。
  4. 启动Express服务器:node server.js。
  5. 在树莓派浏览器打开http://localhost:3000,运行Unity应用测试数据收发。

优化建议

  • 数据格式统一用JSON(比如{"cmd":"move","value":50}),方便两端解析。
  • Unity端加WebSocket断连重连逻辑,Python脚本加串口断开自动重连逻辑,提升稳定性。
  • 树莓派上可以用pm2托管Express服务器,实现开机自启和进程守护:pm2 start server.js

内容的提问来源于stack exchange,提问作者Emotibots

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:05:28