Processing是一种具有革命前瞻性的新兴计算机语言,它的概念是在电子艺术的环境下介绍程序语言,并将电子艺术的概念介绍给程序设计师。谁会去学或是去用Processing呢?大致上是对科学与艺术之间的跨领域表现有兴趣的人。艺术与代码对每个现代人都是时尚而着迷的东西,特别是颇具新思想的青年学生,但原先或许只是作为看客去了解它,而不是近距离去触摸它,而有了Processing语言,就有了亲身实践的手段。为了追求美感,而去熟练编程能力,同时在敲击程序的过程中,去构造优美的画面。

  现在主要介绍的是:Andriod手机蓝牙遥控程序的Processing编程方法,看此文前,希望看看文章:“在安卓手机上运行Processing程序的方法”,该文章网址:

http://www.eefocus.com/zhang700309/blog/14-12/307377_88e74.html

 

手机截图.png

图1 安卓手机的人机界面

一、安卓手机与Arduino蓝牙模块的联机

   图1中手机人机界面上方是一个能“变色”的圆形图形,下方是三条水平的“红色”、“绿色”和“蓝色”滚动条。滚动条上滑块的X坐标位置从左到右,对应着R、G、B颜色值0到255。当手指分别轻触三条滚动条的滑块,并拖动其移动时,R、G、B值也随之变化,然后把RGB三个值通过蓝牙串口无线通信给Arduino UNO控制板,Arduino会把RGB值模拟输出给RGB实物彩盘,如图2所示。与此同时,Arduino又会把下传的RGB值,再回传给Processing程序,并把这三个RGB值反映到手机界面上方那个能“变色”的圆形图形。

bluetooth bee编程与运行切换.jpg

图2  Arduino控制器、蓝牙模块和RGB彩盘

    要实现安卓手机与Arduino蓝牙模块的联机,需采取以下步骤:

1.1、在你的手机,点击安卓手机界面,设备→应用程序,把“未知来源”的√打上。点击设备→应用程序→开发,把“USB调试”的的√打上。

1.2、在设备→无线与网络,点击蓝牙,进入蓝牙设置界面,打开蓝牙并搜索蓝牙设备,这时如果图2中蓝牙模块Bluetooth_Bee_V2处于上电状态,在“可用设备”下方就会出现这个模块的名称。

蓝牙设备搜索.jpg

图3搜索蓝牙设备

1.3 、点击Bluetooth_Bee_V2名称,进行蓝牙配对,输入PIN号为1234,并按下“确定”按钮。

蓝牙配对.JPG

图4蓝牙配对过程

1.4、蓝牙配对成功,显示“已配对的设备”有Bluetooth_Bee_V2。

蓝牙设备已配对.jpg

图5 蓝牙配对成功

      做了以上设置后,当在Processing的安卓编程环境中下载程序时,会在手机界面中显示已成功配对的蓝牙设备,然后选择Bluetooth_Bee_V2,即可建立安卓手机与Arduino蓝牙模块的联机。

 

二、 Arduino实物系统

    根据图2所示,受控于安卓手机的Arduino实物系统,包含Arduino UNO控制板、IO传感器扩展板V7.1、蓝牙模块Bluetooth_Bee_V2和RGB彩盘。

     Bluetooth Bee V2蓝牙无线数传模块采用XBEE造型设计,体积尺寸紧凑,可以直接插在IO传感器扩展板的XBEE扩展底座。其说明书网址为:

http://wiki.dfrobot.com.cn/index.php/(SKU:TEL0023)Bluetooh_Bee_V2

Bluetooth Bee V2.0.jpg

图6  Bluetooth Bee V2蓝牙无线数传模块

  由于USB版本的Arduino是通过USB转成TTL串口下载程序的,数字接口0和1就是TTL串口RX和TX。同时蓝牙模块Bluetooth_Bee_V2插在XBEE的扩展底座上,也占用了TTL串口,所以下载程序和运行蓝牙通信不能同时进行。DFRobot公司的老版本扩展板在使用XEEE这类通讯模块的时候,由于串口使用冲突,所以每次下载程序都需要把通讯模块拔下,下载完代码后重新插上模块,比较麻烦。现在新版的扩展板增加了“运行”与“下载代码”的切换键。如图7所示,下载代码时,拨到“PROG”档。运行时,拨到“RUN”档。这样调试程序就无需重复插拔通讯模块了。

