ESP32 → UDP广播 → 手机浏览器 → Three.js 实时旋转立方体( yaw、pitch、roll )。


1 总体流程

ESP32(Wi-Fi) ➜ UDP 广播 ➜ 手机(同局域网)  
➜ 浏览器打开 index.html ➜ Three.js 接收 ➜ 立方体实时旋转

2 ESP32 端(Arduino 代码)

① 安装依赖

arduino-cli lib install "WiFi"

② 在原来 DMP 代码尾部加 UDP 发送

#include <WiFi.h>
#include <WiFiUdp.h>

const char *ssid     = "your_AP";
const char *password = "your_PW";
WiFiUDP        udp;
const uint16_t udpPort = 3000;          // 任意>1024
IPAddress      broadcastIp;             // 自动计算

void setup_UDP(){
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  // 计算广播地址 192.168.x.255
  IPAddress ip = WiFi.localIP();
  IPAddress mask = WiFi.subnetMask();
  broadcastIp = ip | ~mask;
  udp.begin(udpPort);
}

// 在 loop() 里每帧调用
void sendYPR(float y,float p,float r){
  char buf[64];
  snprintf(buf,sizeof(buf),"Y%.2fP%.2fR%.2f",y,p,r);
  udp.beginPacket(broadcastIp, udpPort);
  udp.write((uint8_t*)buf, strlen(buf));
  udp.endPacket();
}

③ 在 loop() 里打印完 ypr 后调用

sendYPR(ypr[0]*180/M_PI, ypr[1]*180/M_PI, ypr[2]*180/M_PI);

上传后打开串口监视器,确认 Wi-Fi 连接成功即可。


3 手机端准备

  1. 连入 同一路由器 Wi-Fi。
  2. 记住手机 IP(设置→关于手机→状态信息,例如 192.168.3.55)。
  3. 下面网页可直接用浏览器打开,无需安装 App

4 Three.js 网页(index.html)

把下面文件放到 电脑/树莓派 任意目录,用 Python 临时 http 即可手机访问。 我是直接再树莓派上创建了一个目录temp_web

python -m http.server 8000

手机浏览器输入
http://<树莓派IP>:8000/index.html

index.html(完整单文件)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>ESP32 YPR Three.js</title>
  <style>body{margin:0;overflow:hidden;background:#000}</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<script>
/* ---------- 1. 场景、相机、渲染器 ---------- */
const scene    = new THREE.Scene();
const camera   = new THREE.PerspectiveCamera(60,innerWidth/innerHeight,0.1,1000);
camera.position.z = 3;
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(innerWidth,innerHeight);
document.body.appendChild(renderer.domElement);

/* ---------- 2. 立方体 ---------- */
const geo = new THREE.BoxGeometry(1,1,1);
const mat = new THREE.MeshNormalMaterial();
const cube= new THREE.Mesh(geo,mat);
scene.add(cube);

/* ---------- 3. UDP 接收 ---------- */
const udp = new WebSocket('ws://192.168.3.55:8765'); // 我的pi的ip地址,后面用 WebSocket 转发
let y=0,p=0,r=0;
udp.onmessage = (ev)=>{
  const m = ev.data.match(/Y([-\d.]+)P([-\d.]+)R([-\d.]+)/);
  if(m){ y=+m[1]; p=+m[2]; r=+m[3]; }
};

/* ---------- 4. 动画循环 ---------- */
function animate(){
  requestAnimationFrame(animate);
  cube.rotation.y = THREE.MathUtils.degToRad(y);
  cube.rotation.x = THREE.MathUtils.degToRad(p);
  cube.rotation.z = THREE.MathUtils.degToRad(r);
  renderer.render(scene,camera);
}
animate();

/* ---------- 5. 窗口大小 ---------- */
addEventListener('resize',()=>{
  camera.aspect = innerWidth/innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth,innerHeight);
});
</script>
</body>
</html>

注意:浏览器无法直接收 UDP,需要中间人把 UDP 转成 WebSocket
下面用 20 行 Python 脚本当“桥梁”。


5 UDP→WebSocket 桥梁(ws_bridge.py)

pip install asyncio websockets
import asyncio, websockets, socket, re

UDP_IP = ''          # 监听所有网卡
UDP_PORT = 3000
WS_PORT  = 8765      # 浏览器连 ws://ip:8765

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
sock.setblocking(False)

CLIENTS = set()

async def udp_to_ws():
    global CLIENTS
    loop = asyncio.get_event_loop()
    while True:
        data = await loop.sock_recv(sock, 1024)
        data = data.decode().strip()
        if re.match(r'Y-?\d+\.\d+P-?\d+\.\d+R-?\d+\.\d+', data):
            dead = set()
            for ws in CLIENTS:
                try: await ws.send(data)
                except Exception: dead.add(ws)
            CLIENTS -= dead

async def handler(websocket):
    CLIENTS.add(websocket)
    await websocket.wait_closed()
    CLIENTS.remove(websocket)

async def main():
    await asyncio.gather(
        udp_to_ws(),
        websockets.serve(handler, '0.0.0.0', WS_PORT)
    )

asyncio.run(main())

启动:

python ws_bridge.py

6 最终数据流

ESP32 UDP广播 → ws_bridge.py(UDP→WebSocket)  
→ 手机浏览器(WebSocket)→ Three.js 实时旋转

7 一键验证

  1. 确认 ESP32 串口已打印 Wi-Fi 连接成功。
  2. 电脑/树莓派运行 ws_bridge.py
  3. 手机浏览器输入
    http://<树莓派IP>:8000/index.html
  4. 转动 ESP32,立方体立即跟随 yaw / pitch / roll 旋转。

8 进阶可选

需求 快速做法
更低延迟 把桥脚本放树莓派,与 ESP32 同有线
多手机同时看 WebSocket 天然支持多客户端
真·直连 UDP 微信小程序 + 微信 UDP 插件
  • 至此,ESP32 → 手机 Three.js 实时 3D 姿态 通路全部打通!

9 视频效果