Login
A   A   A  
welcome

 Album 

米Teen唔鐘意玩現成品,喜歡由零件開始砌。99次失敗唔係問題,最緊要係有1次成功!

米Teen總部設在聖公會白約翰會督中學506室,在午膳後和放學後集會。有興趣參與的同學,請與會長或導師聯絡。

米Teen專頁

506室內 2020-11-04 21:43:57
溫度 26℃ 濕度 95%
街景 2020-11-04 21:41:52
街景
5樓室外 2020-11-04 21:43:43
溫度 22℃ 濕度 95%
街景 2020-11-04 21:34:34
街景

「山竹」電子氣墊彈珠台

icon

Home>製作項目...>「山竹」電子氣墊彈珠...

「山竹」電子氣墊彈珠台是由加德士「推動學校」計劃贊助製作的STEAM項目。米Teen成員負責設計及製作一台約3呎x6呎x3呎的電子氣墊彈珠台供校內師生在課餘娛樂之用。整個製作都是由基本材料組成,成員可以學到DIY和各種技術,計劃內容包括有各種STEAM的元素。此氣墊彈珠台遊戲機名為"山竹Mangkhut",是因2018年9月山竹的威力和狂風怒號,與本機的設計一致。

「山竹」電子氣墊彈珠台

工作小組

程式編寫:組長--洪子洛
電子設備:組長--鄧皓然
機械裝嵌:組長--陳皓、黃修譽、梅君豪
外觀設計:組長--鄧凱兒
磨擦力研究:組長--林樂賢
音響效果:組長--洪子洛

規格(2019.6.21更新)

面板:3呎X6呎,可拆出更換,8mm亞膠力膠板,73行共2640個5mm氣孔,底部噴油,窗邊膠條密封底部,四邊加象膠條加強摩擦力及返彈力
風扇:12cm DC12V 2.7A,矩陣排列x11,裝在底板的底部
底板:開多個大圓孔,底板底裝風扇,底板面裝12V紅藍LED燈條及支撐柱
底架:枱腳安裝可調校高度的腳墊
氣墊球物料:亞膠力膠板,4x2mm中空層叠
輸入:底線入球感應器(laser detector)
輸出:風扇開關、底板LED燈效(紅藍綠白),分數輸出(5分)(1左1右)
音效:輸贏、雙方打成平手、各種事件的音效,喇叭裝在底架
燈效:LED燈條
電子:Arduino Mega 2560、製作PCB、MP3模組
電源:AC220V轉DC12V,風扇要用獨立變壓器及用solid state relay(固態繼電器)開關
程式:Arduino Mega裝在底架,用外置5V DC regulator
規則:氣墊球接觸底線龍門的感應器取得一分,即時繼續比賽,無須暫停發球,節奏快,比賽用計分及計時制

工作進度

完成日期
	2019.6月完成
程式編寫
	2018.12.4 Python與Arduino能透過serial port通訊
電子設備
	2018.12.5 成功製作第一塊PCB
	2018.11.20 開始學習設計PCB
機械裝嵌
	2018.12.13 購買框架用的木材
	2018.12.6 開始掌握木工工具,多次練習製作木榫
	2018.11.27 學習製作木榫及使用基木工具
	2018.11.21 完成裝嵌實驗用的風箱、學習使用電動工具
外觀設計
	2018.12.4 完成製作大型圖案貼紙的實驗品
磨擦力研究
	2018.12.11 實驗得出十分成功的模型,可懸浮旋轉中的氣墊球超過30秒
	2018.12.6 實驗得出最基本能運作的模型
	2018.11.26 釐定磨擦力的斜板實驗方法
	2018.11.20 開始製作實驗用的風箱
音響效果
	2018.12.6 開始展開創作

2640個氣孔

控制線路

完成計劃後感--鄧皓然

在這一次製作氣墊球機的過程,我們分工成4個小組分別是程式組、電子組、木工組和美術組。程式組主要負責氣墊球機的程式編寫。木工組主要負責氣墊球機的底架,而且負責在面板鑽了2640個氣孔,重複6回合共15840次的人手鑽孔。美術組負責氣墊球機的外觀。我是電子組的同學,所以我學到不少關於電子線路的知識例如Darlington電路、晶體管的運用等等。
這部氣墊球機以Arduino電路板作為核心配合不同的電子線路運作來控制檯下的風扇、面板下的LED燈帶。計分的運作原理是以氣墊球餅截斷雷射後,訊號經過debouncing電路輸出至Arduino電路板,再由Arduino電路板控制計分燈。
在是次計劃中如果我們沒有分工合作是不可能完成整個項目的。
另外,是次計劃中最困難的是時間管理。因為氣墊球機的規模大,內部有大量複雜的線路,而且有一定的體積和重量,加上大部分電路位於桌下,大量的電路伴隨大量的電線,走線的工序比較吃力,所以安裝電路的工作較為吃力和困難。幸好我們最後可以趕上工作的進度,如期完成計劃。
雷射的校準也是一個大問題,由於我們把雷射系統分成三個部份組成,進行校準時常有誤差。下次維修時,一定會改善這設計。
最後,我們一眾Miteen成員在無數個課後的日子,日以繼夜地進行工作、測試,終於完成了我們的氣墊球機「山竹」。

