分类目录归档:业余研究

会说话的树莓派,将文字转换为语音

树莓派带了个音频输出接口,可外接小音箱。要是能实现文本到语音转换(text2speech)的话。 它的可玩性大大的提高了,比如 起床的时候语音播报天气、朗读电子邮件…更多的发挥你的想象力吧

这里介绍两种方式:1.通过本地程序转换 2使用在线api接口,这个需要联网

本地通过软件转换

我使用的是festival 一个免费的文字转语音软件,不需要联网。

在树莓派上可直接安装

$ apt-get install festival
$ festival -v
festival: Festival Speech Synthesis System: 2.1:release November 2010

安装好后 测试下

直接输入festival可进入交互方式

$ festival
festival> (SayText "hello boy")

或者直接通过命令行

$ echo 'hello boy' |festival --tts

festival 默认带的声音kal_diphone效果并不好(呃,有点模糊,电音效果?)

官方也有其他的声音,效果也不错online demo 遗憾的是这些没有开放下载

在官方FAQ http://www.cstr.ed.ac.uk/projects/festival/demofaq.html#voices

Q:I really like your demo, where can I download voice XYZ?

A: ….

The good news, though, is that we’re currently putting together a portfolio of dozens and dozens (really!) of voices which will be available to download shortly. Some voices will be available for commercial use only, some for non-commercial use only, and indeed some for both.

不知道shortly是什么时候

但是我们可以选择安装一些第三方的语音库,下面介绍两个

mbroal

官方mbroal安装说明

我按照说明做了一下,路径稍微有点不同,上面说要解压 festvox_us1到 /usr/share/festival/lib/voices, 而实际目录是/usr/share/festival/voices/ 不然会报错,可能跟festival的版本有关系

1.Install the festival voice wrapper. 安装 festvox_us1

root@coolpi:/tmp# 
$ wget http://www.cstr.ed.ac.uk/downloads/festival/1.95/festvox_us1.tar.gz
$ tar -xzvf festvox_us1.tar.gz
festival/lib/voices/english/us1_mbrola/festvox/us1_mbrola.scm
festival/lib/voices/english/us1_mbrola/festvox/usdurtreeZ.scm
festival/lib/voices/english/us1_mbrola/usradio
$ cp festival/lib/voices/english/us1_mbrola /usr/share/festival/voices/english/ -R 

2.Get the MBROLA voice and binary. 到 http://tcts.fpms.ac.be/synthesis/mbrola.html

下载 MBROLA binary 和 MBROLA Voices

分别选择

Raspberri_pi 注意binary要选择适用于树莓派的版本

us2: American English Male (6.3Mb) Babel Technology 也可以选择其它声音

压缩包中的文件 $ wget http://tcts.fpms.ac.be/synthesis/mbrola/bin/raspberri_pi/mbrola.tgz #里面只有一个二进制文件mbrola,把它解压到 /usr/local/bin下 $ tar -xzvf mbrola.tgz -C /usr/local/bin/

#
$ wget http://tcts.fpms.ac.be/synthesis/mbrola/dba/us1/us1-980512.zip
$ unzip us1_mbrola.zip -d /usr/share/festival/voices/english/us1_mbrola/

最后目录结构看起来是这样的

/usr/share/festival/voices/english/us1_mbrola/
├── festvox
│   ├── us1_mbrola.scm
│   └── usdurtreeZ.scm
├── us1
│   ├── license.txt
│   ├── TEST
│   │   ├── alice.pho
│   │   ├── mbrola.pho
│   │   ├── mbroli.ini
│   │   ├── push.pho
│   │   └── xmas.pho
│   ├── us1
│   ├── us1mrpa
│   └── us1.txt
└── usradio

查看 已安装的语音

festival> (voice.list)
(us1_mbrola kal_diphone)

选择声音,测试下

festival> (voice_us1_mbrola)
us1_mbrola
festival> (SayText "hello boy")

嗯 比自带的那个声音好点…

cmu(更接近真人声音的)

1.安装 festlex-cmu

$ apt-get install festlex-cmu

2.下载 cmu

