工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Raspberry PiとArduinoで作るWi-Fiインターネットラジオ:世界中の局をストリーミング

必要な部品と材料

部品数量備考
Arduino UNO1
Raspberry Pi 3 Model B1内蔵Wi-Fi搭載、アンテナ不要
SainSmart LCDキーパッドシールド (Arduino用)1プッシュボタン付きLCD
5V電源1

使用するアプリとオンラインサービス

プロジェクト概要

概要

工作や料理中にラジオを聴くのが好きですが、私の住んでいる場所ではFM受信状態が悪く、インターネット経由で世界中の局を聴きたいと考えていました。スマホで聴くのは避けたいため、ネットで調べたいくつかの解決策を組み合わせてこのプロジェクトを作りました。

ベースにしたのは akellyirl氏の「Arduino / Raspberry Pi Internet Radio」 というチュートリアルです。Raspberry Pi上でPythonコードが動作し、Linuxの音楽プレイヤーデーモン mpd とクライアント mpc を使用します。nanpy というライブラリでPythonからArduinoを操作し、ボタン入力とLCD表示を制御しています。

Arduino用のLCD/キーパッドシールド(SainSmart製)を使用し、後から壊れた目覚まし時計から取り出した4ボタンストリップを追加しました。当初はRaspberry Pi 2とUSB Wi-Fiアダプタを使っていましたが、現在は内蔵Wi-Fiを持つRP3に移行しています。

一番の難関は、聴きたい局の正しいストリーミングURLを見つけることでした。最終的に URL HELPER という、再生中のメディアURLをスニッフィングするツールを見つけて解決しました。音声出力は、ジャンクから回収したアクティブスピーカーを使用しています。

Raspberry PiとArduinoで作るWi-Fiインターネットラジオ:世界中の局をストリーミング
Raspberry PiとArduinoで作るWi-Fiインターネットラジオ:世界中の局をストリーミング

インストール手順 (RP3用)

元チュートリアル (akellyirl氏、Arduino掲載) に基づく手順です。

  1. Raspbianを最新パッケージに更新:
    $ sudo apt-get update
  2. mpd/mpc パッケージをインストール:
    $ sudo apt-get install mpc mpd

PythonからArduinoと通信するため、nanpy ライブラリ(Python側)とファームウェア(Arduino側)を導入します。

  1. Arduinoパッケージをインストール(nanpyファームウェアビルド用):
    $ apt-get install arduino
  2. nanpy Pythonライブラリを取得・展開(/home/piにて):
    $ wget https://pypi.python.org/packages/source/n/nanpy/nanpy-v0.7.tar.gz
    $ tar xvf nanpy-v0.7.tar.gz
  3. setuptools (nanpyの依存) を取得・展開:
    $ wget https://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz#md5=7df2a529a074f613b509fb44feefe74e
    $ tar xvf setuptools-0.6c11.tar.gz
  4. pyserial (nanpyの依存) を取得・展開:
    $ wget https://pypi.python.org/packages/source/p/pyserial/pyserial-2.6.tar.gz
    $ tar xvf pyserial-2.6.tar.gz
  5. setuptools をインストール:
    $ cd setuptools-0.6c11
    $ sudo python setup.py install
  6. nanpy Pythonライブラリをインストール:
    $ cd ../nanpy
    $ sudo python setup.py install
  7. pyserial をインストール:
    $ cd ../pyserial-2.6
    $ sudo python setup.py install

必要なファイルが揃ったので、Arduinoにnanpyファームウェアを書き込みます。

ファームウェア書き込み

nanpy は、Raspberry Pi上のPythonプログラムから、慣れ親しんだArduinoスケッチ風の構文でArduinoを操作できるようにするものです。例えばアナログ入力読み取りは Python側で int val = Arduino.analogRead(14) のように書けます。

nanpyには2つの構成要素があります:

