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

node-sense-hat中RTIMULib2的getData()作用域失效及定时读取问题

树莓派Sense Hat传感器读取问题与解决

问题背景

我使用Node.js的node-sense-hat包读取树莓派2上Sense Hat的传感器数据并保存到文件。单次读取或无限循环读取可正常工作,但需要在读取间添加延迟以确保测量可靠。

首次尝试:使用sleep包导致回调失效

尝试用sleep包添加延迟,但会让整个Node进程休眠,回调函数无法执行:

const libsensehat = require("node-sense-hat");
const libsleep    = require("sleep");
var sleep         = libsleep.sleep;
var IMU = new libsensehat.Imu.IMU;

function sensor_read_callback(err, data)
{
...process data...
}

while(true)
{
  IMU.getData(sensor_read_callback);
  sleep(1000);  // 单位:ms
}

这段代码无法写入数据,因为Node休眠时回调无法执行。

第二次尝试:setInterval触发回调错误

改用setInterval()后,出现Node.js错误:

const libsensehat = require("node-sense-hat");
var IMU = new libsensehat.Imu.IMU;
var sensor_read_interval_handle;

function sensor_read_callback(err, data)
{
...process data...
}

sensor_read_interval_handle = setInterval(IMU.getData, 1000, sensor_read_callback);  // 单位:ms
}

错误信息:

internal/validators.js:223
    throw new ERR_INVALID_CALLBACK(callback);
    ^

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined
    at setInterval (timers.js:210:3)
    at Object.<anonymous> (/root/uwrf-rocket-club-flight-recorder/sense-hat.js:92:31)
    at Module._compile (internal/modules/cjs/loader.js:1114:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
    at Module.load (internal/modules/cjs/loader.js:979:32)
    at Function.Module._load (internal/modules/cjs/loader.js:819:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)
    at internal/main/run_main_module.js:17:47 {
  code: 'ERR_INVALID_CALLBACK'
}

将IMU.getData替换为console.log后可正常输出,说明问题出在node-sense-hat的RTIMULib2上。

最终解决:bind绑定作用域

发现RTIMULib2的getData()需要处于父对象作用域才能访问,使用bind绑定IMU后代码正常工作:

const libsensehat = require("node-sense-hat");
var IMU = new libsensehat.Imu.IMU;
var sensor_read_interval_handle;

function sensor_read_callback(err, data)
{
...process data...
}

sensor_read_interval_handle = setInterval(IMU.getData.bind(IMU), 1000, sensor_read_callback);  // 单位:ms
}

我的问题

  1. 如何按固定间隔(调试后约20ms)读取Sense Hat的数据?
  2. RTIMULib2出现此行为的原因是什么?是否是IMU对象作用域变化导致绑定失效或进程退出?

注:使用Node.js v14.21.3,因node-sense-hat不兼容新版本Node(v19.8.1)。


问题解答

1. 按20ms固定间隔读取数据的实现

你已验证的bind方案可直接调整间隔为20ms使用,注意回调内的处理逻辑需用异步方式(比如异步文件写入),避免阻塞读取节奏:

const libsensehat = require("node-sense-hat");
const fs = require('fs');
const IMU = new libsensehat.Imu.IMU;
let sensorReadInterval;

function sensorReadCallback(err, data) {
    if (err) {
        console.error('读取传感器数据失败:', err);
        return;
    }
    // 异步写入文件,避免阻塞
    fs.appendFile('sensor-data.log', JSON.stringify(data) + '\n', (writeErr) => {
        if (writeErr) console.error('写入文件失败:', writeErr);
    });
}

// 设置20ms间隔读取
sensorReadInterval = setInterval(IMU.getData.bind(IMU), 20, sensorReadCallback);

// 如需停止读取,调用:clearInterval(sensorReadInterval);

另外,也可使用setTimeout递归调用,保证每次读取完成后再等待20ms,避免因回调耗时导致间隔不准:

const libsensehat = require("node-sense-hat");
const fs = require('fs');
const IMU = new libsensehat.Imu.IMU;
const READ_INTERVAL = 20;

function sensorReadCallback(err, data) {
    if (err) {
        console.error('读取传感器数据失败:', err);
    } else {
        // 异步处理数据
        fs.appendFile('sensor-data.log', JSON.stringify(data) + '\n', (writeErr) => {
            if (writeErr) console.error('写入文件失败:', writeErr);
        });
    }
    // 读取完成后,触发下一次读取
    setTimeout(() => IMU.getData(sensorReadCallback), READ_INTERVAL);
}

// 启动首次读取
IMU.getData(sensorReadCallback);

2. RTIMULib2出现该行为的原因

这是JavaScript函数作用域与this绑定的问题,和进程退出无关:

  • 当你直接把IMU.getData传给setInterval时,函数会脱离IMU对象的上下文,此时函数内部的this不再指向IMU实例。
  • RTIMULib2的getData方法内部依赖this访问IMU实例的内部状态或资源,当this指向错误(比如默认指向全局对象或undefined),方法无法正常获取回调参数,最终导致传入的回调被识别为undefined,触发ERR_INVALID_CALLBACK错误。
  • 使用IMU.getData.bind(IMU)会强制将函数内部的this绑定到IMU实例上,确保方法执行时能访问正确的上下文,因此可以正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:43:27