cd /usr/share/festival/voices/english/
#这个压缩包100多M
sudo wget -c http://www.speech.cs.cmu.edu/cmu_arctic/packed/cmu_us_clb_arctic-0.95-release.tar.bz2
sudo tar jxf cmu_us_clb_arctic-0.95-release.tar.bz2 
sudo ln -s cmu_us_clb_arctic cmu_us_clb_arctic_clunits

选择声音,测试下

festival> (voice_cmu_us_clb_arctic_clunits)
cmu_us_clb_arctic_clunits
festival> (SayText "hello boy")   

声音又上了一个档次,但是解析的时候能明显感觉出来有延迟。估计放到配置高点的电脑上会好些。

可以在配置文件中设置默认的声音

sudo cp /etc/festival.scm /etc/festival.scm.backup
sudo echo "(set! voice_default 'voice_cmu_us_clb_arctic_clunits)" >> /etc/festival.scm      

在线tts api接口

找到两个

1.tts-api这个接口是免费的,效果还行,起码比festival好

http://tts-api.com/tts.mp3?q=hello+world.

2.google翻译的接口

这个接口并不是官方正式提供的,不过从速度,声音效果来说是最好的(非常好!),网速好的话基本上感觉不出来延迟

点这里测试下

http://translate.google.com/translate_tts?ie=UTF-8&tl=en&q=hello+world

三个参数 q=要转换的文字; tl=文字的语言 中文选择zh-cn; ie 要转换的文字q的编码方式;

上面接口返回音频格式是mp3的,可使用mpg123 直接播放

$ apt-get install mpg123
$ mpg123 'http://translate.google.com/translate_tts?ie=UTF-8&tl=en&q=today+is+sunday'

上面两种方式可以结合着使用,比如在为联网的时候使用festival,联网使用效果更好的在线接口

参考

给树莓派添加重启关机按钮

最近一段时间开始捣鼓树莓派了,弄的都是试验性质的。经常会出现些问题 导致连不上树莓派可能是卡死或者断网什么的,有没有显示器也不知道到底是什么情况。 没办法只有拔掉电源重启了。

后来想想长期这样弄也不是办法SD卡禁不起折腾啊,于是就想办法给它添加了个“关机和重启按钮”。

这里实现上用了GPIO接口,通过读取一个接口的高低状态然后调用 重启以及关机命令。

我的pi是B版v1。GPIO接口和v2稍微不一样。具体看下图 把代码的接口定义替换成对应的就行了

rasberrypi GPIO

下面这个两幅图更容易看

树莓派v1 GPIO接口定义 树莓派v2 GPIO接口定义

另外使用pin的编号有两种方式

  1. Board Pin 这种是自然排序的,重p1到p26
  2. BCM GPIO Broadcom的编号方法 (上图中的绿色方块部分GPIO*)

我在代码中使用的是 *BCM *。

这里用到了两个GPIO接口,7和17 你也可以自己修改下。 一个用来接收按键信号,另外一个驱动led显示状态

led有三个状态 长亮:正在重启, 闪动:正在关机, 不亮:等待状态。

面包板连接 树莓派重启面包板连接图
若你有杜邦线的话也可以不通过面包板连接,按钮那个GND的线也不是必须的,用手直接触摸 GPIO7 也能起到把这个电压拉低的效果

实现代码

#!/usr/bin/env python
# coding=utf-8
# author:ksc

import RPi.GPIO as GPIO
import time
import os,sys
import signal

GPIO.setmode(GPIO.BCM)

#define GPIO pin
pin_btn=7
pin_led=17

GPIO.setup(pin_btn, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin_led, GPIO.OUT, initial=GPIO.LOW)

press_time=0
count_down=10
led_on=1

def cleanup():
    '''释放资源,不然下次运行是可能会收到警告
    '''
    print('clean up')
    GPIO.cleanup()

def handleSIGTERM(signum, frame):
    #cleanup()
    sys.exit()#raise an exception of type SystemExit

def onPress(channel):
    global press_time,count_down
    print('pressed')
    press_time+=1
    if press_time >3:
        press_time=1
    if press_time==1:
        GPIO.output(pin_led, 1)
        print('system will restart in %s'%(count_down))
    elif press_time==2:
        print('system will halt in %s'%(count_down))
    elif press_time==3:
        GPIO.output(pin_led, 0)
        print 'cancel '
        count_down=10

GPIO.add_event_detect(pin_btn, GPIO.FALLING, callback= onPress,bouncetime=500)

