---
tags: setup, PYNQ, 創創
---
# 創創PYNQ Setup
## Hardware
使用12V變壓器以及wifi網卡,IO:
> PYNQ Z2: AR0 <----> TRIG of HC-SR04
> PYNQ Z2: AR1 <----> ECHO of HC-SR04
> PYNQ Z2: GND <----> GND of HC-SR04
> PYNQ Z2: 5V <----> VCC of HC-SR04
> Connect HDMI out to an Monitor
>
如果無誤,開機完成後會閃爍綠燈數次。
## Connectivity
參考[我寫的](https://hackmd.io/u9v46niKQLq7E50d7Z_zdg)與[官方](https://pynq.readthedocs.io/en/latest/getting_started/pynq_z2_setup.html)的教學資料。
目前插上[usb wifi](https://www.ruten.com.tw/item/show?21822097904925)網卡,重開機(軟體重開機,參考前面兩個連結進到板子的terminal)後會自動連上`SSID=4a0c` `password=10000111`的wifi AP,跑圖片的PC/laptop要連到同一個wifi AP。如果懶得去改pynq的wifi設定,可以直接把手機熱點的SSID跟密碼改成跟上述一樣就好,記得手機熱點設定藥可供搜尋,若連上了,手機熱點*已連線的裝置* 中會有pynq。如果斷線了板子連不上,那就重開機。
## Python runtime and the script
主要功能的程式已經config成服務,開機後就會自動執行,相關指令:
```bash
systemctl status hdmi-hcsr04.service # 查看狀態
systemctl restart hdmi-hcsr04.service
systemctl start hdmi-hcsr04.service
systemctl stop hdmi-hcsr04.service
systemctl enable hdmi-hcsr04.service # 開機自動啟動
systemctl disable hdmi-hcsr04.service # 取消開機自動啟動
systemctl show hdmi-hcsr04.service # 顯示service設定
journalctl -xeu hdmi-hcsr04.service # 查log
```
服務設定檔路徑:
> `/etc/systemd/system/hdmi-hcsr04.service`
修改服務設定檔,要立即生效的話要重新載入系統服務:
`systemctl daemon-reload`
py檔路徑:
> `/home/xilinx/jupyter_notebooks/StupidMirror/Distance_Detection_http_get_3_picture/hdmi_hcsr04_service.py`
修改py檔,需要重啟服務:
`systemctl restart hdmi-hcsr04.service`
## Code Setup
在`/home/xilinx/jupyter_notebooks/StupidMirror/Distance_Detection_http_get_3_picture/hdmi_hcsr04_service.py`中,修改以下幾個變數以符合要求
```python=1
DISTANCE_THRES = 50 # if the distance if under this, LED_NEXT_PAGE toggles. unit: cm
DISTANCE_READ_WINDOW = 0.2 # sleep for how long after DISTANCE_THRES detected
IMAGE_UPDATE = 15 # seconds to GET images from url
IMAGE_TIMEOUT = 0.7 # seconds timeout for one requests
urls=['http://192.168.43.209:8000/mainpage/mainpage.jpg',
'http://192.168.43.209:8000/history/history.jpg',
'http://192.168.43.209:8000/detect/detect.jpg']
```
看到綠燈閃爍數次代表程式已經開始運行,如果第一次下載圖片失敗,程式將自動重啟,綠燈會再次閃爍。
如果要手動重啟程式,撥動SW0程式就會停止運作,systemctl會自動把他重啟。
如果發現HDMI out輸出畫面有偏移或是色偏,代表該程式被強制停止或是有exception沒處理到,需要重開機。
```shell
sudo shutdown
```
## Indicator Lights
1. 程式重啟初始化完成會閃爍綠燈數次,若此時http server未開啟,程式將重啟,綠燈再次閃爍。
2. 下載(抓取)圖片時,`LD0`會亮(或暗)(狀態反向啦乾)
3. 抓取圖片時`LD1`會閃爍黃燈
## Code backup
- /home/xilinx/jupyter_notebooks/StupidMirror/Distance_Detection_http_get_3_picture/hdmi_hcsr04_service.py
```python=
# Using Arduino IO pins on PYNQ Z2 to interact with HC-SR04
# PYNQ Z2: AR0 <----> TRIG of HC-SR04
# PYNQ Z2: AR1 <----> ECHO of HC-SR04
# Connect HDMI out to an Monitor
SW_OFF_DETECT = 0 # which switch(SW0 or SW1) to toggle to exit this program
LED_NEXT_PAGE = 0 # toggle which led(LD0~3) when gesture detected.
LED_DOWNLOAD = 1 # turn on which led(LD0~3) to indicating if downloading
DISTANCE_THRES = 50 # if the distance if under this, LED_NEXT_PAGE toggles. unit: cmd
DISTANCE_READ_WINDOW = 0.2 # sleep for how long after
IMAGE_UPDATE = 15 # seconds to GET images from url
IMAGE_TIMEOUT = 0.7 # seconds timeout for one requests
urls=['http://192.168.43.238:8000/mainpage/mainpage.jpg',
'http://192.168.43.238:8000/history/history.jpg',
'http://192.168.43.238:8000/detect/detect.jpg']
#'http://192.168.137.1:8000/RGB_test.png']
"""urls=['http://192.168.43.209:8000/IMG_2900.JPG',
'http://192.168.43.209:8000/IMG_3043.JPG',
'http://192.168.43.209:8000/IMG_4127.JPG',
'http://192.168.43.209:8000/BGR_test.jpg']
#'http://192.168.137.1:8000/RGB_test.png']"""
print("[INFO]Importing libraries...", end='\r')
from pynq.overlays.base import BaseOverlay
from pynq.lib.video import *
from pynq.lib.arduino import Arduino_DevMode
from pynq.lib.arduino import ARDUINO_SWCFG_DIOALL
from pynq.lib.arduino import ARDUINO_DIO_BASEADDR
from pynq.lib.arduino import ARDUINO_DIO_TRI_OFFSET
from pynq.lib.arduino import ARDUINO_DIO_DATA_OFFSET
from pynq.lib.arduino import ARDUINO_CFG_DIO_ALLINPUT
from pynq.lib.arduino import ARDUINO_CFG_DIO_ALLOUTPUT
from pynq.lib.arduino import ARDUINO_NUM_ANALOG_PINS
from pynq.lib.arduino import ARDUINO_NUM_DIGITAL_PINS
from pynq.overlays.base import BaseOverlay
from pynq.lib.arduino.arduino_io import Arduino_IO
from pynq.lib.arduino.arduino_analog import Arduino_Analog
from urllib.request import urlopen
import time, sys, cv2
import numpy as np
print("[INFO]Libraries imported.", end='\n')
print("[INFO]Initializing HDMI Out...", end='\r')
from pynq.overlays.base import BaseOverlay
from pynq.lib.video import *
base = BaseOverlay("base.bit")
# monitor configuration: 1920*1080 @ (8 bits)*(BGR)=24, 60Hz
Mode = VideoMode(width=1920,height=1080,bits_per_pixel=24,fps=60)
hdmi_out = base.video.hdmi_out
hdmi_out.stop()
hdmi_out.close()
hdmi_out.configure(Mode,PIXEL_BGR) # OpenCV default color space is BGR
try:
hdmi_out.start()
except:
print("[Error]HDMI Out failed to initialize. ")
hdmi_out.close()
else:
print("[INFO]HDMI out initialized. ")
def hdmi_show(hdmi_stream, img):
outframe = hdmi_stream.newframe()
outframe[:] = img
hdmi_stream.writeframe(outframe)
def url_to_image(url,timeout):
# download the image, convert it to a NumPy array, and then read
# it into OpenCV format
resp = urlopen(url=url,timeout=timeout)
image = np.asarray(bytearray(resp.read()), dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
# return the image
return image
def get_imgs(urls,timeout):
global base
base.leds[LED_DOWNLOAD].on()
imgs=[]
for url in urls:
try:
img = url_to_image(url=url, timeout=timeout)
if img is None:
print("[ERROR]Failed to download image from %s" % url)
imgs.append(img) #(cv2.cvtColor(img,4))
except:
print("[ERROR]Failed to download images with error message:%s" % sys.exc_info()[0])
print("[ERROR]Failed to download image from %s" % url)
if imgs is not None and len(imgs) == len(urls):
print("[INFO]All images downloaded. ")
base.leds[LED_DOWNLOAD].off()
return imgs
else:
print("[ERROR]Given %d urls of images but only %d images accquired." % (len(urls), len(imgs)))
base.leds[LED_DOWNLOAD].off()
print("[INFO]Initializing HC-SR04 distance reader...", end='\r')
PT=Arduino_IO(base.ARDUINO,0,'in')
# being careful, set all digital IO as input
Arduino_IO.write_cmd(PT,ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET, ARDUINO_CFG_DIO_ALLINPUT)
"""
parameters:
pin: int, 0~13 corresponding pin AR0~AR13 on the board
value: int/boolean, the output state
return:
None
"""
def io_write(pin, value):
if pin in range(ARDUINO_NUM_ANALOG_PINS + ARDUINO_NUM_DIGITAL_PINS):
if value:
cur_val = Arduino_IO.read_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET)
new_val = cur_val | (0x1 << pin)
Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, new_val)
else:
cur_val = Arduino_IO.read_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET)
new_val = cur_val & (0xffffffff ^ (0x1 << pin))
Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, new_val)
"""
parameters:
pin: int, 0~13 corresponding pin AR0~AR13 on the board
return:
int/boolean, the state read from the pin
"""
def io_read(pin):
if pin in range(ARDUINO_NUM_ANALOG_PINS + ARDUINO_NUM_DIGITAL_PINS):
raw_value = Arduino_IO.read_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET)
return (raw_value >> pin) & 0x1
"""
return:
floaot, distance read from HC-SR04
"""
def read_distance():
Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, 0b0000) # io_write(PIN_TRIG,0)
time.sleep(0.05) # send trigger signal
Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, 0b0001) # io_write(PIN_TRIG,1)
Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, 0b0000) # io_write(PIN_TRIG,0)
while io_read(PIN_ECHO) == 0: pass
start_time = time.time()
while io_read(PIN_ECHO) == 1: pass
end_time = time.time()
return 17150 * (end_time - start_time)
# these just tell you where the pins located, changing value of these two var may not change anything
PIN_TRIG = 0 # AR0, output
PIN_ECHO = 1 # AR1, input
# set pin0(labeled AR0 on the board) as output and the rest as input
Arduino_IO.write_cmd(PT,ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET,
0b1111_1111_1111_1111_1111_1111_1111_1110)
rgbleds = [base.rgbleds[i] for i in range(4, 6)]
# Toggle board LEDs leaving small LEDs lit
for i in range(8):
[rgbled.off() for rgbled in rgbleds]
time.sleep(.2)
[rgbled.on(2) for rgbled in rgbleds]
time.sleep(.2)
[rgbled.off() for rgbled in rgbleds]
print("[INFO]HC-SR04 distance reader initialized. ", end='\n')
print("[INFO]Downloading images from urls...")
imgs = get_imgs(urls, timeout=IMAGE_TIMEOUT)
t_flag = 0
sw_state = base.switches[SW_OFF_DETECT].read()
img_index = 0
if imgs is not None:
print("[INFO]All images downloaded.")
hdmi_show(hdmi_out, imgs[img_index])
else:
print("[ERROR]Not even a image accquired. Go check the url, stupid user.")
sw_state = not sw_state # this will skip the while block
print("[INFO]Toggle SW%d on the board to stop reading." % SW_OFF_DETECT)
while base.switches[SW_OFF_DETECT].read() == sw_state:
if time.time()-t_flag >= IMAGE_UPDATE:
t_flag = time.time()
imgs_new = get_imgs(urls=urls,timeout=IMAGE_TIMEOUT)
if imgs_new is not None:
for i in range(len(imgs_new)):
imgs[i] = imgs_new[i] if imgs_new[i] is not None else imgs[i]
del imgs_new
hdmi_show(hdmi_out, imgs[img_index])
distance = read_distance()
print('[INFO]distance: {:.1f}cm '.format(distance), end='\r')
if distance<DISTANCE_THRES and distance>0:
print('[INFO]Triggered at distance: {:.1f}cm '.format(distance), end='\r')
base.leds[LED_NEXT_PAGE].toggle()
if img_index == len(imgs)-1:
img_index = 0
else:
img_index = img_index + 1
if imgs[img_index] is not None:
hdmi_show(hdmi_out, imgs[img_index])
else:
print('[ERROR]Image No.%d is not available.')
time.sleep(DISTANCE_READ_WINDOW)
print("[INFO]SW%d toggled, distance measuring stopped." % SW_OFF_DETECT)
hdmi_out.stop()
hdmi_out.close()
del hdmi_out
```
- /etc/systemd/system/hdmi-hcsr04.service
```service=
[Unit]
Description=HDMI out + HCSR04 distance reader
After=boot_leds.service
Conflicts=boot_leds.service
[Service]
Type=simple
ExecStart=/usr/bin/python3 /home//xilinx/jupyter_notebooks/StupidMirror/Distance_Detection_http_get_3_picture/hdmi_hcsr04_service.py
Restart=always
[Install]
WantedBy=multi-user.target
```