橡皮筋槍
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);
}