#signal.signal(signal.SIGTERM, handleSIGTERM)
try:
    while True:
        if press_time==1:
            if count_down==0:
                print "start restart"
                os.system("shutdown -r -t 5 now")
                sys.exit()
            led_on=not led_on
            GPIO.output(pin_led, led_on)# blink led
        if press_time==2 and count_down==0:
            print "start shutdown"
            os.system("shutdown  -t 5 now")
            sys.exit()

        if press_time==1 or press_time==2:
            count_down-=1
            print "%s second"%(count_down)
        time.sleep(1)
except KeyboardInterrupt:
    print('User press Ctrl+c ,exit;')
finally:
    cleanup()

使用方法

#创建程序,把代码粘贴进去保存
root@mypi:~# vi reboot.py
#修改可执行
root@mypi:~# chomod 775 reboot.py
#测试下
root@mypi:~# ./reboot.py

按一下按钮 系统进入重启状态倒计时10秒,在这段时间内你可以接着按一下切换到关机状态。 按第三下取消关机进入等待状态。这三种状态可通过按按钮不断切换。

#若没问题就可以让它后台运行了,
root@mypi:~# nohup ./reboot.py &
#想结束后台运行?
ps auxf #查找PID
kill PID

参考

上拉电阻和下拉电阻

使用 RPI.GPIO 模块的输入(INPUT)功能

RPI.GPIO WIKI

把树莓派打造成智能无线路由器(可对国外网站自动选择线路)

本文的目的是教大家访问特定网站时走加密线路(vpn)时更加方便不用来回切换网络

前提

能有正常上网的环境 即pi插上网线后就能上网(如何上网不在此文讨论范围)

  1. 树莓派一个 (B型的带有线网卡)
  2. USB无线网卡一个( 我的是在京东上买的 二十块钱左右)
  3. vpn账户一个,并且能正常连通上网

我这里用的是openvpn,如果你有国外vps 如何配置请查看  OpenVPN安装配置教程

在这里我只简单说下客户端的配置

开始配置

ifconfig 
eth0      Link encap:Ethernet  HWaddr b8:27:eb:3c:2b:11
          inet addr:192.168.2.11  Bcast:255.255.255.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:47072 errors:0 dropped:0 overruns:0 frame:0
          TX packets:48828 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:29137358 (27.7 MiB)  TX bytes:9871271 (9.4 MiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:693 errors:0 dropped:0 overruns:0 frame:0
          TX packets:693 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:121328 (118.4 KiB)  TX bytes:121328 (118.4 KiB)

wlan0     Link encap:Ethernet  HWaddr c8:3a:35:c1:29:ab
          inet addr:192.168.10.1  Bcast:192.168.10.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:29999 errors:0 dropped:0 overruns:0 frame:0
          TX packets:27439 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3228721 (3.0 MiB)  TX bytes:27597707 (26.3 MiB)

eth0是我的有线网卡 已经获自动获取了ip(我现在就是通过有线ssh控制pi的)

wlan0就是那个无线网卡了(一般情况下是wlan0,若没有的话,你可以输入lsusb,看一下有没有显示出 你的无线网卡设备 。没有的就是驱动问题。)

修改 网络配置文件 给wlan0设置固定ip 在这里我设置的是192.168.10.1

注意一定不要和eth0在同一个网段
另外若你启用了wicd等网络管理服务请关闭

root@coolpi:~# cat /etc/network/interfaces
auto lo

iface lo inet loopback
iface eth0 inet dhcp

#allow-hotplug wlan0
#iface wlan0 inet manual
#wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp

iface wlan0 inet static
address 192.168.10.1
netmask 255.255.255.0

1 vpn客户端配置

安装openvpn,这里我们只是用它的客户端功能(如何配置,看上面的连接)

apt-get install openvpn

下面是我的配置文件

client
dev tun       #要与前面server.conf中的配置一致。
proto udp              #要与前面server.conf中的配置一致。
remote chicago.vps 8080    #将服务器IP替换为你的服务器IP,端口与前面的server.conf中配置一致。

resolv-retry infinite
nobind
persist-key
persist-tun

ca ca.crt
cert client.crt
key client.key
ns-cert-type server

#是否作为网关出口,会影响路由表的默认出口
;redirect-gateway

keepalive 20 60
#tls-auth ta.key 1
comp-lzo
verb 3
mute 20
route-method exe
route-delay 2

需要注意的是

ca ca.crt
cert client.crt
key client.key

这几个证书文件最好写成得路径,否则执行命令

openvpn /etc/openvpn/client.conf

会提示找不到这几个文件
只有cd /etc/openvpn/ 然后 openvpn client.conf 才行
若配置的没有有问题的话 输入ifconfig 会多出来一个虚拟网络设备tun0

tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          inet addr:10.2.2.10  P-t-P:10.2.2.9  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:22212 errors:0 dropped:0 overruns:0 frame:0
          TX packets:18882 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:26477654 (25.2 MiB)  TX bytes:1607636 (1.5 MiB)

记住这两个地址 inet addr:10.2.2.10 P-t-P:10.2.2.9 待会要用到

2 安装路由软件

下一步就是安装两个软件hostapd isc-dhcp-server

1) AP热点 hostapd 服务