2019.6.29在觀塘海濱發現號展出

在校內供同學使用

磨擦力研究實驗得出十分成功的模型

Author: HUNG TSZ LOK (SKH Bishop Baker Secondary School, class 4C)

Last modified: 2019.6.27

1
const int L0 = 46;  // fan led ''
2
const int L1 = 47;
3
const int L2 = 48;
4
const int L3 = 49;
5
const int L4 = 50;
6
const int L5 = 51;
7
const int L6 = 52;
8
const int L7 = 53;  // fan led ''
9
const int S0_0 = 22;  // score indicators 0 ''
10
const int S0_1 = 23;
11
const int S0_2 = 24;
12
const int S0_3 = 25;
13
const int S0_4 = 26;  // score indicators 0 ''
14
const int S1_0 = 31;  // score indicators 1 ''
15
const int S1_1 = 32;
16
const int S1_2 = 33;
17
const int S1_3 = 34;
18
const int S1_4 = 35;  // score indicators 1 ''
19
const int Fans = 13;  // Fan (SSR) control
20
const int S0 = 44;  // Left start button
21
const int S1 = 45;  // Right start button
22
const int Laser0 = 42;  // Left laser diode
23
const int Laser1 = 43;  // Right laser diode
24
const int vr = A0;
25
26
const int Spins[22] = {S0_0, S0_1, S0_2, S0_3, S0_4, S1_4, S1_3, S1_2, S1_1, S1_0, S1_0, S1_0, S1_1, S1_2, S1_3, S1_4, S0_4, S0_3, S0_2, S0_1, S1_0, S1_0};
27
const int Lpins[10] = {L7, L0, L1, L6, L3, L4, L5, L2, L7, L0};
28
const int S0pins[5] = {S0_0, S0_1, S0_2, S0_3, S0_4};
29
const int S1pins[5] = {S1_0, S1_1, S1_2, S1_3, S1_4};
30
const char startSound[3] = {0x02, 0x03, 0x04};
31
const char rb_win[2] = {0x08, 0x09};
32
33
bool _60sw; bool _30sw; bool _10sw;
34
bool endState;
35
bool isDraw;
36
int vrValue;
37
unsigned long timeLimit;
38
unsigned long startTime;
39
int winSide;
40
bool restartState = true;
41
bool startState = false;
42
int score0 = 0;
43
int score1 = 0;
44
bool hitState0 = false;
45
bool hitState1 = false;
46
47
// var
48
const int scoreFlashDelayTime = 77;
49
const int ledDelayTimes[5] = {500, 200, 100, 350, 250};
50
int ledDelayTime;
51
const char volume = 0x15;  // MP3 volume (00~1E)
52
const unsigned long limits[3] = {60e3, 120e3, 180e3};
53
54
// MP3
55
unsigned char mp3_setvol[5] = {0x7e, 0x03, 0x31, volume, 0xef};
56
unsigned char mp3_stop[4] = {0x7e, 0x02, 0x0e, 0xef};
57
unsigned char mp3_sd[5] = {0x7e, 0x03, 0x35, 0x01, 0xef};
58
unsigned char mp3_single[5] = {0x7e, 0x03, 0x33, 0x04, 0xef};
59
60
void setup() {
61
  pinMode(L0, OUTPUT);
62
  pinMode(L1, OUTPUT);
63
  pinMode(L2, OUTPUT);
64
  pinMode(L3, OUTPUT);
65
  pinMode(L4, OUTPUT);
66
  pinMode(L5, OUTPUT);
67
  pinMode(L6, OUTPUT);
68
  pinMode(L7, OUTPUT);
69
  pinMode(Fans, OUTPUT);
70
  pinMode(S0, INPUT_PULLUP);
71
  pinMode(S1, INPUT_PULLUP);
72
  pinMode(S0_0, OUTPUT);
73
  pinMode(S0_1, OUTPUT);
74
  pinMode(S0_2, OUTPUT);
75
  pinMode(S0_3, OUTPUT);
76
  pinMode(S0_4, OUTPUT);
77
  pinMode(S1_0, OUTPUT);
78
  pinMode(S1_1, OUTPUT);
79
  pinMode(S1_2, OUTPUT);
80
  pinMode(S1_3, OUTPUT);
81
  pinMode(S1_4, OUTPUT);
82
  pinMode(Laser0, INPUT);
83
  pinMode(Laser1, INPUT);
84
  pinMode(vr, INPUT);
85
  
86
  // Serial3
87
  Serial3.begin(9600);
88
  Serial3.write(mp3_sd, 5);
89
  delay(500);
90
  Serial3.write(mp3_setvol, 5);
91
  Serial3.write(mp3_single, 5);
92
}
93
94
void loop() {
95
  if (restartState) {  // restart
96
    Serial3.write(mp3_stop, 4);
97
    digitalWrite(Fans, LOW);
98
    ledDelayTime = ledDelayTimes[0];
99
    _60sw = true; _30sw = true; _10sw = true;
100
    score0 = 0; score1 = 0;
101
    clearScore();
102
    ledAll(LOW);
103
    startState = false; endState = false;
104
    hitState0 = false; hitState1 = false;
105
106
    while (true) {  // waiting for buttons
107
      if (digitalRead(S0) == LOW && !startState) {
108
        scoreLedAll(0, LOW); scoreLedAll(1, LOW);
109
        for (int i = 0; i < 50; i++) {
110
          if (digitalRead(S1) == LOW) { startState = true; break; }
111
          delay(100); scoreLedControl(true, 0);
112
        }
113
      }
114
      if (digitalRead(S1) == LOW && !startState) {
115
        scoreLedAll(0, LOW); scoreLedAll(1, LOW);
116
        for (int i = 0; i < 50; i++) {
117
          if (digitalRead(S0) == LOW) { startState = true; break; }
118
          delay(100); scoreLedControl(true, 1);
119
        }
120
      }
121
      scoreLedControl(false, 0);
122
      if (startState) {
123
        scoreLedAll(0, LOW); scoreLedAll(1, LOW);
124
        vrValue = map(analogRead(vr), 0, 1023, 0, 2);
125
        timeLimit = limits[vrValue];
126
        restartState = false; startState = false;
127
        digitalWrite(Fans, HIGH);
128
        delay(2000);
129
        // on
130
        mp3_play(0x00, startSound[vrValue]);
131
        startTime = millis();
132
        break;
133
      }
134
    }
135
  }
136
  if (_60sw || _30sw || _10sw) {
137
    if (millis() - startTime > timeLimit - 60e3 && timeLimit > 60e3 && _60sw) {  // 60 seconds warning
138
      mp3_play(0x00, 0x05);
139
      _60sw = false;
140
    }
141
    else if (millis() - startTime > timeLimit - 30e3 && timeLimit > 30e3 && _30sw) {  // 30 seconds warning
142
      mp3_play(0x00, 0x06);
143
      ledDelayTime = ledDelayTimes[1];
144
      ledAll(LOW);
145
      _30sw = false;
146
    }
147
    else if (millis() - startTime > timeLimit - 10e3 && timeLimit > 10e3 && _10sw) {  // 10 seconds warning
148
      mp3_play(0x00, 0x07);
149
      ledDelayTime = ledDelayTimes[2];
150
      ledAll(LOW);
151
      _10sw = false;
152
    }
153
  }
154
155
  if (millis() - startTime > timeLimit) {  // time's up
156
    endState = true; isDraw = false;
157
    if (score0 > score1) { winSide = 0; }
158
    else if (score1 > score0) { winSide = 1; }
159
    else { isDraw = true; }
160
  }
161
162
  if (!digitalRead(Laser1) && !hitState0) {  // 0 scoring
163
    hitState0 = true;
164
    digitalWrite(S0pins[score0++], HIGH);
165
    mp3_play(0x00, 0x01);  // sound ding
166
  }
167
  if (!digitalRead(Laser0) && !hitState1) {  // 1 scoring
168
    hitState1 = true;
169
    digitalWrite(S1pins[score1++], HIGH);
170
    mp3_play(0x00, 0x01);  // sound ding
171
  }
172
173
  if (hitState0 && digitalRead(Laser1)) { hitState0 = false; }
174
  if (hitState1 && digitalRead(Laser0)) { hitState1 = false; }
175
176
  if ((score0 >= 5) || (score1 >= 5)) {
177
    endState = true;
178
    winSide = (int)score1 >= 5;
179
    isDraw = false;
180
    }
181
182
  if (score0 == 4) { score0Flash(); ledDelayTime = ledDelayTimes[2]; ledAll(LOW); }
183
  if (score1 == 4) { score1Flash(); ledDelayTime = ledDelayTimes[2]; ledAll(LOW); }
184
185
  if (endState) {  // end
186
    for (int i = 0; i < score0; i++) { digitalWrite(S0pins[i], HIGH); }
187
    for (int i = 0; i < score1; i++) { digitalWrite(S1pins[i], HIGH); }
188
    delay(234);
189
    
190
    // sound end
191
    if (!isDraw) {
192
      mp3_play(0x00, rb_win[winSide]);
193
      for (int i = 0; i < 5; i++) { ledWave(winSide + 2, 70); delay(100); }
194
    }
195
    else { mp3_play(0x00, 0x0a); }
196
    ledAll(LOW); delay(100);
197
    for (int i = 0; i < 2; i++) { ledAll(HIGH); delay(200); ledAll(LOW); delay(200); }
198
    ledAll(HIGH); delay(1000);
199
    restartState = true;
200
    score0 = 0; score1 = 0;
201
    delay(2000);
202
  }
203
204
  ledControl();
205
}
206
207
void scoreLedAll(int side, int val) {
208
  for (int i = 0; i < 5; i++) {
209
    if (side == 0) { digitalWrite(S0pins[i], val); }
210
    if (side == 1) { digitalWrite(S1pins[i], val); }
211
    }
212
}
213
214
void scoreLedControl(int isPushed, int side) {
215
  if (!isPushed) {
216
    unsigned long timeindex = (millis() / ledDelayTimes[3]) % 22;
217
    digitalWrite(Spins[timeindex], HIGH);
218
    if (timeindex == 10 || timeindex == 21) { scoreLedAll(0, LOW); scoreLedAll(1, LOW); }  
219
  }
220
  else {
221
    unsigned long timeindex = (millis() / ledDelayTimes[4]) % 2;
222
    scoreLedAll(side, timeindex);
223
  }
224
}
225
226
void ledControl() {
227
  unsigned long timeindex = ((millis() / ledDelayTime) % 4) * 2;
228
  digitalWrite(Lpins[timeindex],  LOW); digitalWrite(Lpins[++timeindex],  LOW); digitalWrite(Lpins[++timeindex],  HIGH); digitalWrite(Lpins[++timeindex],  HIGH);
229
}
230
231
void ledAll(int val) {
232
  for (int i = 0; i < 8; i++) {
233
    digitalWrite(Lpins[i], val);
234
  }
235
}
236
237
void ledWave(int s, int dur) {
238
  ledAll(LOW);
239
  for (int i = s; i < 10; i += 2) {
240
    digitalWrite(Lpins[i], HIGH); delay(dur);
241
  }
242
}
243
244
void score0Flash() {
245
  unsigned long timeindex = ((millis() / scoreFlashDelayTime) % 10);
246
  if (timeindex == 0 || timeindex == 2 || timeindex == 4) {
247
    digitalWrite(S0pins[0], LOW); digitalWrite(S0pins[1], LOW); digitalWrite(S0pins[2], LOW); digitalWrite(S0pins[3], LOW);
248
  }
249
  else {
250
    digitalWrite(S0pins[0], HIGH); digitalWrite(S0pins[1], HIGH); digitalWrite(S0pins[2], HIGH); digitalWrite(S0pins[3], HIGH);
251
  }
252
}
253
254
void score1Flash() {
255
  unsigned long timeindex = ((millis() / scoreFlashDelayTime) % 10);
256
  if (timeindex == 0 || timeindex == 2 || timeindex == 4) {
257
    digitalWrite(S1pins[0], LOW); digitalWrite(S1pins[1], LOW); digitalWrite(S1pins[2], LOW); digitalWrite(S1pins[3], LOW);
258
  }
259
  else {
260
    digitalWrite(S1pins[0], HIGH); digitalWrite(S1pins[1], HIGH); digitalWrite(S1pins[2], HIGH); digitalWrite(S1pins[3], HIGH);
261
  }
262
}
263
264
void clearScore() {
265
  for (int i = 0; i < 5; i++) {
266
    digitalWrite(S0pins[i], LOW); digitalWrite(S1pins[i], LOW);
267
  }
268
}
269
270
void mp3_play(char indexlow, char indexhigh) {
271
  unsigned char mp3_songplay[6] = {0x7e, 0x04, 0x41, indexlow, indexhigh, 0xef};
272
  Serial3.write(mp3_songplay, 6);
273
}

