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

树莓派Flask应用引入onoff库后p5.js报require未定义错误

问题根源

Uncaught ReferenceError: require is not defined报错来自前后端运行环境的混淆:

  • onoff是Node.js服务端专用库,只能在树莓派本地的Node runtime中运行,直接调用系统接口访问GPIO硬件。浏览器端既不支持CommonJS规范的require语法,也没有权限直接访问树莓派的本地硬件,把包含onoff调用的JS文件直接发给浏览器加载必然报错。
  • 终端运行JS文件能正常执行,是因为终端调用的是Node.js解释器,原生支持require语法和onoff的硬件调用能力,和浏览器的JS运行环境是完全独立的两套体系。
    你当前代码还存在一个语法错误:文件末尾多了一个冗余的右大括号},后续拆分代码时记得删除。
修复方案

不要把服务端硬件控制逻辑和前端画布渲染逻辑混写在同一个JS文件里,严格拆分前后端职责:

  • 后端(树莓派本地常驻运行的服务):负责调用GPIO库监听引脚脉冲,和前端建立通信通道传递触发信号
  • 前端(浏览器加载运行的p5.js代码):负责画布渲染,接收后端传递的脉冲信号,修改坐标参数更新圆形位置

具体实现步骤

  • 第一步:剥离GPIO相关的服务端逻辑
    所有require('onoff')、引脚监听、进程退出处理的代码,都不要放到前端引用的静态JS文件里。你用Flask作为服务端的话,直接用Python生态的GPIO库(gpiozero、RPi.GPIO)实现监听逻辑更简单,不需要额外维护Node服务。最简Flask后端参考:

    from flask import Flask, render_template
    from flask_socketio import SocketIO
    from gpiozero import Button
    
    app = Flask(__name__)
    socketio = SocketIO(app, cors_allowed_origins="*")
    
    # 对应BCM编码的4号引脚,和你原有onoff配置一致
    pulse_input = Button(4)
    
    # 引脚检测到脉冲时,向前端推送实时事件
    def pulse_trigger():
        socketio.emit('gpio_event', {'pulse': 1})
    
    pulse_input.when_pressed = pulse_trigger
    
    @app.route('/')
    def index_page():
        return render_template('index.html')
    
    if __name__ == '__main__':
        socketio.run(app, host='0.0.0.0', port=5000)
    

    如果你更习惯用JS写后端,也可以用Express+Socket.IO编写独立的Node服务运行onoff监听逻辑,核心思路一致:所有硬件操作都在树莓派本地的服务层完成,不暴露给前端。

  • 第二步:精简前端p5.js逻辑,和后端建立通信
    前端加载的JS文件中删除所有Node专属的API调用(require、process相关代码),只保留画布绘制逻辑,通过WebSocket和后端建立长连接,收到脉冲信号时再更新坐标参数:

    const w = 672;
    const h = 504;
    let canvas;
    let idx = 0;
    let idy = 0;
    let Xcoords = [150, 541, 149, 541];
    let Ycoords = [168, 175, 375, 376];
    // 连接后端WebSocket服务
    const socket = io();
    
    function setup() {
        canvas = createCanvas(w, h);
        canvas.parent("canvasHolder");
        noFill();
        stroke(255, 204, 0);
        strokeWeight(6);
        // 监听后端推送的GPIO脉冲事件
        socket.on('gpio_event', (data) => {
            console.log('检测到脉冲,值:', data.pulse);
            // 在这里自定义idx、idy的更新规则,示例为循环切换坐标点
            idx = (idx + 1) % Xcoords.length;
            idy = (idy + 1) % Ycoords.length;
        })
    }
    
    function draw() {
        // 每帧重绘前清屏,避免圆形轨迹重叠
        background(0);
        ellipse(Xcoords[idx], Ycoords[idy], 40, 40);
    }
    
  • 第三步:调整HTML模板结构
    页面中本地引入p5.js、Socket.IO客户端的前端脚本,不要引入任何onoff相关代码,参考结构:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>GPIO脉冲控制画布</title>
        <script src="/static/p5.min.js"></script>
        <script src="/static/socket.io.min.js"></script>
    </head>
    <body>
        <div id="canvasHolder"></div>
        <script src="/static/canvas.js"></script>
    </body>
    </html>
    
注意事项
  • 不要尝试用打包工具把onoff编译成前端可运行的代码:浏览器的沙箱机制从操作系统层面隔离了硬件访问权限,前端永远不可能直接读写树莓派的GPIO引脚,所有硬件操作必须通过本地运行的服务层中转。
  • 注意统一引脚编码规则:你原有代码注释标注的是17号引脚,实际传入的参数是4,要确认使用的是BCM编码还是BOARD物理编码,避免引脚对应错误无法检测到脉冲。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:36:13