前ステップでPython側をインストールし、Arduino側ファームウェアもPi上にダウンロード済みです。これをArduinoに書き込みます。

ArduinoをRaspberry PiのUSBポートに接続してください。

  1. nanpyファームウェアディレクトリへ移動し、書き込み実行:
    $ cd ../nanpy/firmware
    $ export BOARD=uno
    $ make
    $ make upload
  2. /dev/ttyACM0 でデバイスが見つからないエラーが出たら、Arduinoをもう一方のUSBポートに挿し直してください。

私はプレイリスト読み込み用スクリプトとメインのPythonスクリプト(コードタブに掲載)を作成し、PythonスクリプトをRaspberry Pi起動時に自動実行するよう設定しました。また、IPアドレス表示や音声出力切替などのメニュー機能用に追加ボタンも設けました。

最新アップデート:ロータリーエンコーダーを追加して選局と音量調整ができるようにし、3Dプリンタでケースを作り直しました。

Raspberry PiとArduinoで作るWi-Fiインターネットラジオ:世界中の局をストリーミング

ソースコード

piradio (Python)

from datetime import datetime
from subprocess import *
from time import sleep, strftime
from Queue import Queue
from threading import Thread
import os
from nanpy import Arduino, Lcd
import socket

Arduino.pinMode(14, input)
lcd = Lcd([8,9,4,5,6,7],[16,2])  # Sainsmartシールド用LCDピン設定
lcd.printString("Ruben's RadioZ",0,0)
lcd.printString("Loading" + "."*3,0,1)
sleep(5)

max_trax = 10
x = 1
loop_menu = 1
loop_radio = 1
stations=[]
# ボタン押下時に局名表示するためのリスト
stations.append("Ecco 99 ")
stations.append("Galgalaz ")
stations.append("Galaz ")
stations.append("88 FM ")
stations.append("Gimel ")
stations.append("Radios 100fm ")
stations.append("Kol Hamusica ")
stations.append("WQXR New York ")
stations.append("WPR Winsconsin ")
stations.append("BBC world servic")
stations.append("LINN jazz")
stations.append("LINN classical")

def get_local_ip_address(target):
    ipaddr = ''
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect((target, 8000))
        ipaddr = s.getsockname()[0]
        s.close()
    except:
        pass
    return ipaddr

print "Raspberry Pi - Local IP Address"
print(get_local_ip_address('10.0.1.1'))
print(get_local_ip_address('google.com'))

def display_ipaddr():
    # IPアドレス表示 (wlan0/eth0対応)
    show_wlan0 = "ip addr show wlan0 | cut -d/ -f1 | awk '/inet/ {printf \"w%15.15s\", $2}'"
    show_eth0 = "ip addr show eth0 | cut -d/ -f1 | awk '/inet/ {printf \"e%15.15s\", $2}'"
    ipaddr = get_local_ip_address('10.0.1.1')
    lcd.printString('IP Address:',0,0)
    lcd.printString(ipaddr,0,1)
    sleep(2)

def displaymenu():
    # 5番目のボタンでメニュー表示
    if x==1:
        lcd.printString("1. Display ",0,0); lcd.printString(" IP Address ",0,1)
    elif x==2:
        lcd.printString("2. Audio Output ",0,0); lcd.printString(" to hdmi Port ",0,1)
    elif x==3:
        lcd.printString("3. Audio Output ",0,0); lcd.printString(" to Analog port",0,1)
    elif x==4:
        lcd.printString("4. Audio Output ",0,0); lcd.printString(" Auto Sel. Port",0,1)
    elif x==5:
        lcd.printString("5. Reload the ",0,0); lcd.printString(" Playlist ",0,1)
    elif x==6:
        lcd.printString("6. ShutDown ",0,0); lcd.printString(" the System ",0,1)
    else:
        lcd.printString("7. Exit to ",0,0); lcd.printString(" Main Menu ",0,1)

