本篇示範如何使用樹莓派自己打造一個自動音樂播放器,長時間自動重複播放音樂。

最近想要一個可以長時間自動重複播放音樂的設備,普通音響功能不錯,但是體積太大,而一些可插 Micro SD 卡的隨身喇叭雖然很不錯,但是幾乎都是以鋰電池供電的,電池需要充電的話就不適合長時間播放,也怕電池過充問題(買過一個沒有過充保護的,不太敢用)。

我在網路上有找到 KINYO MPS-376 這款讀卡喇叭,價格功能都符合預期,但是擔心品質不知道好不好,所以現在先自己用樹莓派自己打造一個來用,未來若確定 KINYO 的喇叭品質好的話,再買來用用看。


樹莓派可以透過安裝 RuneAudio 來建立音樂播放器,不過我用第一代樹莓派測試的結果,發現從耳機孔輸出的音源品質會有很嚴重的雜音,後來改用最新的 Raspbian 配合 OMXPlayer 後,就比較沒有出現音源品質的問題,以下是整個安裝與設定過程。

準備 Raspbian Lite 系統

由於我們要打造的系統是專門用來長時間播放音樂用的,不做其他用途、也不需要使用者操作介面,所以選擇 Raspbian Lite 這種沒有 X Window 的環境會比較合適,可以節省非常多的 Micro SD 卡空間,多出來的空間可以用來放置 mp3 音樂檔。

Raspberry Pi 的官方網站下載 Raspbian Lite 的影像檔,並解壓縮:

# 解壓縮 Raspbian Lite 影像檔
unzip 2018-04-18-raspbian-stretch-lite.zip

解壓縮之後,會得到一個 img 影像檔,參考寫入影像檔的教學,將 Raspbian Lite 的影像檔寫入 Micro SD 卡中:

# 將影像檔寫入 Micro SD 卡
sudo dd bs=1M if=2018-04-18-raspbian-stretch-lite.img of=/dev/sdc

將寫入 Raspbian Lite 影像檔的 Micro SD 卡插入樹莓派,插上螢幕、鍵盤並開機後,以預設帳號 pi 進入系統,預設密碼是 raspberry

設定網路

樹莓派預設會以 DHCP 的方式自動取得 IP 連上網路,如果自己手上沒有可用的 DHCP 伺服器,就必須另外設定,網路的設定有很多種方式,請依據自己的狀況調整,原則上就是讓樹莓派可以正常上網就可以了。

這裡我是範以 Debian 傳統的 interfaces 設定方式,設定樹莓派使用固定 IP 位址,並透過普通 Ubuntu Linux 筆電架設臨時的 NAT 來上網,這樣就只需要一條 RJ45 的網路線即可搞定網路問題,不需要準備網路交換器或是其他設備。

樹莓派設定固定 IP 位址

修改樹莓派的 /etc/network/interfaces 網路介面設定檔,加入以下固定 IP 的設定:

# 設定 /etc/network/interfaces
auto eth0
iface eth0 inet static
  address 192.168.1.2
  netmask 255.255.255.0
  gateway 192.168.1.254

接著停用樹莓派的 dhcpcd 服務,改用傳統的 networking

# 停用 dhcpcd 服務
sudo systemctl disable dhcpcd
sudo systemctl stop dhcpcd

# 啟用 networking 服務
sudo systemctl enable networking
sudo systemctl start networking

設定好之後,看看網路設定是否正確:

ifconfig

測試重新開機:

sudo reboot

重新開機後,若 eth0 的 IP 位址依然正確,這樣固定 IP 位址的設定就完成了。

樹莓派開啟 SSH 服務

為了方便未來可以在筆電端直接操控樹莓派,可以將樹莓派的 SSH 服務開啟:

# 啟用 ssh 服務
sudo systemctl enable ssh
sudo systemctl start ssh

這樣之後就可以在筆電上透過 SSH 連線操控樹莓派,樹莓派上面就只需要接一條電源與網路線即可,鍵盤與螢幕都可以拔掉了。

