這篇文章介紹的感測器是一款基於彈簧擺動原理設計的震動感測器,震動勢能傳到彈簧末端引起共振,左右擺動碰觸到金屬外壁形成通路。由於導通時間和彈簧的剛性有關,所以該震動感測器的輸出帶寬很窄,建議使用外部中斷功能來讀取震動觸發。
這個Processing與Arduino互動作品視頻說明:當用震動感測器敲擊桌面時,產生觸發信號,引發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);
}
}
沒有留言:
張貼留言