綜述
由樹莓派作爲上位機,定時運行python爬蟲程序,將結果通過藍牙發送給Arduino,Arduino接收到數據,將數據顯示在1602LCD屏上,如果數據中顯示會下雨,則亮起紅色LED以提醒並(拓展:使用SIM900GSM模塊,通過Arduino發信息給手機實時提醒。)
電子器件:
- raspberry pi 3B
- Arduino Uno
- HC-05藍牙主從一體模塊
- 1602LCD顯示屏
- HC-SR04超聲波測距模塊
- 9V電池
- 1000Ω電阻
- 紅色,綠色LED
- SIM900 GSM模塊(拓展)
樹莓派上位機:
一:藍牙配置
目前知道有2種方法:
A:完全通過linux命令行完成
在Python環境下使用“import bluetooth”如果報出錯誤信息“ImportError: No module named bluetooth”則說明沒有安裝相應的包,執行一下命令安裝。
$sudo apt-get update
$sudo apt-get install bluetooth bluez python-bluez
進入藍牙連接工具
$ bluetoothctl
[NEW] Controller B8:27:EB:D3:61:B0 raspberrypi [default]
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful
開始掃描周圍藍牙設備
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:D3:61:B0 Discovering: yes
[NEW] Device 98:14:01:10:C5:32 HC-05
連接藍牙設備
[bluetooth]# pair 98:14:01:10:C5:32
Attempting to pair with 98:14:01:10:C5:32
[CHG] Device 98:14:01:10:C5:32 Connected: yes
Connected: yes
Request PIN code
[agent] Enter PIN code: 1234
[CHG] Device 98:14:01:10:C5:32 UUIDs:
00001101-0000-1000-8000-00805f9b34fb
[CHG] Device 98:14:01:10:C5:32 Paired: yes
Pairing successful
生成rfcomm0 文件(要用)
$ sudo rfcomm bind 0 98:14:01:10:C5:32
連接藍牙設備後,會在樹莓派的【/dev】目錄中創建一個藍牙設備的虛擬文件 /dev/rfcomm0
如果大家覺得這方法繁瑣且難以記住,還有一種相對簡答方法:
B:先通過桌面,再通過命令行
較新的樹莓派桌面支持顯示藍牙設備,我們可以通過桌面操作連接藍牙
升級安裝藍牙相關軟件包
關鍵第三步用來更新桌面環境,我的桌面版本老,故要執行
$sudo apt-get update
$sudo apt-get upgrade -y
$sudo apt-get dist-upgrade -y
$sudo apt-get install pi-bluetooth bluez bluez-firmware blueman
找到桌面藍牙圖標
之後的操作和命令行一樣:
先進入bluetoothctl
$ bluetoothctl
找到對應的藍牙地址(這是會自動顯示再桌面下已連接的藍牙設備)
再退出
exit
最後生成rfcomm0 文件(要用)
$ sudo rfcomm bind 0 98:14:01:10:C5:32
二: python網絡爬蟲獲取天氣預報
首先導入python相應模塊
INDEX:
Requests 是用Python語言編寫,基於 urllib,採用 Apache2 Licensed 開源協議的 HTTP 庫。它比 urllib 更加方便,可以節約我們大量的工作,完全滿足 HTTP 測試需求。Requests 的哲學是以 PEP 20 的習語爲中心開發的,所以它比 urllib 更加 Pythoner。更重要的一點是它支持 Python3Beautiful Soup提供一些簡單的、python式的函數用來處理導航、搜索、修改分析樹等功能。它是一個工具箱,通過解析文檔爲用戶提供需要抓取的數據,因爲簡單,所以不需要多少代碼就可以寫出一個完整的應用程序。
Beautiful Soup自動將輸入文檔轉換爲Unicode編碼,輸出文檔轉換爲utf-8編碼。你不需要考慮編碼方式,除非文檔沒有指定一個編碼方式,這時,Beautiful Soup就不能自動識別編碼方式了。然後,你僅僅需要說明一下原始編碼方式就可以了。
Beautiful Soup已成爲和lxml、html6lib一樣出色的python解釋器,爲用戶靈活地提供不同的解析策略或強勁的速度。serial 用於讀串口的數據,使用非常的方便
time 處理與時間有關的操作,包括程序中斷等
import requests
from bs4 import BeautifulSoup
import serial
from time import sleep#程序中斷執行函數
如果導入出現困難,用linux命令行進行下載更新
法1:
$sudo apt-get install python-requests
法2:(前提是已經下載python pip 模塊)
$sudo pip install python-requests
獲得各城市天氣預報網站函數
def get_url(city_name):#輸入參數爲城市名
url = 'http://www.weather.com.cn/weather/'
#打開存儲對應城市對應網址地址的txt文檔
with open('city.txt', 'r', encoding='UTF-8') as fs:
lines = fs.readlines()
#對文件讀取遍歷
for line in lines:
if(city_name in line):#發現城市名
code = line.split('=')[0].strip()#取得相應數字
return url + code + '.shtml'#加到網址地址後
raise ValueError('invalid city name')#未找到該城市
同路徑下有個存儲對應城市具體地址的txt文檔
格式:
101010100=北京
101010200=海淀
網絡爬蟲獲取地址中的內容
用簡單的 requests 配合 BeautifulSoup 獲取預報信息並保存。
下面兩步根據鏈接地址把網頁內容抓下來,然後進行解析,得到要保存的數據,返回的 content 是一個列表,每個元素是要保存的一行內容。
def get_content(url, data=None):
rep = requests.get(url)
rep.encoding = 'utf-8'
return rep.text
def get_data(htmltext, city):
content = []
bs = BeautifulSoup(htmltext, "html.parser")
body = bs.body
data = body.find('div', {'id': '7d'})
ul = data.find('ul')
li = ul.find_all('li')
for day in li:
line = [city]
date = day.find('h1').string
line.append(date)
text = day.find_all('p')
line.append(text[0].string)
if text[1].find('span') is None:
temperature_H = None
else:
temperature_H = text[1].find('span').string.replace('℃', '')
temperature_L = text[1].find('i').string.replace('℃', '')
line.append(temperature_H)
line.append(temperature_L)
content.append(line)
return content
對所獲得信息進行處理
def finds(strings):#中文字符串
#找相應中文
a=strings.find("雨",0)
b=strings.find("雲",0)
c=strings.find("晴",0)
if a!=-1:
return 'r'#有雨發送‘r’
if b!=-1:
return 'c'#有云發送‘c’
if c!=-1:
return 's'#有陽發送‘s’
#對沒有天氣情況的返回爲‘N’,result列表儲存今明2天天氣情況
if result[0][3]==None:
result[0][3]='N'
if result[0][4]==None:
result[0][4]='N'
if result[1][3]==None:
result[1][3]= 'N'
if result[1][4]==None:
result[1][3]='N'
三: 與Arduino下位機通信
#藍牙串口虛擬文件
port='/dev/rfcomm0'
serial=serial.Serial(port,9600)#設置藍牙波特率
for i in range(1,10):#多次發送保證發送成功
#調用serial.write()其在python3中只能一位一位發送,故將數據轉爲按位發送
serial.write(bytes(finds(result[0][2]),'UTF-8'))
#發送空格,分開各數據
serial.write(bytes(' ','UTF-8'))
serial.write(bytes(result[0][3],'UTF-8'))
serial.write(bytes(' ','UTF-8'))
serial.write(bytes(result[0][4],'UTF-8'))
serial.write(bytes(' ','UTF-8'))
serial.write(bytes(finds(result[1][2]),'UTF-8'))
serial.write(bytes(' ','UTF-8'))
serial.write(bytes(result[1][3],'UTF-8'))
serial.write(bytes(' ','UTF-8'))
serial.write(bytes(result[1][4],'UTF-8'))
serial.write(bytes(' ','UTF-8'))
serial.flushInput()#清除串口緩衝區
sleep(.8)#程序終止運行0.8s,太快CPU費勁,程序也容易卡,LCD也會有反應不過來,更新過快
Arduino 下位機:
一: 獲得樹莓派數據
在arduino中藍牙與串口使用方法相同
void got ()
//收到藍牙信號
{if (Serial.available())
//不停讀取發送的一個個位,最多會有16位數據
{for (int i=0;i<16;i++)
{
a=Serial.read();
//將數據給數組
b[i]=a;
if (b[i]=='s')
//如果接收到要下雨信息,pin8至高電平,點亮紅色LED提醒
{digitalWrite(9,HIGH);
}
if (b[i]=='r')
//如果接收到要天晴信息,pin9至高電平,點亮綠色LED
{digitalWrite(8,HIGH);
}
二:在LCD上顯示
要導入”LiquidCrystal”庫
這樣2行便解決
# include <LiquidCrystal.h>
//設置光標位置
lcd.setCursor(i,2);
//寫入字符串
lcd.print(b[i]);
三:數據更新
有2種不同的選擇:
A:通過超聲波傳感器接收距離信息,如果距離小於某值,則說明有人來了,向樹莓派發送信息,樹莓派進行數據更新
獲得距離
//超聲波傳感器輸出端
# define 6 trig
//超聲波傳感器輸入端
# define 6 trig
float cm;//存儲探測距離
float temp;//存儲高脈衝信號長度
void distance ()
{digitalWrite(trig,LOW);
delayMicroseconds(2);
digitalWrite(trig,HIGH);//給一個10us秒的高脈衝,激發傳感器
delayMicroseconds(10);
digitalWrite(trig,LOW);
temp=float(pulseIn(echo,HIGH));//檢測計算傳感器發出後接受到的高脈衝時長,其正比於距離
cm=temp*17/1000;//公式換算}
}
循環loop函數中進行檢測更新發數據給樹莓派
void loop()
{ distance();//獲得距離
if(cm<50)
{Serial.write(int(cm));//發送信息給樹莓派
for (int i=0;i<11;i++)
{got();//多次獲得數據,保證數據正確完整
lcd.setCursor(1,0);
lcd.print("today tomorrow");//寫明今明兩天
delay(800);}}//延時與樹莓派相匹配
}
B:使用程序中斷定時進行:
這也有2種方法:
a:使用python time 模塊的sleep函數,執行中斷一段時間,之後繼續執行
例如我們讓每3小時更新一下,只要加上”sleep(60*60*3)”並稍微改動即可
b:使用linux下的crontab工具,設置程序定時執行
打開在pi用戶下的crontab
$sudo crontab -u pi -e
寫下
7 0 * * * python weather2.py
11 0 * * * python weather2.py
16 0 * * * python weather2.py
20 0 * * * python weather2.py
其格式是:
hour minute day month year command
退出vim編輯器後,很重要的一點是一定要執行如下命令,否則無法執行
$sudo /etc/init.d/cron restart
則python程序將在7,11,16,20點執行
四:電路連接
不想用Fritzing畫圖了,直接寫了
1.LCD-Arduino
將電位器換成1000Ω電阻,另一端接地
2.HC-SR04
trig-6
echo-7
3.HC-05
TX-RX
RX-TX
4.LED
紅+-pin8
綠+-pin9
5.電源
考慮到盒子小體積,我使用了較小的9V電池,分別直接接IO口的VIN與GND,沒有接電源接口,主要是縮小體積。
五:拓展短信通知(沒錢買模塊啊!樹莓派一買就要吃土了!!還有關鍵Uno上只有一個RX,TX,得換arduino mega)
加個函數再調用就行
void sendSms(String phonecode ,String content)
{//電話號碼 ,短信內容
Serial3.println("AT+CMGS=\""+phonecode+"\"");
delay(500);//必須延時,不加延時可以自己看結果
Serial3.print(content);//短內容爲content;
//不知爲什麼加這個?
Serial3.write(0x1A)
}
總體包裝:
先是用杜邦線連接調試,然後花了一個下午多把電路焊在洞洞板上(佈線自己還算滿意,學長或許就不這麼認爲了…),然後偶然看到實驗室的一個盒子大小剛好適合,便順便把盒子改造了下,把他塞進去了,還不錯。時間比較緊,焊接製作各過程都沒拍照,關鍵是近期手機壞了,不能拍照!
最後給一張我用老手機拍的模糊的最終成品照:
總結:
大一下學期學的較亂,黑白道(軟硬件)通吃,卻都很不精,感覺有點不踏實,不過想想以後又不是靠這些吃飯(至少不大可能),覺得現在多瞭解些挺好,打好通識工科,爲以後打基礎吧,這學期從最初的stm32,到python與opencv圖形處理,再到樹莓派與linux,計劃之後再學學電路基礎,偏點硬件。
PS:
該項目是實驗室二輪考覈的題目,在匆忙之中將其完成,應該包含了大部分我學習的內容,還是比較綜合的吧,可能偏簡答了,但覺得實驗室應該沒人做過這個,應該算是較新的領域了,
相對比較實用(這也是我選擇項目的主要考慮因素)。也是完成了,感覺滿滿的成就感 ,別人是難以體會的,一種自我價值實現與創造,按柏格森說法,就是”生命創造論”,—個人創造衝動與工具理性的結合而產生,或者說是二者之間的一種相互妥協,這或許是2者最好的歸宿。。。