牟曉東
在進(jìn)行開(kāi)源硬件編程和創(chuàng)客作品開(kāi)發(fā)時(shí),我們都會(huì)先借助各種傳感器進(jìn)行各種數(shù)據(jù)的即時(shí)采集,再根據(jù)設(shè)定的相關(guān)判定條件去控制LED燈等外設(shè)做出響應(yīng)。對(duì)于傳感器在每個(gè)瞬間所“捕獲”的數(shù)據(jù),程序通常都是“用完便棄”的一次性處理,如果后期對(duì)數(shù)據(jù)想要進(jìn)行整理和圖像繪制等二次使用的話,就必須將傳感器在實(shí)驗(yàn)過(guò)程中所采集的數(shù)據(jù)以文件形式存儲(chǔ),從而達(dá)到將實(shí)驗(yàn)數(shù)據(jù)圖形化“再現(xiàn)”的目的——尤其是多個(gè)不同傳感器同時(shí)快速采集數(shù)據(jù)的情況。以常見(jiàn)的掌控板“聲光雙控?zé)簟表?xiàng)目為例,如何同時(shí)對(duì)聲音傳感器、光線傳感器的數(shù)據(jù)采集進(jìn)行同步存儲(chǔ)和Python作圖呢?
在mPython X中通過(guò)圖形化編程實(shí)現(xiàn)傳感器數(shù)據(jù)存儲(chǔ)。首先,初始化掌控板的OLED顯示屏進(jìn)行提示信息的顯示——清除第2行和第3行的信息、在對(duì)應(yīng)坐標(biāo)位置顯示“按A鍵采集數(shù)據(jù)”和“按B鍵結(jié)束”、OLED顯示生效;接著,編寫“當(dāng)按鍵A被按下…執(zhí)行…”主函數(shù),先是初始化兩個(gè)文本文件sound.txt和light.txt,分別對(duì)應(yīng)聲音傳感器和光線傳感器采集數(shù)據(jù)的目標(biāo)存儲(chǔ)文件;再進(jìn)入一個(gè)“一直重復(fù)…執(zhí)行…”循環(huán)結(jié)構(gòu),將兩個(gè)傳感器的“聲音值”和“光線值”分別賦值給對(duì)應(yīng)的兩個(gè)變量:“測(cè)試聲音值”和“測(cè)試光線值”,接著再調(diào)用“采集并存儲(chǔ)”函數(shù);接下來(lái),進(jìn)入一個(gè)判斷“按鍵B是否已經(jīng)按下”的選擇結(jié)構(gòu),如果條件成立的話,則先調(diào)用“讀取并輸出”函數(shù),再執(zhí)行“中斷循環(huán)”模塊跳出該層循環(huán);為了控制兩個(gè)傳感器采集數(shù)據(jù)的時(shí)間間隔,需要在循環(huán)結(jié)構(gòu)中加入“等待1秒”模塊語(yǔ)句。
自定義的“采集并存儲(chǔ)”函數(shù)包括:先將變量測(cè)試聲音值和測(cè)試光線值由數(shù)值型轉(zhuǎn)為文本再分別寫入sound.txt和light.txt兩個(gè)文本文件,注意設(shè)置為以回車來(lái)分隔相鄰的兩個(gè)數(shù)據(jù);接著,將這些數(shù)據(jù)附加提示信息后進(jìn)行顯示輸出;“讀取并輸出”函數(shù)先打印輸出“數(shù)據(jù)采集結(jié)束”的提示信息,然后定義sound_list和light_list兩個(gè)列表,通過(guò)“讀取文本文件為列表”模塊語(yǔ)句進(jìn)行賦值,實(shí)現(xiàn)從對(duì)應(yīng)的文本文件中讀取已經(jīng)存儲(chǔ)過(guò)的傳感器數(shù)據(jù)(注意同樣也要設(shè)置為對(duì)應(yīng)的“以回車分隔”);最后,將所有的聲音數(shù)據(jù)和光線數(shù)據(jù)顯示輸出(如圖1)。
將掌控板通過(guò)數(shù)據(jù)線連接至電腦的USB接口,正常的話會(huì)在窗口上方有“掌控板”、“COM4”等提示信息。程序保存后點(diǎn)擊“刷入運(yùn)行”按鈕,當(dāng)右下角有“刷入成功”提示信息后,在掌控板的OLED顯示屏上會(huì)出現(xiàn)兩行提示信息“按A鍵采集數(shù)據(jù)、按B鍵結(jié)束”;接著,輕觸一下掌控板的A鍵,提示窗口就會(huì)每隔1秒鐘出現(xiàn)一行類似于“聲音值為0,光線值為1063”的信息,此時(shí)可嘗試敲擊桌子或?qū)χ瓶匕搴叱獛拙涓枨瑫r(shí)還可以用手捂住光線傳感器或使用手機(jī)的“手電筒”進(jìn)行照射;采集周圍的聲音數(shù)據(jù)和光線數(shù)據(jù)一段時(shí)間后,輕觸一下掌控板的B鍵,程序則會(huì)停止數(shù)據(jù)的采集(輸出“數(shù)據(jù)采集結(jié)束”),并且將采集的聲音數(shù)據(jù)和光線數(shù)據(jù)以列表形式輸出(如圖2)。
點(diǎn)擊mPython X頂端的“文件管理”按鈕,彈出“板載文件管理”窗口,找到其中的sound.txt和light.txt文本文件,分別選中后再點(diǎn)擊“下載到電腦”按鈕,從掌控板的SD卡將它們下載至電腦本地(比如D盤根目錄中);再使用記事本程序分別打開(kāi)進(jìn)行查看,其中所存儲(chǔ)的數(shù)據(jù)正是之前聲音傳感器和光線傳感器每隔一秒鐘所采集到的幾十個(gè)數(shù)據(jù),每個(gè)數(shù)據(jù)占據(jù)一行(如圖3)。
在Spyder編輯器中進(jìn)行Python代碼編程。
首先,進(jìn)行matplotlib和numpy庫(kù)模塊的導(dǎo)入:“import matplotlib.pyplot as plt”、“import numpy as np”;接著,設(shè)置圖像坐標(biāo)軸能夠正常顯示中文(比如仿宋)和“負(fù)數(shù)”數(shù)據(jù):“plt.rcParams['font.sans-serif'] = ['FangSong']”、“plt.rcParams['axes.unicode_minus'] = False”;然后,從sound.txt和light.txt兩個(gè)文本文件中分別讀取之前兩個(gè)傳感器所采集到的41個(gè)數(shù)據(jù),其中的“x = np.linspace(0,40,41)”是用來(lái)構(gòu)建圖像的橫坐標(biāo)數(shù)據(jù),代表每隔1秒鐘進(jìn)行一次數(shù)據(jù)采集;分別初始化y_sound和y_light兩個(gè)空列表后,使用“with open”方法以只讀方式打開(kāi)對(duì)應(yīng)的文本文件后,通過(guò)range()循環(huán)以append()列表數(shù)據(jù)追加的方法將每個(gè)數(shù)據(jù)添加到列表中,注意還要使用eval()方法將每個(gè)原始的文本數(shù)據(jù)轉(zhuǎn)換為int整型數(shù)據(jù);最后,進(jìn)行圖像的坐標(biāo)軸、標(biāo)題、圖例和網(wǎng)格等的設(shè)置,并且調(diào)用plt.plot()進(jìn)行圖像的同步繪制,再將生成的圖像以png圖片文件形式進(jìn)行保存:“plt.savefig(‘傳感器采集數(shù)據(jù).png’,dpi=200)”。
將程序保存為“Python繪制傳感器的采集數(shù)據(jù).py”,按F5功能鍵運(yùn)行測(cè)試,在右側(cè)的控制臺(tái)中就會(huì)顯示有預(yù)覽圖像的輸出結(jié)果;同時(shí),在D盤中也生成了“傳感器采集數(shù)據(jù).png”文件(如圖4),實(shí)現(xiàn)了將兩個(gè)傳感器采集的實(shí)時(shí)數(shù)據(jù)先以文本文件的形式存儲(chǔ)后、再通過(guò)Python代碼編程繪制圖像展示的目的,大家不妨一試。