news 2026/9/23 12:15:07

使用 Johnny-Five 与 EVShield EV3 红外测距传感器构建距离报警器(Proximity - EVS_EV3_IR)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Johnny-Five 与 EVShield EV3 红外测距传感器构建距离报警器(Proximity - EVS_EV3_IR)
  • IoT
  • 机器人
  • 嵌入式

【免费下载链接】johnny-five

JavaScript Robotics and IoT programming framework, developed at Bocoup.

项目地址:https://gitcode.com/gh_mirrors/jo/johnny-five
点击查看免费下载

导读

本文基于 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 中可以看到完整控制器表,包括GP2Y0A21YKGP2Y0A02YK0FHCSR04LIDARLITE等,其中与本文相关的两个 EV3 控制器为:

控制器名适用传感器底层实现要点
EVS_EV3_IRLEGO EV3 红外传感器通过 EVShield 读取 Proximity 寄存器,toCm直接返回原始值(单位已为厘米)
EVS_EV3_USLEGO EV3 超声波传感器读取方式相同,toCm将原始值除以 10 换算为厘米

本示例使用EVS_EV3_IRpin参数必须是 EVShield 的合法端口名,支持BAS1BAS2BBS1BBS2(传感器口)以及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 可还原完整调用链:

  1. EVS.shieldPort(pin)解析端口名,得到bankmodeoffsetsensor等字段;
  2. new EVS({io})创建 EVShield 驱动实例。构造函数会把 Bank A(0x1A)与 Bank B(0x1B)两个 I2C Bank 都建立连接,并通过模块级shared变量保证同一主板只实例化一次;
  3. state.ev3.setup(...)向对应 Bank 的模式寄存器写入EVS.Type_EV30x13),通知扩展板该端口接入了 EV3 类型传感器;
  4. state.ev3.read(...)EVS.Proximity寄存器(0x83)连续读取EVS.Proximity_Bytes(2 字节),回调中用data[0] | (data[1] << 8)合成 16 位原始距离值;
  5. 原始值被写入Proximity内部状态,随后toCm原样返回(因为 EV3 红外传感器输出的已是厘米单位的整数值)。

数据刷新与事件

Proximity构造器在 lib/proximity.js 中通过setIntervalfreq(默认 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.setupEVS.prototype.readi2cRead,模拟返回[15, 0]
  • within测试断言this.inches === 5.85,即原始值 15 厘米 → 15 × 0.39 = 5.85 英寸,与Proximity.prototypeinches = centimeters * 0.39的换算完全吻合;
  • data/change测试使用假时钟tick(100)验证事件按freq触发。

这从测试层面确认了:EVS_EV3_IRcm就是毫米级原始值的直接厘米表达,incm乘以 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(红灯亮则绿灯灭,反之亦然);
  • LedLeds是 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,如该口被占用可换BAS2BBS1BBS2,只需同步修改pin
  • 事件粒度data事件按固定频率持续触发,适合做平滑显示;change仅在值变化时触发,适合做阈值判断,本示例正是利用这一点避免无效计算;
  • 数据单位proximity.cmproximity.centimeters等价,proximity.inproximity.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.

项目地址:https://gitcode.com/gh_mirrors/jo/johnny-five
点击查看免费下载
上一篇:当华硕笔记本性能失控时,G-Helper如何成为你的轻量级控制中心
下一篇:MongoDB Join Optimization 之 $project 投影与字段重命名:Golden 测试解析与执行计划解读

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 12:14:42

有载调压分接开关部件组成与故障排查实用指南

1. 整体结构拆解&#xff1a;先搞懂有载调压分接开关在变压器里到底扮演什么角色有载调压分接开关&#xff0c;业内通常简称OLTC&#xff08;On-Load Tap Changer&#xff09;&#xff0c;我一直觉得它是变压器里最“精分”的一个设备——既要承受主回路的大电流&#xff0c;又…

作者头像 李华
网站建设 2026/9/23 12:13:55

二进制、八进制、十六进制相互转换:原理、技巧与实战应用

1. 为什么值得花时间搞懂进制转换很多人第一次接触二进制、八进制、十六进制&#xff0c;是在计算机基础课上。老师讲了一遍“逢二进一”“逢八进一”“逢十六进一”&#xff0c;然后给了一堆练习题&#xff0c;做完就忘了。等到真正需要用到的时候——比如看一个二进制文件头、…

作者头像 李华
网站建设 2026/9/23 12:13:52

企业IM私有化部署不等于数据安全:数据边界才是核心判据

最近半年&#xff0c;我至少接过五六位负责企业数字化建设的朋友来咨询同一件事&#xff1a;公司想上企业IM&#xff0c;为了数据安全&#xff0c;要求必须私有化&#xff0c;让我帮忙把关。他们的第一句话往往是“我们准备把服务器放到机房&#xff0c;让所有消息、后台都跑在…

作者头像 李华
网站建设 2026/9/23 12:12:58

Go Context 并发控制实战:从 goroutine 泄漏到 Gin 超时取消

1. 从一个真实场景说起&#xff1a;为什么你的 goroutine 关不掉刚写 Go 那会儿&#xff0c;我做过一个定时同步数据的小服务。主流程很简单&#xff1a;起一个 goroutine 每隔几秒拉一次接口&#xff0c;把结果写进数据库。上线跑了一周&#xff0c;某天运维告诉我内存一直在涨…

作者头像 李华