IO传感器扩展板V7.1说明书网址:

http://wiki.dfrobot.com.cn/index.php/(SKU:DFR0265)IO_%E4%BC%A0%E6%84%9F%E5%99%A8%E6%89%A9%E5%B1%95%E6%9D%BF_V7.1  

IO 传感器扩展板 V7.1.jpg

图7  IO传感器扩展板V7.1

   这次在processing编程环境下编写安卓手机蓝牙遥控程序,反复下载测试纠错,次数不会低于40次,多亏新版的扩展板增加了“运行”与“下载代码”的切换键,否则会无端地承受很多劳力和心力,让我能从反复试探中,找出安卓手机蓝牙测控processing编程的正确方法。

 

三、Processing中具有蓝牙通信功能的ketai库文件安装

     Processing语言之所以强大,其中一个原因就是它有许多第三方库文件的支持,例如openCV、kinect和leap motion等,在这个蓝牙测控程序中,我用了第三方库,ketai库,它有很强的功能,要深入学习它,可以看看英文电子书“Rapid Android Development: Build Rich, Sensor-Based Applications with Processing”。

    在Arduino中如果要新增函式库,您需要将所要新增的函式库手动放到/libraries文件夹下,有点麻烦…在Processing中就不用这样了,只要依照下列步骤操作即可:

3.1、执行翻墙软件,不翻墙就下载不了ketai库文件。

3.2、在Processing安卓编程环境下,点击速写本–>引入库文件…中,选择「添加库文件…」

添加库文件.jpg

图8 添加ketai库文件

3.3、  然后会跳出Library Manager窗口,您可从中看到所有可下载的函式库

3.4、 找到ketai库,直接按「安装」即可

Library Manager.jpg

图9 安装ketai库文件
3.5、 安装完毕之后您就可在点击文件->范例文件, 在Andriod范例文件窗口下,看到ketai的范例了,您可以找些范例来学习喔。

ketai范例程序.jpg

图10 ketai库的范例程序

 

四、Processing与Arduino蓝牙通信程序

    看懂下面样例程序(有详细注释),就可了解基于processing编程的安卓手机蓝牙通信的一般方法,由于这个样例程序所展示的是多字节连续双向通信,这应该是串口通信中最困难的一种模式,掌握了此模式,那么对单字节传送或者由事件触发的字符串传送就更容易达成。在这个样例程序中,我把在任意一个Processing蓝牙通信程序都要用到的程序段用蓝色斜体字来表示,把蓝牙发送字符串的程序段用红色字体来表示,把接受字符串的程序段用绿色字体来表示。

Processing程序:

/*程序任务是:手机界面上方是一个能“变色”的圆形图形,下方是三条水平的“红色”、“绿色”和“蓝色”滚动条。滚动条上滑块的X坐标位置从左到右,对应着R、G、B颜色值0到255。

当手指分别轻触三条滚动条的滑块,并拖动其移动时,RGB值也随之变化,然后把RGB三个值从0到255转换为0到127,并把这三个范围为0到127的值,通过蓝牙串口无线通信给Arduino UNO控制板,Arduino会把0到127的值再转换为0到255的值,模拟输出给RGB实物彩盘。与此同时,Arduino又会把下传的RGB值,再上传回Processing程序,并把这三个RGB值反映到手机界面上方那个能“变色”的圆形图形。

由于Processing语言规定一个字节的数据类型为byte,它所表达的数据范围为-128到+127,所以数据类型为byte字节数据的正数范围是0到127,而RGB颜色值范围为0到255,同时水平滚动条滑块的X坐标变化范围为20到380,以上三种数据范围虽然适用不同场合,但是所反映的内容都是RGB颜色值的大小程度,故程序中通过map()函数对它们相互转换。*/

