人工智能-樹莓派小車(5)——用微信控制智能小車

之前所做的有一個特點就是需要在樹莓派上連接一個USB麥克風(fēng),通過這個麥克風(fēng)來進行語音的輸入,但是在實際使用場景上來看,這是不合理的,因此需要一個可以遠程操控智能小車的方案,因此萌發(fā)了將控制端移植到手機上的想法,移植到手機上也有幾個不同的方案。

  1. 通過Zigbee無線傳輸技術(shù)進行數(shù)據(jù)的傳輸
    優(yōu)點:易于進行擴展,可方便的與其他智能家居連接起來
    缺點:傳輸?shù)臄?shù)據(jù)量很小,不適用于語音數(shù)據(jù)以及圖像數(shù)據(jù)的傳遞
  2. 通過搭建一個服務(wù)器,開發(fā)一個手機APP,通過服務(wù)器進行數(shù)據(jù)的傳輸
    優(yōu)點:自己搭建服務(wù)器, 可控制性強
    缺點:開發(fā)門檻高(需要進行服務(wù)器的搭建以及手機應(yīng)用的開發(fā),不易實現(xiàn))以及使用門檻高(需要單獨在手機上安裝一個APP)
  3. 通過微信平臺,進行數(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,有四種搜索方式:

  1. 僅獲取自己的用戶信息
  2. 獲取特定UserName的用戶信息
  3. 獲取備注、微信號、昵稱中的任何一項等于name鍵值的用戶
  4. 獲取備注、微信號、昵稱分別等于相應(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,有兩種搜索方法:

  1. 獲取特定UserName的公眾號
  2. 獲取名字中含有特定字符的公眾號

如果兩項都做了特定,將會僅返回特定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,有兩種搜索方法:

  1. 獲取特定UserName的群聊
  2. 獲取名字中含有特定字符的群聊

如果兩項都做了特定,將會僅返回特定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)備工作。

  1. 首先要成為百度開發(fā)者
  2. 創(chuàng)建應(yīng)用
  3. 獲取密鑰
  4. 合成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,如下圖所示:


獲取APIKEY
編碼方式
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)——用微信控制智能小車

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容