2018.11.27會議記錄

時間:下午1時45分
地點:501室
主席:鄧皓然
秘書:陳皓
出席者:方肇諄、黃修譽、羅孝聰、梅君豪、鄧凱兒、洪子洛、林樂賢
1.通過上次會議紀錄
	紀錄經與會者確認,一致通過。
2.討論事項
	2.1. 規格修改
		2.1.1. 由遮擋龍門改為快閃龍門,以及比賽格式改為計時制。
	2.2. 機械裝嵌組工作
		2.2.1. 12月初前需完成入榫試驗品。
	3.其他事項 
		散會時間:下午二時正

2018.11.21會議記錄

時間:下午1時45分
地點:501室
主席:鄧皓然
秘書:陳皓
出席者:方肇諄、丘祉康、駱灌濤、黃修譽、羅孝聰、梅君豪、馬偉健
1.通過上次會議紀錄
	紀錄經與會者確認,一致通過
2.討論事項
	2.1. 12月6日放學時間為第一次下午茶會議,學生出席人數為16人。
	2.2. 面版底部用反貼膠紙
		2.2.1. 外觀設計小組會為506室設計窗口的反貼膠紙,以作實驗之用。
	2.3. 機械裝嵌小組需負責以下工作
		2.3.1. 製作底架、用窗邊膠條封條、面板需配合風扇的大小及方便裝嵌,以及製作可調校的枱腳。
3.其他事項 
	下次開會日期 :2018年11月27日
	散會時間:下午二時五分

2018.11.13會議記錄

時間:下午1時45分
地點:501室
主席:鄧皓然
秘書:陳皓
出席者:呂樂熙、侯展鵬、丘祉康、方肇諄、駱灌濤、黃修譽、羅孝聰、洪子洛、馬偉健、溫浚耀、許澤耀、林樂賢
1.通過上次會議紀錄
	紀錄經與會者確認,一致通過
2.討論事項
	2.1.外觀設計小組負責以下工作:
		2.1.1.標誌設計,大小為100x100像素
		2.1.2.製成品外觀設計,大小為3呎X6呎
	2.2.摩擦力研究小組負責以下工作:
		2.2.1.面板上風洞的密度、排列、直徑
		2.2.2.面板材料,8mm亞膠力膠板或18mm雙啞白木板
		2.2.3.製成品的承載力
		2.2.4.風扇採用DC12V類型
		2.2.5.氣墊球的物料可採用飛機木、輕身塑膠板或亞膠力膠板
		2.2.6.面板需要時可以拆出更換
	2.3.電子設備組負責以下工作:
		2.3.1.輸入
			入球感應器2個、死角感應器4個、底線感應器4個
		2.3.2.輸出
			風扇開關、輸出(2個數位)(一左一右) 、計時(三個數位)(入球需暫停)(發球後繼續) 、4排助攻轉盤+燈效、2個助守障礙(遊戲完結時或遊戲途中發揮作用)、燈效在入球的時候閃、勝出一局的時候長亮
	2.4.音樂效果小組需負責以下工作:
			贏及輸的聲音各2種(分別左方及右方)、雙方打成平手的聲音一組、各種事件的音效
3.其他事項 
	下次開會日期 :2018年11月21日
	散會時間:下午二時十分

2018.11.12會議記錄

時間:下午1時40分
地點:501室
主席:鄧皓然
秘書:陳皓
出席者:阮栢謙、丘祉康、方肇諄、駱灌濤、羅孝聰、梅君豪、張浩謙、洪子洛、馬偉健
1.討論事項
    1.1.分工
        經過今次會議商討,以下為個各小組的主席:
        程式:洪子洛
        電子:鄧皓然
        機械:陳皓
        外觀設計:鄧凱兒
        磨擦力研究:林樂賢
    1.2.第一階段工作進度安排 
        經過今次會議商討,以下為今次項目的完成時間表:
        11月26日前,研究小組需提交項目結果
        12月份,完成電腦音效、電子感應、氣墊台面板、風扇底座等各種組件
        1月17日至2月1日,完成特別機關裝置
        2月後,外觀設計小組開始工作
2.其他事項 
    2.1.下次開會日期 :2018年11月13日
    2.2.散會時間:下午二時正
welcome

 Album 

米Teen唔鐘意玩現成品,喜歡由零件開始砌。99次失敗唔係問題,最緊要係有1次成功!

米Teen總部設在聖公會白約翰會督中學506室,在午膳後和放學後集會。有興趣參與的同學,請與會長或導師聯絡。

米Teen專頁

506室內 2020-11-04 21:43:57
溫度 26℃ 濕度 95%
街景 2020-11-04 21:41:52
街景
5樓室外 2020-11-04 21:43:43
溫度 22℃ 濕度 95%
街景 2020-11-04 21:34:34
街景
 ⇧