Arduino 运行 C 语言,而主控端运行 JavaScript,一次要编写和维护两种程序。既然浏览器和服务器都用 JavaScript,若 Arduino 也能用 JavaScript 控制,那岂不完美?
这就是 Rick Waldron 设计 Johnny-Five 库文件的原因。Johnny-Five 是1986 年上映的科幻电影“Short Circuit(直译为“短路”,译作“霹雳五号”)”当中的机器人主角的名字。电影中的机器人原本是人工智能军武,由于雷击造成短路,让它有了自我意识而开始一连串的故事。
霹雳五号:用 JavaScript 控制 Arduino
Johnny-Five(以下称“霹雳五号”)是在电脑或树莓派之类的高端控制板上运行的 Node.js 包,通过电脑上的 JavaScript 运行所有程序逻辑,而 Arduino 控制板只充当乖乖听话的“外设接口”。
实际的硬件接线如下,电脑或树莓派通过USB 接口( 或GPIO 串口引脚)与 Arduino 板控制相连。
《完美图解Arduino 互动设计入门》的17-3 节提到,有一种在电脑软件和微处理器之间传递数据的通用消息格式,叫作 Firmata。“霹雳五号”的 JavaScript 代码和 Arduino 控制板就是用 Firmata 协议来沟通的。
Arduino IDE 提供了一个“StandardFirmata” 程序, 让 Arduino 控制板能收发 Firmata 消息。我们不需要了解 Firmata 的语法,霹雳五号的 JavaScript 程序会搞定一切。
除了霹雳五号,普遍用于儿童电脑教育的 Scratch,也是运用 Firmata 协议与 Arduino 控制板沟通的。
霹雳五号不仅支持 Arduino 控制板, 也支持 Raspberry Pi、
BeagleBone Black、Intel Galileo、Edison 等控制板,详细的列表与说明,请参阅:http://johnny-five.io/platform-support/。
霹雳五号的基本结构
和 Arduino 的C 语言不同,霹雳五号程序至少包含三大要素:
- 引用“johnny-five”库文件。
- 创建 board 对象,通过它跟Arduino控制板的串口相连。
- 创建连接回调函数。
基本程序架构如下:
霹雳五号会自动查找连接在USB 串口的Arduino 控制板,也可以通过代码明确指定串口(若是通过树莓派的GPIO 串口连接Arduino 控制板的,就一定要设置串口名,否则会产生错误)。
如下是在不同的操作系统上指定USB 串口的方式,星号(*)代表串口编号:
// Windows 系统 var board = new five.Board({ port:"COM*"}); // Mac OS X 系统 var board = new five.Board({ port:"/dev/tty.usbmodem****"}); // Linux(Raspberry Pi) 系统 var board = new five.Board({ port:"/dev/ttyUSB*"}); // 树莓派GPIO 串口 var board = new five.Board({ port:"/dev/ttyAMA0"});
用霹雳五号指挥 Arduino 闪烁 LED
实验说明:学习霹雳五号的基本程序架构以及相关设置;编写JavaScript 代码令 Arduino 控制板的 13 脚闪烁。
实验材料:Arduino UNO 控制板,一片。
实验代码:请先添加一个存放Node 程序的文件夹,这里将此文件夹命名为blink。然后打开终端窗口,在blink 路径下运行下面的安装霹雳五号模块的指令:
> npm install johnny-five
安装完毕后,在此路径下添加一个index.js 文件,并输入闪烁LED 代码(请自行修改串口名)。
Arduino 控制板要上传StandardFirmata 程序,请打开Arduino IDE 中的“文件”→“示例”→“Firmata”→“StandardFirmata”,并上传到Arduino 控制板。
实验结果:在终端窗口中输入“node index.js”指令,Node 将响应连接状况并且初始化一个REPL 环境(参阅下文说明),紧接着,操控Arduino 的程序将开始运行,让13 脚的LED 开始闪烁。
若运行Node 程序时,终端窗口中出现类似于下面的错误消息,则代表无法跟Arduino 控制板连接:
1440865565684 Connected /dev/ttyAMA0 1440865575745 Device or Firmware Error A timeout occurred while connecting to the Board.
Please check that you've properly flashed the board with the correct firmware.
请检查代码里的USB 端口名是否正确, 以及Arduino 控制板是否上传了 StandardFirmata 程序。
霹雳五号与Arduino 的C 语言代码架构比较
Arduino 的编程语言是简化版的C/C++,它提供了许多标准C语言所没有的指令,例如setup()、loop()、delay()、digitalRead() 等。同样地,霹雳五号也向Arduino 看齐,
提供了在标准JavaScript 语言中不存在,但是简单易懂的指令和对象,方便我们操控微电脑。
通过比较使用Arduino 的C 语言和霹雳五号的JavaScript 代码来控制LED,霹雳五号不需要事先设置Arduino 引脚的模式(即:输入或输出),也不需要通过循环控制 LED 闪烁,因为霹雳五号把一些常用的电子元器件控制模式都写成对象(参阅下文),我们无须理会背后的运作细节。
Arduino 的C 语言程序经过编译之后,保存在微控器里面运行。霹雳五号的 JavaScript 程序则是在电脑上运行的,Arduino 无法独立运作。换句话说,如果电脑关机或者拔除USB 连接,霹雳五号程序和Arduino 控制板就没有作用了……看到这里,读者一定感到疑惑,这种运作模式好吗?
视情况而定。若只为了闪烁LED,当然不好。但若是在电脑上运行Node 网站服务器或者复杂的运算,同时需要与外界环境交互时,那就不失为一种良好的解决方案。
此外,树莓派和其他高端微控制板,甚至是能安装Windows 或Linux 系统的电视棒,也能运行Node 与霹雳五号,不一定要使用耗电量较高的电脑。
通过REPL 模式操控Arduino
霹雳五号会在运行阶段自动设置一种REPL 操作模式,也就是让我们在终端窗口中直接输入JavaScript 语句来操控Arduino。至于要开放哪些指令在终端窗口中操作,由 repl 对象的inject() 方法设置:
如下程序将提供Led 对象给REPL 模式操作,请将此程序文件命名为index.js,保存在上一节的blink 文件夹中:
运行此node.js 程序后,即可在终端窗口中测试上文提到的led 对象方法,回力例如led.on() 将点亮LED。
接着输入led.blink(500) 或led.strobe(500),LED 将以500ms 时间间隔闪烁(默认间隔时间为100ms),直到输入led.stop() 为止。测试完毕后,按两次“Ctrl+C”快捷键退出程序。
repl 对象也能包含自定义函数,方便我们运行一连串事先定义好的语句。如下代码注入名为“on”和“off”的自定义函数,分别运行点亮和关闭LED 的方法。
运行此程序进入REPL 模式后,输入on() 可点亮LED ;输入off() 则关闭LED。
若程序不需要使用REPL 模式,则可以在创建Board 对象时取消。取消之后,程序里的REPL 相关代码将无法运行(会报错)。
霹雳五号的方法与内置对象
霹雳五号提供的数字和模拟引脚控制指令,都刻意设计成和Arduino 的C 语言指令同名。例如:
-
pinMode(引脚 , 模式 ):设置引脚模式。“模式”的可能值如下 :
- 数字输入:Pin.INPUT
- 数字输出:Pin.OUTPUT
- 模拟输入:Pin.ANALOG
- PWM 输出:Pin.PWM
- 舵机信号:Pin.SERVO
-
digitalWrite(引脚 , 信号 ):输出数字信号,可能值为 0 或 1。
- digitalRead(引脚 , 处理函数 ( 值 )):读取数字输入信号。如下代码将读取数字 2 脚,武汉试管婴儿并将其值显示在终端窗口中:
- analogWrite(引脚 , 值 ):输出 0~255 的 PWM 值。
- analogRead(引脚 , 处理函数 (值 )):读取模拟输入信号,可能值为 0~1023。如下程序片段,将读取A0 引脚的模拟输入值:
board.on("ready", function() { this.pinMode(0, five.Pin.ANALOG); // A0 引脚设置成模拟输入 this.analogRead(0, function(value) { // 持续读取A0 引脚值 console.log(value);
});
});
- loop(毫秒, 处理函数):相当于Arduino的loop()循环函数,也是JavaScript的setInterval() 方法的简化版。如下代码将每隔0.5 秒变换一次13 脚的输出状态:
完整的API 指令列表, 请参阅霹雳五号官网的Board 类的API 单元(http://johnny-five.io/api/board/#api)。
霹雳五号也内置了常用的控制对象(Component Class,组件类),有助于精简代码。
- Button:读取开关或按钮的状态,支持上拉电阻设置。
- Led :控制普通的发光二极管。
- Led.Matrix :控制矩阵 LED显示器,内置 ASCII字符集。
- LCD :支持并列连接或者用 I2C 接口串联的HD44780 液晶显示器。
- Sensor :传感器,泛指读取所有模拟输入元器件的输入值。
- Servo :控制普通或者 360°旋转的舵机。
- Motor :控制碳刷电机,支持 H 桥式电路和 PWM 速度与转向控制。
- Ping:读取超音波测距模块的返回值。
- IR.Reflect.Array :读取连接在模拟脚的数个反射或遮光型光电传感器。
- ShiftRegister :控制并输出数据给 74HC595 位移寄存器。
- Thermometer :读取温度值。
完整的控制对象列表和示例代码,请参阅霹雳五号官网的API 单元(http://johnny-five.io/api/)。
JavaScript 程序和霹雳五号并没有Arduino 的delay(延迟或暂停)指令,JavaScript 采用setTimeout() 函数来设置要延后运行的语句
或者,使用霹雳五号board 对象的wait() 方法(代表“等待”)。例如,如下程序一开始点亮13 脚的LED,经过3 秒之后,将它关闭:
JavaScript 也没有Arduino 的millis() 指令,JavaScript 提供的是 getTime() 函数和Date(日期)对象。
millis() 可返回从Arduino 开机到现在所经过的毫秒数。
getTime() 可返回从1970 年1 月1 日零时到现在所经过的毫秒数。
作者:赵英杰,网昱多媒体技术总监,美国密歇根 S.V. 州立大学传播与多媒体硕士,开源硬件技术达人。专长为 Arduino、Flash、Dreamweaver 等,在台湾大学、台湾科技大学等大专院校及教育训练单位担任讲师、并著有《超图解Arduino 互动设计入门》、《超图解物联网IoT 实作入门》、 《Dreamweaver CS6 教学范本(适用SiliconStone 认证考试教材)等多本相关书籍。 《超图解 Arduino 互动设计入门》 已授权 Arduino 原厂发行多国语言版本,为华文世界 Arduino 教材首例!
本文选自《完美图解物联网IoT实操:使用JavaScript,Node.JS,Arduino,Raspberry Pi》第 5 章。