成為樂齡maker
退休三年都在忙房子的事,搞得灰頭土臉比上班還忙。房子蓋好了,卻好像永遠有改善不完的事,投入再多時間都不夠。該告一段落往前走了,若無法全然放下,至少時間的比重也要逐漸減輕。看到樂齡maker這個標題就知道和蓋房子沒多大關係,這是我接下來想走的路想做的事。房子沒蓋好的人,請專注在房子上,不要進入這個領域,以免分心「誤入歧途」!
自我期許期Be a maker
Maker 網路翻譯成「自造世代」。Maker簡單的說:就是不分領域、年齡用自己的知識、資源,自己動手打造,實現心中渴望的想法。這比蓋房子仰賴不怎麼令人放心的「專業人士」,處處充滿無法掌控的變數受限於人好玩多了。而且退休後不再有太多的得失心,既無「進度」的壓力,亦無關「效率」,因此更能從容地享受成為maker的樂趣。若因此,能將自己的生活經驗與歲月淬鍊出解決問題的能力繼續應用,不但可以「廢物利用」造福自己和家人,聰明才智高者還能造福他人。總之,退休後成為maker的好處多多,個人觀察體驗至少有以下理由支持我成為maker。
退休者成為 maker的六大理由
1. 充實人生,不虛度光陰。
2. Maker的樂趣能驅散憂鬱,忘卻煩惱病痛。
3. 符合老年少吃多動的健康法則;動腦可防癡呆、動手可減緩退化。
4. 自娛或實用即可,無關專不專業、卸下得失心,更能自由發揮。
5. 經濟實惠,maker量力而為無須花大錢,成就感遠遠超越感官的快樂。
6. 學習永無止境。做一個海闊天空自由自在的maker,優游於浩瀚的知識與追求無限的智能,滿足學習的渴望與動手圓夢踏實。
成為maker,我想做什麼?
鍾鼎山林,各有天性。有人喜歡烹飪美食、有人愛唱歌、有人愛畫畫、有人喜歡木工創作、有人喜歡機械設計。個人自幼對聲光電學情有獨鍾,對音響、控制、微處理器有表淺的涉獵,因此,目標會優先創作與生活相關的機電整合,若行有餘力,會再追求永無止境的音響設計製作。生活中充滿機電的應用,針對這些應用,永遠有做不完的議題、改善不完的缺失、學不完的知識,以及無止境的成長空間。空談無益,先要踏出簡單的一小步,才能引發後續的發展。
My first Arduino
Arduino是幫助maker實現構想的利器,是個開放原始碼的設計平台,簡單易學的高階的語言、平易近人的開發環境、強大的功能,加上網路上無窮盡的分享資源,真是令人驚艷。個人一向習慣用8051或PLC,重入江湖,見獵心喜,立刻捨8051&PLC,擁抱新歡Arduino。上Arduino官網發覺它的產品分為五大類,共有21種模組或開發板,選了一片入門板Arduino Nano,在本地網拍網站一片賣260元,一口氣買二塊,三天就到7-11取貨。拆封立刻上Arduino官網下載ARDUINO 1.6.5開發軟體,再快速溜覽一下官網提供的指令集與範例,就開始測試這二塊Arduino Nano,一路順到底,真是如獲至寶。
牛刀小試―監控抽水馬達
Arduino Nano能做什麼?上網搜尋一下它的硬體結構圖,發現用於一般小型的控制綽綽有餘。我想先解決我的抽水問題,因為附近在蓋大樓,地下水抽的兇,導致地下水水位嚴重下降,我的馬達常會抽不到水,我一直想設計一個保護機制,讓我的馬達抽不到水時能自動切斷電源,並發出警告,以期達到保護馬達、與提醒及早維修的目的,避免水塔內的水用罄才發現馬達早已故障多時。
設計目標概述:
1.啟動異常保護:馬達未於設定時間內完成啟動程序時,進入異常模式給予保護。
2.運轉異常保護:完成啟動後,持續運轉卻未正常進水時,進入異常模式給予保護。
3.運轉逾時保護:馬達連續抽水超過預設時間時,進入異常模式給予保護。
4.提供ByPASS功能:方便除錯、維修。
使用流程圖具體化
把構想具體化是重要的實現步驟,透過這個過程可釐清設計目標,讓後續的硬體、軟體都可根據此步驟所得結果,一一實現。我習慣用流程圖把構想具體表達出來,其優點是,流程圖可以把每一個步驟明確的規劃出來,矛盾衝突之處很容易發現,效率與實現難易度也容易評估;同時也方便日後系統除錯、維護、修改。
硬體規劃
1. 暖身―整理抽水馬達配線
想要設計監控抽水馬達,必須先對現場配線與設備充分了解才能規劃設計,為了達到這個目的,整整花了將近一天的時間才把配電箱線路整理好。首先是在IF電源箱和5F水塔之間來回爬了數趟(maker不光是動腦和動手,腿部肌肉也有鍛鍊到),確認各個控制點的配線;接著切斷電源把線路拉出來,用配線架把每條線上架、整理、標示;現場忙完再用Orcad(免費的體驗版就夠用)劃出配線圖。如此肢體運動、腦力激盪後,身體達到陰陽平衡,心理不再掛念理不清的配線,接著要怎麼進行後續處理也胸有成竹,天道酬勤,一夜好眠。
整理電源箱配線架與水塔抽水控制配線圖
2. 設計Arduino I/O介面
要設計I/O介面就要先知道I/O Pin 的驅動能力,在Arduino官網上,Arduino NANO I/O Pin的輸出電流可達40mA。一般而言,很少人自己窩在冷氣房,卻讓微處理器工作得這麼辛苦。個人一向慈悲為懷(對人可不一定),通常會在I/O輸出端加個緩衝級,讓微處理器涼快些,因此1-5mA就很夠用了。本次製作需要2個input Pin用於偵測馬達與進水;2個output Pin用於切斷馬達電源與發出警訊,電路設計如下:
a.1st_Input―偵測馬達電源:
抽水馬達自動抽水的原理是,當水塔的水位下降至預設的低水位時,水塔內的浮球開關就會ON,於是馬達220V電源接通、馬達開始運轉抽水;開始抽水後,水位會上升、上升至預設的滿水位時,浮球開關就會OFF,於是電源切斷、馬達停止抽水。因此,要監測抽水馬達,就需要產生一個「狀態信號」告訴Arduino,「開始或停止抽水啦!」,Arduino收到這個「狀態信號」就會啟動後續監控程序。要如何產生這個「狀態信號」呢?最簡單的方法就是偵測馬達的220V電源,當偵測到220V電源時就表示馬達電源已經接通,開始抽水啦,反之亦然!偵測220V的方法有很多,我用的方法是用220V電源去驅動光耦合電晶體(手邊正好有4N35),使Arduino D2外部接腳成為LOW2電位,Arduino用輪詢(polling)方式偵測到LOW電位後,就會進行後續的運算。電路很簡單,只是把220V交流電源整流,再加上濾波電容轉成直流電源,這樣就可以讓Arduino D2維持穩定的LOW狀態,不至誤判;因為濾波電容的充放電特性,220V on/off 會有數十ms的延遲,但這對抽水馬達而言可忽略不計。各零件組值計算如手稿圖,基本上歐姆定理就夠用。
AC220V偵測電路
b. 2nd_Input―偵測水塔進水:
要偵測到水確實有進水塔,最保險的做法是在水塔進水處偵測,現成的感測開關都不太好用,只好自己動手打造一個進水偵測元件,如下圖。動作原理很簡單,水的阻抗大概20kΩ(用指針式三用電表量),我在水塔進水口串入一個彎頭,彎頭嵌入二根白鐵螺絲釘當作偵測探棒。當水流經彎頭時,由於水的阻抗會等效於一個20kΩ的電阻跨接於偵測探棒(白鐵螺絲釘)的二端,形成ib路徑,讓ib流進Q1 ,於是Q1導通、LED亮、Q2 截止(Q2在無進水時ON)、Arduino D3由LOW電位變成HIGH電位(進水啦!),Arduino內部偵測到這個變化,軟體就會進行相關監控程序。
自製進水偵測探棒
配線組裝圖
彎頭內部,當作探測電極的白鐵螺絲釘圖
組裝完成圖
水塔進水檢知電路圖
c.1st_Output―切斷馬達電源:
當偵測到異常狀況必須切斷馬達電源時,Arduino D7輸出端會拉到HIGH電位,驅動Q3導通,繼電器RL1動作(約需100mA),220V R相電源經RL1動作接點,使馬達的保護電驛MS動作。MS一旦動作,220V R相電源會經由MS本身的動作接點(稱為自保接點)持續送電,讓MS保持動作;另一方面,由於MS常閉接點串入抽水馬達電源控制迴路,MS動作就會切斷馬達電源達到保護的目的。故障排除後,要再次啟動馬達時,由於MS「自保電路」會一直保持動作,因此必須把MS的R相,或S相電源斷開,才能使MS釋放,馬達才能重新啟動。
保護馬達控制電路圖
d. 2nd_Output―發出警訊:
在異常狀況切斷馬達時,系統也要能發出警訊提醒注意,以便及早發覺故障及早維修。發生異常狀況時,Arduino D8輸出端會依記錄異常訊息的變數(Er_code)產生HIGH、LOW電位間歇地變化,發出聲音。考慮一般蜂鳴器的聲音都不太悅耳,因此,我決定用小喇叭來發聲。喇叭驅動電路是採用二個電晶體組成達靈頓電路;由於白天讓人聽到示警即可,因此,不需太大聲,以免夜間擾人,所以我在喇叭端串入一個47Ω限流電阻,讓喇叭小聲些。電路是很簡單的開關電路,輸出的頻率、聲音的長短都由軟體操控,作法非常簡單,一個指令就搞定;由於Q4集極串入一只LED,發出警訊聲時,該LED也會閃爍示警。
Arduino 驅動喇叭發聲電路圖
e. by pass 功能:
by pass的功能對複雜的控制系統是很重要的功能,它能快速隔離監控系統的干預,簡化故障判斷。本製作雖然簡單,但是我希望若發生故障,能用by pass功能,回歸原有的抽水系統迴路,維修的水電師傅只要照一般維修抽水馬達的知識就能維修,他不需要了解監控電路,維修時也感覺不到監控電路。為了達到這個目的,整個監控系統中設計時,只在抽水控制迴路中串入一個保護電驛(MS1)的常閉接點,當保護電路驅使保護電驛動作時,該常閉接點開路,抽水馬達電源就被截斷。By pass的作法是,簡單地用一個開關把該常閉接點二端短路,這樣馬達就回歸原有的控制電路,與保護電驛動作與否無關。
by pass電路圖
3.設計PCB
Diy PCB一直是令人頭痛的問題,因為量少(通常只有一片),總覺得是曠日廢時的零和遊戲,失敗就得重來。早年用手繪佈局、用膠布製作感光罩、感光、蝕刻、鑽孔,一塊PCB要經過多道手續才能完成。這樣洗了一陣子PCB,後來乾脆用萬用洞洞板直接焊省事多了,這樣似乎不太專業,但只要焊得牢靠,能解決問題,外觀就不太計較了,這樣也過了將近20年。曾幾何時,眼力愈來愈不濟,洞洞板的焊點愈來愈模糊。不得已情況下只好重操賤業,再度洗PCB。拜科技之賜,現在有許多工具可用,而且有些還是免費的,對maker而言不須投資重金就能利用,真是一大祝福。PCB layout我用免費的pad2pad佈局。簡單易學、對maker而言,已夠好用。
本製作因電路簡單,既非高頻電路亦非類比線性電路,因此佈局無需考慮過多,為使PCB佈局簡單、好鑽孔、線條粗些(細線傷眼,且手工不好處理),我能不用IC就不用IC,能用單面就不用雙面設計。佈局完成後用描圖紙從列表機印出,接著就是用曝光機曝光、顯影、蝕刻、鑽孔,完成PCB製作。因為眼力不濟,鑽孔必須使用頭戴式放大鏡才能看清楚,畢竟歲月不饒人啊!慢慢鑽,當作是怡情養性終究還是完成了。
由於是手洗,如前述希望線條粗些、間隙寬些,在pad2pad的Tools/Route/Router Settings有幾個重要參數要注意:
1. Trace’s layer:Botton -------底層單層佈局
2. Minimal gap:0.4mm-------視零件疏密情況,「間隙」僅可能寬。
3. Width of new traces:07mm-----視零件疏密情況「佈線寬度」僅可能寬。
說明:其中2、3參數若佈局無法成功,就要把參數調小。
單層板佈線較困難,程式預設參數是佈線3次,若是無法完成佈線,就會出現下列畫面。只要多設定幾次(例如設定100次),讓電腦去傷腦筋,自己趁等待時間起來活動活動還有益健康呢。
PCB佈局完成圖;旁邊多餘的空間規劃當萬用板用。
PCB感光顯影完成圖
PCB蝕刻完成圖
4. 完成實體
PCB完成後,插上零件焊好,再用酒精清潔後,控制電路板就完成囉;軟體在麵包板電路階段就完成(程式內容後述),接著要裝箱、配線。機箱也是很傷腦筋的問題,因為裝置地點在電源箱旁,最後考慮用配電箱當機箱用,反正是裝在配電區,裝潢時已製作一大扇電器櫥櫃掩飾起來,外表看不到內部電源設備。又因操作簡單,而且正常情況是不需要去操控它的,為簡化配線,電路裝箱時把電源開關、保險絲,保護電驛、繼電器、by pass開關,都集中安裝在PCB上。
控制電路板完成圖
裝箱配線完成圖;配線箱故意選大些,剩餘空間將來還可利用!
這個偵測系統從構思到完成,花了數個月的時間,拖這麼久的原因是因為在這個領域停工太久,需要暖身與補充設備;另一個原因是,雜事太多,有空時才捏一下當作是消遣,還好總算完成了。
軟體規劃
監測軟體是按照當初規劃的流程圖,翻譯成Arduino語言就成了。在Arduino官網上,已列出所有指令,每一指令都有範例。個人體驗的感覺是簡單易學,即使毫無基礎要上手也不難;若熟悉電腦語言,就更能輕鬆上手。程式分成「啟動程序」、「持續抽水程序」、「錯誤處理程序」三部分。程式中使用for…next迴圈作計時控制,在啟動程序中規劃為10秒鐘;在持續抽水程序中規劃為15分鐘,超過規劃時間就會進入錯誤處理程序。偵測部分是用if指令輪詢,由於輪詢控制的對象是抽水馬達,因此速度不須很快,大約每秒輪詢一次足矣。
goto結構:本製作程式用了許多goto的指令,一般程式設計的書通常不鼓勵使用goto指令,主要原因是太多的goto指令會增加程式除錯的複雜度,也不利於後續的維護。本程式有明確的流程圖指引,不致有上述問題產生,使用goto指令可以使程式更簡單完成。
異常處理程式:程式在輪詢過程中,若有異常狀況就會把預設的錯誤碼存入記憶體,然後直接跳(用goto指令)到異常處理程式;程式會切斷馬達電源,並根據記憶體的錯誤碼發出相應的錯誤訊息,達到保護與示警的目的。
完整抽水馬達監控程式碼
// Pumping motor monitoring system 2015/8/24
int TowerSW = 2; //PIN-5
int WaterDetectSW =3; //PIN-6
int StopRL =7; //PIN-10
int Alarm = 8; //PIN-11
int Er_Code = 0;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(TowerSW, INPUT); //demanding pumping water.
pinMode(WaterDetectSW, INPUT); // detecting if water be pumped up.
pinMode(StopRL, OUTPUT); //stop motor if the motor is unnormal.
pinMode(Alarm, OUTPUT); //alarm as pumping system fails.
pinMode(13, OUTPUT); //blinking as different process loop.
}
void loop() {
// the loop routine runs for drawing water into water tank:
Start:
//==================================================================
//--------------------1. initial process----------------------------
//==================================================================
if ( digitalRead(TowerSW) == LOW ){ // main if loop ;pumping water wanted
for(int i=0;i<10;i++){ //set initial process for 10 sec
digitalWrite(13,HIGH);
//-----------------check motor---------------------------
if (digitalRead(TowerSW) == HIGH ){ //check if motor off?
Er_Code = 1; //if so, keeps alarm_1 and ending
goto Alarm1_And_Ending; //Alarm_1
}
//---------------------------------------------------------------
//----------------check water coming up--------------------
if (digitalRead(WaterDetectSW) ==HIGH ){ // == HIGH => water coming up!
goto Normal_process ; // water coming up within 10sec?
} // Yes,ends initial process and goes on next process.
//--------------------------------------------------------
delay(100); //for blinking 2 times in per cycle
digitalWrite(13,LOW);
delay(200);
digitalWrite(13,HIGH);
delay(100);
digitalWrite(13,LOW);
delay(600);
} //for next loop --gets 10sec initial process
//-----------------time up(10sec)-------------------------------
Er_Code = 2; water can't pump up within 10sec => keeps alarm_2 and ending
goto Alarm1_And_Ending; //Alarm_2
//-------------------------------------------------------------------
//==================================================================
//---------- 2. keeps pumping water process:-------------------------
//==================================================================
Normal_process:
for(int i=0;i<750;i++){ //sets running process for 15min (1.2sec*750=900sec=15min)
digitalWrite(13,HIGH); //for blinking 3 times in per loop
delay(100);
digitalWrite(13,LOW);
delay(200);
digitalWrite(13,HIGH);
delay(100);
digitalWrite(13,LOW);
delay(200);
digitalWrite(13,HIGH);
delay(100);
//*********************** end process ************************
if (digitalRead(TowerSW) ==LOW ){ //check if motor off within 15min ?
goto Start ; //if so, end pumping process;restart.
}
//**************************************************************
//----------------check water coming up--------------------
if (digitalRead(WaterDetectSW) == LOW ){ //if water coming up while motor is running?
Er_Code = 3; //if fails,goes for error and ending process
goto Alarm1_And_Ending;
}
//--------------------------------------------------------
digitalWrite(13,LOW);
delay(500);
} //for next loop---gets 15min loop
//-----------------time up(15min)-------------------------------
Er_Code = 4; // pumping water more than 10min => keeps alarm_4 and ending
goto Alarm1_And_Ending; //Alarm_4
//------------------------------------------------------------------
} //main if loop
digitalWrite(13,HIGH);
delay(10);
digitalWrite(13,LOW);
delay(500);
goto Start ; //main loop
//==================================================================
//------------------3. Error and Ending Loop------------------------
//==================================================================
Alarm1_And_Ending:
digitalWrite(StopRL,HIGH); //turns motor off
for(int i= 1;i<= Er_Code;i++){ //Bee with error code
tone(Alarm, 1000, 200);
delay(300);
}
delay(1000);
goto Alarm1_And_Ending;
} //maim void loop
//====================================================================