# 微電腦應用實習 Author 曾鏹毅 圖片來源: [raspberrypi.org](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) ![](https://i.imgur.com/6UIAHyP.png) :::info ## 所需軟體 ::: 1. [mobaxterm下載](https://mobaxterm.mobatek.net/download-home-edition.html) 2. [VNC](https://www.realvnc.com/en/connect/download/viewer/) 3. [Notepad++](https://notepad-plus-plus.org/downloads/) 4. [Visual Studio Code](https://code.visualstudio.com/) ## 燒錄raspberry pi os {%youtube a9Hs0nqD7LQ%} ### *使用 raspberry pi imager* ![image](https://hackmd.io/_uploads/Sy3CbB3sA.png) ![image](https://hackmd.io/_uploads/H1pZfB3s0.png) #### 選擇樹梅派型號、OS版本以及micro SD卡(這裡以pi4、piOS(64bit Bookworm)與16G sd卡Demo ![image](https://hackmd.io/_uploads/H1yuzr2iR.png) ![image](https://hackmd.io/_uploads/SJEtGS3iR.png) ![image](https://hackmd.io/_uploads/BJQXQH3oC.png) #### 按下 NEXT ![image](https://hackmd.io/_uploads/rJ3B7BnsR.png) #### 接著選擇 編輯設置後如下圖 ![image](https://hackmd.io/_uploads/BkpFQS3jC.png) #### 設定主機名稱、使用者名稱、密碼、WiFi的ssid名稱、WiFi連線密碼、WiFi國家 #### 接著切換到第2頁籤 SERVICES,並將SSH服務勾選(如下圖),並按下保存離開 ![image](https://hackmd.io/_uploads/Bk5mNBhi0.png) #### 接著按下是(如下圖) ![image](https://hackmd.io/_uploads/Hk8pErnj0.png) ![image](https://hackmd.io/_uploads/HJo1rBhsA.png) #### 開始下載並寫入micro sd卡 ![image](https://hackmd.io/_uploads/HkrQrHni0.png) ![image](https://hackmd.io/_uploads/ryD5OHnjC.png) --- ## visual studio code 下載與安裝 {%youtube c-jJO9A68wM%} ## [線上python程式練習(Colab;使用學校google帳戶登入)](https://colab.research.google.com/drive/1EQjJolXH6azjcpJOZaqJuY0xKirH56lr?usp=sharing) ## [3D建模軟體onshape](https://www.onshape.com/) ## 樹梅派4b正面配置 ##### 圖片來源 [BeginnersGuide-4thEd-Eng_v2.pdf](https://magpi.raspberrypi.com/books/beginners-guide-4th-ed) ![](https://i.imgur.com/sV832Ll.png) ## GPIO接腳 [raspberrypy.org](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#gpio-and-the-40-pin-header) ![](https://i.imgur.com/nUia1SM.png) ## GPIO各接腳 pull up 與 pull down 狀態 ![](https://i.imgur.com/h9iZnmm.png) ## pull up 與 pull down(拉高、拉低電阻) * ## [Multisim Live 模擬](https://www.multisim.com/content/FJ79pZWTZPdWfX6in6XmL4/pull_up_down-resistor/) * ![](https://i.imgur.com/K9CEzjZ.png) * 啟動上拉電阻 python 語法 ``` import RPi.GPIO as gpio gpio.setmode(gpio.BCM) button=7 gpio.setup(button,gpio.IN,pull_up_down=gpio.PUD_UP) ``` * 啟動下拉電阻 python 語法 ``` import RPi.GPIO as gpio gpio.setmode(gpio.BCM) button=26 gpio.setup(button,gpio.IN,pull_up_down=gpio.PUD_DOWN) ``` ## BCM模式與Board模式差異 * BOARD 選項是指定在電路版上接脚的號碼 * python寫法 ``` import RPi.GPIO as gpio gpio.setmode(gpio.BOARD) #設定為BOARD模式 ``` * BCM 選項是指定GPIO後面的號碼 * python寫法 ``` import RPi.GPIO as gpio gpio.setmode(gpio.BCM) #設定為BCM模式 ``` ## Python 相關語法 * 異常處理 try…except…finally… ``` try: .... .... except KeyboardInterrupt: break finally: ... ... ``` # 實驗 ## 單顆LED on off http://bit.ly/3tB2okQ ``` import RPi.GPIO as gpio import time gpio.setmode(gpio.BCM) gpio.setup(17,gpio.OUT) gpio.output(17,1) time.sleep(1) gpio.output(17,0) gpio.cleanup() ``` ![](https://i.imgur.com/VP6mxMj.png) ## 單顆LED 間隔1秒閃爍 http://bit.ly/3UE7EAk ``` import RPi.GPIO as io import time io.setmode(io.BCM) io.setup(17,io.OUT) while True: try: io.output(17,1) time.sleep(1) io.output(17,0) time.sleep(1) except KeyboardInterrupt: break pass io.cleanup() ``` ## 作業 單方向流水燈(8顆LED) 提示:使用串列list簡化程式 http://bit.ly/3AgD9rP ![](https://i.imgur.com/fCJyH8W.png) --- ## PWM測試 從暗到最亮,單向循環 http://bit.ly/3O5T16q ``` import RPi.GPIO as gpio import time led=17 gpio.setmode(gpio.BCM) gpio.setup(led,gpio.OUT) led=gpio.PWM(led,100) #設定pwm頻率100Hz while True: try: for a in range(0,101,2): led.start(a) # 啟動PWM DutyCycle,dutycycle從0~100,間隔2 time.sleep(0.2) except KeyboardInterrupt: break pass gpio.cleanup() ``` ## 單按鈕測試(pull down) http://bit.ly/3tyE0Ao 按下按鈕時,終端機顯示 Button Pressed!! ![](https://i.imgur.com/TfHIBDU.png) ``` # pull down 測試 import RPi.GPIO as gpio import time button1=26 gpio.setmode(gpio.BCM) gpio.setup(button1,gpio.IN,pull_up_down=gpio.PUD_DOWN) while True: try: input_state=gpio.input(button1) if (input_state==True): print('Button Pressed!!') time.sleep(0.3) except KeyboardInterrupt: break pass gpio.cleanup() ``` ## 三顆按鈕測試(pull down) ##### 開關彈跳問題未解 ![](https://i.imgur.com/4dgZBdJ.png) {%youtube VKR4m-85HVU %} ``` # pull down 測試 import RPi.GPIO as gpio import time button1=13 button2=19 button3=26 gpio.setmode(gpio.BCM) gpio.setup(button1,gpio.IN,pull_up_down=gpio.PUD_DOWN) gpio.setup(button2,gpio.IN,pull_up_down=gpio.PUD_DOWN) gpio.setup(button3,gpio.IN,pull_up_down=gpio.PUD_DOWN) while True: try: in_state1=gpio.input(button1) in_state2=gpio.input(button2) in_state3=gpio.input(button3) if in_state1==True: print('Button1 Pressed!') elif in_state2==True: print('Button2 Pressed!') elif in_state3==True: print('Button3 Pressed!') time.sleep(0.3) except KeyboardInterrupt: break pass gpio.cleanup() ``` ## 簡易Webcam相機應用-使用fswebcam 安裝fswebcam ``` sudo apt-get install fswebcam ``` {%youtube xO0SJ8wduG0 %} fswebcam用法可下指令查詢 ``` fswebcam --help ``` ![](https://i.imgur.com/4Qgsv8o.png) 最簡易的使用方式: fswebcam+ +檔名 即可透過webcam拍攝一張照片,並存放於當下目錄中 ``` fswebcam test.jpg ``` {%youtube 5bMK6H2rCvE %} --- ## 練習:使用按鈕開關拍照--呼叫外部程式(fswebcam) ![](https://i.imgur.com/DDCSVuZ.png) 提示: python呼叫外部程式 ``` import os os.system('指令') ``` {%youtube 6u6ET7vAqKk %} ``` import RPi.GPIO as gpio import time import os button=13 gpio.setmode(gpio.BCM) gpio.setup(button,gpio.IN,pull_up_down=gpio.PUD_DOWN) while True: button_state=gpio.input(button) try: if button_state==True: print('button pressed') os.system('fswebcam a.jpg') os.system('gpicview a.jpg') time.sleep(0.3) except KeyboardInterrupt: break pass gpio.cleanup() ``` --- ## 同上電路功能,增加line notify通知 [Line Notify網站](https://notify-bot.line.me/zh_TW/) ``` import RPi.GPIO as gpio import requests, os #line notify用 import time import os bt1=13 gpio.setmode(gpio.BCM) gpio.setup(bt1,gpio.IN,pull_up_down=gpio.PUD_DOWN) #啟動內建下拉電阻 def lineNotify(token, msg, picURI): #定義linenotify函式 url = "https://notify-api.line.me/api/notify" headers = {"Authorization": "Bearer " + token} payload = {'message': msg} files = {'imageFile': open(picURI, 'rb')} r = requests.post(url, headers = headers, params = payload, files = files) return r.status_code while True: button_state=gpio.input(bt1) try: if button_state==True: print('BT_pressed!') os.system('fswebcam a.jpg') token='填入自己建立的line notify token' #line notify token msg = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) #lineNotify中傳送的文字訊息,這裡擷取系統時間來發送 picURI = 'a.jpg' #發送圖片的檔名 lineNotify(token, msg, picURI) #呼叫linenotify函式 except KeyboardInterrupt: break pass gpio.cleanup() \ ``` # 建立python虛擬環境 因為python程式常有版本和不同套件的需求,因此須針對版本建立不同的python環境,以便於開發 ## 建立虛擬環境(使用venv) 首先須有python3-venv套件 安裝 ``` sudo apt install python3-venv ``` 建立虛擬環境 ``` python -m venv 環境名稱 ``` 啟動環境 ``` source 環境名稱/bin/activate ``` 退出環境 ``` deactivate ``` # 安裝ubuntu 20.04 server 燒錄img ![](https://hackmd.io/_uploads/S1qO-1qon.png) ![](https://hackmd.io/_uploads/B1Wcby5i2.png) ![](https://hackmd.io/_uploads/BkCoW1co3.png) 燒錄完成後,將micro sd放回raspberry pi並開機 第一次開機預設帳密皆為ubuntu(登入後會要求變更) 檢視網卡狀態 ``` ip a ``` ![](https://hackmd.io/_uploads/H12JQkqi3.png) 啟動有線網卡 ``` sudo ip link set eth0 up ``` 修改有線網卡ip( /etc/netplan 下的yaml檔) ![](https://hackmd.io/_uploads/rkRqQJ9o2.png) 修改此yaml檔內容 ![](https://hackmd.io/_uploads/Hklg1VJci2.png) 完成ip設定 ``` sudo netplan apply ``` 修改無線網卡部分 修改同上yaml檔案 ![](https://hackmd.io/_uploads/BJO8sk5on.png) 變更後重啟,wifi即可使用 安裝Desktop(檔案很大,需要一些時間) ``` sudo apt-get install ubuntu-desktop ``` ![](https://hackmd.io/_uploads/ByLSnyqs2.png) # 安裝Node-RED [參考資料](https://nodered.org/docs/getting-started/raspberrypi) * 藉由官網提供的scrip來安裝 ``` sudo apt install build-essential git curl ``` ``` bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) ``` This script will: * remove the existing version of Node-RED if present. * if it detects Node.js is already installed, it will ensure it is at least v14. If less than v14 it will stop and let the user decide whether to stay with Node-RED version 1 - or upgrade Nodejs to a more recent LTS version. If nothing is found it will install the Node.js 16 LTS release using the NodeSource package. * install the latest version of Node-RED using npm. * optionally install a collection of useful Pi-specific nodes. * setup Node-RED to run as a service and provide a set of commands to work with the service. ![](https://i.imgur.com/OQAPte4.png) ![](https://i.imgur.com/MsGkfvF.png) * 啟動Node-RED ``` node-red-start ``` * 樹梅派啟動時,自動啟動node-red ``` sudo systemctl enable nodered.service ``` --- # 安裝OpenCV * {%youtube sSX6zt8kxS4 %} ## 使用script安裝 OS:32bit [GitHUB](https://github.com/Qengineering/Install-OpenCV-Raspberry-Pi-32-bits/) OS:64bit [GitHUB](https://github.com/Qengineering/Install-OpenCV-Raspberry-Pi-64-bits/) ## RaspOS Buster+opencv4.5.5+mediapipe 影像檔下載[img](https://hhvstncedu-my.sharepoint.com/:u:/g/personal/tseng_ms_hhvs_tn_edu_tw/ETSnLpP_T11HueyM9mjYNQMBgB9biqPyEeDg4RCPb-l23A?e=iQBido) ## 快速安裝 opencv與 FFmpeg ## [參考來源](https://pypi.org/project/mediapipe-rpi4/) ``` sudo apt install ffmpeg python3-opencv python3-pip ``` 安裝完後,opencv為4.6版 另一種安裝方式 ``` pip install opencv-contrib-python ``` ## 安裝相依套件 (libdc1394-22 libopenexr23這兩個找不到) ``` sudo apt install libxcb-shm0 libcdio-paranoia-dev libsdl2-2.0-0 libxv1 libtheora0 libva-drm2 libva-x11-2 libvdpau1 libharfbuzz0b libbluray2 libatlas-base-dev libhdf5-103 libgtk-3-0 libdc1394-22 libopenexr23 ``` ## For rpi4 ``` sudo pip3 install mediapipe-rpi4 ``` 上面指令若無法安裝;改用;[參考](https://developers.googleblog.com/2023/08/mediapipe-for-raspberry-pi-and-ios.html) ``` python -m pip install mediapipe ``` 安裝後,opencv會更新至4.9版(2024.02.16.) ## **解決 EXTERNALLY-MANAGED問題** [參考](https://www.yaolong.net/article/pip-externally-managed-environment/) 1.直接把 EXTERNALLY-MANAGED這個檔案刪除(變更檔名) 檔案位置 /usr/lib/python3.x/EXTERNALLY-MANAGED (x為python版本) 另兩種方式請參閱上述參考連結 2.使用python虛擬環境(參閱上面) # 使用RC522及DHT22 * 簡易環境溫溼度紀錄推播及mifare感應運用 * 使用函式庫 * [RC522](https://github.com/ondryaso/pi-rc522) * [Adafruin CircuitPython Libraries](https://learn.adafruit.com/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging/python-setup) * 下圖GPIO12接紅色LED:無效卡片顯示燈號 * GPIO16接 Relay,控制磁力鎖 * 樹梅派GPIO與RC522連接如下表 |RFID-RC522 | Raspberry pi | | -------- | -------- | | 3.3V | 3.3V | | RST | GPIO25 | | GND | GND | | IRQ | GPIO24 | | MISO | GPIO9 | | MOSI | GPIO10 | | SCK | GPIO11 | | SDA | GPIO8 | * ![](https://i.imgur.com/337Cw6a.png) * 溫溼度紀錄與line Notify![](https://i.imgur.com/KA5ncsn.png) * [google sheet紀錄](https://docs.google.com/spreadsheets/d/1RB332Ojkv6eNKpdKVBhbPMRCWochZPRbe5JXnOL9nBk/edit?usp=sharing) ``` import time import board import adafruit_dht #======for ifttt======= import urllib, json import requests, time from urllib import request ifttturl="https://maker.ifttt.com/trigger/****" #填寫申請的ifttt URL #=================== #=========for google sheet============= import gspread from oauth2client.service_account import ServiceAccountCredentials auth_json_path='****.json' #填寫申請的憑證檔檔名 gss_scopes=['https://spreadsheets.google.com/feeds'] credentials=ServiceAccountCredentials.from_json_keyfile_name(auth_json_path,gss_scopes) gss_client=gspread.authorize(credentials) spreadsheet_key='**************' #填寫key值 sheet=gss_client.open_by_key(spreadsheet_key).sheet1 #listtile=["日期時間","溫度","濕度"] #sheet.append_row(listtile) #============================================ # Initial the dht device, with data pin connected to: dhtDevice = adafruit_dht.DHT22(board.D18) # you can pass DHT22 use_pulseio=False if you wouldn't like to use pulseio. # This may be necessary on a Linux single board computer like the Raspberry Pi, # but it will not work in CircuitPython. # dhtDevice = adafruit_dht.DHT22(board.D18, use_pulseio=False) list1=["溫度:","濕度:"] while True: try: # Print the values to the serial port temperature_c = dhtDevice.temperature temperature_f = temperature_c * (9 / 5) + 32 humidity = dhtDevice.humidity # print( # "Temp: {:.1f} F / {:.1f} C Humidity: {}% ".format(temperature_f, temperature_c, humidity) # ) localtime=time.ctime() #取得目前系統時間 data={'value1':localtime ,'value2':list1[0]+str(temperature_c) ,'value3':list1[1]+str(humidity)} # for ifttt use(呼叫line notify) requests.post(ifttturl, json=data) # for ifttt use listdata=[localtime,temperature_c,humidity] sheet.append_row(listdata) except RuntimeError as error: # Errors happen fairly often, DHT's are hard to read, just keep going print(error.args[0]) time.sleep(2.0) continue except Exception as error: dhtDevice.exit() raise error time.sleep(1800.0) #每隔30分鐘發送一次line notify ``` * Mifare感應(RC522) ``` #!/usr/bin/env python import signal import time import sys import RPi.GPIO as GPIO #======for ifttt======= import urllib, json import requests, time from urllib import request ifttturl="https://maker.ifttt.com/trigger/*****" #填寫申請的ifttt URL #=================== from pirc522 import RFID run = True rdr = RFID() util = rdr.util() util.debug = True Gled=36 #(Board mode pin) Rled=32 def GBlink(speed): GPIO.setup(Gled,GPIO.OUT) GPIO.output(Gled,True) time.sleep(speed) GPIO.output(Gled,False) time.sleep(speed) def RBlink(speed): GPIO.setup(Rled,GPIO.OUT) GPIO.output(Rled,True) time.sleep(speed) GPIO.output(Rled,False) time.sleep(speed) def end_read(signal,frame): global run print("\nCtrl+C captured, ending read.") run = False rdr.cleanup() sys.exit() signal.signal(signal.SIGINT, end_read) print("Starting") while run: rdr.wait_for_tag() (error, data) = rdr.request() if not error: print("\nDetected: " + format(data, "02x")) (error, uid) = rdr.anticoll() if not error: print("Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])) if (uid[0]==** and uid[1]==**): #uid[0]與uid[1]請依據所使用的mifare card # print("Welcom!") GBlink(2) localtime=time.ctime() #取得目前系統時間 data={'value1':localtime ,'value2':"Welcom! John" } #line notify通知資料 requests.post(ifttturl, json=data) # ifttt : line notify發送進入機房人員與時間通知 else: print("Permission Deny!") RBlink(0.1) RBlink(0.1) RBlink(0.1) localtime=time.ctime() #取得目前系統時間 data={'value1':localtime ,'value2':"Warning! Jane Doe try to open door!!! " } #line notify通知資料 requests.post(ifttturl, json=data) # ifttt : line notify發送異常刷卡時間通知 time.sleep(0.5) ``` ## 113-1 上課資料 ### [上課用程式碼](https://github.com/chiangyih/113-1) ### [mediapipe程式碼](https://github.com/chiangyih/113-1-SoftwarePractice) ### [mediapipe操作](https://hackmd.io/@johnt/Bki9xeRl1x) :::success ### 基本 IO Lab #### 參閱範例01-07 ::: --- :::info ### 使用opencv拍照 1.先建立opencv用虛擬環境 ``` python -m venv py-opencv ``` 2.切換至虛擬環境 ``` source py-opencv/bin/activate ``` 3.進入虛擬環境後,類似下圖 ![image](https://hackmd.io/_uploads/B1bVCvfJ1e.png) 4.安裝opencv套件 ``` pip install opencv-contrib-python ``` ![image](https://hackmd.io/_uploads/SJYORwzykg.png) ![image](https://hackmd.io/_uploads/Bk21J_f1ke.png) 5.程式碼請存放於py-opencv資料夾下 ![image](https://hackmd.io/_uploads/BkONkuGJkg.png) :::