###### tags: `自駕車`
# 自駕車 Orange Pi 建置工作
以下都請先登入成 root 再執行, OrangePi 若登入成一般使用者再使用 sudo 就是有些地方怪怪的, 執行登入成 root 比較簡單。
:::info
預設密碼都是 orangepi。
:::
## 建置 OpenCV 環境
1. 將檔案系統延伸, 擴大可用空間:
:::info
本步驟主要參考 [OrangePi 論壇討論](http://www.orangepi.org/orangepibbsen/forum.php?mod=viewthread&tid=844)。
:::
首先調整分割區:
```
# fdisk /dev/mmcblk0
Command (m for help): p
Disk /dev/mmcblk0: 15.8 GB, 15804137472 bytes
4 heads, 16 sectors/track, 482304 cylinders, total 30867456 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x34605ba5
Device Boot Start End Blocks Id System
/dev/mmcblk0p1 40960 124927 41984 83 Linux
/dev/mmcblk0p2 124928 7170047 3522560 83 Linux
Command (m for help): d
Partition number (1-4): 2
Command (m for help): n
Partition type:
p primary (1 primary, 0 extended, 3 free)
e extended
Select (default p): p
Partition number (1-4, default 2): 2
First sector (2048-30867455, default 2048): 124928
Last sector, +sectors or +size{K,M,G} (124928-30867455, default 30867455):
Using default value 30867455
Command (m for help): w
```
要注意重建分割區時起始磁區要跟原本一樣。完成後重新開機:
```
# reboot
```
開機後重新登入, 延伸調整後的分割區:
```
# resize2fs /dev/mmcblk0p2
```
:::info
如果要更極致的節省空間, 也可以將不需要的程式刪除, 例如根本跑不起來的 Firefox、還有幾乎用不到的 LibreOffice:
```
# apt remove firefox thunderbird
# apt remove "libreoffice*"
# apt autoremove
```
:::
2. 設置並啟用置換檔, 避免記憶體空間不足:
```
# touch /swapfile
# dd if=/dev/zero of=/swapfile bs=1M count=1024
# mkswap /swapfile
# swapon /swapfile
```
這個步驟非常重要, 沒有置換檔, 系統會卡到不行, 很容易在建置過程中死當, 瀏覽器也幾乎處於無法使用的超頓狀態。也請將 `swapon /swapfile` 這一行放入 /etc/local.rc 檔中, 讓系統開機時自動啟用置換檔。
4. 安裝必要的套件:
```
# apt-get update
# apt-get upgrade
```
:::info
使用 Orangepilite2_2.1.0_ubuntu_focal_desktop_linux5.4.65.7z 這個映像檔會在 `apt update` 時發生以下錯誤:
```
Traceback (most recent call last):
File "/usr/lib/cnf-update-db", line 26, in <module>
col.create(db)
File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 94, in create
self._fill_commands(con)
File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 138, in _fill_commands
self._parse_single_commands_file(con, fp)
File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 176, in _parse_single_commands_file
suite=tagf.section["suite"]
KeyError: 'suite'
Error in sys.excepthook:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 153, in apport_excepthook
with os.fdopen(os.open(pr_filename,
FileNotFoundError: [Errno 2] No such file or directory: '/var/crash/_usr_lib_cnf-update-db.0.crash
```
根據[這篇文章](https://bugs.launchpad.net/ubuntu/+source/command-not-found/+bug/1876034/comments/2)的說法, 可如下繞過問題暫時解決:
1. 在 /etc/apt/ 下建立 apt 的設定檔 apt.conf, 並在其中加入這行取消 gzip 格式索引的設定:
```
Acquire::GzipIndexes "false";
```
3. 確認沒有 gzip 格式的索引檔:
```
grep -r GzipIndexes /etc/apt
```
1. 刪除清單快取檔:
```
rm -rf /var/lib/apt/lists
```
1. 重新執行 update 指令:
```
apr update
```
:::
```
# apt-get install unzip build-essential cmake libgtk2.0-dev libgtk-3-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libjpeg8-dev libtiff5-dev libjasper-dev libpng12-dev libv4l-dev libxvidcore-dev libx264-dev python3-numpy
# apt-get install python3-pip
# python3 -m pip install --upgrade pip
# apt-get install python3.5-dev
```
:::info
使用 Orangepilite2_2.1.0_ubuntu_focal_desktop_linux5.4.65.7z 這個映像檔會找不到 libjasper-dev 與 libpng12-dev, 不過系統已經有 libpng-dev, 而 libjasper-dev 可以自行到[這裡](https://ubuntu.pkgs.org/16.04/ubuntu-main-arm64/libjasper-dev_1.900.1-debian1-2.4ubuntu1_arm64.deb.html)下載 \.deb 檔案裝, 它需要先安裝 [libjasper1](https://ubuntu.pkgs.org/16.04/ubuntu-main-arm64/libjasper1_1.900.1-debian1-2.4ubuntu1_arm64.deb.html)。
:::
3. 檢查 Python 開發工具的嵌入檔路徑:
```
# python3.5-config --includes #列出 .h 檔所在的路徑
```
4. 複製 OpenCV 遠端倉庫:
```
# mkdir OpenCV-tmp
# cd OpenCV-tmp
# wget https://github.com/opencv/opencv/archive/3.4.5.zip
# unzip 3.4.5.zip
```
5. 建置 OpenCV 所需的前置作業:
```
# cd opencv-3.4.5/
# mkdir build
# cd build
# cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local PYTHON3_EXECUTABLE=/usr/bin/python3 PYTHON_INCLUDE_DIR=/usr/include/python3.5m PYTHON_LIBRARY=/usr/lib/aarch64-linux-gnu/libpython3.5m.so PYTHON3_NUMPY_INCLUDE_DIRS=/usr/local/lib/python3.5/dist-packaes/numpy/core/include/ ..
```
:::info
請仔細觀察輸出結果, 如果你看到的 Python 開發工具嵌入檔路徑和輸出結果不同, 就需要自行在指令中指定路徑:
```
# cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local PYTHON3_EXECUTABLE=/usr/bin/python3 PYTHON_INCLUDE_DIR=/usr/include/python3.5m PYTHON_LIBRARY=/usr/lib/aarch64-linux-gnu/libpython3.5m.so PYTHON3_NUMPY_INCLUDE_DIRS=/usr/local/lib/python3.5/dist-packaes/numpy/core/include/ ..
```
:::
1. 使用 j4 選項以多核心平行編譯:
```
# make -j4
```
6. 編譯完成後將 OpenCV 安裝至系統:
```
# make install
```
## 安裝 TightVNCServer
:::info
本節內容參考 [OrangePi 官網](http://www.orangepi.org/Docs/LogintotheOrangePi.html#Using_VNC)。
:::
OrangePi 的作業系統預設會安裝並啟用 ssh server, 但是並不會安裝 VNC server, 請依照以下程序安裝:
1. 安裝 TightVNCServer 套件:
```
$ apt-get install tightvncserver
```
2. 初次執行設定登入密碼:
```
# vncserver
You will require a password to access your desktops.
Password:
Verify:
Would you like to enter a view-only password (y/n)? n
New 'X' desktop is orangepilite2:1
Creating default startup script /root/.vnc/xstartup
Starting applications specified in /root/.vnc/xstartup
Log file is /root/.vnc/orangepilite2:1.log
```
3. 修改 VNC 啟動檔, 設定登入後要執行的桌面環境:
```bash
vim /root/.vnc/xstartup
```
由於預設的桌面環境是 xfce, 所以我們設定遠端登入時也使用相同的桌面環境, 這樣就不需要再安裝額外的套件了:
```bash
#!/bin/sh
xrdb $HOME/.Xresources
xsetroot -solid grey
x-terminal-emulator -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
xfce4-session &
#x-window-manager &
# Fix to make GNOME work
export XKL_XMODMAP_DISABLE=1
/etc/X11/Xsession
```
修改完後請記得存檔。
4. 重新啟動 VNC server:
先把目前執行的 VNC server 停掉:
```bash
vncserver -kill :1
```
再重新執行 VNC server:
```bash
vncserver :1
```
5. 遠端即可連上 5901 埠號啟用遠端桌面了。
:::info
在 Ubuntu 20.04 下的 tightvncserver 有 bug, 會讓遠端登入時視窗都沒有標題列, 也就無法用滑鼠直接移動視窗、關閉視窗等, 這是因為系統上 xfwm 4.14.1 的 bug, 這個問題已經在 4.14.2 修正, 不過系統的軟體倉庫內並沒有更新, 必須自行下載新版的[套件檔案](https://launchpad.net/ubuntu/groovy/arm64/xfwm4/4.14.2-1), 然後手動更新:
```
dpkg -i xfwm4_4.14.2-1_arm64.deb
```
重新開機後, 再從 VNC 登入就正常了。
:::
## 開機時自動執行 tightvncserver
:::info
本節內容參考[這篇文章](https://leesiropi.blogspot.com/2019/12/installsetup-xfce-and-tightvnc-to.html)。
:::
使用 systemctl 方式讓 tightvncserver 可以再開機時自動執行。
1. 編輯 /usr/local/bin/tightvncserver 檔案為以下內容:
```bash
#!/bin/bash
PATH="$PATH:/usr/bin/"
DISPLAY="1"
DEPTH="16"
GEOMETRY="1024x768"
OPTIONS="-depth ${DEPTH} -geometry ${GEOMETRY} :${DISPLAY}"
case "$1" in
start)
/usr/bin/vncserver ${OPTIONS}
;;
stop)
/usr/bin/vncserver -kill :${DISPLAY}
;;
restart)
$0 stop
$0 start
;;
esac
exit 0
```
1. 將剛剛建立的檔案設定為可執行:
```bash
sudo chmod +x /usr/local/bin/tightvncserver
```
1. 建立 systemctl 腳本檔案 /lib/systemd/system/tightvncserver.service 如下:
```ini
[Unit]
Description=Manage tightVNC Server
[Service]
Type=forking
ExecStart=/usr/local/bin/tightvncserver start
ExecStop=/usr/local/bin/tightvncserver stop
ExecReload=/usr/local/bin/tightvncserver restart
User=root
[Install]
WantedBy=multi-user.target
```
1. 重新載入 systemd 服務並啟用 tightvncserver 服務:
```bash
sudo systemctl daemon-reload
sudo systemctl enable tightvncserver.service
```
如此一來, 就可以使用以下幾種指令控制 tightvncserver 了:
```bash
sudo systemctl start tightvncserver.service
sudo systemctl stop tightvncserver.service
sudo systemctl restart tightvncserver.service
sudo systemctl status tightvncserver.service
```
1. 重新啟動 Orange Pi, 開機後就會自動執行 tightvncserver 了。
1. 由於上述自動執行時會以 cron 的身份採用預設的 sh 當成 shell, 如果要改用不同的 shell, 請在 ~/.vnc/xstartup 中加入以下這行:
```bash
export SHELL=/bin/bash
```
## 開機自動登入帳號
OrangePi 使用 lightdm 管理登入事宜, 請依照以下步驟設定要自動登入的帳號, 請編輯 /etc/lightdm/lightdm.conf 檔案如下:
```ini
[SeatDefaults]
autologin-user=root
autologin-user-timeout=0
```
重新開機後就會自動以 root 帳號登入, 不會顯示 (其實是顯示 0 秒) 登入畫面。
## 建立 Wi-Fi AP
```bash
iw dev wlan0 interface add uap0 type __ap
nmcli con add type wifi ifname uap0 con-name Hotspot autoconnect yes ssid "FlagCar"
nmcli con modify Hotspot 802-11-wireless.mode ap 802-11-wireless.band bg ipv4.method shared
nmcli con modify Hotspot wifi-sec.key-mgmt wpa-psk
nmcli con modify Hotspot wifi-sec.psk "12345678"
nmcli con modify Hotspot connection.autoconnect yes
nmcli con up Hotspot
```
之後在 /etc/rc.local 中加入以下指令讓開機後自動啟用 AP:
```
iw dev wlan0 interface add uap0 type __ap
```
## 設定 ttyS3
Orangepilite2_2.1.0_ubuntu_focal_desktop_linux5.4.65.7z 這個映像檔不知道為什麼預設 uart3 是停用的, 用 `dmesg | grep tty` 查詢就會發現 ttyS3 沒有作用。請修改設定檔 /boot/orangepiEnv.txt 檔, 加入以下這行:
```
overlays=uart3
```
存檔後重新開機即可啟用 uart3, 也就是 ttyS3。
## 製作 img 檔
### 利用圖形化工具
最簡單的方法可用 Mac 上的 [Apple Pi Baker](https://www.tweaking4all.com/software/macosx-software/applepi-baker-v2/), 它有自動縮放的選項, 可以在製作 img 檔時有自動根據使用空間縮小 img 檔的功能, 或是從 img 檔寫回 SD 卡時根據 SD 卡大小自動調整分割區空間。唯一的缺點是好像不大穩定。
### 使用命令列工具
如果不使用上述工具, 可以根據[這一篇的說明](https://www.instructables.com/How-to-BackUp-and-Shrink-Your-Raspberry-Pi-Image/)製作並調整 img 檔的大小。
#### 製作與 SD 卡一樣大小的映像檔
1. 先使用讀卡機將 RPi 的 SD 卡插入。
2. 確認 SD 卡的裝置名稱:
```
# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mmcblk0p2 57G 3.7G 51G 7% /
devtmpfs 478M 0 478M 0% /dev
tmpfs 487M 24K 487M 1% /dev/shm
tmpfs 487M 7.4M 480M 2% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 487M 0 487M 0% /sys/fs/cgroup
/dev/mmcblk0p1 50M 19M 32M 38% /boot
/dev/sda1 50M 19M 32M 38% /media/usb0
/dev/sda2 29G 3.7G 24G 14% /media/usb1
tmpfs 98M 36K 98M 1% /run/user/0
```
上例中可以看到 USB 對應的裝置名稱是 /dev/sda1 和 /dev/sda2。
1. 先將剛剛看到的 SD 卡從檔案系統上卸載:
```
# umount /dev/sda1 /dev/sda2
```
1. 安裝 dcfldd 工具:
```
# apt install dcfldd
```
1. 製作目前 SD 卡的映像檔:
```
# dcfldd if=/dev/sda of=orangepi.img
955392 blocks (29856Mb) written.
955584+0 records in
955584+0 records out
```
1. 原本是使用 32G 的 SD 卡, 所以製作出的映像檔是 32G 大小:
```
# ls -l
-rw-r--r-- 1 root root 31312576512 Jan 26 17:41 orangepi.img
```
#### 使用 PiShrink 工具縮減映像檔大小
1. 安裝 [PiShrink](https://github.com/Drewsif/PiShrink) 工具:
```
# wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
--2021-01-26 17:42:49-- https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
Resolving raw.githubusercontent.com (raw.githubusercontent.com)...
151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10729 (10K) [text/plain]
Saving to: ‘pishrink.sh’
pishrink.sh 100%[========>] 10.48K --.-KB/s in 0.003s
2021-01-26 17:42:50 (3.94 MB/s) - ‘pishrink.sh’ saved [10729/10729]
# chmod +x pishrink.sh
# sudo mv pishrink.sh /usr/local/bin/
```
1. 使用 PiShrink 工具縮減映像檔大小:
```
# pishrink.sh orangepi.img
pishrink.sh v0.1.2
pishrink.sh: Gathering data ...
Kernel not configured for semaphores (System V IPC). Not using udev synchronisation code.
Kernel not configured for semaphores (System V IPC). Not using udev synchronisation code.
Kernel not configured for semaphores (System V IPC). Not using udev synchronisation code.
Creating new /etc/rc.local
pishrink.sh: Checking filesystem ...
rootfs: 151026/1856544 files (0.1% non-contiguous), 1095340/7626752 blocks
resize2fs 1.42.13 (17-May-2015)
pishrink.sh: Shrinking filesystem ...
resize2fs 1.42.13 (17-May-2015)
Resizing the filesystem on /dev/loop0 to 1365241 (4k) blocks.
Begin pass 2 (max = 105962)
Relocating blocks ------------------------------------XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 3 (max = 233)
Scanning inode table ------------------------------------XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 4 (max = 9759)
Updating inode references ------------------------------------XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The filesystem on /dev/loop0 is now 1365241 (4k) blocks long.
Kernel not configured for semaphores (System V IPC). Not using udev synchronisation code.
Kernel not configured for semaphores (System V IPC). Not using udev synchronisation code.
pishrink.sh: Shrinking image ...
Kernel not configured for semaphores (System V IPC). Not using udev synchronisation code.
pishrink.sh: Shrunk orangepi.img from 30G to 5.3G ...
```
1. 調整後的映像檔縮小到 5.3G 了:
```
# ls -l orangepi.img
-rw-r--r-- 1 root root 5665427968 Jan 26 18:00 orangepi.img
```
#### 將新的映像檔寫到空白的 SD 卡上
1. 接著請插上有空白 SD 卡片的讀卡機, 一樣先卸載 SD 卡:
```
# umount /dev/sda1 /dev/sda2
```
1. 將剛剛縮減大小的映像檔寫到 SD 卡上:
```
# dcfldd of=/dev/sda if=orangepi.img
172800 blocks (5400Mb) written.
172895+1 records in
172895+1 records out
```
1. PiShrink 有個貼心的功能, 預設縮減過的映像檔寫入 SD 卡後, 會在 SD 卡第一次啟動 OrangePi 時自動擴展檔案系統到 SD 卡的大小, 例如若將映像檔寫到 8G 的卡上, 啟動後看到的檔案系統就是這樣:
```
# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mmcblk0p2 7.0G 3.7G 3.0G 56% /
devtmpfs 478M 0 478M 0% /dev
tmpfs 487M 24K 487M 1% /dev/shm
tmpfs 487M 14M 474M 3% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 487M 0 487M 0% /sys/fs/cgroup
/dev/mmcblk0p1 50M 19M 32M 38% /boot
tmpfs 98M 36K 98M 1% /run/user/0
```