學(xué)生畢業(yè)設(shè)計選題linux+qt嵌入式物聯(lián)網(wǎng)智能出行助手項目基于stm32mp157開發(fā)板
stm32mp157開發(fā)板FS-MP1A是華清遠(yuǎn)見自主研發(fā)的一款高品質(zhì)、高性價比的Linux+單片機(jī)二合一的嵌入式教學(xué)級開發(fā)板。開發(fā)板搭載ST的STM32MP157高性能微處理器,集成2個Cortex-A7核和1個Cortex-M4 核,A7核上可以跑Linux操作系統(tǒng),M4核上可以跑FreeRTOS、RT-Thread等實時操作系統(tǒng)。開發(fā)板搭配仿真器、顯示屏、攝像頭、資源擴(kuò)展板等豐富的擴(kuò)展模塊,可拓展物聯(lián)網(wǎng)、人工智能等相關(guān)技術(shù)學(xué)習(xí),還可以拓展豐富的項目實戰(zhàn),非常貼合企業(yè)當(dāng)下開發(fā)需求,是一款嵌入式Linux入門進(jìn)階必備開發(fā)板!
可學(xué)習(xí)技術(shù):嵌入式Linux應(yīng)用/系統(tǒng)/驅(qū)動開發(fā)、ARM裸機(jī)開發(fā)、Qt界面編程、STM32單片機(jī)、FreeRTOS、人工智能機(jī)器視覺等。其中ARM Cortex-A7裸機(jī)開發(fā)課程是華清遠(yuǎn)見獨(dú)有特色課程,可關(guān)注:https://www.bilibili.com/video/BV1Xe4y1i7vm/,持續(xù)更新中。

可實戰(zhàn)項目:14個Linux+Qt綜合項目案例,6個MP1A物聯(lián)網(wǎng)拓展項目
關(guān)注公眾號“華清遠(yuǎn)見在線實驗室”,回復(fù)“mp157項目”,即可領(lǐng)取項目配套文檔及源碼。
Linux+Qt綜合項目案例:華清遠(yuǎn)見stm32mp157開發(fā)板優(yōu)勢特色部分,包括音樂播放器、智慧家庭、智能工業(yè)電表、智能出行助手、智能貓眼、環(huán)境監(jiān)測、智能安防、智能語音識別等10余個項目案例,涉及家居、醫(yī)療、農(nóng)業(yè)多種應(yīng)用方向,在案例中使用了多種物聯(lián)網(wǎng)和嵌入式技術(shù),包括OT開發(fā)、linux應(yīng)用開發(fā)、linux驅(qū)動開發(fā)、物聯(lián)網(wǎng)云端接入、MQTT協(xié)議、json字符串等知識點(diǎn)。
基于Linux+Qt的智能出行助手項目
項目功能簡介:
1、 調(diào)用百度 AI 開發(fā)平臺 API 進(jìn)行語音識別,進(jìn)行語音控制傳感器的聯(lián)動,實現(xiàn)智能語音識別平臺的功能。
2、 調(diào)用天氣生活指數(shù) API,獲取不同城市每天的運(yùn)動指數(shù)、 舒適度指數(shù)、化妝指數(shù)等等。
3、 調(diào)用百度地圖 api,顯示不同城市的地圖。
4、 實現(xiàn)智能鬧鐘,定時提醒。?
開發(fā)平臺:
華清遠(yuǎn)見stm32mp157開發(fā)板豪華套餐(開發(fā)板+仿真器+五寸屏+攝像頭+資源擴(kuò)展板+tf卡+讀卡器)
項目實戰(zhàn):
Qt 開發(fā)環(huán)境搭建
主機(jī)開發(fā)環(huán)境說明
1) 本文檔主要介紹 linux 環(huán)境下的 Qt 程序開發(fā);
2) 主機(jī) Qt 版本為 5.14.1;
主機(jī) Qt 環(huán)境搭建及使用
Qt Creator 安裝
將 qt-creator-opensource-linux-x86_64-4.10.1.run(Qt 實驗源碼\工具軟件) 復(fù)制到 ubuntu 主機(jī)中,可以采用共享文件夾的方式也可以使用 tfp方式將文 件存入家目錄下的 Downloads 目錄。我們需要在終端中賦予安裝程序可執(zhí)行的權(quán)限

我們可以使用圖形化的文件管理器來查看

雙擊“qt-creator-opensource-linux-x86_64-4.10.1.run”圖標(biāo)運(yùn)行安裝程序。出現(xiàn)如下界面:

等待程序驗證完成后點(diǎn)擊“Next”

這里我們需要登錄或者注冊一個賬號,如果我們之前已經(jīng)注冊過直接登錄就可以。如果沒有注冊過則需要新注冊有一個賬號后登錄。這里筆者已經(jīng)注冊過賬號,所以直接登錄。 登錄成功后出現(xiàn)如下界面,點(diǎn)擊 Next

這里選擇安裝路徑

可以直接默認(rèn),Next

這路選擇安裝的組件,直接默認(rèn)即可

這里我們需要同意用戶協(xié)議

這個界面告訴我們安裝完成后需要占用的空間。點(diǎn)擊”Install”按鈕后開始安裝。

安裝完成后出現(xiàn)如下界面

點(diǎn)擊“Finish”按鈕后將彈出 Qt Creator 主界面

