113-2學期課程企劃書
專題名稱 : 無畏戰車(編號:0604)
大綱:
還原1989年6月3日晚間至6月4日凌晨 發生之天門事變
背景與動機 :
天安門事變對我們來說是耳熟能詳,想透過3D技術復刻當年場景。也想透過本堂課程使用Arduino將坦克車模型改造為可以進行遙控的坦克車進行操控。
定義與內容:
利用Tinkercad打造出天安門、59式坦克等模型。戰車履帶改用四輪設置。因印表機精細度問題,零件組裝問題還需要再一步進行設計。
坦克車內估計含有3個Arduino版、倒車雷達(蜂鳴器*1、超音波感測器*1)、頭(尾)燈(發光二極體*2 (數量暫定))、左右兩側顯示0604字樣(TM1637*2)、輪子四顆、杜邦線些許(視情況決定是否使用焊接方式)。目前有考慮是否安裝音響使戰車發出打仗音效,或是在天安門模型中裝置此設備。)
專題製作的方法與進行步驟:
目前從網路上找到其他人對天安門、59式坦克的3D建模,目前打算先設計幾個零件交給3D印表機打印檢視成果,進而設計出坦克、天安門的大小與各零件的拆解與拼裝。
同步進行倒車雷達、側邊TM1637、頭燈、音效等之線路設計。
預定進度表:
於113-2學期
前七週將坦克、天安門模型拆解成各子零件並使用印表機印出進行拼裝測試。
於七到十一週完成拼裝、線路組裝及測試。
於十一週至學期末完成成果並展示。
預期結果 :
製作好天安門後擺放至地上並操作遙控戰車於其前面駕駛。
戰車具備功能:
1:頭(尾)燈,可開關
2:倒車雷達
3:左右兩側顯示0604數字
4:具前進、後退之功能
5:前輪可左右擺使進行時具備轉向之功能
預估成本
項目 數量 單價(約) 總價(約) 備註
Arduino UNO (副廠板) 3 80/片 0
USB連接線 (Arduino適用) 1 15 0
超音波感測器(HC-SR04) 1 25 0
蜂鳴器(Buzzer) 1 10 0
DC馬達(小型直流馬達) 4 40/顆 160
馬達驅動模組(L298N) 1 50 50
舵機(Servo, SG90) 1~2 30/個 60
TM1637 顯示器 2 20/個 0
LED燈(含電阻) 4 約10/組 0
擴音小喇叭 1 40 40
MP3播放模組(DFPlayer Mini) 1 50 50
Micro SD 卡(小容量) 1 50 50
可充電鋰電池組(簡易套件) 1組 200 200
DC-DC降壓模組(Buck) 1 30 30
杜邦線組合 1包 30 0
麵包板(原型用) 1~2 20/個 0
焊錫、烙鐵(工具) 1組 100 0 暫定
車輪(含輪胎) 4 20/顆 80
車架底板(壓克力/金屬) 1 50 50 暫定書局
3D列印戰車車殼 1套 0 0
3D列印天安門模型 1套 0 0
螺絲、螺帽、墊片 1組 50 50
黏著劑(ABS膠、環氧樹脂) 1組 50 50
上色塗料、噴漆 若干 100 100
藍牙模組(HC-05) 1 100 100
或2.4GHz無線遙控套件 1組 200 200
10/21:
這堂課老師簡單介紹了arduino的基本作用和功能,還有講一些簡單的程式碼,像是透過接線和寫程式將led點亮和閃爍。
/*可以這樣進行註解*/
//或是這樣進行註解
//宣告
int GLED=9;//根據要儲存的資料種類不同,C++變數有許多型態,int在這裡可以定義為整數,也代表定義角位的Pin角,畢竟 Pin角就是以整數做代表的,在Arduino這塊板子中。
int RLED=8;
//只做一次事情
void setup() {
pinMode(RLED, OUTPUT);//設定角位功能
pinMode(GLED, OUTPUT);
digitalWrite(RLED, HIGH);//執行角位的高低電位輸出狀態
digitalWrite(GLED, HIGH);
delay(3000);
digitalWrite(RLED, LOW);
digitalWrite(GLED, LOW);
}
//一直做某件事
void loop()
{
}
11/11: 這堂課將開發版、led與按鈕做結合,以及講解一些有關按鈕控制訊號輸出的方式(ex:按一下顯示0,不按顯示1),還有介紹如何透過寫程式將上拉電阻用到按鈕中,讓它在輸出訊號時更穩定,不會跳來跳去。
int buttonState = 0;
void setup()
{
pinMode(13, OUTPUT); // 13pin是Arduino內建LED的顯示角位
pinMode(7, INPUT); // 設定7pin是讀取訊號的位置
}
void loop()
{
buttonState = digitalRead(7);
if (buttonState == HIGH)
{
digitalWrite(13, HIGH);
}
else
{
digitalWrite(13, LOW);
}
}
/*透過這個程式碼,讓我們來看看序列埠是怎麼運作的,同時也來看看你所設定的數位訊號被讀出來是什麼樣子吧*/
int buttonState = 0;
int pushButton = 7; // 定義PIN7為 pushButton
void setup()
{
Serial.begin(9600);
pinMode(pushButton, INPUT); // 設定PIN7為訊號接收腳位
}
void loop()
{
buttonState = digitalRead(pushButton);
Serial.println(buttonState); // 小提示!往後如果遇到不知道是什麼的變數,就試著把它print出來看看吧!
delay(1);
}
11/18: 這堂課介紹如何用程式碼、顯示器、驅動馬達做出一個時鐘,這另我感到很有趣,自己動手跟看別人做是不一樣的。
#include <Wire.h>
#include <ThreeWire.h>
#include <RtcDS1302.h>
ThreeWire myWire(A6, A5, A7); //接腳: DAT/IO, SCLK/CLK, RST/CE (DS1302的接線自行更改)
RtcDS1302<ThreeWire> Rtc(myWire);
void setup ()
{
Serial.begin(9600);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
Rtc.Begin();
//__DATE__,__TIME__,是程式碼編譯時的日期和時間
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
//判斷DS1302是否接好
if (!Rtc.IsDateTimeValid())
{
// Common Causes:
// 1) first time you ran and the device wasn't running yet
// 2) the battery on the device is low or even missing
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
if (Rtc.GetIsWriteProtected())
{
Serial.println("RTC was write protected, enabling writing now");
Rtc.SetIsWriteProtected(false);
} if (!Rtc.GetIsRunning())
{
Serial.println("RTC was not actively running, starting now"); Rtc.SetIsRunning(true);
} //判斷DS1302上紀綠的時間和編譯時的時間,哪個比較新
//如果編譯時間比較新,就進行設定,把DS1302上的時間改成新的時間
//now:DS1302上紀綠的時間,compiled:編譯時的時間
RtcDateTime now = Rtc.GetDateTime();
if (now < compiled)
{
Serial.println("RTC is older than compile time! (Updating DateTime)");
//編譯時間比較新,把DS1302上的時間改成編譯的時間
Rtc.SetDateTime(compiled);
}
else if (now > compiled)
{
Serial.println("RTC is newer than compile time. (this is expected)");
}
else if (now == compiled)
{
Serial.println("RTC is the same as compile time! (not expected but all is fine)");
}
}
void loop ()
{
RtcDateTime now = Rtc.GetDateTime(); printDateTime(now); Serial.println(); //判斷DS1302是否正常,如果不正常,一般是線沒接好,或是電池沒電了
if (!now.IsValid())
{
Serial.println("RTC lost confidence in the DateTime!");
}
delay(10000); // 10秒更新一次
}
#define countof(a) (sizeof(a) / sizeof(a[0]))
//顯示完整年月日時間的副程式
void printDateTime(const RtcDateTime& dt)
{
char datestring[20];
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),
dt.Day(),
dt.Year(),
dt.Hour(),
dt.Minute(),
dt.Second() );
Serial.print(datestring);
}
#include <ThreeWire.h>
#include <RtcDS1302.h>
#include <TM1637Display.h>
#define countof(a) (sizeof(a) / sizeof(a[0]))
#define CLK 11
#define DIO 12
TM1637Display display(CLK, DIO);
ThreeWire myWire(7, 6, 5); //接腳: DAT/IO, SCLK/CLK, RST/CE (DS1302的接線自行更改)
RtcDS1302<ThreeWire> Rtc(myWire);
void setup()
{
Serial.begin(9600);//鮑率57600
display.setBrightness(7);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
// Common Causes:
// 1) 第一次使用但設備還沒跑好
// 2) 電池電量低
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
if (Rtc.GetIsWriteProtected())
{
Serial.println("RTC was write protected, enabling writing now");
Rtc.SetIsWriteProtected(false);
}
if (!Rtc.GetIsRunning())
{
Serial.println("RTC was not actively running, starting now");
Rtc.SetIsRunning(true);
}
//判斷DS1302上紀綠的時間和編譯時的時間,哪個比較新
//如果編譯時間比較新,就進行設定,把DS1302上的時間改成新的時間
//now:DS1302上紀綠的時間,compiled:編譯時的時間
RtcDateTime now = Rtc.GetDateTime();
if (now < compiled)
{
Serial.println("RTC is older than compile time! (Updating DateTime)");
Rtc.SetDateTime(compiled);
}
else if (now > compiled)
{
Serial.println("RTC is newer than compile time. (this is expected)");
}
else if (now == compiled)
{
Serial.println("RTC is the same as compile time! (not expected but all is fine)");
}
}
void loop()
{
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);//呼叫副函數
Serial.println();
if (!now.IsValid())
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
}
void printDateTime(const RtcDateTime &dt)
{
char datestring[20];
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),//月
dt.Day(),//日
dt.Year(),//年
dt.Hour(),//小時
dt.Minute(),//分鐘
dt.Second());//秒
Serial.println(dt.Minute());
display.showNumberDecEx(dt.Hour(), 0b11100000, 2, 2); //前兩位數設定為小時
display.showNumberDecEx(dt.Minute(), 0b11100000, true, 2, 2); //後兩位數設定為分鐘
delay(1000);
}
11/25:今天的課程介紹了伺服馬達,用上禮拜學習到的知識,匯入函式庫將馬達驅動,做出了一個簡易破解遊戲小恐龍的結構。
//only for 360 motor
#include <Servo.h> //載入函式庫,這是內建的,不用安裝
Servo myservo; // 建立SERVO物件
int r = A0 ; //假設一個字母R代替A0的孔洞
int sensorValue;
void setup() {
Serial.begin(9600);
myservo.attach(9); // 設定要將伺服馬達接到哪一個PIN腳
// myservo.write(0); //歸零
// put your setup code here, to run once:
}
void loop() {
sensorValue = analogRead(r);
Serial.println(sensorValue);
if(sensorValue <= 130){ //如果光敏電阻的數值小於或大於某一數值時,則伺服馬達轉動。
myservo.write(10); //旋轉到30度
delay(200); //延遲0.5 秒
myservo.write(170); //旋轉到0度
delay(200); //延遲0.5秒 可自行更改
}
else{
myservo.write(90); //停止
delay(15);
}
}
12/2:今天的內容有兩個:1.利用DHT11的函式庫使溫濕度感測器感測出當前的溫度、濕度。2.要做一個簡易的倒車雷達,
溫濕度感測器
溫濕度感測器
//使用DHT11函式庫
#include <SimpleDHT.h>
//定義腳位自行更改
int pinDHT11 = 18;
//建立DHT11函式庫物件
SimpleDHT11 dht11;
void setup() {
Serial.begin(9600);
}
void loop() {
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
// start working...
Serial.println("=================================");
if ((err = dht11.read(pinDHT11, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT11 failed, err="); Serial.println(err);delay(1000);
return;
}
Serial.print("Humidity = ");
Serial.print((int)humidity);
Serial.print("% , ");
Serial.print("Temperature = ");
Serial.print((int)temperature);
Serial.println("C ");
delay(1000); //每1秒顯示一次
}
倒車雷達
#define m1 294 //頻率1
#define m5 440 //頻率2
#define h5 880 //頻率3
int red = 2;
int yellow = 3;
int green = 4;
int v=5; //蜂鳴器輸出
int trigPin = 12; //定義 觸發輸出腳位 Trig Pin
int echoPin = 11; //定義 回音接收腳位 Echo Pin
float duration, distance; //定義 時間長度duration 與 距離distance 格式為 浮點數
void setup(){
Serial.begin(9600); //設定 序列埠 鮑率
while (!Serial){ ;} //等待序列埠接通
pinMode(red, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(green, OUTPUT);
pinMode(v, OUTPUT);
pinMode(trigPin, OUTPUT); //設定 觸發輸出腳位(trigPin)的功能為 輸出(OUTPUT)
pinMode(echoPin, INPUT); //設定 回音接收腳位(echoPin)的功能為 輸入(INPUT)
}void loop(){
//於 觸發輸出腳位 Trig Pin 產生觸發脈衝(應大於 10微秒)
digitalWrite(trigPin, LOW); // 讓觸發腳位trigPin 確實降回低電位,持續 20微秒 (us)
delayMicroseconds(20);
digitalWrite(trigPin, HIGH); // 觸發腳位trigPin 變成高電位,持續 20微秒 (us)
delayMicroseconds(20);
digitalWrite(trigPin, LOW); // 觸發腳位trigPin 再降回低電位,完成脈衝,使HC-SR04產生聲音脈衝出去duration = pulseIn(echoPin, HIGH); // 於回音接收腳位(Echo Pin) 收到高電位(High) 的時間 (微秒 us)
distance = duration*0.0170; // 將聲音 "來回" 時間(us) 換算成距離 (cm) [ 假設聲波速率為 340 m/s ]
if (distance >= 25 ){
digitalWrite(green, HIGH);
digitalWrite(yellow, LOW); digitalWrite(red, LOW);
tone(v, m1, 200);
delay(250);
}
else if (distance >= 10 and distance <= 25){
digitalWrite(yellow, HIGH);
digitalWrite(green, LOW); digitalWrite(red, LOW);
tone(v, m5, 150);
delay(200);
}
else {
digitalWrite(red, HIGH);
digitalWrite(green, LOW); digitalWrite(yellow, LOW);
tone(v, h5, 100);
delay(150); }
//Serial.println(distance); // 將 距離distance 傳送到序列埠暫存器
Serial.flush(); // 等待序列埠暫存器中的數據傳送至電腦完畢
delayMicroseconds(duration*1.5); //避免收到更早發出的聲音脈衝 回音
}