#安装
apt-get install hostapd
#编辑默认配置文件路径
vi /etc/default/hostapd
将
#DAEMON_CONF= ""
这一行修改为
DAEMON_CONF="/etc/hostapd/hostapd.conf"

#解压默认配置文件
zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz >/etc/hostapd/hostapd.conf
#修改默认配置文件 
vi /etc/hostapd/hostapd.conf

刚开始的时候可以不加密直接使用默认配置就行 只需要修改下 ssid 和channel

注意: 默认是不加密的连接,建议等你完全测试成功了再修改为wpa加密的(配置文件中有各种模版)

ssid= test_ap #搜索无线信号时看到的那个
channel = 11 #此值最好不要与其他无线路由器重复。但是我试了一下别的信道 13、12等 hostapd 提示错误 貌似是网卡不支持

2) ip地址自动分配 dhcpd服务

#安装
apt-get install isc-dhcp-server
#将一下配置添加进  /etc/dhcp/dhcpd.conf 

subnet 192.168.10.0 netmask 255.255.255.0 {
  range 192.168.10.10 192.168.10.100; #分配给客户端的ip范围
  option routers 192.168.10.1;#网关地址 
  option broadcast-address 192.168.10.255; #广播地址 注意和上面的子网掩码255.255.255.0 对应
  option domain-name-servers 8.8.8.8,8.8.4.4; #DNS服务器地址
  default-lease-time 600; #租约时间 到期后客户端需要重新发起请求获取ip地址(可以续约原来的ip)
  max-lease-time 7200;
}

注意:

  1. 配置文件中的网段,子网掩码,以及网关要和给wlan0设置的静态ip【相对应】wlan0就是这个网段的网关)
  2. dns目前最好是配置成google的dns。因为国内的在根上都被污染了, google的dns走vpn的话没问题不会被污染,相应的解析速度也会变慢

(还有一种解决办法就是修改hosts,但是这个太麻烦,国外大网站不止一个域名,ip地址也是多个,收集这些信息也挺麻烦,相对来说收集国外网站ip段来说还是容易的)

3) 全部配置完毕后 ,启动服务

ifup wlan0 #启用网卡
service hostapd  start

or

hostapd -ddK /etc/hostapd.conf #方便查看调试信息

service isc-dhcp-server  start #注意在这一步的时候一定要确保wlan0已经启用并配置好了ip地址 不然会dhcpd会报错

4. 连接测试

现在你拿出手机搜索一下无线信号 有没有 [test_ap] 然后连接上试试。

若能成功连接并且获取ip,则表明你的pi无线路由器了

但是现在你得到手机还不能上网
需要设置一下NAT转发,即把wlan0上的网络连接转发到eth0上面通过有线来上网

3. 路由转发

