橡皮筋槍

code

#include <Servo.h> //伺服馬達的函示庫

#include <Wire.h> //啟用I2C介面(LCD)

#include <LiquidCrystal_I2C.h> //LCD的函示庫

LiquidCrystal_I2C lcd(0x3F,16,2);

Servo servo1, servo2, servo3; //宣告三個馬達的名稱

void setup(){

Serial.begin(9600);

servo1.attach(8);

servo2.attach(9);

servo3.attach(10);

lcd.init();

lcd.backlight();

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Servo in D8");

lcd.setCursor(0,1);

lcd.print("Wait command...");

}

void loop(){

int x = analogRead(A0);//讀取A0腳位的輸入,0~1023

int y = analogRead(A1);//讀取A1腳位的輸入,0~1023

int z = analogRead(A2);//讀取A2腳位的輸入,0~1023

lcd.clear();

lcd.setCursor(0,0);

lcd.print(x);

lcd.setCursor(5,0);

lcd.print(y);

lcd.setCursor(10,0);

lcd.print(z);

delay(100);

}

以上只是可以讀取香菇頭讀數的程式碼,

你需要把修改程式碼。

其中香菇頭的讀數左右軸與上下軸是0~1023,擊發按鈕按下後是0

你需要把香菇頭的讀數換算成伺服馬達的角度

你會用到一個函數 map(變數, 輸入的下界, 輸入的上界, 輸出的下界, 輸出的上界);

ex.

int angle1 = map(x, 0, 1023, 0, 180); //angle1 就是計算出來的角度

控制伺服馬達的方式

伺服馬達名稱.write(角度);

ex.

servo1.write(90); //轉動伺服馬達1到90度的位置

如果修改成功,你會發現伺服馬達會隨香菇頭的按壓而移動,

但因為香菇頭會復位,所以伺服馬達很難保持在同一個位置

因此程式碼

伺服馬達角度 = 現在角度 + 改變量(香菇頭的讀數)

(1)向前推少一點:

= 90(起始值) + 1

(2)向前推多一點:

= 90(起始值) + 5

以下是兩種控制法的比較

#include <Servo.h> //伺服馬達的函示庫

#include <Wire.h> //啟用I2C介面(LCD)

#include <LiquidCrystal_I2C.h> //LCD的函示庫

LiquidCrystal_I2C lcd(0x3F,16,2);

Servo servo1, servo2, servo3; //宣告三個馬達的名稱

int RL0=90 , UD0=90 ;

int RL1 , UD1 ; //

void setup(){

Serial.begin(9600);

servo1.attach(8);

servo2.attach(9);

servo3.attach(10);

lcd.init();

lcd.backlight();

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Servo in D8");

lcd.setCursor(0,1);

lcd.print("Wait command...");

}

void loop(){

int x = analogRead(A0);//讀取A0腳位的輸入,0~1023

int y = analogRead(A1);//讀取A1腳位的輸入,0~1023

int z = analogRead(A2);//讀取A2腳位的輸入,0~1023

UD1 = UD0 + map(x, 0, 1023, -5, 5);

servo1.write(UD1);

UD0=UD1 ;

lcd.clear();

lcd.setCursor(0,0);

lcd.print(x);

lcd.setCursor(5,0);

lcd.print(y);

lcd.setCursor(10,0);

lcd.print(z);

delay(100);

}

觸發機構的程式碼

觸發SW 接在 A2 (數位16)

所以要在 void setup(){ }

內加入

pinMode(16, INPUT_PULLUP);

在 void loop(){ }

加入

if(digitalRead(16)==0){

servo3.write(180); // 擊發瞬間servo3的角度

}else{

servo3.write(90); //未擊發時servo3 的角度

}

第一版程式碼

#include<Servo.h>

#include<Wire.h>

#include<LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

////////////////////////////////////////////////////////////////////////////////////////////////////

int angle_lunch=180; //設定觸發時servo的角度

int angle_ready=120; //設定預備時servo的角度

/////////////////////////////////////////////////////////////////////////////////////////////////////

Servo servo1,servo2,servo3;

int rl0=90,ud0=90 ;

int rl1,ud1;