設定 NAT 網路

拿一條網路線,從樹莓派直接接到 Ubuntu Linux 的筆電上(或是其他不同的 Linux 系統亦可),然後在 shell 底下,使用以下指令設定臨時的 NAT 網路。

這裡我的筆電有一個乙太網路卡(enp2s0),用於連接樹莓派,另一張內建的無線網路卡(wlp3s0),用於對外網路的連線:

# 對外網路卡
EXTIF="enp2s0"

# 對內網路卡
INTIF="wlp3s0"

設定乙太網路卡的 IP 位址(也可以用 Ubuntu 桌面的 GUI 工具來設定):

# 設定網路
sudo ifconfig $INTIF 192.168.1.254 netmask 255.255.255.0

開啟系統的 IP Forward 功能(需用 root 權限):

# 開啟 ip_forward
echo 1 > /proc/sys/net/ipv4/ip_forward

設定 NAT 網路功能(需用 root 權限):

# 設定 NAT
iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

設定好之後,測試一下是否可以連線至樹莓派:

ssh pi@192.168.1.2

正常的話,應該就可以連線進去,而且樹莓派的對外網路應該也是通的。

SSH 登入金鑰

為了工作方便,可以參考 SSH 公開金鑰認證教學,產生好金鑰之後,將金鑰複製到樹莓派上面:

# 複製 SSH 登入用的金鑰
ssh-copy-id pi@192.168.1.2

這樣以後用 SSH 登入樹莓派時,就不需要打密碼了。

OMXPlayer 音樂播放器

OMXPlayer 是一個支援硬體加速的多媒體播放器,功能簡單、實用,效能也很好,支援耳機孔與 HDMI 兩種聲音輸出

首先使用 apt 安裝 OMXPlayer:

# 安裝 omxplayer
sudo apt-get update
sudo apt-get -y install omxplayer

接著使用 scp 等指令,將一些 mp3 音樂檔放進樹莓派的 /home/pi/Music 目錄下。

建立一個自動重複播放 mp3 音樂的指令稿,儲存於 /home/pi/player.sh

#!/bin/sh
# 音樂放置位置
MP3_PATH="/home/pi/Music"

