Arduino 和 Web: 使用 NodeJS 和 SerialPort2






4.65/5 (22投票s)
本文重点介绍如何使用 SerialPort2 Node.JS 模块监听 Arduino 通过串行端口(Linux、Mac)或 Windows 的 COM 端口发送的信号,并使用 Socket.IO 将信号数据实时提供给 Web。
引言
本文介绍了允许您的 Arduino 板使用每个人都可以使用的、新颖但开源的技术与 Web 连接的必要步骤。这早已可用,但使用其他替代方法,如使用 Arduino 的 LAN 或 Zigbee 模块/扩展板,可能会非常昂贵。但是,根据用途,这个简单的解决方案可能已经足够了。
您可以通过观看这个简单的视频来简单演示使用 Arduino 和 Web 可以做什么。
背景
通过 USB,Arduino 板串行连接到 PC 的某个 COM 端口,该端口由操作系统分配。Node.JS,异步服务器端 JavaScript 引擎,然后使用一个名为 SerialPort2 的 Node.JS 模块监听该端口。当收到信号时,使用 Node.JS Socket.IO 模块,数据也以异步方式提供给 Web,从而提供 Arduino 信号的实时馈送。
以下是用于展示此方法对特定问题可行性的关键技术:
- Arduino - 一个小型电子原型板。有多种版本,但在本文中使用的版本是 Arduino Mega 2560 Version 1。只要 Arduino 有串行输出数据的方式,就可以将相同的方法应用于其他版本的 Arduino。
- NodeJS - 服务器端 JavaScript 解释器。
- NodeJS SerialPort2 - 一个用于监听 COM 端口的 Node.JS 模块。
- NodeJS Socket.IO - 一个用于使用 WebSockets 等技术向 Web 提供异步数据的 Node.JS 模块。
- NPM - 一个 Node.JS 包管理器,已包含在 Node.JS 的官方安装程序中。
- jQuery - 一个便于编写脚本的 JavaScript 库。
- Flot - Flot 是一个纯 JavaScript 的、用于 jQuery 的绘图库。
- Apache - 本项目用于提供静态内容。建议使用WAMP 套件以方便安装。用户也可以使用WAMP 套件来托管 PHP 和 MySQL。
对于 Windows 用户,SerialPort2 需要以下组件才能成功构建:
- Python 2.7.3
- Visual Studio 2010
- Windows SDK 7.1
解决方案
假设用户已经具备 Arduino 的工作知识。在本文中,我们将创建一个特定场景并为其创建解决方案。将一个电位器连接到 Arduino 板的模拟引脚 0(以下简称 A0)。我们希望将模拟信号电平流式传输到 Web,并使用 Google Chrome、Firefox 或 Internet Explorer 等 Web 浏览器进行查看。信号电平必须随着电位器的旋转实时更新。
准备 Arduino 板
您可以使用以下原理图来设置电位器和 Arduino 板。
编写 Arduino 程序
您可以使用以下代码来编写 Arduino 程序。代码已充分注释。建议读者了解代码如何与 Arduino 一起工作,以便完全理解后续步骤。
const int analogInPin = A0; // Analog input pin that the potentiometer is attached to
int sensorValue = 0; // value read from the pot
int prevsensorValue = 0;
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
}
void loop() {
// read the analog in value:
sensorValue = analogRead(analogInPin);
// If the previous value is the same as the new one, the do not send to save
// communication link between the Arduino and the PC.
if (prevsensorValue != sensorValue) {
// print the results to the serial monitor:
Serial.print("A"); // Print the letter A to signal the beginning of an Input
Serial.print(sensorValue); // Send the sensor Value (this is an integer)
Serial.print("B"); // Print the letter B to signal the end of an Input
prevsensorValue = sensorValue; // Change the previous sensor value
}
// wait 100 milliseconds before the next loop
// for the analog-to-digital converter to settle
// after the last reading. If you are sending too fast
// there is also a tendency to flood the communication line.
delay(100);
}
准备 Node.JS
您可以从 Node.JS 官方网站下载官方安装程序。推荐版本是 Node.JS v0.7.8。此外,为了在 Windows 上成功构建 SerialPort2,您需要安装 Python 2.7.3 和 Microsoft Visual Studio 2010 以及 Microsoft Windows SDK 7.1。NPM 模块(已包含在 Node.JS v0.7.8 中)将负责构建过程。但是,为了简化操作,您可能需要将 *python.exe* 的目录路径添加到 PATH 环境变量。
要使用命令提示符安装所需的 Node.JS 模块,请进入您的工作目录。以下命令将下载、构建和安装必要的 Node.JS 模块。
npm install serialport2 socket.io
您应该会看到类似如下的输出。
准备服务器端
在工作目录中创建一个名为 *server.js* 的文件。
以下代码行准备了 Node.JS 和端口所需的连接。接收到的数据是全局变量
var SerialPort = require('serialport2').SerialPort;
var portName = 'COM3';
...
然后以下代码打开串行端口连接
...
var sp = new SerialPort(); // instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
baudRate: 9600, // this is synced to what was set for the Arduino Code
dataBits: 8, // this is the default for Arduino serial communication
parity: 'none', // this is the default for Arduino serial communication
stopBits: 1, // this is the default for Arduino serial communication
flowControl: false // this is the default for Arduino serial communication
});
...
以下代码仅在串行端口接收到指定端口的消息时触发。
...
var cleanData = ''; // this stores the clean data
var readData = ''; // this stores the buffer
sp.on('data', function (data) { // call back when data is received
readData += data.toString(); // append data to buffer
// if the letters 'A' and 'B' are found on the buffer then isolate what's in the middle
// as clean data. Then clear the buffer.
if (readData.indexOf('B') >= 0 && readData.indexOf('A') >= 0) {
cleanData = readData.substring(readData.indexOf('A') + 1, readData.indexOf('B'));
readData = '';
/*
More code here later...
*/
}
});
...
现在我们可以将清理后的数据发送到 Web 了。为此,我们必须先设置 Socket.IO 模块。在文件的顶部,插入 Socket.IO 模块的实例化。
var SerialPort = require('serialport2').SerialPort;
var portName = 'COM3';
var io = require('socket.io').listen(8000); // server listens for socket.io communication at port 8000
io.set('log level', 1); // disables debugging. this is optional. you may remove it if desired.
...
下一步是启动 Socket.IO。
io.sockets.on('connection', function (socket) {
// If socket.io receives message from the client browser then
// this call back will be executed.
socket.on('message', function (msg) {
console.log(msg);
});
// If a web browser disconnects from Socket.IO then this callback is called.
socket.on('disconnect', function () {
console.log('disconnected');
});
});
最后一步是允许服务器端 Socket.IO 在有新的传感器数据时向所有正在监听的客户端发出消息。为此,请将以下行插入到 `sp.on('data')` 中。
...
io.sockets.emit('message', cleanData);
...
更新代码后,`sp.on('data')` 将如下所示:
...
var cleanData = ''; // this stores the clean data
var readData = ''; // this stores the buffer
sp.on('data', function (data) { // call back when data is received
readData += data.toString(); // append data to buffer
// if the letters 'A' and 'B' are found on the buffer then isolate what's in the middle
// as clean data. Then clear the buffer.
if (readData.indexOf('B') >= 0 && readData.indexOf('A') >= 0) {
cleanData = readData.substring(readData.indexOf('A') + 1, readData.indexOf('B'));
readData = '';
io.sockets.emit('message', cleanData);
}
});
...
您的整个服务器端源代码 *server.js* 将如下所示:
var SerialPort = require('serialport2').SerialPort;
var portName = 'COM3';
var io = require('socket.io').listen(8000); // server listens for socket.io communication at port 8000
io.set('log level', 1); // disables debugging. this is optional. you may remove it if desired.
var sp = new SerialPort(); // instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
baudRate: 9600, // this is synced to what was set for the Arduino Code
dataBits: 8, // this is the default for Arduino serial communication
parity: 'none', // this is the default for Arduino serial communication
stopBits: 1, // this is the default for Arduino serial communication
flowControl: false // this is the default for Arduino serial communication
});
io.sockets.on('connection', function (socket) {
// If socket.io receives message from the client browser then
// this call back will be executed.
socket.on('message', function (msg) {
console.log(msg);
});
// If a web browser disconnects from Socket.IO then this callback is called.
socket.on('disconnect', function () {
console.log('disconnected');
});
});
var cleanData = ''; // this stores the clean data
var readData = ''; // this stores the buffer
sp.on('data', function (data) { // call back when data is received
readData += data.toString(); // append data to buffer
// if the letters 'A' and 'B' are found on the buffer then isolate what's in the middle
// as clean data. Then clear the buffer.
if (readData.indexOf('B') >= 0 && readData.indexOf('A') >= 0) {
cleanData = readData.substring(readData.indexOf('A') + 1, readData.indexOf('B'));
readData = '';
io.sockets.emit('message', cleanData);
}
});
准备客户端
这就是我们希望客户端看起来的样子:
进度条由 jQuery 提供支持。图表输出由 Flot 提供支持。值、进度条和图表会像此视频中所示那样实时更新。
为了使此功能正常工作,您的工作目录中必须包含 jQuery 库和适当的 jQuery UI 库。此外,还需要 Flot 库来使图表正常工作。
有关 index.html 的确切代码,请参阅源代码部分。
最后一步
使用 USB 将 Arduino 连接到 PC,并确定它被分配到的正确端口。您通常可以通过使用 Arduino 编程器软件并检查可用端口来轻松做到这一点。对于 Windows,它通常高于 COM 端口 1。
设置 Apache 配置,使其指向您的工作目录,并让它为客户端提供 *index.html*。
在命令提示符下进入您的工作目录,您可以执行以下命令来运行 *server.js*:
node server.js
然后您可以旋转电位器,看到电位器值、条形图和折线图实时响应变化。
最新更新
NodeJS SerialPort2 目前似乎已合并到原始的 SerialPort 项目中。您可以在此处查看项目,并在此处阅读这些优秀模块的作者的消息。
关注点
当然,如果您想要一个更简单的解决方案,可以购买以太网盾或 ZigBee 盾,以实现更复杂的实现。
历史
- 2012 年 8 月 19 日 上午 1:03 PHT - 已编辑链接并添加了一些信息。
- 2012 年 5 月 22 日 上午 7:02 PHT - 已提交发布。