———-分割线下面这些 觉得麻烦的可以不看,我在后面提供了一个脚本 不过最好还是看一下,有助于理解————-

  • 1)
    将192.168.10.0/24 这个网段的流量转发到 eth0上
    注意:192.168.2.11 是eth0的ip

    iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j SNAT --to-source 192.168.2.11

    目前位置,手机连上无线后应该就能上网了,但访问国外网站还是不行的

  • 2)
     iptables -t nat -F #先把上面那条规则删除了

    下面事例中我用8.8.8.8 代指国外ip ,你可以任意修改成“任意国外ip地址”

    将192.168.10.0/24 并且是去往8.8.8.8(任意国外ip地址) 的流量通过 10.2.2.10转发出去

    iptables -t nat -A POSTROUTING -s 192.168.10.0/24 --dst 1.1.1.1 -j SNAT  --to-source 10.2.2.10
  • 3)
    注意:目前默认的网关仍然是eth0 192.168.2.1
    看一下下面的路由表 默认是从 192.168.2.1出去的

    root@coolpi:~/raspi_router# route
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
    default         192.168.2.1     0.0.0.0         UG    0      0        0 eth0
    10.2.2.0        10.2.2.9        255.255.255.0   UG    0      0        0 tun0
    10.2.2.9        *               255.255.255.255 UH    0      0        0 tun0
    192.168.2.0     *               255.255.255.0   U     0      0        0 eth0
    192.168.10.0    *               255.255.255.0   U     0      0        0 wlan0

    所以我们要添加一个路由项 (10.2.2.9 就是上面tun0 p-t-p 那一项,我的理解就是vpn的虚拟网关)。
    把去往8.8.8.8的流量路由到vpn上面去,不走原来的路线了

    route add -net 8.8.8.8/32 gw 10.2.2.9 dev tun0
    root@coolpi:~/raspi_route# traceroute 8.8.8.8
    traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
     1  10.2.2.1 (10.2.2.1)  306.001 ms  308.014 ms  308.195 ms
     2  省略……

    用traceroute命令可以看到 现在走的是vpn

    若你只设置8.8.8.8的路由而不设置该ip的NAT转发,在pi上没有什么问题,会按照你的设置自动选择线路

    但是无线网络下面的终端(手机等)还是只能访问国内的ip地址 你设置的“国外ip”将不能访问(假如原来能访问的话hehe)

    总的来说 路由规则,NAT转发缺一不可

    route add -net 8.8.8.8/32 gw 10.2.2.9 dev tun0
    iptables -t nat -A POSTROUTING -s 192.168.10.0/24 --dst 8.8.8.8 -j SNAT  --to-source 10.2.2.10

    vpn

  • 4)
    现在国外的网站能访问了,我们再把第一步在重复一遍 设置默认转发规则
    *注意:这一步一定要放到最后执行 *iptables规则就像一个筛子 第一层被挡住以后就不会往下走了

    iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j SNAT --to-source 192.168.2.11

—————————–结束——————————–

我写了个脚本,python写的(shell不是很熟悉)

check.py
build_sh.py #根据route.txt 生成 添加路由表和 iptables NAT转发命令
route.txt #国外的ip网段,不是很全

可以把一些网段自动转换称shell脚本 已经传到了 git@osc 上面

你可以 用git检出一份

apt-get install git
git clone http://git.oschina.net/ksc/raspi_router

或者直接下载zip压缩包

wget http://git.oschina.net/ksc/raspi_router/repository/archive?ref=master -O t.zip
unzip t.zip
cd raspi_router/

check.py 检查你前几步的设置是否有效
若你用的是openvpn 一般不需要修改,直接运行即可

root@coolpi:~/raspi_route# ./check.py
eth0 ok
eth0_ip=192.168.2.11
wlan0 ok
wlan0_ip=192.168.10.1/24
tun0 ok
tun0_ip=10.2.2.10
p-t-p:10.2.2.9
检查通过 请运行一下命令生成 路由及转发脚本
./build_sh.py

安照提示运行上述命令

root@coolpi:~/raspi_route# ./build_sh.py   
/root/raspi_route/route.txt
linux_route.sh 及 linux_nat.sh 已经生成 请运行

然后执行

./linux_route.sh && ./linux_nat.sh

以后若ip信息都没有变化的话 ,直接运行如下命令即可

ifup wlan0 #若wlan0已经启用并获取ip地址了、则不用执行此命令
service hostapd start
service isc-dhcp-server start
openvpn client.conf #具体看你的配置文件而定
./linux_route.sh 
./linux_nat.sh

最后

  1. route表是我从网上搜集的,只有几个常用的网段,不是很全。
  2. 上述过程我检查了几遍,但难免有疏漏的地方。若您发现请指正

原文地址