# 重複播放音樂
while true; do
  for entry in $MP3_PATH/*.mp3; do
    omxplayer --vol -602 "$entry" > /dev/null
  done
done

這個指令稿就是用迴圈,不斷重複播放 $MP3_PATH 目錄中的所有 mp3 檔案。

omxplayer--vol 參數可以用來指定音量的大小,不過它的指定方式比較特別,單位是使用 millibels(mB),若要將音量百分比轉換成 millibels,可以使用下公式:

millibels = log(音量比) * 2000

這裡的 log 是以 10 為底數的對數。例如若想要設定音量為 50%,則 millibels = log(0.5) * 2000 = -602.06,其餘以此類推。

開機自動播放音樂

修改 /etc/rc.local 設定檔,在最後一行 exit 0 之前,加入自動播放 mp3 音樂的指令(也就是執行上面建立好的指令稿):

# 開機自動播放音樂
sudo -u pi sh /home/pi/player.sh &

這樣就大公告成了,重新開機之後,樹莓派應該就會自動不停的播放音樂,未來我們只要將樹莓派插上電源、接上喇叭,就可以聽音樂了,不需要任何操作。

OMXPlayer 在執行時,比較沒會耗費太多的 CPU 資源,以下我自己實際測試的結果:

top 指令輸出

若是以 VLC 來播放 mp3 音樂的話,大概都要吃掉 30% 左右的 CPU,而用 OMXPlayer 的話大致上都在 10% 以下,差異很大。

省電與節能

由於這個音樂播放器是長時間運轉的,所以要盡可能關閉沒用的功能,讓電力的耗損降到最低,同時避免過熱問題。

停用 IPv6 模組

我們的樹莓派只會用來播放音樂,不會做其他的用途,需求非常單純,所以可以將一些沒用到的 Linux 核心模組停用,讓系統更輕巧。

首先查看一下目前所有被載入的核心模組:

lsmod
Module                  Size  Used by
snd_bcm2835            22991  0
snd_pcm                89590  1 snd_bcm2835
snd_timer              22396  1 snd_pcm
snd                    60154  3 snd_timer,snd_bcm2835,snd_pcm
uio_pdrv_genirq         3718  0
uio                     9901  1 uio_pdrv_genirq
fixed                   3033  0
ip_tables              12427  0
x_tables               22098  1 ip_tables
ipv6                  401778  16

其中 ipv6 應該是大小最大,又最沒用處的模組了,若要把它停用,可以編輯 /etc/modprobe.d/ipv6.conf 設定檔,加入一行設定:

blacklist ipv6

這樣即可停用 ipv6 模組,其餘模組的停用方式也是類似。

停用 HDMI 顯示

在所有的設定都完成之後,可以將 HDMI 的輸出關閉,讓它更省電。

編輯 /etc/rc.local 設定檔,加入以下指令:

# 關閉 HDMI
/usr/bin/tvservice -o

動態時脈

參考樹莓派的超頻文件,編輯 /boot/config.txt,加入以下設定,啟用動態時脈(dynamic clocking),讓系統負載較輕的時候,自動降低 CPU 與相關硬體的運作頻率(較省電):

# For Power Saving
arm_freq_min=250
core_freq_min=100
sdram_freq_min=150
over_voltage_min=0

設定完後,要重新開機才生效。

sudo reboot

若要查看 CPU 的時脈,可以執行:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

另外亦可使用 vcgencmd 指令,查看其他的硬體資訊,例如 CPU 溫度:

vcgencmd measure_temp

停用 USB Hub

若沒有用到任何 USB 設備以及乙太網路的話,可將 USB Hub 的電源關閉,這樣可以節省非常多的能源消耗。

以下是關閉 USB Hub 電源的指令稿:

#!/bin/bash
# 停用 USB Hub
systemctl stop ssh
systemctl stop networking
echo 0x0 > /sys/devices/platform/soc/20980000.usb/buspower

這是開啟 USB Hub 電源的指令稿:

#!/bin/bash
# 啟用 USB Hub
echo 0x1 > /sys/devices/platform/soc/20980000.usb/buspower
sleep 2
systemctl start networking
systemctl start ssh

不同 Raspberry Pi 版本的 buspower 設定檔位置會不同,可以使用以下指令尋找:

#  尋找 buspower 位置
find /sys/devices/ -name `dmesg -t | grep dwc_otg | grep "DWC OTG Controller" | awk '{print $2}' | cut -d":" -f1`
/sys/devices/platform/soc/20980000.usb

關閉 USB Hub 的電源之後,所有的 USB 連接埠與乙太網路都會無法使用,只能從序列埠登入,所以請確定所有的東西都設定完成後,再考慮這個措施。

我的作法是在 /etc/rc.local 中加入以下指令,於開機之後等待 5 分鐘,然後再關閉 USB Hub 的電源,這樣如果需要修改東西的話,可以在這 5 分鐘內透過網路連線進去處理:

# 等待 5 分鐘後,關閉 USB Hub 電源
(sleep 300; systemctl stop ssh; systemctl stop networking; echo 0x0 > /sys/devices/platform/soc/20980000.usb/buspower) &

如果 5 分鐘不夠處理的話,就在登入之後,先用 pstree 指令找出 rc.local 的行程,用 kill 指令砍掉這個行程,再進行其他的工作即可。

停用 LED 燈號

/boot/config.txt 加入以下設定,即可停用板子上的 LED 燈:

# Disable the ACT LED.
dtparam=act_led_trigger=none
dtparam=act_led_activelow=off

# Disable the PWR LED.
dtparam=pwr_led_trigger=none
dtparam=pwr_led_activelow=off

參考資料:StackOverflowStackExchangeStackExchangescriblesBaba AweSam