def load_playlist():
    output = run_cmd("mpc clear")
    output = run_cmd("/home/pi/radio/radio_playlist.sh")

def run_cmd(cmd):
    p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)
    output = p.communicate()[0]
    return output

def getKey():
    val = Arduino.analogRead(14)
    if val == 1023: return "NONE"
    elif val < 100: return "RIGHT"
    elif val < 150: return "UP"
    elif val < 330: return "DOWN"
    elif val < 510: return "LEFT"
    elif val < 750: return "SEL"
    else: return "KBD_FAULT"

load_playlist()

def getTrack():
    L= [S.strip('\n') for S in os.popen('mpc').readlines()]
    output = run_cmd("mpc current")
    station = output[0:16]
    track = output[-17:-1]
    lcd.printString(station + " "*(16 - len(station)), 0, 0)
    lcd.printString(track + " "*(16 - len(track)), 0, 1)
    track_num = 1
    os.system("sudo service mpd restart")
    os.system("mpc play "+str(track_num))

while loop_radio == 1:
    getTrack()
    loop_menu = 1
    x = 1
    key = getKey()
    if key == "UP":
        track_num += 1
        if track_num > max_trax: track_num = 1
        lcd.printString(stations[track_num-1],0,0)
        os.system("sudo service mpd restart")
        os.system("mpc play " + str(track_num))
        getTrack()
    elif key == "DOWN":
        track_num -= 1
        if track_num < 1: track_num = max_trax
        lcd.printString(stations[track_num-1],0,0)
        os.system("sudo service mpd restart")
        os.system("mpc play " + str(track_num))
        getTrack()
    elif key == "LEFT":
        os.system("mpc volume +10")
        lcd.printString(16*" ", 0, 0); lcd.printString(16*" ", 0, 1)
        output = run_cmd("mpc volume")
        lcd.printString("VOLUME UP:", 0, 0); lcd.printString(output, 5, 1)
        sleep(.25)
        lcd.printString(16*" ",0,0); lcd.printString(16*" ",0,1)
    elif key == "RIGHT":
        os.system("mpc volume -10")
        lcd.printString(16*" ",0,0); lcd.printString(16*" ", 0,1)
        output = run_cmd("mpc volume")
        lcd.printString("VOLUME DOWN:", 0, 0); lcd.printString(output, 5, 1)
        sleep(.25)
        lcd.printString(16*" ",0,0); lcd.printString(16*" ",0,1)
    elif key == "SEL":
        while loop_menu == 1:
            displaymenu()
            key = getKey()
            if key == "RIGHT":
                os.system("mpc volume +10")
                lcd.printString(16*" ", 0, 0); lcd.printString(16*" ", 0, 1)
                output = run_cmd("mpc volume")
                lcd.printString("VOLUME UP:", 0, 0); lcd.printString(output, 5, 1)
                sleep(.25)
                lcd.printString(16*" ",0,0); lcd.printString(16*" ",0,1)
            elif key == "LEFT":
                os.system("mpc volume -10")
                lcd.printString(16*" ",0,0); lcd.printString(16*" ", 0,1)
                output = run_cmd("mpc volume")
                lcd.printString("VOLUME DOWN:", 0, 0); lcd.printString(output, 5, 1)
                sleep(.25)
                lcd.printString(16*" ",0,0); lcd.printString(16*" ",0,1)
            elif key == "UP":
                if x <= 1: x = 7
                else: x = x - 1
            elif key == "DOWN":
                if x >= 7: x = 1
                else: x = x + 1
            elif key == "SEL":
                if x == 1: display_ipaddr(); sleep(1)
                elif x == 2:
                    output = run_cmd("amixer -q cset numid=3 2")
                    lcd.printString("Audio OUT-->HDMI", 0, 0); lcd.printString("output ", 0, 1); sleep(.5)
                elif x == 3:
                    output = run_cmd("amixer -q cset numid=3 1")
                    lcd.printString("Audio OUT->Analog", 0, 0); lcd.printString("output ", 0, 1); sleep(.5)
                elif x == 4:
                    output = run_cmd("amixer -q cset numid=3 0")
                    lcd.printString("Audio OUT-> Auto", 0, 0); lcd.printString("output ", 0, 1); sleep(.5)
                elif x == 5:
                    load_playlist(); os.system('mpc play 1')
                elif x == 6:
                    lcd.printString("Good Bye ", 0, 0); lcd.printString("Have a Nice Day ", 0, 1)
                    output = run_cmd("mpc stop"); quit()
                elif x == 7:
                    loop_menu = 0; getTrack(); break
            elif key == "RIGHT":
                os.system("mpc volume +2")
                lcd.printString(16*" ",0,0); lcd.printString(16*" ", 0,1)
                output = run_cmd("mpc volume")
                lcd.printString("VOLUME UP:", 0, 0); lcd.printString(output, 5, 1)
                sleep(.25)
                lcd.printString(16*" ",0,0); lcd.printString(16*" ",0,1)
            elif key == "LEFT":
                os.system("mpc volume -2")
                lcd.printString(16*" ", 0, 0); lcd.printString(16*" ", 0, 1)
                output = run_cmd("mpc volume")
                lcd.printString("VOLUME DOWN:", 0, 0); lcd.printString(output, 5, 1)
                sleep(.25)
                lcd.printString(16*" ",0,0); lcd.printString(16*" ",0,1)

