この回で「RubicでGR-CITRUSのmrubyプログラミング事始め」は最後です。
今までのことを踏まえインターネット鳩時計を作ります。
#動作
動作は単純に
- 起動時、NTPで時刻を取得
- GR-CITRUSの時計を設定
- 1時間ごとに時刻のMP3ファイルをしゃべる
としたいと思います。単純!
#今回使うもの
- GR-CITRUS
- WA-MIKAN
- MicroSDカード
- 圧電素子かスピーカー
- ブレッドボード
- ブレッドボード・ジャンパーコード(オス-ワニグチ)×適当
#音声集め
まずは、時報の元となる音声素材を集めます。
以下のようなフリーで提供しているソフトやサイトがありますので利用させていただきます。
学術研究目的ならばNICTの杉浦孔明さんが開発されたrospeexなんていうのも試せます。
K. Sugiura, Y. Shiga, H. Kawai, T. Misu and C. Hori: "A Cloud Robotics Approach towards Dialogue-Oriented Robot Speech," Advanced Robotics, Vol. 29, Issue 7, pp. 449-456, 2015.
有料のものならもVOICEROIDいいですね
##音声ファイル作成
上記ソフトを使い以下セリフ用ファイルを用意しました。
ファイル名 | 用途 | セリフ |
---|---|---|
0.mp3~23.mp3 | 時報用のmp3 | 「0時なのです」「15時でおやつの時間です」とか |
now.mp3 | 時報用前置き用のmp3 | 「現在の時刻は」とか |
WA-MIKANのSDカード直下に以上のファイルを保存しておきます。
#スピーカーもしくは圧電素子とつなげる
第2回の時と同じように、GR-CITRUSと圧電素子(またはスピーカー)を接続します。
CITRUSの端子番号 | 接続先 |
---|---|
0 | 圧電素子またはスピーカーの+ |
GND | 圧電素子またはスピーカーの― |
#Rubicに書き込み
Ruby使いじゃないのでにわかですが一応クラスっぽく書きました。
###mruby-time使用版
mrbgemsのmruby-timeを使っています。ない場合は第4回の記事に従ってmruby-timeを入れるか、または次項のmruby-timeを使用しない版を使ってください。
#!mruby
SSID="あなたのSSID"
PASS="あなたのPASS"
class Cts_ntp
@@NTP_PACKET_SIZE = 48
@@timeZone = 9 #Tokyo
@@pollIntv = 150 # poll every this many ms
@@maxPoll = 15 # poll up to this many times
@@timeServer="129.6.15.28" #time.nist.gov
#@@timeServer="132.163.4.101" #time-a.timefreq.bldrdoc.gov
@@sendport = 123
@@localport = 8788
def initialize(params)
@wifi = params[:wifi] || WiFi
@wifiport = params[:wifiport] || 1
@timeserver = params[:timeserver] || @@timeServer
@sendport = params[:sendport] || @@sendport
@localport = params[:localport] || @@localport
end
def wifi
@wifi
end
def wifiport
@wifiport
end
def timeserver
@timeserver
end
def localport
@localport
end
def sendport
@sendport
end
def sendPacket
packetBuffer = Array.new(@@NTP_PACKET_SIZE , 0)
packetBuffer[0] = 0b11100011 # LI, Version, Mode , 0xE3
packetBuffer[1] = 0 # Stratum, or type of clock
packetBuffer[2] = 6 # Polling Interval
packetBuffer[3] = 0xEC # Peer Clock Precision
packetBuffer[12] = 49
packetBuffer[13] = 0x4E
packetBuffer[14] = 49
packetBuffer[15] = 52
binary = packetBuffer[0].chr
for num in 1..@@NTP_PACKET_SIZE-1 do
binary += packetBuffer[num].chr
end
@wifi.udpOpen(@wifiport, @timeserver, @sendport, @localport)
@wifi.send(@wifiport,binary)
end
def receivePacket
@array = @wifi.recv(@wifiport)
@@maxPoll.times do
delay(@@pollIntv)
if (@array[0] != nil) then
if (@array[0] >= 0) then
if (@array.length == @@NTP_PACKET_SIZE) then
break
end
end
end
@array = @wifi.recv(@wifiport)
end
if @array.length != @@NTP_PACKET_SIZE then
"receive error"
else
time = @array[40]
for i in 1..3 do
time = time << 8 | @array[40+i]
end
@unixTime = time - 2208988800
@unixTimeJST = @unixTime + (@@timeZone * 60 * 60)
"receive ok"
end
end
def unixTime
@unixTime
end
def unixTimeJST
@unixTimeJST
end
def packet
@array
end
end
#Main
Usb = Serial.new(0)
#WiFi PART
#ESP8266を一度停止させる(リセットと同じ)
pinMode(5,1)
digitalWrite(5,0) # LOW:Disable
delay 500
digitalWrite(5,1) # LOW:Disable
if( System.useWiFi() == 0)then
Usb.println "WiFi Card can't use."
System.exit()
end
Usb.println "WiFi Ready"
Usb.println "WiFi disconnect"
Usb.println WiFi.disconnect
Usb.println "WiFi Mode Setting"
Usb.println WiFi.setMode 3 #Station-Mode & SoftAPI-Mode
Usb.println "WiFi ipconfig"
Usb.println WiFi.ipconfig
Usb.println "WiFi connecting"
con=WiFi.connect(SSID,PASS)
Usb.println con
if (con != "WIFI CONNECTED\r\nWIFI GOT IP\r\n\r\nOK\r\n") then
System.exit()
end
Usb.println "WiFi multiConnect Set"
Usb.println WiFi.multiConnect 1
#NTP PART
Usb.println "Ntp new"
ntp=Cts_ntp.new(wifi:WiFi,wifiport:1)
Usb.println "Send Packet"
ntp.sendPacket
Usb.println "Receive Packet"
Usb.println ntp.receivePacket
Usb.println ntp.packet.to_s
Usb.println ntp.unixTimeJST.to_s
WiFi.cClose(1)
#UNIX TIME
t = Time.at(ntp.unixTimeJST)
Usb.println t.to_s
#RTC PART
Usb.println "Rtc init"
Usb.println Rtc.init().to_s
Usb.println Rtc.setTime([t.year,t.month,t.day,t.hour,t.min,t.sec]).to_s
#LOOP PART
while true do
ct=Rtc.getTime()
Usb.println ct.to_s
if (ct[4]==0 && ct[5]==0) then
if( System.useMP3(3,4) == 0)then
Usb.println "MP3 can't use."
System.exit()
end
f = ct[3].to_s + ".mp3"
Usb.println f
3.times do
led 1
Usb.print MP3.play "now.mp3"
delay(10)
Usb.print MP3.play f
led 0
delay(100)
end
end
delay(10)
end
###mruby-timeを使用しない版
こちらはmruby-timeを使用しない版です。素のGR-CITRUSで動くと思います。
#!mruby
SSID="あなたのSSID"
PASS="あなたのPASS"
class Cts_ntp
@@NTP_PACKET_SIZE = 48
@@timeZone = 9 #Tokyo
@@pollIntv = 150 # poll every this many ms
@@maxPoll = 15 # poll up to this many times
@@timeServer="129.6.15.28" #time.nist.gov
#@@timeServer="132.163.4.101" #time-a.timefreq.bldrdoc.gov
@@sendport = 123
@@localport = 8788
def initialize(params)
@wifi = params[:wifi] || WiFi
@wifiport = params[:wifiport] || 1
@timeserver = params[:timeserver] || @@timeServer
@sendport = params[:sendport] || @@sendport
@localport = params[:localport] || @@localport
end
def wifi
@wifi
end
def wifiport
@wifiport
end
def timeserver
@timeserver
end
def localport
@localport
end
def sendport
@sendport
end
def sendPacket
packetBuffer = Array.new(@@NTP_PACKET_SIZE , 0)
packetBuffer[0] = 0b11100011 # LI, Version, Mode , 0xE3
packetBuffer[1] = 0 # Stratum, or type of clock
packetBuffer[2] = 6 # Polling Interval
packetBuffer[3] = 0xEC # Peer Clock Precision
packetBuffer[12] = 49
packetBuffer[13] = 0x4E
packetBuffer[14] = 49
packetBuffer[15] = 52
binary = packetBuffer[0].chr
for num in 1..@@NTP_PACKET_SIZE-1 do
binary += packetBuffer[num].chr
end
@wifi.udpOpen(@wifiport, @timeserver, @sendport, @localport)
@wifi.send(@wifiport,binary)
end
def receivePacket
@array = @wifi.recv(@wifiport)
@@maxPoll.times do
delay(@@pollIntv)
if (@array[0] != nil) then
if (@array[0] >= 0) then
if (@array.length == @@NTP_PACKET_SIZE) then
break
end
end
end
@array = @wifi.recv(@wifiport)
end
if @array.length != @@NTP_PACKET_SIZE then
"receive error"
else
time = @array[40]
for i in 1..3 do
time = time << 8 | @array[40+i]
end
@unixTime = time - 2208988800
@unixTimeJST = @unixTime + (@@timeZone * 60 * 60)
"receive ok"
end
end
def unixTime
@unixTime
end
def unixTimeJST
@unixTimeJST
end
def packet
@array
end
end
class Cts_time
def IsLeapYear(year)
if ((year % 4)==0 && ((year % 100)!=0 || (year % 400)==0)) then
return true
else
return false
end
end
def initialize(unixtime)
# 閏年でない年の各月の日数
dayofm = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
dayoflm = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
monthstr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
weekstr = ["Sat","Sun", "Mon", "Tue", "Wed", "Thr", "Fri"]
# 日付の計算
wt = unixtime
@sec = wt % 60
wt -= sec
@min = ( wt.div(60) ) % 60
wt -= min
@hour = ( wt.div(60*60)) % 24
wt -= hour
@day = ( wt.div(60*60*24) )
@year = 1970
@month = 1
while (@day>366) do
if IsLeapYear(@year) then
@day -= 366
else
@day -= 365
end
@year+=1
end
@day+=1 # 1 月 1 日は 0 だから
while (1) do
if (IsLeapYear(@year)) then # もし閏年なら
if (@day <= dayoflm[@month-1]) then # 月の日数より day が少なければ
break
else #月の日数より day が多ければ
@day -= dayoflm[@month-1] #月の日数を引き
@month+=1 #月を 1 増やす
end
end
if (!IsLeapYear(year)) then #もし閏年でなければ
if (@day <= dayofm[@month-1]) then #以下同上
break
else
@day -= dayofm[@month-1]
@month+=1
end
end
end
# Zeller's congruence
zC = year/100
zY = year%100
zT = -2*zC+zC/4
h=(@day+(26*(@month+1)/10)+zY+zY/4+zT) % 7
@week=weekstr[h]
@weekno=h
@today=@year.to_s + "/" + @month.to_s + "/" + @day.to_s + " " + @hour.to_s + ":" + @min.to_s + ":" + @sec.to_s + " " + monthstr[@month-1] +" "+@week
end
def today
@today
end
def sec
@sec.to_i
end
def min
@min.to_i
end
def hour
@hour.to_i
end
def day
@day.to_i
end
def month
@month
end
def year
@year
end
def week
@week
end
def weekno
@weekno.to_i
end
end
#Main
Usb = Serial.new(0)
#WiFi PART
#ESP8266を一度停止させる(リセットと同じ)
pinMode(5,1)
digitalWrite(5,0) # LOW:Disable
delay 500
digitalWrite(5,1) # LOW:Disable
if( System.useWiFi() == 0)then
Usb.println "WiFi Card can't use."
System.exit()
end
Usb.println "WiFi Ready"
Usb.println "WiFi disconnect"
Usb.println WiFi.disconnect
Usb.println "WiFi Mode Setting"
Usb.println WiFi.setMode 3 #Station-Mode & SoftAPI-Mode
Usb.println "WiFi ipconfig"
Usb.println WiFi.ipconfig
Usb.println "WiFi connecting"
con=WiFi.connect(SSID,PASS)
Usb.println con
if (con != "WIFI CONNECTED\r\nWIFI GOT IP\r\n\r\nOK\r\n") then
System.exit()
end
Usb.println "WiFi multiConnect Set"
Usb.println WiFi.multiConnect 1
#NTP PART
Usb.println "Ntp new"
ntp=Cts_ntp.new(wifi:WiFi,wifiport:1)
Usb.println "Send Packet"
ntp.sendPacket
Usb.println "Receive Packet"
Usb.println ntp.receivePacket
Usb.println ntp.packet.to_s
Usb.println ntp.unixTimeJST.to_s
WiFi.cClose(1)
#UNIX TIME
time=Cts_time.new(ntp.unixTimeJST)
Usb.println time.today
#RTC PART
Usb.println "Rtc init"
Usb.println Rtc.init().to_s
Usb.println Rtc.setTime([time.year,time.month,time.day,time.hour,time.min,time.sec]).to_s
#LOOP PART
while true do
ct=Rtc.getTime()
Usb.println ct.to_s
if (ct[4]==0 && ct[5]==0) then
if( System.useMP3(3,4) == 0)then
Usb.println "MP3 can't use."
System.exit()
end
f = ct[3].to_s + ".mp3"
Usb.println f
3.times do
led 1
Usb.print MP3.play "now.mp3"
delay(10)
Usb.print MP3.play f
led 0
delay(100)
end
end
delay(10)
end
#完成
GR-Citrusで時報を喋らせてみました。音声はrospeexを利用させていただきました。#gr_citrus pic.twitter.com/oKBdvf3lRe
— shimocchi (@shimo_cchi) 2016年12月17日