void setup(){

Serial.begin(9600);

servo1.attach(8);

servo2.attach(9);

servo3.attach(10);

pinMode(16, INPUT_PULLUP);

lcd.init();

lcd.backlight();

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Servo in D8");

lcd.setCursor(0,1);

lcd.print("Wait command...");

}

void loop() {

int x=analogRead(A0)-7;

int y=analogRead(A1)-11;

rl1=rl0+map(x,0,1023,-5,5);

if(rl1>180)

{

rl1=180;

}

if(rl1<0)

{

rl1=0;

}

servo1.write(rl1);

rl0=rl1;

ud1=ud0+map(y,0,1023,-5,5);

if(ud1>180)

{

ud1=180;

}

if(ud1<0)

{

ud1=0;

}

servo1.write(ud1);

ud0=ud1;

if(digitalRead(16)==0)

{

servo3.write(angle_lunch);

delay(200);

servo3.write(angle_ready);

delay(300);

}

else

{

servo3.write(angle_ready);

}

lcd.clear();

lcd.setCursor(0,0);

lcd.print(x);

lcd.setCursor(5,0);

lcd.print(y);

lcd.setCursor(10,0);

lcd.print(digitalRead(A2));

delay(30);

}

用上列程式碼的缺點是,有時候會亂飄,因此加入濾波,

除此之外香菇頭復位後,輸出不一定等於512(中點)

因此需要校正並且先設定初始角度 x_set 與 y_set

#include<Servo.h>

#include<Wire.h>

#include<LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f,16,2);

Servo servo1,servo2,servo3;

////////////////////////////////////////////////////////////////////////////////////////////////////

int angle_lunch=180; //設定觸發時servo的角度

int angle_ready=120; //設定預備時servo的角度

/////////////////////////////////////////////////////////////////////////////////////////////////////

int rl0=90 , ud0=90 ;

int rl1,ud1,x,y;

long x_avg,x_set;

long y_avg,y_set;

unsigned long t1,t2;

void lcd_disp(){

t2=millis();

if(t2>t1+50){

lcd.clear();

lcd.setCursor(0,0);

lcd.print(rl1);

lcd.print("(");

if(x>=0){

lcd.print("+");

}

lcd.print(x);

lcd.print(")");

lcd.setCursor(8,0);

lcd.print(ud1);

lcd.print("(");

if(y>=0){

lcd.print("+");

}

lcd.print(y);

lcd.print(")");

t1=t2;

}

}

void setup(){

Serial.begin(9600);

servo1.attach(8);

servo2.attach(9);

servo3.attach(10);

pinMode(16, INPUT_PULLUP);

lcd.init();

lcd.backlight();

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Servo in D8");

lcd.setCursor(0,1);

lcd.print("Don't move control");

delay(1000);

for(int i=0 ; i<50 ; i++){ //這一段程式碼是對香菇頭的讀數做歸零調整,取平均

x_set += analogRead(A0);

y_set += analogRead(A1);

}

x_set=x_set/50;

y_set=y_set/50;

t1=millis();

}

void loop() {

for(int i=0 ; i<50 ; i++){ //這一段程式碼是對香菇頭的讀數變化取平均,作濾波,可以濾掉不穩定的變動值

x_avg += analogRead(A0);

y_avg += analogRead(A1);

}

x_avg=x_avg/50;

y_avg=y_avg/50;

x =(x_set-x_avg)/100;

y =(y_set-y_avg)/100;

rl1=rl0+x;

if(rl1>180)

{

rl1=180;

}

if(rl1<0)

{

rl1=0;

}

servo1.write(180-rl1);

rl0=rl1;

ud1=ud0+y;

if(ud1>180)

{

ud1=180;

}

if(ud1<0)

{

ud1=0;

}

servo2.write(180-ud1);

ud0=ud1;

if(digitalRead(16)==0)

{

servo3.write(angle_lunch);

lcd.setCursor(0,1);

lcd.print("Lunch!!");

delay(200);

servo3.write(angle_ready);

lcd.setCursor(0,1);

lcd.print("ready...");

delay(300);

}

else

{

servo3.write(angle_ready);

lcd.setCursor(0,1);

lcd.print("ready...");

}

lcd_disp();

delay(5);

}