//蓝牙BT在启动时,导入所需的java类

import android.content.Intent;

import android.os.Bundle;

import ketai.net.bluetooth.*;

import ketai.ui.*;

import ketai.net.*;

KetaiBluetooth bt;//创建一个KetaiBluetooth类型变量

KetaiList klist; //创建一个KetaiList变量,使用它来选择连接的蓝牙设备。

boolean isConfiguring;//蓝牙配置状态

//启用蓝牙时,需要下面的代码

void onCreate(Bundle savedInstanceState) {

 super.onCreate(savedInstanceState);

 bt = new KetaiBluetooth(this);

}

void onActivityResult(int requestCode, int resultCode, Intent data) {

 bt.onActivityResult(requestCode, resultCode, data);

}

//设置变量,以下变量与蓝牙通信无关

byte[] val_read  =new byte[4]; //数组定义用于接受Arduino上传的数据

byte[] val_write =new byte[4];  //数组定义用于下达给Arduino的数据

byte slider_R;       //区间0到127的颜色值

byte slider_G;

byte slider_B;

int circle_color_R;   //区间0到255的颜色值

int circle_color_G;

int circle_color_B;

int mouseX_keep_R;  //暂存滚动条上滑块的X坐标值

int mouseX_keep_G;

int mouseX_keep_B;

int old_time=0;

int new_time=0;

//初始化

void setup() {

  size(400,750); //绘制一个宽度为400像素,高度为750像素的画布

  smooth();

  background(255);

  noStroke();

 orientation(PORTRAIT); //把显示模式锁定为手握手机时的纵向显示,

 isConfiguring = true;//设置蓝牙配置状态为真

 //启动蓝牙连接

 bt.start();

//设置变量初始值

 slider_R =0;       

 slider_G =0;

 slider_B =0;

 mouseX_keep_R =20;

 mouseX_keep_G =20;

 mouseX_keep_B =20;

}

//主程序

void draw()

{

 //开始配置蓝牙连接,选择已配对的蓝牙设备

 if (isConfiguring)

 {

  ArrayList names; 

  klist = new KetaiList(this, bt.getPairedDeviceNames());

  isConfiguring = false;//设置蓝牙配置状态为假,配置结束

 }

 //配置结束后,进入主界面,开始手机与所配置的蓝牙设备数据交互

 else

 {

    background(126);//设置画布背景灰度等级,数值范围0~255,数值越小越黑

    fill(255,0,0);

    rect(20,500-5,360,10);//绘制红色水平滚动条

    fill(0,255,0);

    rect(20,600-5,360,10); //绘制绿色水平滚动条

    fill(0,0,255);

    rect(20,700-5,360,10); //绘制蓝色水平滚动条

    //如果手指按下并且光标Y坐标在红色水平滚动条附近

    if(mousePressed ==true && (mouseY>500-50 && mouseY<500+50)){

      //把红色水平滚动条的滑块X坐标值转换为范围为0到127的R值

      slider_R=slider_change(500);

      //同时,绿色和蓝色水平滚动条的滑块位置不变

      mouseX_keep_G =int(map(slider_G, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_G,600);

      mouseX_keep_B =int(map(slider_B, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_B,700);

    }

    //如果手指按下并且光标Y坐标在绿色水平滚动条附近

    if(mousePressed ==true && (mouseY>600-50 && mouseY<600+50)){

      //把绿色水平滚动条的滑块X坐标值转换为范围为0到127的G值

      slider_G=slider_change(600);

      //同时,红色和蓝色水平滚动条的滑块位置不变

      mouseX_keep_R =int(map(slider_R, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_R,500);

      mouseX_keep_B =int(map(slider_B, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_B,700);

    }

    //如果手指按下并且光标Y坐标在蓝色水平滚动条附近

    if(mousePressed ==true && (mouseY>700-50 && mouseY<700+50)){

      //把蓝色水平滚动条的滑块X坐标值转换为范围为0到127的B值

      slider_B=slider_change(700);

      //同时,红色和绿色水平滚动条的滑块位置不变

      mouseX_keep_R =int(map(slider_R, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_R,500);

      mouseX_keep_G =int(map(slider_G, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_G,600);

    }

    //手指松开,或者手指所在光标不在三条滚动条附近位置

    if(mousePressed == false || (mouseY>0 && mouseY<500-50)){

      //红色、绿色和蓝色水平滚动条的滑块位置不变

      mouseX_keep_R =int(map(slider_R, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_R,500);

      mouseX_keep_G =int(map(slider_G, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_G,600);

      mouseX_keep_B =int(map(slider_B, 0, 127,20, 380 ));

      slider_stop(mouseX_keep_B,700);

    } 

   //把三个范围为0到127的RGB值,通过数组val_write[],

    //无线蓝牙串口下达给Arduino UNO

    new_time= millis();//每50ms发送一次

    if((new_time-old_time)>50 ){

      val_write[0] = -1; //起始标志字节-1,-1的补码为255    

      val_write[1] =slider_R;

      val_write[2] =slider_G;

      val_write[3] =slider_B;

      bt.broadcast(val_write);

      old_time =new_time;

    }

  /*根据该程序最下方的“接受蓝牙设备数据子程序”,

  从Arduino上传的三个范围为0到127的RGB值,

  已经存放在数组val_read[]中。如果接收到-1的补码255时,那么跟在

   255后面的就是三个范围为0到127的RGB值*/

   if(val_read[0]==-1){

      //把范围为0到127的RGB值转换为范围为0到255的RGB值

      circle_color_R = int(map(val_read[1], 0,127, 0, 255));

      circle_color_G = int(map(val_read[2], 0,127, 0, 255));

      circle_color_B = int(map(val_read[3], 0,127, 0, 255));

    }

    //根据0到255的RGB值确定手机界面上方的圆型图形填充色

    fill(circle_color_R,circle_color_G,circle_color_B);

    ellipse(200,250,250,250);

  }

}

//滚动条的滑块位置随手指轻触的位置变化而变化,同时把滑块位置转换为

//范围为0到127的颜色值,并且把这个颜色值作为该函数的返回值。

byte slider_change(int slider_y){    

   byte color_val=0;

  //如果手指光标位于滚动条X坐标值在20到380之间

  if(mouseX>20 && mouseX<380)

  {

    //滑块坐标平移的影响范围在pushMatrix()与popMatrix()之间的语句

    pushMatrix();

    //将原点从画布的左上角移动到X坐标为mouseX,Y坐标为slider_y处

    translate(mouseX,slider_y);

    fill(255);//绘制圆形滑块,圆内填充为白色

    ellipse(0,0,33,33);//以新坐标原点画直径为33的圆

    //白色圆的位置只受光标X坐标值的影响,而它的Y坐标值始终为slider_y

    //这个白色圆就是水平滚动条上的滑块,

    //白色圆只能约束在水平滚动条上,随手指光标X值的变化而移动    

    popMatrix();//恢复坐标原点到画布的左上角

    //把区间在20到380的mouseX当前值正比换算为区间0到127的值

    //这个算式的执行,可以使X坐标当前值成正比地影响区间0到127的颜色值

     color_val =byte(map(mouseX, 20, 380, 0, 127));     

  }

  //当手指光标当前X值小于等于滑块位于水平滚动条左端点的X值时,

  //白色滑块会固定在其左端点

  else if(mouseX<=20)

  {

    fill(255);

    ellipse(20,slider_y,33,33);

    color_val=0;    

  }

  //当手指光标当前X值大于等于滑块位于水平滚动条右端点的X值时,

  //白色会固定在其右端点 

  else if(mouseX>=380)

  { 

    fill(255);

    ellipse(380,slider_y,33,33);

    color_val=127;       

  }

  //把范围为0到127的颜色值作为该函数的返回值

  return color_val;

}

//当手指松开,或者手指所在光标不在三条滚动条附近位置时,

//水平滚动条的滑块位置不变

void slider_stop(int mouseX_keep,int mouseY_keep) { 

  fill(255);//圆内填充为白色

  ellipse(mouseX_keep,mouseY_keep,33,33);//以新坐标原点画直径为33的圆

}

 

//蓝牙设备列表中选择要连接的蓝牙设备

void onKetaiListSelection(KetaiList klist) {

 String selection = klist.getSelection();

 bt.connectToDeviceByName(selection);

 //dispose of list for now

 klist = null;

}

//接受蓝牙设备数据子程序

void onBluetoothDataEvent(String who, byte[] data) {

 if (isConfiguring)

 return;

 //接受字符串数据

 val_read=data;

}

 

    下面的Arduino程序发送字符串的程序段用红色字体来表示,接受字符串的程序段用绿色字体来表示。

Arduino程序:

/*接受上位机Processing程序下达的R、G、B颜色值,并通过analogWrite()

模拟输出命令把RGB值所对应的PWM信号输出给RGB彩灯。同时,把RGB值再回传给

上位机Processing程序,以使Processing画面中的圆形图形填充色与物理世界

中RGB彩灯颜色相一致。*/

int led_R = 11;//定义RGB灯红色引脚,一定要能发PWM信号的数字端口

int led_G = 9;//定义RGB灯绿色引脚

int led_B = 10;//定义RGB灯蓝色色引脚

byte start_flag;  //Processing下达的字符串的起始标志字节

byte val_read_R;//定义val_read为接收数据的变量,数据范围0~127

byte val_read_G;

byte val_read_B;

byte val_color_R;//定义RGB值,数据范围0~255

byte val_color_G;

byte val_color_B;

long old_time=0;

long new_time=0;

//初始化

void setup() {               

  pinMode(led_R, OUTPUT);//将RGB红色引脚设置为输出模式

  digitalWrite(led_R, LOW);//关闭RGB红灯

  pinMode(led_G, OUTPUT);//将RGB绿色引脚设置为输出模式

  digitalWrite(led_G, LOW);//关闭RGB绿灯

  pinMode(led_B, OUTPUT);//将RGB蓝色引脚设置为输出模式

  digitalWrite(led_B, LOW);//关闭RGB蓝灯

 Serial.begin(9600);//设置通讯波特率,启动串行通信

}

//主程序

void loop() {

 if(Serial.available() > 0)//检查串口有没有数据

  {

    start_flag= Serial.read();

    delay(10);

    //如果接收到起始标志字节255,则接下来继续读取范围为0到127的RGB值

    if(start_flag == 255){

      val_read_R=Serial.read();//读取串口数据

      val_read_G=Serial.read();

      val_read_B=Serial.read();

      delay(10);

      //通过analogWrite()模拟输出命令把RGB值所对应

      //的PWM信号输出给RGB彩灯

      val_color_R = map(val_read_R, 0, 127, 0, 255);

      analogWrite(led_R, val_color_R);

      val_color_G = map(val_read_G, 0, 127, 0, 255);

      analogWrite(led_G, val_color_G);

      val_color_B = map(val_read_B, 0, 127, 0, 255);

      analogWrite(led_B, val_color_B);     

    } 

  }

 //每50ms把RGB值回传给上位机Processing程序

  new_time= millis();

  if((new_time-old_time)>50 ){

    Serial.write(255);  

    Serial.write(val_read_R);

    Serial.write(val_read_G);

    Serial.write(val_read_B);

  }

}

    对于创客的理解,不考虑国情,应该是较为单纯地从兴趣出发动手去制作作品,并通过朋友圈或者网络媒介与他人分享,我很喜欢这种状态。写博客,筹措这些文字,对一些人感觉是个头痛的事,而我却能心安理得地尽可能详细地表达出来,以方便自己和朋友观看。但是目前N多事一起涌来,作为现实社会中的人也必须直面承担。