2013年1月31日

Arduino製作老鼠轉圈計數器


老鼠養了幾週之後,突然想起當初買的籠子是附有滾輪的。當時的想法是倉鼠才會愛跑滾輪吧,小白鼠應該不會跑滾輪才是,所以買回的那天起,就沒把滾輪裝上去。誰知道,我裝上滾輪之後,兩隻小白鼠對它好奇得很,然後其中一隻(科科)就抓到要領,馬上弄懂怎麼玩滾輪了。

我對老鼠玩滾輪這件事一直很納悶,老鼠明明知道在上面跑並不會讓身體前進,牠怎麼會願意在上面一直跑一直跑呢?難道老鼠也懂得「玩」?有動物行為學者拿動物的玩樂作為研究題目,像小貓小狗的玩,其實就是練習長大之後的捕獵行為。但老鼠在滾輪上跑,這又幫了牠什麼?還是說因為牠是圈養的動物,籠子裡面很無聊,所以難得有好玩的就會一直玩?

看老鼠玩滾輪好像很開心似的,我突然想到有沒有機器可以測牠轉了幾圈啊?一查之下才知道,現在賣的滾輪原來有些有附計數器功能的啊。再繼續查,原來有小學生的科展是想用倉鼠跑滾輪來發電的啊。
報告連結:鼠力發電廠

且先不管最後發電成不成,但他們的實驗數據讓我覺得很有趣,他們觀察到楓葉鼠一天最多可以跑34833圈,而老公公鼠可以跑到82730圈,不知道我這邊的科科一天會跑幾圈啊?

在那份科展作品中計算圈數的方式,他們一開始是用跳繩的計數器,但發現位數不夠用(僅有四位),所以改用電子計步器外接磁簧開關,感測的方式是在滾輪上黏一個強力磁鐵,外頭再用磁簧開關感應磁鐵的靠近,。滾輪轉一圈之後,磁鐵靠近磁簧開關,使開關短路,然後就可以讓計步器數字加一。而計算一分鐘可轉幾圈的方式,則是用攝影的方式拍攝一分鐘內計步器增加了多少數字。這個感測裝置很有創意呢!給他們拍拍手。

這也給了我一個想法,我也想來測小白鼠跑幾圈,但是我不只要知道總數,我還想知道他們何時跑,跑多久,跑多快。既然要知道這麼多東西,就不能單用一個電子計步器了,這就得要Arduino出馬啦。


同樣是在滾輪上黏一個強力磁鐵,外面有磁簧開關感測磁鐵的靠近,再把磁簧開關的兩端接到Arduino,再連接到電腦。
IMG_0670



整個運作的過程就是這樣
 


我用這樣的裝置紀錄24小時之內滾輪轉動的圈數,在這一天中滾輪轉了17620圈,以滾輪內徑32公分來計算,這隻老鼠一天就跑了5.638公里呢!

那麼牠是在什麼時候跑的呢?統計後發現在晚上九點到早上五點之間是最密集的時候,而中午12點到下午三點則是另外一階段。

mouse

速度上的分析是這樣的,牠們的速度大約落在90-130 RPM之間,偶而可以有跑出150 RPM以上的佳績

speed

再來看的是耐力部份,我以60 RPM為界限,看看科科能夠以60 RPM以上的速度持續跑幾秒鐘。分析後發現大多是能持續3-4秒鐘的奔跑,但也有可以連續跑5秒鐘以上的能耐,不過都跑不太久就是了。所以科科應該是練短跑的,若要牠長跑,可能就比較沒辦法了。

duration

如果未來要作更精確的分析,可以改用兩個磁鐵配合兩個磁簧開關,偵測更真實的瞬間速度,也可以得知滾輪是順時針轉還是逆時針轉。甚至也可以拿來作些什麼實驗,比如餵牠們吃什麼營養保健食品,看看有沒有更會跑滾輪。

以上是結果分析,看起來好像很容易,實際上在數據處理花了不少功夫。接下來就是講怎麼寫程式,怎麼分析畫圖,所以是很硬斗的內容了。


Arduino的程式

Arduino的檔案在此
https://sites.google.com/site/pancala/Home/mouseWheel.ino?attredirects=0&d=1

這程式所作的事情就是把磁簧開關當按鈕來用,Arduino要紀錄按鈕什麼時候被按下,然後把被按下的時間傳給電腦的終端機印出來,我使用的終端機程式是Access Port

本來我用gobetwino來接收,想說gobetwino就有增加時間戳記的功能,我可以省去撰寫時間戳記的程式,但測試一天後發現我的舊電腦配上gobetwino會delay,以致於無法正確產生時間。不知道是電腦的問題還是gobetwino的問題。所以後來我直接用Arduino來產生時間戳記,程式修改自官方網站附的函式庫Time

