- IoT
- 机器人
- 嵌入式
【免费下载链接】johnny-five
JavaScript Robotics and IoT programming framework, developed at Bocoup.
导读
本文基于 Johnny-Five 官方示例 docs/proximity-EVS_EV3_IR-alert.md,讲解如何在 johnny-five 项目中通过 EVShield 扩展板接入 LEGO EV3 红外传感器(控制器标识EVS_EV3_IR),实现"近距离触发红灯 / 远距离恢复绿灯"的距离报警器。读完本文,你将掌握 EV3 红外测距在 Johnny-Five 中的接线、Proximity组件初始化、cm/inches属性读取、change事件驱动逻辑,以及Led/Leds组合控制 LED 的完整实战方案。
示例概述:距离阈值触发的双色 LED 报警器
本示例的核心思路非常简单:用一个 EV3 红外传感器持续测量前方物体距离,当距离小于 35 厘米时点亮红灯(报警),否则保持绿灯常亮。代码分为三步:初始化主板、创建Proximity传感器实例、在change事件中依据proximity.cm切换 LED 状态。
const { Board, Led, Leds, Proximity } = require("johnny-five"); const board = new Board(); board.on("ready", () => { const proximity = new Proximity({ controller: "EVS_EV3_IR", pin: "BAS1" }); const red = new Led(10); const green = new Led(11); const leds = new Leds([red, green]); green.on(); proximity.on("change", () => { if (proximity.cm < 35) { if (!red.isOn) { leds.toggle(); } } else if (!green.isOn) { leds.toggle(); } }); });这段代码与示例文件 eg/proximity-EVS_EV3_IR-alert.js 完全一致,可直接运行。
从命令行运行示例
该文档是 Johnny-Five 官方示例体系的一部分,运行方式与仓库内其他示例一致,在仓库根目录执行:
node eg/proximity-EVS_EV3_IR-alert.js运行前提:
- 已在本机安装并连接 EVShield 扩展板,板载固件为支持 EV3 传感器的版本;
- EVShield 上 BAS1 口接入 LEGO EV3 红外传感器(本示例对应
pin: "BAS1"); - Arduino 等主控通过 Firmata 固件与主机通信,Johnny-Five 会通过
Board自动建立连接; - 数字引脚 10、11 分别连接红灯、绿灯(示例中以
Led(10)、Led(11)声明); - 仓库依赖已安装,即执行过
npm install(参考 package.json)。
与基础测距示例的对照
仓库还提供了一份不带 LED 的纯日志版本 eg/proximity-EVS_EV3_IR.js,其文档见 docs/proximity-EVS_EV3_IR.md。两者唯一差异在"如何使用测量结果":
// 纯日志版:每次距离变化时打印 cm / in proximity.on("change", () => { const {centimeters, inches} = proximity; console.log("Proximity: "); console.log(" cm : ", centimeters); console.log(" in : ", inches); console.log("-----------------"); });对照学习可以更清楚:EVS_EV3_IR控制器负责把原始红外数据换算成厘米,而"报警"是应用层在change事件里自行实现的业务逻辑。
Proximity 组件的控制器与参数说明
Proximity是 Johnny-Five 中的测距组件,通过controller指定具体传感器型号,初始化时执行对应的数据采集与单位换算。在 lib/proximity.js 中可以看到完整控制器表,包括GP2Y0A21YK、GP2Y0A02YK0F、HCSR04、LIDARLITE等,其中与本文相关的两个 EV3 控制器为:
| 控制器名 | 适用传感器 | 底层实现要点 |
|---|---|---|
EVS_EV3_IR | LEGO EV3 红外传感器 | 通过 EVShield 读取 Proximity 寄存器,toCm直接返回原始值(单位已为厘米) |
EVS_EV3_US | LEGO EV3 超声波传感器 | 读取方式相同,toCm将原始值除以 10 换算为厘米 |
本示例使用EVS_EV3_IR。pin参数必须是 EVShield 的合法端口名,支持BAS1、BAS2、BBS1、BBS2(传感器口)以及BAM1/BAM2/BBM1/BBM2(电机口)。端口解析逻辑在 lib/evshield.js 的EVS.shieldPort中实现:以BA开头映射到 Bank A(I2C 地址0x1A),以BB开头映射到 Bank B(地址0x1B);S1/S2后缀决定使用哪一路传感器模式、模拟读取寄存器与偏移量(S2偏移为 52,见EVS.S2_OFFSET)。
底层原理:EVS_EV3_IR 控制器如何读取红外距离
EVS_EV3_IR控制器的实现位于 lib/proximity.js 的Controllers.EVS_EV3_IR:
EVS_EV3_IR: { initialize: { value(options, callback) { const state = priv.get(this); state.shield = EVS.shieldPort(options.pin); state.ev3 = new EVS(Object.assign(options, { io: this.io })); state.ev3.setup(state.shield, EVS.Type_EV3); state.ev3.read(state.shield, EVS.Proximity, EVS.Proximity_Bytes, data => callback(data[0] | (data[1] << 8))); } }, toCm: { value(value) { return value; } } }结合 lib/evshield.js 可还原完整调用链:
EVS.shieldPort(pin)解析端口名,得到bank、mode、offset、sensor等字段;new EVS({io})创建 EVShield 驱动实例。构造函数会把 Bank A(0x1A)与 Bank B(0x1B)两个 I2C Bank 都建立连接,并通过模块级shared变量保证同一主板只实例化一次;state.ev3.setup(...)向对应 Bank 的模式寄存器写入EVS.Type_EV3(0x13),通知扩展板该端口接入了 EV3 类型传感器;state.ev3.read(...)从EVS.Proximity寄存器(0x83)连续读取EVS.Proximity_Bytes(2 字节),回调中用data[0] | (data[1] << 8)合成 16 位原始距离值;- 原始值被写入
Proximity内部状态,随后toCm原样返回(因为 EV3 红外传感器输出的已是厘米单位的整数值)。
数据刷新与事件
Proximity构造器在 lib/proximity.js 中通过setInterval按freq(默认 25 毫秒)周期性地把当前距离封装为{ cm, centimeters, in, inches }并发出data事件;只有当raw相对上次发生变化时才额外发出change事件。此外还通过Withinablemixin 提供within([min, max], unit, callback)区间回调能力。
单元测试佐证
test/proximity.js 中Proximity: EVS_EV3_IR测试套件(exports["Proximity: EVS_EV3_IR"])验证了该控制器的完整行为:
- stub 掉
EVS.prototype.setup、EVS.prototype.read与i2cRead,模拟返回[15, 0]; within测试断言this.inches === 5.85,即原始值 15 厘米 → 15 × 0.39 = 5.85 英寸,与Proximity.prototype中inches = centimeters * 0.39的换算完全吻合;data/change测试使用假时钟tick(100)验证事件按freq触发。
这从测试层面确认了:EVS_EV3_IR的cm就是毫米级原始值的直接厘米表达,in由cm乘以 0.39 得到。
报警逻辑逐行拆解
回到本示例的报警实现,理解三处关键写法:
green.on(); // 启动时绿灯常亮,表示"安全"proximity.on("change", () => { if (proximity.cm < 35) { // 距离小于 35cm:进入报警区 if (!red.isOn) { // 仅当红灯未亮时才翻转 leds.toggle(); } } else if (!green.isOn) { // 距离 >= 35cm:离开报警区 leds.toggle(); } });- 阈值 35 厘米:LEGO EV3 红外传感器官方有效测距范围约为 5–70 厘米,35 厘米取中段,误报少且响应灵敏。你可以根据实际场景调整这个数字,也可以改用
proximity.within([0, 35], "cm", ...)表达同样的区间逻辑; - 用
red.isOn/green.isOn做状态判断,是为了避免change高频触发时反复调用toggle()造成 LED 抖动;只有当状态确实需要切换时才翻转leds(红灯亮则绿灯灭,反之亦然); Led与Leds是 Johnny-Five 的 LED 组件与集合组件:Led(10)、Led(11)分别控制数字引脚 10、11,Leds([red, green])把两个灯聚合,toggle()会整体翻转集合内每个灯的开关状态。
扩展思路与注意事项
- 改用超声波传感器:仓库提供对应的
EVS_EV3_US版本 eg/proximity-EVS_EV3_US-alert.js(文档见 docs/proximity-EVS_EV3_US-alert.md),除控制器名改为EVS_EV3_US、阈值改为 25 厘米外结构完全一致,可对照移植; - 端口选择:示例使用
BAS1,如该口被占用可换BAS2、BBS1、BBS2,只需同步修改pin; - 事件粒度:
data事件按固定频率持续触发,适合做平滑显示;change仅在值变化时触发,适合做阈值判断,本示例正是利用这一点避免无效计算; - 数据单位:
proximity.cm与proximity.centimeters等价,proximity.in与proximity.inches等价,二者由Proximity的只读属性统一提供(见 lib/proximity.js)。
相关资源
- 组件源码:lib/proximity.js
- EVShield 驱动与寄存器定义:lib/evshield.js
- 示例入口:eg/proximity-EVS_EV3_IR-alert.js、eg/proximity-EVS_EV3_IR.js
- 基础测距文档:docs/proximity-EVS_EV3_IR.md、docs/proximity-EVS_EV3_US-alert.md
- 测试用例:test/proximity.js(
Proximity: EVS_EV3_IR套件)
- IoT
- 机器人
- 嵌入式
【免费下载链接】johnny-five
JavaScript Robotics and IoT programming framework, developed at Bocoup.
相关推荐
Johnny-Five 实战:用 EVShield 驱动 LEGO EV3 超声波测距传感器(Proximity EVS_EV3_US)
Johnny Five 实战:用 EVShield 驱动 LEGO EV3 超声波测距传感器(Proximity EVS_EV3_US) 本文是一份面向 Joh
IoT机器人嵌入式Johnny-Five 距离传感实战:用 Proximity 模块驱动红外测距传感器(GP2Y0A21YK 示例)
Johnny Five 距离传感实战:用 Proximity 模块驱动红外测距传感器(GP2Y0A21YK 示例) Johnny Five 是运行在 Node.
IoT机器人嵌入式johnny-five 红外测距实战:GP2Y0A710K0F 长距传感器接入与距离换算原理
johnny five 红外测距实战:GP2Y0A710K0F 长距传感器接入与距离换算原理 本指南以 johnny five 官方示例文档 docs/prox
IoT机器人嵌入式
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考