點(diǎn)擊“Cancel”按鈕后即可正常使用
?
Qt5.14.1 安裝
復(fù)制到 qt-opensource-linux-x64-5.14.1.run(Qt 實驗源碼\工具軟件)到 ubuntu 主機(jī)中,可以采用共享文件夾的方式也可以使用 tfp 方式將文件存入家目錄下的 Downloads 目錄。進(jìn)入所在文件夾,先給執(zhí)行權(quán)限
輸入命令
chmod +x ./qt-opensource-linux-x64-5.14.1.run
安裝在命令行輸入
./qt-opensource-linux-x64-5.14.1.run
會有可視化引導(dǎo)安裝,一直 next 就行了
在選擇安裝組件的時候要是不知道選擇那些就全選了 大概有 4 個 G 左右
下載 gcc 和 g++
sudo apt-get install gcc g++
?
下載 cmake
sudo apt-get install cmake
?
下載鏈接庫
sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev
?
Qt Creator 配置
1)配置 GCC
運(yùn)行 QtCreator 后,依次點(diǎn)擊"Tool"->"Options",出現(xiàn)選項對話框,在左側(cè)點(diǎn)擊"Kits",右 邊選擇"Compilers"標(biāo)簽。 檢查有沒有下圖標(biāo)注的 C++和 C ,般按上面步驟執(zhí)行后都會有

點(diǎn)擊右側(cè)"Add"按鈕,彈出下拉列表后,選擇"GCC"的"C"

填寫信息如下,"Name"為"Auto-GCC","Compiler path"點(diǎn)擊旁邊的"Browse.."按鈕選擇編譯器的路徑,例子中的路徑是 “/usr/bin/gcc”

2)配置 G++
點(diǎn)擊右側(cè)"Add"按鈕,彈出下拉列表后,選擇"GCC"的"C++",下面的文本框填寫"Name" 為"Auto-G++","Compiler path"點(diǎn)擊旁邊的"Browse.."按鈕選擇編譯器的路徑,例子中的路徑是" /usr/bin/g++"。


填寫完成后,點(diǎn)擊"Apply"。
3)配置 qmake
選擇"Qt Versions"標(biāo)簽,如果有下面紅框中的文本,可以跳過下面步驟

如果沒有,在右側(cè)點(diǎn)擊"Add..."

會彈出 qmake 路徑選擇對話框,這里以"/home/linux/Qt5.14.1/5.14.1/gcc_64/bin/qmake"為例子。 選擇”qmake”文件后,點(diǎn)擊"Open"按鈕

"Version name"改為" Qt %{Qt:Version} GCC"。然后點(diǎn)擊"Apply"按鈕。
?
4)配置 Kits
點(diǎn)擊左側(cè)"Kits",右側(cè)選擇"Kits"標(biāo)簽。檢查有沒有下圖紅框選中的文本,如果有可以跳過下面步驟

然后沒有,點(diǎn)擊 Add:
在彈出的對話框中"Name"為"Desktop","Device Type"選擇"Desktop"選項, "Sysroot"選擇目標(biāo)設(shè)備的系統(tǒng)目錄,"Compiler"選擇之前配置的名稱"Auto-GCC"和"Auto-G++","Qt version"選擇之前配 置的名稱"Qt 5.14.1GCC",其它默認(rèn)即可,最后點(diǎn)擊"Apply"和"OK"按鈕。?
Qt Creator 新建工程
注意:工程路徑最好不要包含中文、特殊字符、空格等。
我們可以新建一個“qt”文件夾,該文件夾用作我們以后存放源代碼。

打開 Qt Creator,在歡迎頁面點(diǎn)擊 “New”按鈕,來新建一個工程。

在出現(xiàn)的新建項目窗口中,我們選則“Application”->“Qt Widgets Application”,然后點(diǎn)擊右下方“Choose…”按鈕,來創(chuàng)建一個桌面 Qt 應(yīng)用。

我們在這里設(shè)置項目介紹和源碼位置,我們這里創(chuàng)建一個名為“HelloWorld”的示例項目,設(shè)置完成之后點(diǎn)擊 next

直接點(diǎn)擊 next

隨后進(jìn)行細(xì)節(jié)設(shè)置,主要設(shè)置要創(chuàng)建的源碼文件的基本類信息,包括類名等。這里我們可以根據(jù)自己的項目特點(diǎn)進(jìn)行設(shè)置。需要說明的一點(diǎn)就是基類的選擇,這里基類有 QMainWindow、QWidget、QDialog 三種,它們的不同之處如下:
QMainWindow 類提供一個帶有菜單條,工具條和一個狀態(tài)條的主應(yīng)用程序窗口。主窗口通常提供一個大的中央窗口部件,以及周圍菜單,工具條,和一個狀態(tài)欄。QMainWindow 窗口經(jīng)常被繼承,使得封裝中央部件,菜單,工具條,狀態(tài)欄等都變得很容易,當(dāng)用戶點(diǎn)擊它的時候,相應(yīng)的槽就會被調(diào)用;
QWidget 類是所有用戶界面對象的基類,窗口部件是用戶界面的一個基本單元,它從窗口系統(tǒng)接收鼠標(biāo),鍵盤和其他消息,并在屏幕上繪制自己。一個窗口部件可以被他的父窗口或者是其他窗口擋住一部分;
QDialog 類是對話框窗口的基類,對話框窗口主要用于短期任務(wù)和用戶進(jìn)行短期通訊的頂級窗口,QDialog 可以是模態(tài)對話框或者是非模態(tài)對話框。QDialog 支持?jǐn)U展并帶有返回值,他們可以帶有默認(rèn)值;我們在這里選擇 QDialog 類即可,點(diǎn)擊 next 完成類信息設(shè)置。

直接點(diǎn)擊 next 按鈕即可。

然后進(jìn)行工具選擇,該頁面可以選擇我們創(chuàng)建的工程可以使用的工具,選擇想要使用的編譯器模塊,例如下圖 。點(diǎn)擊 next

最后我們設(shè)置匯總信息,如果不需要版本控制等功能,直接點(diǎn)擊完成finish 即可。

