之前所做的有一個特點就是需要在樹莓派上連接一個USB麥克風(fēng),通過這個麥克風(fēng)來進行語音的輸入,但是在實際使用場景上來看,這是不合理的,因此需要一個可以遠程操控智能小車的方案,因此萌發(fā)了將控制端移植到手機上的想法,移植到手機上也有幾個不同的方案。
- 通過Zigbee無線傳輸技術(shù)進行數(shù)據(jù)的傳輸
優(yōu)點:易于進行擴展,可方便的與其他智能家居連接起來
缺點:傳輸?shù)臄?shù)據(jù)量很小,不適用于語音數(shù)據(jù)以及圖像數(shù)據(jù)的傳遞 - 通過搭建一個服務(wù)器,開發(fā)一個手機APP,通過服務(wù)器進行數(shù)據(jù)的傳輸
優(yōu)點:自己搭建服務(wù)器, 可控制性強
缺點:開發(fā)門檻高(需要進行服務(wù)器的搭建以及手機應(yīng)用的開發(fā),不易實現(xiàn))以及使用門檻高(需要單獨在手機上安裝一個APP) - 通過微信平臺,進行數(shù)據(jù)(文本、語音、圖像、視頻)的傳遞
優(yōu)點:人人都有微信,使用門檻低,功能相對全面
缺點:可控制性相對較弱
最終經(jīng)過權(quán)衡,選取第三個方案,通過微信控制智能小車。
itchat
itchat是一個開源的微信個人號接口,使用python調(diào)用微信從未如此簡單??梢酝ㄟ^它進行微信消息的讀取,回復(fù),聯(lián)系人的讀取等等
1. 安裝
pip install itchat
2. 簡單入門
1.登陸配置
登陸使用的是itchat提供了auto_login方法,調(diào)用即可完成登錄。
一般而言,會在完成消息的注冊之后再進行登陸。
這里需要特別強調(diào)的是兩點,分別是短時間關(guān)閉重連、命令行二維碼。
- itchat提供了登陸狀態(tài)暫存,關(guān)閉程序后一定時間內(nèi)不需要掃碼即可登錄。由于目前微信網(wǎng)頁版提供上一次登錄的微信號不掃碼直接手機確認(rèn)登陸,所以如果開啟登陸狀態(tài)暫存將會自動使用這一功能。
- 為了方便在無圖形界面使用itchat,程序內(nèi)置了命令行二維碼的顯示。
短時間關(guān)閉程序后重連
這樣即使程序關(guān)閉,一定時間內(nèi)重新開啟也可以不用重新掃碼。
最簡單的用法就是給auto_login方法傳入值為真的hotReload。
該方法會生成一個靜態(tài)文件itchat.pkl,用于存儲登陸的狀態(tài)。
import itchat
from itchat.content import TEXT
@itchat.msg_register(TEXT)
def simple_reply(msg):
print(msg.text)
itchat.auto_login(hotReload=True)
itchat.run()
命令行二維碼顯示
通過以下命令可以在登陸的時候使用命令行顯示二維碼:
itchat.auto_login(enableCmdQR=True)
部分系統(tǒng)可能字幅寬度有出入,可以通過將enableCmdQR賦值為特定的倍數(shù)進行調(diào)整:如部分的linux系統(tǒng),塊字符的寬度為一個字符(正常應(yīng)為兩字符),故賦值為2
itchat.auto_login(enableCmdQR=2)
2.聊天對象
在使用個人微信的過程當(dāng)中主要有三種賬號需要獲取,分別為:
- 好友
- 公眾號
- 群聊
itchat為這三種賬號都提供了整體獲取方法與搜索方法。群聊多出獲取用戶列表方法以及創(chuàng)建群聊、增加、刪除用戶的方法。
接下來對三種分別介紹如何使用以及如何通過唯一的Uin確定好友與群聊。
好友
好友的獲取方法為get_friends,將會返回完整的好友列表。
- 其中每個好友為一個字典
- 列表的第一項為本人的賬號信息
- 傳入update鍵為True將可以更新好友列表并返回
好友的搜索方法為search_friends,有四種搜索方式:
- 僅獲取自己的用戶信息
- 獲取特定UserName的用戶信息
- 獲取備注、微信號、昵稱中的任何一項等于name鍵值的用戶
- 獲取備注、微信號、昵稱分別等于相應(yīng)鍵值的用戶
下面是示例程序:
獲取自己的用戶信息,返回自己的屬性字典
itchat.search_friends()
獲取特定UserName的用戶信息
itchat.search_friends(userName='@abcdefg1234567')
獲取任何一項等于name鍵值的用戶
itchat.search_friends(name='littlecodersh')
獲取分別對應(yīng)相應(yīng)鍵值的用戶
itchat.search_friends(wechatAccount='littlecodersh')
其中3、4項功能可以一同使用,將返回同時滿足兩個條件的好友
itchat.search_friends(name='LittleCoder機器人', wechatAccount='littlecodersh')
更新用戶信息的方法為update_friend。
- 該方法需要傳入用戶的UserName,返回指定用戶的最新信息
- 也可以傳入UserName組成的列表,那么相應(yīng)的也會返回指定用戶的最新信息組成的列表
memberList = itchat.update_friend('@abcdefg1234567')
公眾號
公眾號的獲取方法為get_mps,將會返回完整的公眾號列表。
- 其中每個公眾號為一個字典
- 傳入update鍵為True將可以更新公眾號列表并返回
公眾號的搜索方法為search_mps,有兩種搜索方法:
- 獲取特定UserName的公眾號
- 獲取名字中含有特定字符的公眾號
如果兩項都做了特定,將會僅返回特定UserName的公眾號,下面是示例程序:
獲取特定UserName的公眾號,返回值為一個字典
itchat.search_mps(userName='@abcdefg1234567')
獲取名字中含有特定字符的公眾號,返回值為一個字典的列表
itchat.search_mps(name='LittleCoder')
以下方法相當(dāng)于僅特定了UserName
itchat.search_mps(userName='@abcdefg1234567', name='LittleCoder')
群聊
群聊的獲取方法為get_chatrooms,將會返回完整的群聊列表。
- 其中每個群聊為一個字典
- 傳入update鍵為True將可以更新群聊列表并返回通訊錄中保存的群聊列表
- 群聊列表為后臺自動更新,如果中途意外退出存在極小的概率產(chǎn)生本地群聊消息與后臺不同步
- 為了保證群聊信息在熱啟動中可以被正確的加載,即使不需要持續(xù)在線的程序也需要運行
itchat.run() - 如果不想要運行上述命令,請在退出程序前調(diào)用
itchat.dump_login_status(),更新熱拔插需要的信息
群聊的搜索方法為search_chatrooms,有兩種搜索方法:
- 獲取特定UserName的群聊
- 獲取名字中含有特定字符的群聊
如果兩項都做了特定,將會僅返回特定UserName的群聊,下面是示例程序:
獲取特定UserName的群聊,返回值為一個字典
itchat.search_chatrooms(userName='@@abcdefg1234567')
獲取名字中含有特定字符的群聊,返回值為一個字典的列表
itchat.search_chatrooms(name='LittleCoder')
以下方法相當(dāng)于僅特定了UserName
itchat.search_chatrooms(userName='@@abcdefg1234567', name='LittleCoder')
群聊用戶列表的獲取方法為update_chatroom。
- 如果想要更新該群聊的其他信息也可以用該方法
- 群聊在首次獲取中不會獲取群聊的用戶列表,需要調(diào)用該命令才能獲取群聊的成員
- 該方法需要傳入群聊的UserName,返回特定群聊的詳細信息
- 也可以傳入UserName組成的列表,那么相應(yīng)的也會返回指定用戶的最新信息組成的列表
memberList = itchat.update_chatroom('@@abcdefg1234567', detailedMember=True)
創(chuàng)建群聊、增加、刪除群聊用戶的方法如下所示:
- 由于之前通過群聊檢測是否被好友拉黑的程序,目前這三個方法都被嚴(yán)格限制了使用頻率
- 刪除群聊需要本賬號為群管理員,否則會失敗
- 將用戶加入群聊有直接加入與發(fā)送邀請,通過useInvitation設(shè)置
- 超過40人的群聊無法使用直接加入的加入方式,特別注意
memberList = itchat.get_friends()[1:]
chatroomUserName = itchat.create_chatroom(memberList, 'test chatroom') # 創(chuàng)建群聊,topic鍵值為群聊名
itchat.delete_member_from_chatroom(chatroomUserName, memberList[0]) # 刪除群聊內(nèi)的用戶
itchat.add_member_into_chatroom(chatroomUserName, memberList[0], useInvitation=False) # 增加用戶進入群聊
Uins
Uin 就是微信中用于標(biāo)識用戶的方式,每一個用戶、群聊都有唯一且不同的Uin。通過Uin,即使退出了重新登錄,也可以輕松的確認(rèn)正在對話的是上一次登陸的哪一個用戶。但注意,Uin與其他值不同,微信后臺做了一定的限制,必須通過特殊的操作才能獲取。
最簡單來說,首次點開登陸用的手機端的某個好友或者群聊,itchat就能獲取到該好友或者群聊的Uin。
如果想要通過程序獲取,也可以用程序?qū)⒛硞€好友或者群聊置頂(取消置頂)。
這里提供一個提示群聊更新的程序:
import re, sys, json
import itchat
from itchat.content import *
itchat.auto_login(True)
@itchat.msg_register(SYSTEM)
def get_uin(msg):
if msg['SystemInfo'] != 'uins': return
ins = itchat.instanceList[0]
fullContact = ins.memberList + ins.chatroomList + ins.mpList
print('** Uin Updated **')
for username in msg['Text']:
member = itchat.utils.search_dict_list(
fullContact, 'UserName', username)
print(('%s: %s' % (
member.get('NickName', ''), member['Uin']))
.encode(sys.stdin.encoding, 'replace'))
itchat.run(True)
每當(dāng)Uin更新了,就會打印相應(yīng)的更新情況。
3.消息處理
消息內(nèi)容
微信初始化消息、文本消息、圖片消息、小視頻消息、地理位置消息、名片消息、語音消息、動畫表情、普通鏈接或應(yīng)用分享消息、音樂鏈接消息、群消息、紅包消息、系統(tǒng)消息
回復(fù)方法
- 方法:
send(msg='Text Message', toUserName=None)
- 所需值:
- msg:消息內(nèi)容
- '@fil@文件地址'將會被識別為傳送文件
- '@img@圖片地址'將會被識別為傳送圖片
- '@vid@視頻地址'將會被識別為小視頻
- toUserName:發(fā)送對象,如果留空將會發(fā)送給自己
- 返回值:發(fā)送成功->True, 失敗->False
- 程序示例:使用的素材可以在這里下載
#coding=utf8
import itchat
itchat.auto_login()
itchat.send('Hello world!')
# 請確保該程序目錄下存在:gz.gif以及xlsx.xlsx
itchat.send('@img@%s' % 'gz.gif')
itchat.send('@fil@%s' % 'xlsx.xlsx')
itchat.send('@vid@%s' % 'demo.mp4')
4.注冊方法
itchat將根據(jù)接收到的消息類型尋找對應(yīng)的已經(jīng)注冊的方法。如果一個消息類型沒有對應(yīng)的注冊方法,該消息將會被舍棄。
注冊
可以通過兩種方式注冊消息方法
import itchat
from itchat.content import *
# 不帶具體對象注冊,將注冊為普通消息的回復(fù)方法
@itchat.msg_register(TEXT)
def simple_reply(msg):
return 'I received: %s' % msg['Text']
# 帶對象參數(shù)注冊,對應(yīng)消息對象將調(diào)用該方法
@itchat.msg_register(TEXT, isFriendChat=True, isGroupChat=True, isMpChat=True)
def text_reply(msg):
msg.user.send('%s: %s' % (msg.type, msg.text))
消息類型
向注冊方法傳入的msg包含微信返回的字典的所有內(nèi)容。
本api增加Text、Type(也就是參數(shù))鍵值,方便操作。
itchat.content中包含所有的消息類型參數(shù),內(nèi)容如下表所示:
| 參數(shù) | 類型 | Text鍵值 |
|---|---|---|
| TEXT | 文本 | 文本內(nèi)容 |
| MAP | 地圖 | 位置文本 |
| CARD | 名片 | 推薦人字典 |
| NOTE | 通知 | 通知文本 |
| SHARING | 分享 | 分享名稱 |
| PICTURE | 圖片/表情 | 下載方法 |
| RECORDING | 語音 | 下載方法 |
| ATTACHMENT | 附件 | 下載方法 |
| VIDEO | 小視頻 | 下載方法 |
| FRIENDS | 好友邀請 | 添加好友所需參數(shù) |
| SYSTEM | 系統(tǒng)消息 | 更新內(nèi)容的用戶或群聊的UserName組成的列表 |
比如你需要存儲發(fā)送給你的附件:
@itchat.msg_register(ATTACHMENT)
def download_files(msg):
msg['Text'](msg['FileName'])
值得注意的是,群消息增加了三個鍵值:
- isAt: 判斷是否@本號
- ActualNickName: 實際NickName
- Content: 實際Content
可以通過本程序測試:
import itchat
from itchat.content import TEXT
@itchat.msg_register(TEXT, isGroupChat=True)
def text_reply(msg):
print(msg.isAt)
print(msg.actualNickName)
print(msg.text)
itchat.auto_login()
itchat.run()
注冊消息的優(yōu)先級
優(yōu)先級分別為:后注冊消息先于先注冊消息,帶參數(shù)消息先于不帶參數(shù)消息。
以下面的兩個程序為例:
import itchat
from itchat.content import *
itchat.auto_login()
@itchat.msg_register(TEXT)
def text_reply(msg):
return 'This is the old register'
@itchat.msg_register(TEXT)
def text_reply(msg):
return 'This is a new one'
itchat.run()
在私聊發(fā)送文本時將會回復(fù)This is a new one。
import itchat
from itchat.content import *
itchat.auto_login()
@itchat.msg_register
def general_reply(msg):
return 'I received a %s' % msg.type
@itchat.msg_register(TEXT)
def text_reply(msg):
return 'You said to me one to one: %s' % msg.text
itchat.run()
僅在私聊發(fā)送文本時將會回復(fù)You said to me one to one,其余情況將會回復(fù)I received a ...。
STT (Speak To Text)
通過上述的itchat模塊,就可以在樹莓派上用python進行微信的信息接收等,文本消息我們可以利用之前類似的方法進行識別、控制,那么僅僅用文本消息控制就顯得不夠智能了,需要用語音來控制,那么如何用語音來控制小車呢?這就要用到STT模塊,這個模塊做的就是把語音識別為文本信息,目前有多家公司有開源項目可以使用,比如Google、百度、訊飛,綜合考慮語音識別準(zhǔn)確率、易用性上,我選擇了百度的API接口。
百度AI平臺
要想使用百度的語音識別API,有如下幾個準(zhǔn)備工作。
- 首先要成為百度開發(fā)者
- 創(chuàng)建應(yīng)用
- 獲取密鑰
- 合成Access Token
前三部分可以在百度開發(fā)者平臺上很簡單的注冊申請,不再贅述。要注意的是保留好上述申請到的密鑰(API KEY、Secret KEY),會在下面用到;第四部分下面會詳細介紹。
語音識別簡介
百度語音識別通過 REST API 的方式給開發(fā)者提供一個通用的 HTTP 接口。 上傳需要完整的錄音文件,錄音文件時長不超過60s。
調(diào)用流程
1. 獲取Access Token
請求URL數(shù)據(jù)格式
向授權(quán)服務(wù)地址https://aip.baidubce.com/oauth/2.0/token發(fā)送請求(推薦使用POST),并在URL中帶上以下參數(shù):
- grant_type: 必須參數(shù),固定為client_credentials;
- client_id: 必須參數(shù),應(yīng)用的API Key;
- client_secret: 必須參數(shù),應(yīng)用的Secret Key;
Python獲取access_token示例代碼
import urllib, urllib2, sys
import ssl
# client_id 為官網(wǎng)獲取的AK, client_secret 為官網(wǎng)獲取的SK
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【官網(wǎng)獲取的AK】&client_secret=【官網(wǎng)獲取的SK】'
request = urllib2.Request(host)
request.add_header('Content-Type', 'application/json; charset=UTF-8')
response = urllib2.urlopen(request)
content= response.read()
if (content):
print(content)
上述代碼中content是一個JSON格式信息,其中包含你請求到的授權(quán)碼,會在調(diào)用API時用到,有限期一般為一個月。
服務(wù)器返回的JSON文本參數(shù)如下:
- access_token: 要獲取的Access Token;
- expires_in: Access Token的有效期(秒為單位,一般為1個月);
- 其他參數(shù)忽略,暫時不用;
例如:
{
"access_token": "25.b55fe1d287227ca97aab219bb249b8ab.315360000.1798284651.282335-8574074",
"expires_in": 2592000,
"scope": "public wise_adapt",
"session_key": "9mzdDZXu3dENdFZQurfg0Vz8slgSgvvOAUebNFzyzcpQ5EnbxbF+hfG9DQkpUVQdh4p6HbQcAiz5RmuBAja1JJGgIdJI",
"access_token": "24.6c5e1ff107f0e8bcef8c46d3424a0e78.2592000.1485516651.282335-8574074",
"session_secret": "dfac94a3489fe9fca7c3221cbf7525ff"
}
其中access_token即為我們需要的信息,通過Python的json模塊,把它提取出來。
data = json.loads(content)
token = data["access_token"]
2. 請求方式
- 如果音頻在本地,需要將音頻數(shù)據(jù)放在body中。(推薦方式)
- 如果音頻在互聯(lián)網(wǎng)上,可以讓百度服務(wù)器下載,然后回調(diào)到自己服務(wù)器的接口
- 音頻在本地,有JSON和raw兩種方式提交。
- 音頻在在互聯(lián)網(wǎng)上,需要百度服務(wù)器下載,只能通過JSON方式提交
這里只介紹通過json 方式,上傳本地文件(官方推薦,更高效)
JSON方式上傳
語音數(shù)據(jù)和其他參數(shù)通過標(biāo)準(zhǔn) JSON 格式串行化 POST 上傳, JSON 里包括的參數(shù):
| 字段名 | 是必填或選填 | 描述 |
|---|---|---|
| format | 必填 | 語音文件的格式,pcm 或者 wav 或者 amr。不區(qū)分大小寫。推薦pcm文件 |
| rate | 必填 | 采樣率, 8000 或者 16000, 推薦 16000 采用率 |
| channel | 必填 | 聲道數(shù),僅支持單聲道,請?zhí)顚懝潭ㄖ?1 |
| cuid | 必填 | 用戶唯一標(biāo)識,用來區(qū)分用戶,計算UV值。建議填寫能區(qū)分用戶的機器 MAC 地址或 IMEI 碼,長度為60字符以內(nèi)。 |
| token | 必填 | 開放平臺獲取到的開發(fā)者[ access_token](http://yuyin.baidu.com/docs/tts/135#獲取 Access Token "access_token") |
| lan | 選填 | 語種選擇,默認(rèn)中文(zh)。 中文=zh、粵語=ct、英文=en,不區(qū)分大小寫 |
| url | 選填 | 可下載的語音下載地址,與callback連一起使用,確保百度服務(wù)器可以訪問。 |
| callback | 選填 | 用戶服務(wù)器的識別結(jié)果回調(diào)地址,確保百度服務(wù)器可以訪問 |
| speech | 選填 | 本地語音文件的的二進制語音數(shù)據(jù) ,需要進行base64 編碼。與len參數(shù)連一起使用。 |
| len | 選填 | 本地語音文件的的字節(jié)數(shù),單位字節(jié) |
上傳示例(speech, len 參數(shù))
JSON格式POST上傳本地文件,固定頭部header:Content-Type:application/json,4K大小的pcm文件(普通話錄音)請求: speech 參數(shù)填寫為文件內(nèi)容base64后的結(jié)果:
{
"format":"pcm",
"rate":16000,
"channel":1,
"token":xxx,
"cuid":"baidu_workshop",
"len":4096,
"speech":"xxx", // xxx為 base64(FILE_CONTENT)
}
返回示例
{
"corpus_no":"6433214037620997779",
"err_msg":"success.",
"err_no":0,
"result":["北京科技館,"],
"sn":"371191073711497849365"
}
注意事項
- len 字段表示原始語音大小字節(jié)數(shù),不是 base64 編碼之后的長度。
核心代碼
# -*- coding: utf-8 -*-
"""
語音識別功能模塊(語音輸入)
參考:http://open.duer.baidu.com/doc/dueros-conversational-service/device-interface/voice-input_markdown
"""
import urllib.request
import json
import base64
def listen(file):
os.system('ffmpeg -y -i %s -acodec pcm_s16le -f s16le -ac 1 -ar 16000 16k_dai.pcm' % file)
#打開音頻文件,并進行編碼
f = open(WAVE_FILE, "rb")
speech = base64.b64encode(f.read()).decode('utf-8')
size = os.path.getsize(WAVE_FILE)
update = json.dumps({"format":WAVE_TYPE, "rate":VOICE_RATE, 'channel':1,'cuid':USER_ID,'token':token,'speech':speech,'len':size}).encode('utf-8')
update_length = len(update)
headers = { 'Content-Type' : 'application/json' }
url = "http://vop.baidu.com/server_api"
req = urllib.request.Request(url)
req.add_header("Content-Type", "application/json")
req.add_header("Content-Length", update_length)
r = urllib.request.urlopen(url=req, data=update)
t = r.read().decode('utf-8')
result = json.loads(t)
if result['err_msg']=='success.':
command = result['result'][0].encode('utf-8').decode()
return command
else:
return '我沒有聽懂你說什么?。?!'
#設(shè)置應(yīng)用信息
baidu_server = "https://openapi.baidu.com/oauth/2.0/token?"
grant_type = "client_credentials"
client_id = "*****************" #填寫API Key 需自行申請
client_secret = "****************" #填寫Secret Key
#合成請求token的URL
url = baidu_server+"grant_type="+grant_type+"&client_id="+client_id+"&client_secret="+client_secret
#獲取token
res = urllib.request.urlopen(url).read().decode()
data = json.loads(res)
token = data["access_token"]
print ( token )
#設(shè)置音頻屬性,根據(jù)百度的要求,采樣率必須為8000,壓縮格式支持pcm(不壓縮)、wav、opus、speex、amr
VOICE_RATE = 16000
WAVE_FILE = "16k_dai.pcm" #音頻文件的路徑
USER_ID = "hail_hydra" #用于標(biāo)識的ID,可以隨意設(shè)置
WAVE_TYPE = "pcm"
TTS(Text To Speak)
智能小車識別命令做出相應(yīng)動作后要進行反饋,同樣采用百度的語音合成API,將要說的話合稱為語音,這部分我們采用與上面的REST API不同的方式,采用Python SDK的方式獲取。
安裝語音合成 Python SDK
語音合成 Python SDK目錄結(jié)構(gòu)
├── README.md
├── aip //SDK目錄
│ ├── __init__.py //導(dǎo)出類
│ ├── base.py //aip基類
│ ├── http.py //http請求
│ └── speech.py //語音合成
└── setup.py //setuptools安裝
安裝使用Python SDK有如下方式:
- 如果已安裝pip,執(zhí)行pip install baidu-aip即可。
- 如果已安裝setuptools,執(zhí)行python setup.py install即可。
此種方式比較簡單,不做詳細介紹,直接上核心代碼
核心代碼
# -*- coding: utf-8-*-
import os
import sys
from imp import reload
reload(sys)
def say(what):
#配置賬戶信息
from aip import AipSpeech
""" 你的 APPID AK SK """
APP_ID = '10462370'
API_KEY =
SECRET_KEY =
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
result = client.synthesis( what, 'zh', 1, {
'vol': 5,
'per': 3,
})
# 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
if not isinstance(result, dict):
with open('auido.mp3', 'wb') as f:
f.write(result)
os.system("auido.mp3")
if __name__ == '__main__':
say('李博是最最最帥的')
控制代碼
這部分在教程人工智能-樹莓派小車(4)——通過語音玩轉(zhuǎn)智能小車已經(jīng)介紹過,原理相同,這里只放代碼。
def recognize():
file = '/home/pi/Rascar-DuerOS-Python-Client/ord.txt' # 讀取文件
f = open(file,'r')
out = f.read()
command = out.decode('unicode-escape').encode('utf-8')
print command
GPIO.output(LED_CTR, GPIO.LOW)
############################################
###############命令識別######################
############################################
if command.find(u"開") !=-1 and command.find(u"大") !=-1 and command.find(u"燈") !=-1:
print ("打開前大燈")
say(random.choice(['已經(jīng)幫您開燈','開燈了','好的,開燈','是,正在開燈']))
robot.Open_Flight()
GPIO.output(LED_CTR, GPIO.HIGH)
elif command.find(u"關(guān)") !=-1 and command.find(u"大") !=-1 and command.find(u"燈") !=-1:
print ("關(guān)閉前大燈")
say(random.choice(['已經(jīng)幫您關(guān)燈','關(guān)燈了','好的,關(guān)燈','是,正在關(guān)燈']))
robot.Close_Flight()
GPIO.output(LED_CTR, GPIO.HIGH)
elif command.find(u"前") !=-1 and command.find(u"進") !=-1:
print ("前進")
say(random.choice(['好的,前進','向前出發(fā)','是,前進一步']))
robot.Motor_Forward()
time.sleep(2)
robot.Motor_Stop()
GPIO.output(LED_CTR, GPIO.HIGH)
elif command.find(u"后") !=-1 and command.find(u"退") !=-1:
print ("后退")
say(random.choice(['好的,后退','倒車請注意','是,后退一點']))
robot.Motor_Backward()
time.sleep(2)
robot.Motor_Stop()
GPIO.output(LED_CTR, GPIO.HIGH)
elif command.find(u"左") !=-1 and command.find(u"轉(zhuǎn)") !=-1:
print ("左轉(zhuǎn)")
say(random.choice(['好嘞,向左轉(zhuǎn)','拐啦,拐啦,向左拐啦','好的,向左轉(zhuǎn)彎','是,向左轉(zhuǎn)彎']))
robot.Motor_TurnLeft()
p = GPIO.PWM(11, 3)
p.start(20)
time.sleep(0.5)
p.stop()
robot.Motor_Stop()
GPIO.output(11, GPIO.LOW)
GPIO.output(LED_CTR, GPIO.HIGH)
elif command.find(u"右") !=-1 and command.find(u"轉(zhuǎn)") !=-1:
print ("右轉(zhuǎn)")
say(random.choice(['好嘞,向右轉(zhuǎn)','拐啦,拐啦,向右拐啦','好的,向右轉(zhuǎn)彎','是,向右轉(zhuǎn)彎']))
robot.Motor_TurnRight()
p = GPIO.PWM(8, 3)
p.start(20)
time.sleep(0.5)
p.stop()
robot.Motor_Stop()
GPIO.output(8, GPIO.LOW)
GPIO.output(LED_CTR, GPIO.HIGH)
elif command.find(u"黑") !=-1 and command.find(u"線") !=-1:
print ("黑線")
robot.TrackLine()
elif command == "狀態(tài)":
os.system('cat deng.txt door.txt tv.txt >all.txt')
itchat.send_file("/home/pi/dai/command/all.txt",toUserName='filehelper')
return
語音聊天
語音聊天國內(nèi)做的比較好的有圖靈機器人、小i機器人,百度的小度也不錯,不過還沒有什么開放接口,所以目前在使用圖靈機器人(采用WEB API 2.0 接口),下面簡單介紹一下申請、使用方法等基本流程。
簡介
圖靈機器人API是在人工智能的核心能力(包括語義理解、智能問答、場景交互、知識管理等)的基礎(chǔ)上,為廣大開發(fā)者、合作伙伴和企業(yè)提供的一系列基于云計算和大數(shù)據(jù)平臺的在線服務(wù)和開發(fā)接口。
開發(fā)者可以利用圖靈機器人的API創(chuàng)建各種在線服務(wù),靈活定義機器人的屬性、編輯機器人的智能問答內(nèi)容,打造個人專屬智能交互機器人。
使用流程
注冊申請圖靈帳號
登錄圖靈機器人官方網(wǎng)站http://www.tuling123.com/,點擊右上角“注冊”按鈕進行注冊并激活帳號,如下圖所示:

獲取APIKEY
每一個激活用戶都可以通過圖靈機器人開放平臺獲取多個APIKEY(當(dāng)前每個用戶可最多獲取5個APIKEY),用戶可以根據(jù)自己的需要獲取不同的圖靈APIKEY來應(yīng)用于多種場景,獲取成功后就等于拿到了開啟圖靈服務(wù)的鑰匙。
登錄圖靈帳號,進入個人中心,在“我的機器人》機器人詳情》接入”頁面即可看到每一個機器人的API KEY,如下圖所示:

編碼方式
UTF-8(調(diào)用圖靈API的各個環(huán)節(jié)的編碼方式均為UTF-8)
接口地址
http://openapi.tuling123.com/openapi/api/v2
請求方式
HTTP POST
請求參數(shù)
請求參數(shù)格式為 json
請求示例:
{
"reqType":0,
"perception": {
"inputText": {
"text": "附近的酒店"
},
"inputImage": {
"url": "imageUrl"
},
"selfInfo": {
"location": {
"city": "北京",
"province": "北京",
"street": "信息路"
}
}
},
"userInfo": {
"apiKey": "",
"userId": ""
}
}
參數(shù)說明
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| reqType | int | N | - | 輸入類型:0-文本(默認(rèn))、1-圖片、2-音頻 |
| perception | - | Y | - | 輸入信息 |
| userInfo | - | Y | - | 用戶參數(shù) |
perception
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| inputText | - | N | - | 文本信息 |
| inputImage | - | N | - | 圖片信息 |
| inputMedia | - | N | - | 音頻信息 |
| selfInfo | - | N | - | 客戶端屬性 |
注意:輸入?yún)?shù)必須包含inputText或inputImage或inputMedia!
inputText
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| text | String | Y | 1-128字符 | 直接輸入文本 |
inputImage
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| url | String | Y | 圖片地址 |
inputMedia
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| url | String | Y | 音頻地址 |
selfInfo
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| location | - | N | - | 地理位置信息 |
location
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| city | String | Y | - | 所在城市 |
| province | String | N | - | 省份 |
| street | String | N | - | 街道 |
userInfo
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| apiKey | String | Y | 32位 | 機器人標(biāo)識 |
| userId | String | Y | 長度小于等于32位 | 用戶唯一標(biāo)識 |
| groupId | String | N | 長度小于等于64位 | 群聊唯一標(biāo)識 |
| userIdName | String | N | 長度小于等于64位 | 群內(nèi)用戶昵稱 |
輸出參數(shù)
輸出示例:
{
"intent": {
"code": 10005,
"intentName": "",
"actionName": "",
"parameters": {
"nearby_place": "酒店"
}
},
"results": [
{
"groupType": 1,
"resultType": "url",
"values": {
"url": "http://m.elong.com/hotel/0101/nlist/#indate=2016-12-10&outdate=2016-12-11&keywords=%E4%BF%A1%E6%81%AF%E8%B7%AF"
}
},
{
"groupType": 1,
"resultType": "text",
"values": {
"text": "親,已幫你找到相關(guān)酒店信息"
}
}
]
}
參數(shù)說明
| 參數(shù) | 類型 | 是否必須 | 取值范圍 | 說明 |
|---|---|---|---|---|
| intent | - | Y | - | 請求意圖 |
| results | - | N | - | 輸出結(jié)果集 |
intent
| 參數(shù) | 類型 | 是否包含 | 取值范圍 | 說明 |
|---|---|---|---|---|
| code | int | Y | - | 輸出功能code |
| intentName | String | N | - | 意圖名稱 |
| actionName | String | N | - | 意圖動作名稱 |
| parameters | String | N | - | 功能相關(guān)參數(shù) |
results
| 參數(shù) | 類型 | 是否包含 | 取值范圍 | 說明 |
|---|---|---|---|---|
| resultType | String | Y | 文本(text);連接(url);音頻(voice);視頻(video);圖片(image);圖文(news) | 輸出類型 |
| values | - | Y | - | 輸出值 |
| groupType | int | Y | - | ‘組’編號:0為獨立輸出,大于0時可能包含同組相關(guān)內(nèi)容 (如:音頻與文本為一組時說明內(nèi)容一致) |
核心代碼
#coding=utf8
import urllib.request
import json
KEY = 'd4473a5b08da492cad0bc98bb8bc77bb'
def get_response(msg):
apiUrl = 'http://openapi.tuling123.com/openapi/api/v2'
data = json.dumps({
"reqType":0,
"perception": {
"inputText": {
"text": msg
},
"selfInfo": {
"location": {
"city": "北京",
"province": "北京",
"street": "中關(guān)村南大街"
}
}
},
"userInfo": {
"apiKey": KEY,
"userId": "123555"
}
}).encode('utf-8')
try:
r = urllib.request.urlopen(url=apiUrl, data=data)
t = r.read().decode('utf-8')
result = json.loads(t)
return result
except:
return
if __name__ == '__main__':
#get_response('給我一張小狗照片').get('results')('image')
print (get_response('給我一張小狗照片')['results'][0]['values']['url'].encode('utf-8').decode())
完整代碼
所有的代碼都上傳到了我的GitHub上
Rascar-Wechat — A COOL Raspberry Intelligent car based on the Wechat
系列教程
人工智能-樹莓派小車(1)——DuerOS語音喚醒
人工智能-樹莓派小車(2)——GPIO接口介紹
人工智能-樹莓派小車(3)——GPIO控制小車
人工智能-樹莓派小車(4)——通過語音玩轉(zhuǎn)智能小車
人工智能-樹莓派小車(5)——用微信控制智能小車