2013年4月10日 星期三

Arduino + Process


   
   這篇文章介紹的感測器是一款基於彈簧擺動原理設計的震動感測器,震動勢能傳到彈簧末端引起共振,左右擺動碰觸到金屬外壁形成通路。由於導通時間和彈簧的剛性有關,所以該震動感測器的輸出帶寬很窄,建議使用外部中斷功能來讀取震動觸發。
    這個ProcessingArduino互動作品視頻說明:當用震動感測器敲擊桌面時,產生觸發信號,引發Ardunio控制器的外部中斷,自動執行中斷服務副程式,把感測器的震動觸發資訊上傳Processing上位機程式,於是其畫布裏的泡泡彈起,跳躍,撞擊,好一派歡快景象,過一會,由於泡泡重力作用下,泡泡平靜下來,落在矩形框的底部。如果您再次用震動感測器敲擊桌面,位於矩形框的底部的泡泡們又開始彈起,跳躍,重複上述過程。





//Arduino 程式

//震動感測器的輸出帶寬很窄,在使用Arduino讀取時,使用Arduino外部中斷功能

//數位介面2:振動,水銀,幹簧管 數位輸入感測器。
#define SensorLED     13
#define SensorINPUT   2 
//中斷次數計數器初始化為0
unsigned char state = 0;

void setup() 

  pinMode(SensorLED, OUTPUT);//設置LED為輸出 
  pinMode(SensorINPUT, INPUT);
  Serial.begin(9600);//設置串列通信的串列傳輸速率
  attachInterrupt(0, blink, FALLING);//D2口為外部中斷0,當有下降沿觸發的時候調用blink函數

}
void loop()
{
      //如果中斷次數不為0
      if(state!=0)
      {
        //如果震動感測器引發中斷
        Serial.print(1);//向Processing發送標誌值1   
        digitalWrite(SensorLED,LOW);//燈亮
        delay(500);//延時500,
        //中斷計數器清零
        state = 0;//把震動引發的第一次中斷後的若干個中斷遮罩掉         
      }  
      //如果震動感測器不動,沒有引發中斷
      else 
      {
        Serial.print(0); //向Processing發送標誌值0       
        digitalWrite(SensorLED,HIGH);//燈滅 
        delay(20); //每隔20ms,向Processing發送一次標誌值0    
      }


//如果振動感測器引發中斷,將自動調用中斷服務程式
void blink()//數位輸入感測器下降沿觸發中斷服務函數
{
  state++;//中斷計數器加1  
  //Serial.println(state);
}


//Process程式
// RS232 送出0/1  為何Process收到為48/49 ???


import processing.serial.*;//導入serial通信庫
Serial duankou;
//Serial duankou; //創建對象duankou
int data;//變數data作為接受到的資料
//修改這四個變數numBalls、spring、friction和gravity
//觀察畫布裏的泡泡震動景象的變化
int numBalls =13;//定義泡泡的數量
float spring = 0.8;//泡泡之間撞擊後的彈性係數
float friction = -0.9;//泡泡與牆壁之間撞擊後的彈性係數
float gravity = 0.4;//泡泡運動時的重力係數
Ball[] balls = new Ball[numBalls];
//初始化程式
void setup() 
{
  size(700, 250);//設置畫布尺寸,可以再修改變大,試試
  noStroke();
  smooth();

String arduinoPort = Serial.list()[1];//如果[0]不行,就换[1]
duankou = new Serial(this, arduinoPort, 9600);
  //設定通訊埠為COM3,串列傳輸速率為9600
  //duankou = new Serial(this,"COM3",9600);
  //呼叫構造器,初始化Ball物件
  for (int i = 0; i < numBalls; i++) {
    balls[i] = new Ball(random(width), random(height), random(20, 40), i, balls);}
}
//主程序
void draw() 
{
   if(duankou.available()>0)
  {
    //把Arduino傳來的位元組存入變數data
    data=duankou.read();
    //把Arduino傳來的位元組顯示在控制臺中
    println(data);
 //如果震動感測器引發了中斷,Arduino上傳標誌值1   
  if(data==49)  {      
    //調用構造器,初始化Ball物件
    for (int i = 0; i < numBalls; i++) {
    balls[i] = new Ball(random(width), random(height), random(20, 40), i, balls);
    }
  }
  }
  background(128);//畫布用灰色背景刷新
  for (int i = 0; i < numBalls; i++) {
    balls[i].collide();//調用Ball物件的collide函數   
    balls[i].move();//調用Ball物件的move函數 
    balls[i].display();//調用Ball物件的display函數   
  }
}
//對象名稱為Ball
class Ball {
  //定義物件用到的局域變數
  float x, y;
  float diameter;
  float vx = 0;
  float vy = 0;
  int id;
  Ball[] others;
 //定義構造器,給Ball物件變數賦初值
  Ball(float xin, float yin, float din, int idin, Ball[] oin) {
    x = xin;
    y = yin;
    diameter = din;
    id = idin;
    others = oin;
  } 
 //定義Ball物件的collide函數
 //判斷泡泡之間撞擊條件,並修正撞擊後,泡泡的運動參數 
  void collide() {
    for (int i = id + 1; i < numBalls; i++) {
      float dx = others[i].x - x;
      float dy = others[i].y - y;
      float distance = sqrt(dx*dx + dy*dy);
      float minDist = others[i].diameter/2 + diameter/2;
      if (distance < minDist) { 
        float angle = atan2(dy, dx);
        float targetX = x + cos(angle) * minDist;
        float targetY = y + sin(angle) * minDist;
        float ax = (targetX - others[i].x) * spring;
        float ay = (targetY - others[i].y) * spring;
        vx -= ax;
        vy -= ay;
        others[i].vx += ax;
        others[i].vy += ay;
      }
    }   
  }
 //定義Ball物件的move函數
 //判斷泡泡與牆體之間撞擊條件,並修正撞擊後,泡泡的運動參數
 //根據泡泡的運動參數,計算泡泡運動軌跡中各點的座標值
  void move() {
    vy += gravity;
    x += vx;
    y += vy;
    if (x + diameter/2 > width) {
      x = width - diameter/2;
      vx *= friction; 
    }
    else if (x - diameter/2 < 0) {
      x = diameter/2;
      vx *= friction;
    }
    if (y + diameter/2 > height) {
      y = height - diameter/2;
      vy *= friction; 
    } 
    else if (y - diameter/2 < 0) {
      y = diameter/2;
      vy *= friction;
    }
  }
  //定義Ball物件的dispaly函數
  //以泡泡運動軌跡中各點的座標值為圓心畫圓
  //顯示泡泡們的動畫效果
  void display() {
    //fill(255, 204);
    fill(255,255,0,100);
    ellipse(x, y, diameter, diameter);
  }
}



沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...