【教學】Processing 結合 LinkIt 7697 互動專題:控雨

作者/攝影曾吉弘
時間1小時
難度

★★★☆☆

材料表

這學年我在台北科大互動設計系上課,上學期使用 LinkIt 7697 來上互動物聯網專題,這學期則是 Processing 與 Python 各半學期。班上人數居然有79人,4個人一組也是有20組,期中看大家的 demo 真的很累啊… 一組5分鐘就兩個小時過去了。有興趣的朋友歡迎參考我的上課講義以及 CAVEDU blog

Processing 一直是我很喜歡的一個主題,使用相對簡易的語法就可以設計出豐富有趣的介面,加上執行在電腦上就很容易透過 USB 來與 Arduino 這類裝置溝通。所以也很高興看到這組同學有不錯的結合:使用 Processing 讀取裝在 LinkIt 7697 的超音波感測器與三軸感測器,超音波用來控制球的移動速度,三軸則是控制方向。

 

影片:

本文範例與影片,感謝班上鄭同學與朱同學協助整理。

[北科互動系 期中demo]這組使用 Processing 讀取 Arduino 的超音波感測器與三軸加速度感測器,超音波用來控制球的移動速度,三軸則是移動方向。基本的 filter 寫得不錯呢

Posted by 曾吉弘 on Friday, May 1, 2020

功能說明

引用這組的期中報告,專題名稱為 [rit.]。就是樂曲上漸慢的意思

我們從電影「出神入化」中一幕控制雨水暫留於空中甚至向上漂浮的畫面獲得靈感,想要將這樣具戲劇張力的畫面實現,讓平凡人也可以擁有控制地心引力或甚至是時間的超能力。我們的功能主要是透過超音波感測器偵測手部,靠近時,畫面中的雨滴會漸慢停止,而遠離時,雨滴會回流向上,手離開感測器則雨滴恢復原行進狀態。

流程圖

說明

7697端透過 Serial.write(); 語法不斷把超音波與加速度感測器的 Y 軸送出

Processing 則是語法  serial.read(); 語法把資料讀進來之後控制雨點的速度與方向

一般人常碰到的問題是抓不到 Arduino,解決方法要讓 Arduino 的程式先跑起來,且不要開 Arduino Serial Monitor 否則會被占住而無法連線(除非你又開一個 SerialX 來顯示資料但不建議這麼做),語法: serial = new Serial(this, Arduino.list()[0], 9600);   這裡的 Arduino.list()[0] 是指電腦上抓到的第一片 Arduino,也可以直接用 “COMX” 來指定。 

以這樣的概念來說,PC 上要接多片 7697 當然是可行的。設計背景的同學在進入互動裝置時不一定需要寫很複雜的程式,但通常都會以”場域”的概念來思考專題,例如用很多感測器感測人在一個區域中的動作。這與資電背景同學(通常是做一個裝置)相比各有其趣。

 

rit 程式說明 – Processing端程式

Spot[] spots; // Declare array

import processing.serial.*;
import cc.arduino.*;
Serial serial; 
Arduino arduino;

int a1=0;
int a2=0;
int sensorValue;

void setup() {
  size(700, 700);
  serial = new Serial(this, Arduino.list()[1], 9600);  //指定 Arduino 位置
  int numSpots = 100; // Number of objects
  int dia = 15; // Calculate diameter
  spots = new Spot[numSpots]; // Create array
  for (int i = 0; i < 100; i++) {
    float x = 20*random(0, 35); //決定球圓心位置
    float rate = random(-1.0, 1.0);

    for (int i1 = 0; i1 < 100; i1++) {
      float y = 20*random(0, 35); //決定球圓心位置

      // Create each object
      spots[i] = new Spot(x, y, dia, rate);
    }
  }
  noStroke();
}

void draw() {
  fill(0, 15);
  rect(0, 0, width, height);
  fill(255);

  for (int i=0; i < 100; i++) {
    spots[i].move(); // Move each object
    spots[i].display(); // Display each object
  }
}

class Spot {   //自定義雨滴
  float x, y;         // X-coordinate, y-coordinate
  float diameter;     // Diameter of the circle
  float speed;        // Distance moved each frame
  int direction = 5;  // Direction of motion (1 is down, -1 is up)
  float diameter1;     // Diameter of the circle
  float speed1;        // Distance moved each frame
  int direction1 = 5;
  // Constructor
  Spot(float xpos, float ypos, float dia, float sp) {
    x = xpos;
    y = ypos;
    diameter = dia;
    speed = sp;
  }

  void move() {     //根據Arduino 丟過來的值決定雨滴動作
    if ( serial.available() > 0) {
      sensorValue = serial.read();

      a1=sensorValue/10;
      a2=sensorValue;
    }
    if (a1<5) {

      if (a1==0) {
        println("a2"+a2);
        if (a2==2) {
          a2=-1;
        }
        x += a2*(speed * direction1); 
        if ((x > (width - diameter1/2)) || (x < diameter1/2)) { 
          direction1 *= -1;
        }
      } else {  
        y += 0.1*a1*(speed * direction); 
        if ((y > (height - diameter/2)) || (y < diameter/2)) { 
          direction *= -1;
        } 
        x += 0.1*a1*(speed * direction1); 
        if ((x > (width - diameter1/2)) || (x < diameter1/2)) { 
          direction *= -1;
        }
      }
    } else if (a1==5) {
      y += (speed * direction); 
      if ((y > (height - diameter/2)) || (y < diameter/2)) { 
        direction *= -1;
      } 
      x += (speed * direction1); 
      if ((x > (width - diameter1/2)) || (x < diameter1/2)) { 
        direction1 *= -1;
      }
    }
  }

  void display() {   //顯示雨滴
    ellipse(x, y, diameter, diameter);
  }
}

rit 程式說明 – Arduino端(7697)程式

#define Y_PIN A1                //加速度 Y軸
int trigPin = 12;                     //超音波 Trig Pin
int echoPin = 11;                  //超音波 Echo Pin
long duration, cm, inches;
int a = 0;

float toG(float v) {
  return v * 6 / 1023 - 3;       
}

void setup() {
  Serial.begin (9600);             // Serial Port begin
  pinMode(trigPin, OUTPUT);        //Define inputs and outputs
  pinMode(echoPin, INPUT);
}

void loop()
{
  int y  = analogRead(Y_PIN);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);     // 給 Trig 高電位,持續 10微秒
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  pinMode(echoPin, INPUT);             // 讀取 echo 的電位
  duration = pulseIn(echoPin, HIGH);   // 收到高電位時的時間

  cm = (duration / 2) / 29.1;
  a = cm / 8;

  if (a < 5) {
    if (a == 0) {
      if (y > 360) {
        a = a * 10 + 2;
        Serial.write(a);
      }
      else if (y < 300) {
        a = a * 10 + 1;
        Serial.write(a);
      }
      else {
        a = 0;
        Serial.write(a);
      }
    }
    else {
      a = a * 10;
      Serial.write(a);
    }
  }
  else {
    a = 50;
    Serial.write(a);
  }
  delay(100);
}

 

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *