Album
米Teen唔鐘意玩現成品,喜歡由零件開始砌。99次失敗唔係問題,最緊要係有1次成功!
米Teen總部設在聖公會白約翰會督中學506室,在午膳後和放學後集會。有興趣參與的同學,請與會長或導師聯絡。
溫度 26℃ 濕度 95%
街景 2020-11-04 21:41:52
溫度 22℃ 濕度 95%
街景 2020-11-04 21:34:34
「山竹」電子氣墊彈珠台
「山竹」電子氣墊彈珠...
> >「山竹」電子氣墊彈珠台是由加德士「推動學校」計劃贊助製作的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 開始展開創作
完成計劃後感--鄧皓然
在這一次製作氣墊球機的過程,我們分工成4個小組分別是程式組、電子組、木工組和美術組。程式組主要負責氣墊球機的程式編寫。木工組主要負責氣墊球機的底架,而且負責在面板鑽了2640個氣孔,重複6回合共15840次的人手鑽孔。美術組負責氣墊球機的外觀。我是電子組的同學,所以我學到不少關於電子線路的知識例如Darlington電路、晶體管的運用等等。
這部氣墊球機以Arduino電路板作為核心配合不同的電子線路運作來控制檯下的風扇、面板下的LED燈帶。計分的運作原理是以氣墊球餅截斷雷射後,訊號經過debouncing電路輸出至Arduino電路板,再由Arduino電路板控制計分燈。
在是次計劃中如果我們沒有分工合作是不可能完成整個項目的。
另外,是次計劃中最困難的是時間管理。因為氣墊球機的規模大,內部有大量複雜的線路,而且有一定的體積和重量,加上大部分電路位於桌下,大量的電路伴隨大量的電線,走線的工序比較吃力,所以安裝電路的工作較為吃力和困難。幸好我們最後可以趕上工作的進度,如期完成計劃。
雷射的校準也是一個大問題,由於我們把雷射系統分成三個部份組成,進行校準時常有誤差。下次維修時,一定會改善這設計。
最後,我們一眾Miteen成員在無數個課後的日子,日以繼夜地進行工作、測試,終於完成了我們的氣墊球機「山竹」。
磨擦力研究實驗得出十分成功的模型
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.散會時間:下午二時正
Album
米Teen唔鐘意玩現成品,喜歡由零件開始砌。99次失敗唔係問題,最緊要係有1次成功!
米Teen總部設在聖公會白約翰會督中學506室,在午膳後和放學後集會。有興趣參與的同學,請與會長或導師聯絡。
溫度 26℃ 濕度 95%
街景 2020-11-04 21:41:52
溫度 22℃ 濕度 95%
街景 2020-11-04 21:34:34