radio_playlist.sh (シェルスクリプト)

#! /bin/sh
mpc clear 1>/dev/null
#1 ecco99
mpc add https://99.livecdn.biz/99fm_aac
#2 galgalaz
mpc add https://glglzwizzlv.bynetcdn.com/glglz_mp3
#3 galaz
mpc add https://glzwizzlv.bynetcdn.com/glz_mp3
#4 88 fm
mpc add https://ibala.vidnt.com:8000/iba_radio-88fmM
#5 gimel
mpc add https://ibala.vidnt.com:8000/iba_radio-gimelM
#6 radios 100 fm
mpc add https://100fm.streamgates.net/Radios100Fm
#7 kol hamusica
mpc add https://ibala.vidnt.com:8000/iba_radio-kolmusicaM
#8 wqxr
mpc add https://stream.wqxr.org/wqxr
#9 npr current
mpc add https://current.stream.publicradio.org/kcmp.mp3
#10 bbc
mpc add https://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-eieuk
#11 linn jazz
mpc add https://radio.linnrecords.com:8003/autodj
#12 linn classical
mpc add https://radio.linnrecords.com:8004/autodj

回路図

Raspberry PiとArduinoで作るWi-Fiインターネットラジオ:世界中の局をストリーミング

製造プロセス

  1. LIRCでプロフェッショナルなRaspberry Piユニバーサルリモコンを構築
  2. Raspberry PiでRFをDCに変換: エンベロープ検波器の構築とトラブルシューティング
  3. Cycle Chaser: Raspberry Piで自転車をナイトタイムライトショーに変身
  4. Raspberry Piベースの泥棒検知器を構築 - ステップバイステップガイド
  5. Raspberry Pi、MCP9808、InfluxDB、Grafanaで作る家庭温度モニター
  6. Raspberry Piで構築するホームオートメーションシステム:リモート制御対応
  7. MrRobot: Ubuntu Mobile で操作する Rapiro ロボット – 音声、タッチ、シェイクインタラクション
  8. DIY Wall-E 風 Raspberry Pi CD ボックスロボット
  9. Bluetooth 制御 Raspberry Pi ロボットに音声フィードバックを追加して構築
  10. Arduino & Raspberry Pi でインターネット制御ビデオストリーミングロボットを構築
  11. RasPiRobot Board V2:Raspberry Pi を強力なロボットコントローラーに拡張