javascript原生移动云编程13 - 通过蓝牙操控智能硬件
2014-09-11 14:00
399 查看
用javascript在码实云平台上,可以在云里编写原生的移动应用。而原生的移动应用有能力通过蓝牙与其他蓝牙设备通讯。由于多数智能硬件现在都是用蓝牙(主要是蓝牙4.0BLE)与手机通讯,因此,码实平台开发的移动应用,可以轻松地操控智能硬件。
本应用实例的智能硬件是个智能小车,小车上的主要控制电路是最流行的Arduino,通过串行口连接着一个蓝牙模块(前面白色面包板上竖插的小板)。我们使用的蓝牙模块同时兼备串口透传和iBeacon的功能(码实平台另有教程详细介绍iBeacon应用的开发和配置),叫“ZeroBeacon”,产自国内蓝牙硬件公司“四月兄弟”(淘宝上可以找到)。为了简化教程,我们把硬件做的非常简单,用一个标准的L298N模块控制电机,左电机的I1、I2分别接Arduino的8和9端口,PWM调速EA接11端口。同理,右电机的I3、I4分别接入Arduino的6和7端口,PWM调速EB接10端口。蓝牙模块的VCC接Arduino的5V供电VCC,地线GND自然接Arduino的GND,蓝牙模块通讯口TX接Arduino的1端口RX,蓝牙的RX接Arduino的0端口TX。这就是硬件实例的全部信号接线。硬件部分的Arduino程序也写的非常简单。只用一条串口指令来操作小车的两个马达。下面是Arduino的C程序:
在Arduino程序里,我们定义实现了小车左右轮的控制命令,命令格式为"go:f120,b80",解释为左轮向前速度120,右轮向后速度80。手机通过蓝牙向小车发命令,必须遵循这个命令格式。下面是在码实平台上开发的移动应用部分的javascript代码:
程序前半部主要是用Ti.UI.createSlider做了左右轮子的滑杆控制界面,注意我们利用二维变换Ti.UI.create2DMatrix把滑杆从水平变成垂直。两个滑杆都用各自的“change”事件来显示数值变化,但给小车发指令是在“stop”的事件处理中进行,这样避免连续不停地发指令。通过蓝牙发指令是这个调用:
蓝牙设备的读写口是'FFF1'。然后就是我们在Arduino里定义好的命令格式。
程序的后半部负责蓝牙通讯的建立。首先要创建一个外设管理:
这个蓝牙外设的名称是ZeroBeacon,蓝牙模块的出厂名称。可以通过蓝牙模块设置的AT指令去修改。后面是蓝牙连接过程中的各种事件处理,其中
this.peripheralManager.connectService('FFF0') 连接上蓝牙模块的接口服务。
本应用实例的智能硬件是个智能小车,小车上的主要控制电路是最流行的Arduino,通过串行口连接着一个蓝牙模块(前面白色面包板上竖插的小板)。我们使用的蓝牙模块同时兼备串口透传和iBeacon的功能(码实平台另有教程详细介绍iBeacon应用的开发和配置),叫“ZeroBeacon”,产自国内蓝牙硬件公司“四月兄弟”(淘宝上可以找到)。为了简化教程,我们把硬件做的非常简单,用一个标准的L298N模块控制电机,左电机的I1、I2分别接Arduino的8和9端口,PWM调速EA接11端口。同理,右电机的I3、I4分别接入Arduino的6和7端口,PWM调速EB接10端口。蓝牙模块的VCC接Arduino的5V供电VCC,地线GND自然接Arduino的GND,蓝牙模块通讯口TX接Arduino的1端口RX,蓝牙的RX接Arduino的0端口TX。这就是硬件实例的全部信号接线。硬件部分的Arduino程序也写的非常简单。只用一条串口指令来操作小车的两个马达。下面是Arduino的C程序:
// L298N的电机控制模块 int pinI1=8;//定义I1接口 int pinI2=9;//定义I2接口 int speedpin=11;//定义EA(PWM调速)接口 int pinI3=6;//定义I3接口 int pinI4=7;//定义I4接口 int speedpin1=10;//定义EB(PWM调速)接口 String cmd = ""; #define IO_LIGHT 13 //初始化程序段 void setup() { Serial.begin(9600); // 启动串口通信,波特率为9600b/s pinMode(pinI1,OUTPUT); pinMode(pinI2,OUTPUT); pinMode(speedpin,OUTPUT); pinMode(pinI3,OUTPUT); pinMode(pinI4,OUTPUT); pinMode(speedpin1, OUTPUT); pinMode(IO_LIGHT, OUTPUT); Serial.print("***Ready"); } //主程序段 void loop() { // 检查是否有串口写入 while (Serial.available() > 0) { cmd += char(Serial.read()); // 让板子的LED灯闪烁以示串口数据正在传输 digitalWrite(IO_LIGHT, HIGH); delay(5); digitalWrite(IO_LIGHT, LOW); } if (cmd.length() > 0) { // 从串口读取字符串,解析小车控制命令 if (cmd.startsWith("go:")) { // 命令格式 "go:f120,b80" 左轮向前速度120,右轮向后速度80 String left = cmd.substring(3, 4); int pos = cmd.indexOf(","); int left_speed = cmd.substring(4, pos).toInt(); cmd = cmd.substring(pos+1); String right = cmd.substring(0, 1); int right_speed = cmd.substring(1).toInt(); control(left, left_speed, right, right_speed); } cmd = ""; } } void control(String left, int left_speed, String right, int right_speed) { Serial.print(left); Serial.println(right); // speed control analogWrite(speedpin, left_speed); analogWrite(speedpin1, right_speed); // forward/backward direction control if (left == "f") { digitalWrite(pinI1, LOW); digitalWrite(pinI2, HIGH); } else { digitalWrite(pinI1, HIGH); digitalWrite(pinI2, LOW); } if (right == "f") { digitalWrite(pinI4, LOW); digitalWrite(pinI3, HIGH); } else { digitalWrite(pinI4, HIGH); digitalWrite(pinI3, LOW); } }
在Arduino程序里,我们定义实现了小车左右轮的控制命令,命令格式为"go:f120,b80",解释为左轮向前速度120,右轮向后速度80。手机通过蓝牙向小车发命令,必须遵循这个命令格式。下面是在码实平台上开发的移动应用部分的javascript代码:
Class.create(Mash5.Widget, { peripheralManager: null, initialize : function (config, params) { var height = Ti.Platform.displayCaps.platformHeight - dipToPx(66); var width = Ti.Platform.displayCaps.platformWidth; var container = Ti.UI.createView({ width : Ti.UI.FILL, height : Ti.UI.FILL, backgroundColor : '#fff' }); this.setContentView(container); var box = Ti.UI.createView({ top: '20dip', width: '240dip', height: '320dip', borderRadius: dipToPx(20), backgroundColor: '#888', }); container.add(box); // stop line indicator box.add(Ti.UI.createView({ top: '160dip', width: '100%', height: '1dip', backgroundColor: '#f40', })); var matrix = Ti.UI.create2DMatrix(); var left_level = Ti.UI.createSlider({ min: -50, max: 50, value: 0, width: '220dip', center: {x: '60dip', y: '160dip'}, }); left_level.transform = matrix.rotate(-90); box.add(left_level); var right_level = Ti.UI.createSlider({ min: -50, max: 50, value: 0, width: '220dip', center: {x: '180dip', y: '160dip'}, }); right_level.transform = matrix.rotate(-90); box.add(right_level); var left_value = Titanium.UI.createLabel({ color: '#fff', text: 'L:0', font: {fontSize: '16dip'}, center: {x: '60dip', y: '30dip'}, }); box.add(left_value); var right_value = Titanium.UI.createLabel({ color: '#fff', text: 'R:0', font: {fontSize: '16dip'}, center: {x: '180dip', y: '30dip'}, }); box.add(right_value); var stop_button = Ti.UI.createView({ top: '360dip', width: '240dip', height: '60dip', borderRadius: dipToPx(30), backgroundColor: '#f40', }); stop_button.add(Titanium.UI.createLabel({ color: '#fff', text: 'STOP', font: {fontSize: '24dip'}, })); container.add(stop_button); stop_button.addEventListener('click', function() { left_level.setValue(0); right_level.setValue(0); this.peripheralManager.writeValueForCharacteristic('FFF1', "go:f0,f0"); }.bind(this)); var lval = 0; var rval = 0; left_level.addEventListener('change', function() { lval = Math.floor(left_level.getValue()) * 5; left_value.setText('L:' + lval); }); right_level.addEventListener('change', function() { rval = Math.floor(right_level.getValue()) * 5; right_value.setText('R:' + new_rval); }); left_level.addEventListener('stop', function() { lval = Math.floor(left_level.getValue()) * 5; left_value.setText('L:' + lval); this.peripheralManager.writeValueForCharacteristic('FFF1', "go:" + (rval > 0 ? "f" : "b") + Math.abs(rval) + "," + (lval > 0 ? "f" : "b") + Math.abs(lval)); }.bind(this)); right_level.addEventListener('stop', function() { rval = Math.floor(right_level.getValue()) * 5; right_value.setText('R:' + rval); this.peripheralManager.writeValueForCharacteristic('FFF1', "go:" + (rval > 0 ? "f" : "b") + Math.abs(rval) + "," + (lval > 0 ? "f" : "b") + Math.abs(lval)); }.bind(this)); var statusLabel = Titanium.UI.createLabel({ color: '#fff', text: '设备状态:未开电源', font: {fontSize: '12dip'}, left: '20dip', bottom: '10dip', }); box.add(statusLabel); var statusTitle = "设备状态:" this.peripheralManager = new Mash5.BluetoothLE.PeripheralManager({ autoConnect: false, names: ["ZeroBeacon"] }); this.peripheralManager.addEventListener('discoveredPeripheral', function(peripheral) { statusLabel.text = statusTitle + ' 发现外设'; this.peripheralManager.connectPeripheral(peripheral); }.bind(this)); this.peripheralManager.addEventListener('connectedPeripheral', function(peripheral) { statusLabel.text = statusTitle + ' 已连接外设'; }); this.peripheralManager.addEventListener('digestServices', function(services) { this.peripheralManager.connectService('FFF0'); }.bind(this)); this.peripheralManager.addEventListener('digestCharacteristics', function() { statusLabel.text = statusTitle + ' 外设控制就绪'; }); this.peripheralManager.addEventListener('failedToConnectPeripheral', function(peripheral) { statusLabel.text = statusTitle + ' 连接外设失败'; }); this.peripheralManager.addEventListener('disconnectedPeripheral', function(peripheral) { statusLabel.text = statusTitle + ' 已断开外设'; }); var page = this.getCurrentPage(); page.addEventListener('close', function() { this.peripheralManager.close(); this.peripheralManager = null; }.bind(this)); } })
程序前半部主要是用Ti.UI.createSlider做了左右轮子的滑杆控制界面,注意我们利用二维变换Ti.UI.create2DMatrix把滑杆从水平变成垂直。两个滑杆都用各自的“change”事件来显示数值变化,但给小车发指令是在“stop”的事件处理中进行,这样避免连续不停地发指令。通过蓝牙发指令是这个调用:
this.peripheralManager.writeValueForCharacteristic('FFF1', "go:" + (rval > 0 ? "f" : "b") + Math.abs(rval) + "," + (lval > 0 ? "f" : "b") + Math.abs(lval));
蓝牙设备的读写口是'FFF1'。然后就是我们在Arduino里定义好的命令格式。
程序的后半部负责蓝牙通讯的建立。首先要创建一个外设管理:
this.peripheralManager = new Mash5.BluetoothLE.PeripheralManager({ autoConnect: false, names: ["ZeroBeacon"] });
这个蓝牙外设的名称是ZeroBeacon,蓝牙模块的出厂名称。可以通过蓝牙模块设置的AT指令去修改。后面是蓝牙连接过程中的各种事件处理,其中
this.peripheralManager.connectService('FFF0') 连接上蓝牙模块的接口服务。
相关文章推荐
- javascript原生移动云编程5 - 如何做互动按钮和页面跳转
- Cordova提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头、麦克风等。
- javascript原生移动云编程4 - 如何做图文并茂的博客页面UI
- javascript原生移动云编程8 - 如何插入任意web页面
- javascript原生移动云编程6 - 如何做动画效果
- javascript原生移动云编程10 - 如何调用相机并上传下载图片视频
- javascript原生移动云编程3 - 比web还简单的页面UI布局
- javascript原生移动云编程7 - 如何调用云数据服务显示实时天气
- javascript原生移动云编程1 - 十分钟做出跨平台原生App
- javascript原生移动云编程2 - 原生移动UI的起点
- Cordova提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头、麦克风等。
- JavaScript调用底层硬件已成为W3C标准:移动将进入Web时代?
- JavaScript特效:通过拖拽移动网页元素
- 无需编程,DIY自己智能小车的Android蓝牙遥控软件(一)
- 原生JavaScript技巧大收集(31~40)移动篇
- 通过iphone蓝牙与经过苹果MFI授权认证的硬件通讯,传输图片(转)
- [硬件驱动_蓝牙]蓝牙Bluez的编程实现
- 支持移动手持设备智能图表控件JavaScript charts
- 无需编程,DIY自己智能小车的Android蓝牙遥控软件(一)
- 基于SPP协议,通过iphone蓝牙与经过苹果MFI授权认证的硬件通讯,传输图片