但又遇一個問題,電腦必須送出現在時間給Arduino,但時間需用Unix Time才行。若是使用Linux,可直接以終端機送出以下命令,直接校正Arduino
TZ_adjust=8;  echo T$(($(date +%s)+60*60*$TZ_adjust)) > /dev/ttyUSB0

但我接鼠籠的是Windows,所以我得用Excel來轉換Unix Time,轉換方式是參考這個網址的。由於Excel 內部的時間起點是 1900 年 1 月 1 日,日期是整數,時間是小數。而Unix time是從1970年1月1日開始計算,以秒為單位。若是要將Excel time轉換成Unix time則是將excel time減去1900/1/1 到 1970/1/1 的 25569 天,再乘上一天的86400秒,所以轉換公式是
=(NOW()-25569)*86400

我在Excel得到Unix Time之後,在字串前加個T字,用Access Port透過Serial Port送給Arduino來校正時間。(原附的那個Time程式寫法是得在Unix Time前加個T,我沒改,所以得照做囉)

得到的檔案我會再把時間裡的":"取代成空白,藉此把log檔變成像這樣8欄的資料。第7欄是磁簧開關接通時的時間點,單位是毫秒,時間的起點是從Arduino開始執行程式時計算,millis()這個函數會在約50天左右的時候發生溢位,所以有要以此為參考做偵測紀錄的要注意這點。第8欄是計算當時的瞬間速度,計算方式是用這次的時間減去前一次的時間,再用60000去除這個數值,藉此轉換成RPM(每秒幾轉)


2013 1 29 12 18 03 82114827 28
2013 1 29 12 18 09 82120516 10
2013 1 29 12 18 10 82121388 68
2013 1 29 12 18 14 82125460 14
2013 1 29 12 18 15 82125921 130
2013 1 29 12 18 15 82126728 74
2013 1 29 12 18 16 82127560 72
2013 1 29 12 18 18 82129641 28
2013 1 29 12 18 19 82130488 70
2013 1 29 12 18 20 82131546 56





Python計算持續時間
下面這個程式是用Python去算以60 RPM持續跑多少時間,輸入的檔案是mouseWhealNumber,輸出是duration。

#/usr/bin/python
# coding: utf-8
output=open('durationResult','w')
time = []
speed = []
for line in file('mouseWhealNumber'):
  line = line.split()
  a = int(line[6])
  b = int(line[7])
  time.append(a)
  speed.append(b)

start = []
end = []
duration = []
for i in range(len(speed)):
  if speed[i] >= 60 and speed[i-1] < 60 :
    start.append(time[i-1])
  if speed[i] >= 60 and speed[i+1] < 60 :
    end.append(time[i])
for i in range(len(start)):
  duration.append(str((end[i]-start[i])/1000.00)+"\n")
output.writelines(duration)
output.close






Gnuplot繪圖

有了以上的數據資料後,接下來是用Gnuplot繪圖。下面是繪製持續時間的圖

reset
unset title
set terminal postscript landscape enhanced color solid
set output 'duration.ps'
fname2 = 'durationResult'
bin(x, s) = s*int(x/s)
bw = 1.0
set style fill solid 0.4
set xlabel "Duration Time (sec)"
set ylabel "Frequency"
unset key
plot fname2 using (bin($1,bw)+bw/2):(1) smooth frequency  w boxes



這個是繪製什麼時間跑步的圖

reset
set terminal postscript landscape enhanced color solid
set output 'time.ps'
set boxwidth 1
set style fill solid 0.5
set grid ytics
set xtics 0,1,23
set xrange [-1:24]
set xlabel "Hour"
set ylabel "Frequency"
unset key
plot 'mouseWhealNumber' u 4:(1) smooth frequency w boxes




這個是繪製速度的圖

reset
unset title
set terminal postscript landscape enhanced color solid
set output 'speed.ps'
fname2 = 'mouseWhealNumber'
bin(x, s) = s*int(x/s)
bw = 10
set style fill solid 0.4
set xlabel "Speed (RPM)"
set ylabel "Frequency"
set xrange [0:250]
unset key
plot fname2 using (bin($8,bw)+bw/2):(1) smooth frequency  w boxes





Gnuplot繪圖的參考資料有以下幾個
http://www.ruskabebic.com/wp/gnuplot-for-commoners/gnuplot-3/

http://darksair.org/wiki/Gnuplot.html

https://docs.google.com/viewer?a=v&q=cache:Y2D3z5ieX3EJ:ftp://210.45.212.113/pub/soft/gnuplot/gnuplot_tutorial.pdf+&hl=zh-TW&gl=tw&pid=bl&srcid=ADGEESiRvYdsqv1KUTR0pbcdH4dxaSFFlmLH9oQZ3ZyG4oytCqRJf4LLCnB9QW0wI8nXYwZXszPoI8lDB5oEezcyb9_T5Diqdh4YadafDr69YaXQRyFqiq-9hDCcyJ7BdN5_YvnWXtb1&sig=AHIEtbSHeOJQi7weTHewpSf4mi5CK0hqlw