隨后我們就進(jìn)入到了主界面,這時候 Qt 已經(jīng)幫我們做好了一些準(zhǔn)備工作,包括創(chuàng)建了一些文件,寫好了一些前置代碼等等。
我們可以點(diǎn)擊左邊 protect 欄,來查看我們的編譯選項。

我們可以在左下角選擇編譯 Debug 版或者 Release 版,即調(diào)試版或發(fā)行版。

左下角綠色剪頭是編譯并運(yùn)行,錘子是僅編譯,我們可以直接點(diǎn)擊綠色小箭頭將我們導(dǎo)入的工程編譯并運(yùn)行起來。

點(diǎn)擊運(yùn)行按鈕后,我們可以看到 HelloWorld 窗口運(yùn)行起來了。

導(dǎo)入工程
我們可以將已存在的 Qt 程序項目直接打開,這里以上一章節(jié)的HelloWorld 程序為例。首先我們確定源碼存在的位置,如 HelloWorld 程序源碼在 /home/linux/qt/helloworld 路徑下
點(diǎn)擊歡迎頁面的“Open” 按鈕可以打開已有的工程

找到我們剛才解壓好的源碼,選擇“helloworld.pro”文件并點(diǎn)擊打開

接下來我們就可以進(jìn)入到代碼編輯界面了。

左上角是項目欄,點(diǎn)擊項目名稱左邊的小箭頭可以展開項目目錄

我們可以點(diǎn)擊左邊項目欄,來查看我們的編譯選項。需注意的是構(gòu)建設(shè)置中的路徑應(yīng)與工程路徑處于同級目錄下。

我們可以在左下角選擇編譯 Debug 版或者 Release 版,即調(diào)試版或發(fā)行版。

左下角綠色剪頭是編譯并運(yùn)行,錘子是僅編譯,我們可以直接點(diǎn)擊綠色小箭頭將我們導(dǎo)入的工程編譯并運(yùn)行起來

點(diǎn)擊運(yùn)行按鈕后,我們可以看到 HelloWorld 窗口運(yùn)行起來了。

文件說明
通過上面兩個章節(jié),我們學(xué)習(xí)到了 Qt 程序的新建與導(dǎo)入的方法,也知道了Qt 會幫我們做一些基礎(chǔ)工作,比如幫我們建立了一些文件,那么這些文件都是干什么用的呢?我們以HelloWorld 程序來說明一下。

以“.pro”為后綴名的文件,為 Qt 的項目管理文件,存儲項目設(shè)置的文件;

“Qt += core gui”表示項目中加入 core gui 模塊。core gui 是 Qt 用于GUI 設(shè)計的類庫模塊,如果創(chuàng)建的是控制臺(console)應(yīng)用程序,就不需要添加 core gui。
Qt 類庫以模塊的形式組織各種功能的類,根據(jù)項目涉及的功能需求,在項目中添加適當(dāng)?shù)念悗炷K支持。例如,如果項目中使用到了涉及數(shù)據(jù)庫操作的類就需要用到 sql(數(shù)據(jù)庫)模塊,在 pro 文件中需要在后面加上 sql:
1 Qt += core gui sql
“greaterThan(QT_MAJOR_VERSION, 4): QT += widgets”,這是個條件執(zhí)行語句,表示當(dāng) Qt 主版本大于 4 時,才加入 widgets 模塊?!癟ARGET = HelloWorld”表示生成的目標(biāo)可執(zhí)行文件的名稱,即編譯后生成的可執(zhí)行文件是 HelloWorld.exe。
“TEMPLATE = app”表示項目使用的模板是 app,是一般的應(yīng)用程序。
后面的 SOURCES、HEADERS、FORMS 記錄了項目中包含的源程序文件、頭文件和窗體文件(.ui 文件)的名稱。這些文件列表是 Qt Creator 自動添加到項目管理文件里面的,用戶不需要手動修改。當(dāng)添加一個文件到項目,或從項目里刪除一個文件時,項目管理文件里的條目會自動修改。
文件夾“Header”中,存放的是所設(shè)計的窗體類的頭文件;
文件夾“Sources”中,存放著源碼文件。main.cpp 是實現(xiàn) main()函數(shù)的程序文件,HelloWorld.cpp 是 widget.h 里定義類的實現(xiàn)文件。C++中,任何窗體或界面組件都是用類封裝的,一個類一般有一個頭文件(.h 文件)和一個源程序文件(.cpp 文件);
文件夾“Forms”中,存放著界面設(shè)計文件,“.ui”文件是一個 XML 格式存儲的窗體上的元件及其布局的文件,雙擊項目文件目錄樹中的文件 ui,會打開一個集成在 Qt Creator 中的 Qt Designer 對窗體進(jìn)行可視化設(shè)計;

UI 設(shè)計器有以下一些功能區(qū)域:
組件面板:窗口左側(cè)是界面設(shè)計組件面板,分為多個組,如 Layouts、Buttons、Display Widgets 等,界面設(shè)計的常見組件都可以在組件面板里找到。
中間主要區(qū)域是待設(shè)計的窗體。如果要將某個組件放置到窗體上時,從組件面板上拖放一個組件到窗體上即可。
Signals 和 Slots 編輯器與 Action 編輯器是位于待設(shè)計窗體下方的兩個編輯器。Signals 和 Slots 編輯器用于可視化地進(jìn)行信號與槽的關(guān)聯(lián),Action 編輯器用于可視化設(shè)計 Action。
布局和界面設(shè)計工具欄:窗口上方的一個工具欄,工具欄上的按鈕主要實現(xiàn)布局和界面設(shè)計。
對象瀏覽器(Object Inspector):窗口右上方是 Object Inspector,用樹狀視圖顯示窗體上各組件之間的布局包含關(guān)系,視圖有兩列,顯示每個組件的對象名稱(ObjectName)和類名稱。
屬性編輯器(Property Editor):窗口右下方是屬性編輯器,是界面設(shè)計時最常用到的編輯器。屬性編輯器顯示某個選中的組件或窗體的各種屬性及其取值,可以在屬性編輯器里修改這些屬性的值。屬性編輯器的內(nèi)容分為兩列,左側(cè)為屬性的名稱,右側(cè)為屬性的值。屬性又分為多個組,實際上表示了類的繼承關(guān)系,位于下方的類屬性組繼承自位于上方的類屬性組;如果我們需要新建資源文件、源碼文件等,可以在項目文件夾出點(diǎn)擊鼠標(biāo)右鍵,選擇 Add New;如果我們有新的文件需要添加,可以在項目文件夾出點(diǎn)擊鼠標(biāo)右鍵,選擇 Add Existing Files。

幫助文檔
Qt 的幫助文檔是伴隨我們學(xué)習(xí) Qt 開發(fā)的好伙伴。在 Qt 開發(fā)過程中,我們會面臨圖形接口使用的問題,它不像 C 語言那樣就那么幾個函數(shù)接口,圖形接口的接口數(shù)量可以用海量來形容,常用的我們可能能記住,其它的就沒有必要去記了,用到什么就去幫助文檔查看用法是比較方便的。我們可以按 F1 按鍵,或通過上方導(dǎo)航欄的“help->contects”來進(jìn)入幫助文檔。

上方的前進(jìn)后退按鈕方便我們查看文檔,如返回到上一步,返回到下一步。

我們可以通過幫助文檔來查看以下幾個部分:類使用的相關(guān)介紹;查看相關(guān)類的使用介紹,我們可以先進(jìn)入到幫助文檔,然后在左上角選擇“Search”。筆者這里以 QWidget 類為例,輸入我們想要查找的類的名字,然后雙擊查找結(jié)果來查看說明。


也可以先將鼠標(biāo)移動到想要查詢的類的位置,如圖所示,將鼠標(biāo)移動至“QWidget”處,然后按“F1”鍵,即可跳轉(zhuǎn)到相應(yīng)的幫助文檔。


我們可以通過再按一次“F1”鍵來全窗口查看幫助文檔,按“Esc”鍵可以退出。

部分常用的成員元素包括以下幾項:
公有成員函數(shù):操作部件屬性的相關(guān)函數(shù);
公有槽函數(shù):Qt 類中已經(jīng)定義好的槽函數(shù),直接可與信號相連接;
信號:軟中斷,如按下按鈕觸發(fā) pressed() 信號等;
?保護(hù)成員函數(shù):通常事件所對應(yīng)的虛函數(shù)放在此處;
事件:常用事件,如操作鼠標(biāo)觸發(fā)的鼠標(biāo)事件;
滾動鼠標(biāo)滾輪,向下即可看到“Qwdget Class”類的相關(guān)說明了。
部分常用的成員元素包括以下幾項:
公有成員函數(shù):操作部件屬性的相關(guān)函數(shù);
公有槽函數(shù):Qt 類中已經(jīng)定義好的槽函數(shù),直接可與信號相連接;
信號:軟中斷,如按下按鈕觸發(fā) pressed() 信號等;
保護(hù)成員函數(shù):通常事件所對應(yīng)的虛函數(shù)放在此處;
事件:常用事件,如操作鼠標(biāo)觸發(fā)的鼠標(biāo)事件;
滾動鼠標(biāo)滾輪,向下即可看到“Qwdget Class”類的相關(guān)說明了。

1) 查看所用的部件的相應(yīng)成員函數(shù)。
我們可以查找到該類所用部件的相應(yīng)成員函數(shù)的使用方法、功能、參數(shù)、返回值等等,我們以“按鈕”控件,即“QPushButton Class”類為例,我們通過索引搜索的方式,來找到這個類

我們可以通過點(diǎn)擊“Public Functions” 來查看“QPushButton”這個類中的成員函數(shù)。

這里以“QPushButton(const QString &text, QWidget *parent =Q_NULLPTR)”為例,我們點(diǎn)擊函數(shù)名字可以進(jìn)入到函數(shù)詳情中。我們可以看到相應(yīng)的描述為:以“text”為顯示內(nèi)容,以“parent”為父對象,構(gòu)造一個push 按鈕。“text”“parent”為函數(shù)參數(shù),由于是構(gòu)造函數(shù),所以此函數(shù)沒有返回值。

還有一些函數(shù)是繼承自其它類的,例如“Public Functions”中有 21 個繼承自“QAbstractButton”類的函數(shù),我們點(diǎn)擊“QAbstractButton”即可查看。擊“QAbstractButton”即可查看


同樣我們可以點(diǎn)擊相應(yīng)的函數(shù)進(jìn)入查看詳情。如查看“void setText(const QString &text)”。

2) 查看所用的部件的信號。
我們這里還是以“PushButton”為例,我們點(diǎn)擊“Public Slots”。

可以看到“PushButton”本身有一個“void showMenu()”的信號,并且有很多繼承自其他類的信號。

一般來說我們用的“PushButton”的信號,最多的是用到其繼承自基類“QAbstractButton”中的幾個信號,分別是點(diǎn)擊(按下后抬起)、按壓(單按下)、釋放(單抬起)等

我們可以點(diǎn)擊相應(yīng)信號查看詳情

3) 查看所用的部件的事件(所對應(yīng)的虛函數(shù)如何編寫)。部件常用事件主要在 “QWidget”中聲明,選擇“Events”即可查看相關(guān)說明。
每個事件都對應(yīng)著事件函數(shù)。

點(diǎn)擊事件函數(shù)可查看詳情

語音識別模塊?
錄音
在 pro 文件添加
QT += network
QT += multimedia
在 mainwindow.h 頭文件添加下面定義
void RecorderStart(QString fileName);//開始錄音
void RecorderEnd();//結(jié)束錄音并轉(zhuǎn)換格式
QFile *outFile;//錄音時的變量
QAudioInput *my_audio;//錄音時的變量
QAudioFormat audioFormat;//錄音時的變量
Mainwindow.cpp 錄音函數(shù)實現(xiàn):
void MainWindow::RecorderStart(QString fileName)
{
?QAudioDeviceInfo device = QAudioDeviceInfo::defaultInputDevice();
?if(device.isNull())
?{
?QMessageBox::warning(NULL,"QAudioDeviceInfo","錄音設(shè)備不存
在");
?return;
?}
// 設(shè)置通道數(shù)
?audioFormat.setChannelCount(1);
// 設(shè)置編碼
audioFormat.setCodec("audio/pcm");
// 設(shè)置采樣頻率
?audioFormat.setSampleRate(16000);
// 設(shè)置位深
?audioFormat.setSampleSize(16);
// 判斷設(shè)備是否支持該格式
?if(!device.isFormatSupported(audioFormat)){ //當(dāng)前使用設(shè)備是否支持
?audioFormat = device.nearestFormat(audioFormat); //轉(zhuǎn)換為最接近格
式
?}
// 創(chuàng)建錄音對象
?my_audio = new QAudioInput(audioFormat,this);
?outFile = new QFile;
?outFile->setFileName(fileName); //語音原始文件
?outFile->open(QIODevice::WriteOnly);
// 開始錄音
?my_audio->start(outFile);
}?
結(jié)束錄音函數(shù)實現(xiàn)
/**********************
* 結(jié)束錄音并轉(zhuǎn)換格式
**********************/
void MainWindow::RecorderEnd()
{
// 結(jié)束錄音
?my_audio->stop();
?outFile->close();
?delete outFile;
outFile =NULL;
?delete my_audio;
?my_audio = NULL;
}
點(diǎn)擊釋放按鈕槽函數(shù)
右鍵按鈕,轉(zhuǎn)到槽,選擇 pressed 和 released 點(diǎn)擊 ok。會在 mainwindow.cpp生成 on_pushButton_video_pressed()和 on_pushButton_video_released()槽函數(shù)。



在兩個槽函數(shù)分別實現(xiàn)如上圖所示
申請百度 AI 開發(fā)平臺語音識別應(yīng)用
語音識別是利用百度的 API 在線識別。所以需要申請項目 ID。
進(jìn)入百度的 API 平臺:https://ai.baidu.com/
在產(chǎn)品服務(wù)下選擇語音識別:

點(diǎn)擊立即使用:

申請賬號點(diǎn)擊登錄:

點(diǎn)擊創(chuàng)建應(yīng)用:

輸入應(yīng)用名稱、應(yīng)用描述,點(diǎn)擊立即創(chuàng)建:

點(diǎn)擊返回應(yīng)用列表:

獲取 AppID、API Key 和 Secret Key

我們記住其中的 API Key 和 Secret Key,下面會用到。
HTTP 請求類實現(xiàn)
我們錄好的音頻文件需要通過 HTTPS 協(xié)議上傳到百度 AI 開發(fā)平臺進(jìn)行語音識別,之后 AI 平臺會返回給我們識別的結(jié)果。
http 類只需要封裝一個方法
bool post_sync(QString url,QMap<QString,QString>header,QByteArray
requestData,QByteArray &replyData);
使用這個方法去 URL 發(fā)送請求會收到 URL 的返回值。
http.h
#ifndef HTTP_H
#define HTTP_H
#include <QObject>
#include <QMap>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>
class Http : public QObject
{
?Q_OBJECT
public:
?explicit Http(QObject *parent = nullptr);
?bool post_sync(QString url,QMap<QString,QString>header,QByteArray
requestData,QByteArray &replyData);
};
#endif // HTTP_H
http.cpp
這個方法的第一個參數(shù)是 post 方法發(fā)送請求的 URL,第二個參數(shù)是請求的方法頭,第三個參數(shù)是請求的數(shù)據(jù),第四個參數(shù)是返回的數(shù)據(jù)。
這里要說的是必須要設(shè)置 openssl 簽名配置,否則在 ARM 上會報錯。?
bool Http::post_sync(QString url,QMap<QString,QString>header,QByteArray
requestData,QByteArray &replyData)
{
// 發(fā)送請求的對象
?QNetworkAccessManager manager;
// 請求 對象
?QNetworkRequest request;
?request.setUrl(url);
?QMapIterator<QString,QString> it(header);
?while (it.hasNext()) {
?it.next();
?request.setRawHeader(it.key().toLatin1() ,it.value().toLatin1());
?}
//設(shè)置 openssl 簽名配置,否則在 ARM 上會報錯
?QSslConfiguration conf = request.sslConfiguration();
?conf.setPeerVerifyMode(QSslSocket::VerifyNone);
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
?conf.setProtocol(QSsl::TlsV1_0);
#else
?conf.setProtocol(QSsl::TlsV1);
#endif
?request.setSslConfiguration(conf);
QNetworkReply *reply = manager.post(request,requestData);
?QEventLoop l;
?//一旦服務(wù)器返回,reply 會發(fā)出信號
?connect(reply,&QNetworkReply::finished,&l,&QEventLoop::quit);
?l.exec();
?if(reply != nullptr && reply->error() == QNetworkReply::NoError)
?{
?replyData = reply->readAll();
?return true;
?}
?else
?{
?qDebug()<<"request error!";
?return false;
?}
}
發(fā)送請求
這里需要向兩個 URL 發(fā)送兩個請求,第一個請求是把我們 4.2.3 創(chuàng)建應(yīng)用得到的 API Key 和 Secret Key 組合成一個 URL 獲取 access_token,第二個請求是把音頻文件發(fā)送請求到語音識別的 URL 才能返回語音識別的結(jié)果。
我們新建一個類 Speech
Speech.h
這里我們把 API Key 和 Secret Key 作為參數(shù)傳到 const QString baiduTokenUrl 里面去。把主機(jī)名和獲取的 access_token 做為參數(shù)傳入 const QString baiduSpeechUrl。
#include <QObject>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QFile>
#include "http.h"
#include <QHostInfo>
// 獲取 Access Token
const QString baiduTokenUrl =
"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=
%1&client_secret=%2&";
const QString client_id = "我們創(chuàng)建應(yīng)用的 API Key";
const QString client_secret = "我們創(chuàng)建應(yīng)用的 Secret Key";
// 語音識別 url
const QString baiduSpeechUrl =
"https://vop.baidu.com/server_api?dev_pid=1537&cuid=%1&token=%2";
class Speech:public QObject
{
?Q_OBJECT
public:
?Speech();
?QString speechIdentify(QString fileName);
private:
?QString getJsonValue(QByteArray ba,QString key);
};
#endif // SPEECH_H
Speech.cpp
QString Speech::speechIdentify(QString fileName)
{
// 獲取 Access Token
?QString tokenUrl =QString(baiduTokenUrl).arg(client_id).arg(client_secret);
Http my_http;
?QMap<QString,QString>header;
?header.insert(QString("Content-Type"),QString("audio/pcm;rate=16000"));
?QByteArray requestData;//請求內(nèi)容
?QByteArray replyData;//url 返回內(nèi)容
?qDebug()<<tokenUrl;
?bool result = my_http.post_sync(tokenUrl,header,requestData,replyData);
?if(result) {
?QString key = "access_token";
?QString accessToken =getJsonValue(replyData,key);
?qDebug()<<accessToken;
?// 語音識別
?QString speechUrl =
QString(baiduSpeechUrl).arg(QHostInfo::localHostName()).arg(accessToken);
?QFile file;
?file.setFileName(fileName);
?file.open(QIODevice::ReadOnly);
?requestData = file.readAll();
?file.close();
?replyData.clear();
// 再次發(fā)起請求
?result = my_http.post_sync(speechUrl,header,requestData,replyData);
?if(result) {
?QString key = "result";
?QString retText =getJsonValue(replyData,key);
?qDebug()<<retText;
?return retText;
?}
else{
?return NULL;
?}
?}
?else {
?return "error";
?}
}
解析返回的數(shù)據(jù)
返回的數(shù)據(jù)是這種 Json 類型的,我們只需要獲取里邊 result 的值就能得到
我們想要的結(jié)果了。
{"err_no":0,"err_msg":"success.","corpus_no":"15984125203285346378","sn":"
481D633F-73BA-726F-49EF-8659ACCC2F3D","result":["北京天氣"]}
QString Speech::getJsonValue(QByteArray ba,QString key)
{
?QJsonParseError parseError;
?QJsonDocument jsondocument =
QJsonDocument::fromJson(ba,&parseError);
?if(parseError.error ==QJsonParseError::NoError)
?{
?if(jsondocument.isObject())
?{
?QJsonObject jsonObject = jsondocument.object();
?if(jsonObject.contains(key)){
?QJsonValue jsonvalue = jsonObject.value(key);
?if(jsonvalue.isString())
?return jsonvalue.toString();
?else if(jsonvalue.isArray()){
?QJsonArray arr = jsonvalue.toArray();
?QJsonValue val =arr.at(0);
return val.toString();
?}
?}
?}
?}
?return "";
}
MainWindow 類調(diào)用函數(shù)
我們在釋放按鈕的槽函數(shù)里添加以下代碼
void MainWindow::on_pushButton_video_released()
{
?ui->pushButton_video->setText("按住說話");
?RecorderEnd();
?Speech my_speech;
?QString text =my_speech.speechIdentify("./1.pcm");
?ui->textEdit->append(text);
?audioCtrl(text);
}
語音控制設(shè)備聯(lián)動
代碼如下
void MainWindow::audioCtrl(QString text)
{
?if(text == "開燈。")
?{
?system("echo 1 >/sys/class/leds/user1/brightness");
?system("echo 1 >/sys/class/leds/user2/brightness");
?system("echo 1 >/sys/class/leds/user3/brightness");
?ui->textEdit_2->setText("燈已打開");
?}
?else if(text == "關(guān)燈。")
?{
?system("echo 0 >/sys/class/leds/user1/brightness");
?system("echo 0 >/sys/class/leds/user2/brightness");
?system("echo 0 >/sys/class/leds/user3/brightness");
?ui->textEdit_2->setText("燈已關(guān)閉");
?}
?else if(text == "報警。")
?{
?int fd;
?struct input_event event;
?struct timeval time;
?fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);
?event.type = EV_SND;
?event.code = SND_TONE;
?event.value = 1000;
?time.tv_sec = 1;
?time.tv_usec = 0;
?event.time = time;
?write(fd, &event, sizeof(struct input_event));
?ui->textEdit_2->setText("蜂鳴器已報警");
?}
else if(text == "關(guān)閉。")
?{
?int fd;
?struct input_event event;
?struct timeval time;
?fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);
?event.type = EV_SND;
?event.code = SND_TONE;
?event.value = 0;
?time.tv_sec = 0;
?time.tv_usec = 0;
?event.time = time;
?write(fd, &event, sizeof(struct input_event));
?ui->textEdit_2->setText("蜂鳴器報警已關(guān)閉");
?}
?else if(text == "關(guān)風(fēng)扇。")
?{
?unsigned char arg;
?Ioctl(EXIT_FAN,&arg);
?ui->textEdit_2->setText("風(fēng)扇已關(guān)閉");
?}
?else if(text == "開風(fēng)扇。")
?{
?unsigned char arg;
?Ioctl(EXIT_FAN,&arg);
?Ioctl(INIT_FAN,&arg);
?Ioctl(FAN_UP,&arg);
?ui->textEdit_2->setText("風(fēng)扇已打開");
?}
else if(text == "溫度。")
?{
?QString tem = temCollect();
?ui->textEdit_2->setText(QString(" 此 時 溫 度
為:").append(tem).append("'C"));
?}
?else if(text == "濕度。")
?{
?QString hum = humCollect();
?ui->textEdit_2->setText(QString(" 此時濕度
為:").append(hum).append("%"));
?}
}
智慧生活模塊
創(chuàng)建 API 應(yīng)用
瀏覽器進(jìn)入 https://dev.qweather.com/;注冊賬號并登陸,點(diǎn)擊進(jìn)入控制臺

進(jìn)入控制臺后,點(diǎn)擊應(yīng)用管理。

點(diǎn)擊創(chuàng)建應(yīng)用,選擇免費(fèi)開發(fā)板


填寫天氣數(shù)據(jù)應(yīng)用名稱后選擇 WebAPI,自定義天氣數(shù)據(jù)應(yīng)用名稱。



完成上述操作后,把 key 復(fù)制下來,后邊代碼需要用到。
?

方法獲取 API 的 JOSN 數(shù)據(jù)
我們將 key 填寫到下面的 URL 里面,使用 get 方法就能從 API 爬蟲下JOSN 數(shù)據(jù)來了
你的 KEY其中請求參數(shù)
Location:需要查詢地區(qū)的 LocationID 或以英文逗號分隔的經(jīng)度,緯度坐標(biāo)(十進(jìn)制),LocationID 可通過城市搜索服務(wù)獲取。例如 location=101010100
Key:用戶認(rèn)證 key,即上面獲取到的 key。
Type:生活指數(shù)的類型 ID,包括洗車指數(shù)、穿衣指數(shù)、釣魚指數(shù)等。可以一次性獲取多個類型的生活指數(shù),多個類型用英文,分割。例如 type=3,5。具體生活指數(shù)的 ID 和等級參考生活指數(shù)常量。各項生活指數(shù)并非適用于所有城市。
所以我們以參數(shù)的形式將城市的 LocationID 填入 URL 就能獲取不同城市的生活指標(biāo)。
具體代碼參考下面:
//get 方法獲取信息
void LifeWidget::sendQuest(QString cityStr)
{
QString key = "您申請的 key";
?QString quest_url =
"https://devapi.qweather.com/v7/indices/1d?type=0&location=%1&key=%2";
?quest_url = quest_url.arg(cityStr).arg(key);
?QNetworkRequest quest;
?quest.setUrl(QUrl(quest_url));
?//設(shè)置 openssl 簽名配置,否則在 ARM 上會報錯
?QSslConfiguration conf = quest.sslConfiguration();
?conf.setPeerVerifyMode(QSslSocket::VerifyNone);
?#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
?conf.setProtocol(QSsl::TlsV1_0);
?#else
?conf.setProtocol(QSsl::TlsV1);
?#endif
?quest.setSslConfiguration(conf);
?manager->get(quest); /*發(fā)送 get 網(wǎng)絡(luò)請求*/
}
//數(shù)據(jù)接收槽函數(shù)
void LifeWidget::replyFinished(QNetworkReply *reply)
{
?replyall = reply->readAll();
?reply->deleteLater(); //銷毀請求對象
}
void LifeWidget::init_networt_life()
{
?manager = new QNetworkAccessManager(this);
?connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(replyFinished(QNetworkReply*)));//關(guān)聯(lián)信號和槽
}
解析 JOSN 數(shù)據(jù)
{
?"code": "200",
?"updateTime": "2021-02-06T16:36+08:00",
?"fxLink": "http://hfx.link/2ax2",
?"daily": [
?{
?"date": "2021-02-06",
?"type": "2",
?"name": "洗車指數(shù)",
?"level": "2",
?"category": "較適宜",
?"text": "較適宜洗車,未來一天無雨,風(fēng)力較小,擦洗一新的汽車至少
能保持一天。"
?},
?{
?"date": "2021-02-06",
?"type": "1",
?"name": "運(yùn)動指數(shù)",
?"level": "3",
?"category": "較不宜",
?"text": "天氣較好,但考慮天氣寒冷,推薦您進(jìn)行室內(nèi)運(yùn)動,戶外運(yùn)動
時請注意保暖并做好準(zhǔn)備活動。"
?}
?],
?"refer": {
?"sources": [
?"Weather China"
?],
"license": [
?"commercial license"
?]
?}
}
?
我們通過 get 方法獲取到的 JOSN 數(shù)據(jù)如上所示。只需要解析 key 為 daily的值即可。其中 daily 的值是一個數(shù)組類型的數(shù)據(jù),只需要取出我們需要的即可。
void DetaInfo::setInfo(QString info,int type)
{
?qDebug()<<"setINfo";
?QJsonParseError err;
?QJsonDocument json_recv = QJsonDocument::fromJson(info.toUtf8(),
&err);//解析 json 對象
?if (!json_recv.isNull())
?{
?QJsonObject object = json_recv.object();
?if (object.contains("daily"))
?{
?QJsonValue value = object.value("daily"); // 獲取指定 key 對
應(yīng)的 value
?if (value.isArray())
?{
?QJsonObject today_life = value.toArray().at(type).toObject();
?QString category = today_life.value("category").toString();
?QString text = today_life.value("text").toString();
?ui->label_category->setText(category);
?ui->label_text->setText(text);
?}
?}
?}
}
出行地圖模塊
申請百度地圖 API 秘鑰
進(jìn)入百度地圖官網(wǎng) https://lbsyun.baidu.com/

點(diǎn)擊進(jìn)入控制臺

這里需要登錄百度賬號,掃碼或者輸入用戶名密碼登錄即可。

登錄成功后點(diǎn)擊應(yīng)用管理下的我的應(yīng)用。

點(diǎn)擊創(chuàng)建應(yīng)用

自定義應(yīng)用名稱后,應(yīng)用類型選擇瀏覽器端,在白名單輸入框輸入*

這里就是我們需要的 AK 秘鑰。

map.html
復(fù)制百度地圖 API 源碼。

新建 map.html

將上面 API 的源碼復(fù)制到嗎 map.html

將代碼里面的紅框里的您的秘鑰替換剛才申請的 AK 即可。
在 map.html 文件添加方法
添加函數(shù),通過 QT 程序傳參來改變地圖路線的起點(diǎn),途經(jīng)點(diǎn),終點(diǎn)。

QT端實現(xiàn)
這里使用了 webkit 模塊,在 pro 文件中添加 QT += webkit webkitwidgets

具體代碼如下
void MainWindow::mapinit()
{
QWebSettings *settings = QWebSettings::globalSettings();
?settings->setAttribute(QWebSettings::PluginsEnabled, true);//允許插件
?settings->setAttribute(QWebSettings::JavascriptEnabled, true);//JavaScript
?settings->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);//
?settings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
?settings->setFontFamily(QWebSettings::FixedFont,"幼圓");
?ui->webView->setStyle(new CustomStyle());
?ui->webView->load(QUrl("qrc:/map.html"));
?connect(ui->webView->page()->mainFrame(),
SIGNAL(javaScriptWindowObjectCleared()), this,
SLOT(populateJavaScriptWindowObject()));
}
void MainWindow::populateJavaScriptWindowObject()
{
ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("Myweb
kit", this);
}
void MainWindow::onBtnCallJSClicked()
{
?QString strVal = QString("callfromqt(要傳的參數(shù));"));
?ui->webView->page()->mainFrame()->evaluateJavaScript(strVal);
}
智能鬧鐘模塊
開啟線程,檢測時間
這里設(shè)置了四個鬧鐘,即在線程類里邊設(shè)置了四個全局變量(鬧鐘時間)。當(dāng)前時間戳等于設(shè)置的時間戳后設(shè)置蜂鳴器響起。
void TimeAlarmClock::run()
{
?while (1) {
?QDateTime time = QDateTime::currentDateTime(); //獲取當(dāng)前時間
?uint timeT = time.toTime_t(); //將當(dāng)前時間轉(zhuǎn)為時間戳
// qDebug()<<timeT<<alarm_clocktime1;
?if(alarm_clocktime1==timeT){
?beep_on();
// qDebug()<<"open";
?}else{
?}
?if(alarm_clocktime2==timeT){
?beep_on();
?}else{
?}
?if(alarm_clocktime3==timeT){
?beep_on();
?}else{
?}
?if(alarm_clocktime4==timeT){
?beep_on();
?}else{
?}
?}
}
void TimeAlarmClock::beep_on()
{
?int fd;
?struct input_event event;
?struct timeval time;
?fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);
?event.type = EV_SND;
?event.code = SND_TONE;
?event.value = 1000;
?time.tv_sec = 1;
?time.tv_usec = 0;
?event.time = time;
?write(fd, &event, sizeof(struct input_event));
?close(fd);
}
提交鬧鐘時間
使用 QdateTimeEdit 設(shè)置鬧鐘時間,點(diǎn)擊按鈕后,將鬧鐘時間設(shè)置到線程中的全局變量中
void MainWindow::on_time_btn1_clicked()
{
?if(ui->time_btn1->text()==" "){
?ui->time_btn1->setText("\n");
?timeAlarmClock.alarm_clocktime1 =
ui->dateTimeEdit_1->dateTime().toTime_t();
?}else{
?ui->time_btn1->setText(" ");
?timeAlarmClock.alarm_clocktime1 = 0;
?}
}?
實驗源碼
源碼路徑【11-出行助手\實驗源碼\04-Aivideo】
注意事項
1.在開發(fā)板運(yùn)行時,需要導(dǎo)入中文字庫,否則會因為識別不了中文。
將【11-出行助手\工具軟件\wqy-zenhei-0.9.47-nightlybuild.tar.gz 或wqy-zenhei-0.8.38-1.tar.gz】復(fù)制到 ubuntu 下。并使用 scp 命令將文件拷貝到開發(fā)板的 usr/share/fonts 目錄下,使用 tar 命令解壓后即可
linux@ubuntu:~$ scp wqy-zenhei-0.8.38-1.tar.gz
root@192.168.10.128:/usr/share/fonts/

2.如果使用 mipi 五寸屏運(yùn)行此項目,需要進(jìn)行屏幕旋轉(zhuǎn)以適應(yīng)屏幕,具體步驟如下:
在/etc/profile.d/qt-eglfs.sh 添加環(huán)境變量如下


下面變量的 event0 設(shè)備需要填實際的觸摸屏設(shè)備
這里即填 event0
export QT_QPA_EGLFS_ROTATION=90
export QT_QPA_EGLFS_NO_LIBINPUT=1
export
QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0:rotate=90