ROS2 + 科大訊飛 初步實現機器人語音控制

環境配置:

? ? ? ? 電腦端:?ubuntu22.04實體機作為上位機

? ? ????ROS版本:ros2-humble

? ??????實體機器人: STM32 + 思嵐A1激光雷達

? ? ? ? 科大訊飛語音SDK?訊飛開放平臺-以語音交互為核心的人工智能開放平臺

實現步驟:

? ? ? ? 1. 下載和處理科大訊飛語音模塊

? ? ? ? (1)進入官網的控制臺

? ? ? ?

?(2)在左側導航欄中選擇 語音識別-> 語音聽寫

? ? ? ? (3)下載語音模塊

?

?2.科大訊飛SDK的處理

新建一個工作空間,里面新建兩個文件夾 src? ?voice_ros2

將SDK壓縮包解壓后的文件,放入voice_ros2中,進入sample目錄的iat_online_record_sample目錄下,運行下面的命令

source 64bit_make.sh

在bin目錄下執行對應的可執行文件了?

./iat_online_record_sample

?

?如果遇到下列問題:error while loading shared libraries: libmsc.so: cannot open shared object file: No such file or directory


就把在終端中進入下列目錄中

?執行命令:

sudo cp libmsc.so /usr/local/lib
sudo ldconfig
3.上位機實現

?

src 文件夾中放的是 兩個功能包,base 中是stm32的ROS2驅動包,teleop_twist_keyboard是github上下載的鍵盤控制節點功能包,地址如下:

GitHub - ros2/teleop_twist_keyboard at ardent

這個目錄下的文件是SDK解壓后的文件,其中 紅框中的voice.py是也單獨編寫的文件

import subprocess
import multiprocessing
import timedef run_iat_online_record_sample(queue):process = subprocess.Popen(["./bin/iat_online_record_sample"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, )# Communicate with the processstdout, _ = process.communicate(input=b"0\n1\n")# Put the result into the queuequeue.put(stdout.decode('utf-8'))def main():while True:# Create a queue for communication between processesqueue = multiprocessing.Queue()# Start the processprocess = multiprocessing.Process(target=run_iat_online_record_sample, args=(queue,))process.start()# Wait for the process to finish and get the result from the queueprocess.join()result = queue.get()# Print the resultprint("Result:", result)# Save the result to a text file, clearing the file firstwith open("result.txt", "w") as f:f.write(result)# Ask user whether to continue recognitioncontinue_recognition = input("是否繼續識別? (0: 結束, 1: 繼續): ")if continue_recognition == "0":breakif __name__ == "__main__":main()

這個文件運行后會在當前目錄生成一個result.txt文件,如下圖,這個文件的內容每次識別之后都會更新,鍵盤節點就是通過獲取這個文件的數據來通過語音控制機器人移動的

4.修改teleop_twist_keyboard.py文件

在鍵盤控制的代碼前添加讀取文件數據的代碼


這里將剛剛識別到的語音過濾后存儲在voice_command[0]中,以供后續使用,下面會通過判斷voice_command[0]中的值來進行不同的操作

import sys
import threading
import time
import os
from std_msgs.msg import String
import geometry_msgs.msg
import rclpyif sys.platform == 'win32':import msvcrt
else:import termiosimport ttymsg = """
This node takes keypresses from the keyboard and publishes them
as Twist/TwistStamped messages. It works best with a US keyboard layout.
---------------------------
Moving around:u    i    oj    k    lm    ,    .For Holonomic mode (strafing), hold down the shift key:
---------------------------U    I    OJ    K    LM    <    >t : up (+z)
b : down (-z)anything else : stopq/z : increase/decrease max speeds by 10%
w/x : increase/decrease only linear speed by 10%
e/c : increase/decrease only angular speed by 10%CTRL-C to quit
"""moveBindings = {'i': (1, 0, 0, 0),'o': (1, 0, 0, -1),'j': (0, 0, 0, 1),'l': (0, 0, 0, -1),'u': (1, 0, 0, 1),',': (-1, 0, 0, 0),'.': (-1, 0, 0, 1),'m': (-1, 0, 0, -1),'O': (1, -1, 0, 0),'I': (1, 0, 0, 0),'J': (0, 1, 0, 0),'L': (0, -1, 0, 0),'U': (1, 1, 0, 0),'<': (-1, 0, 0, 0),'>': (-1, -1, 0, 0),'M': (-1, 1, 0, 0),'t': (0, 0, 1, 0),'b': (0, 0, -1, 0),
}speedBindings = {'q': (1.1, 1.1),'z': (.9, .9),'w': (1.1, 1),'x': (.9, 1),'e': (1, 1.1),'c': (1, .9),
}def getKey(settings):if sys.platform == 'win32':# getwch() returns a string on Windowskey = msvcrt.getwch()else:tty.setraw(sys.stdin.fileno())# sys.stdin.read() returns a string on Linuxkey = sys.stdin.read(1)termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)return keydef saveTerminalSettings():if sys.platform == 'win32':return Nonereturn termios.tcgetattr(sys.stdin)def restoreTerminalSettings(old_settings):if sys.platform == 'win32':returntermios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)def vels(speed, turn):return 'currently:\tspeed %s\tturn %s ' % (speed, turn)def main():settings = saveTerminalSettings()rclpy.init()node = rclpy.create_node('teleop_twist_keyboard')# parametersstamped = node.declare_parameter('stamped', False).valueframe_id = node.declare_parameter('frame_id', '').valueif not stamped and frame_id:raise Exception("'frame_id' can only be set when 'stamped' is True")if stamped:TwistMsg = geometry_msgs.msg.TwistStampedelse:TwistMsg = geometry_msgs.msg.Twistpub = node.create_publisher(TwistMsg, 'cmd_vel', 10)voice_command = [None]  # Initializing as a listspinner = threading.Thread(target=rclpy.spin, args=(node,))spinner.start()speed = 0.5turn = 1.0x = 0.0y = 0.0z = 0.0th = 0.0status = 0.0twist_msg = TwistMsg()if stamped:twist = twist_msg.twisttwist_msg.header.stamp = node.get_clock().now().to_msg()twist_msg.header.frame_id = frame_idelse:twist = twist_msgtry:print(msg)print(vels(speed, turn))while True:print("當前工作路徑:", os.getcwd())with open('./voice_ros2/result.txt', 'r') as f:# with open('/home/lsg/xufen3_ws/voice_ros2/result.txt', 'r') as f:for line in f:if line.startswith('Result: ['):start = line.find('[')end = line.find(']')if start != -1 and end != -1:voice_command[0] = line[start + 1:end].strip()print("voice_command", voice_command[0])# Clearing the content of result.txtopen('./voice_ros2/result.txt', 'w').close()# open('/home/lsg/xufen3_ws/voice_ros2/result.txt', 'w').close()breakkey = getKey(settings)# print("鍵盤控制按鍵輸出", key)if key in moveBindings.keys():x = moveBindings[key][0]y = moveBindings[key][1]z = moveBindings[key][2]th = moveBindings[key][3]elif key in speedBindings.keys():speed = speed * speedBindings[key][0]turn = turn * speedBindings[key][1]print(vels(speed, turn))if (status == 14):print(msg)status = (status + 1) % 15elif voice_command[0] is not None:if voice_command[0] == "小車后退":print("語音控制小車前進", voice_command[0])x = moveBindings['i'][0]y = moveBindings['i'][1]z = moveBindings['i'][2]th = moveBindings['i'][3]elif voice_command[0] == "小車前進":print("語音控制小車后退", voice_command[0])x = moveBindings[','][0]y = moveBindings[','][1]z = moveBindings[','][2]th = moveBindings[','][3]elif voice_command[0] == "小車左轉":print("語音控制小車左轉", voice_command[0])x = moveBindings['j'][0]y = moveBindings['j'][1]z = moveBindings['j'][2]th = moveBindings['j'][3]elif voice_command[0] == "小車右轉":print("語音控制小車右轉", voice_command[0])x = moveBindings['l'][0]y = moveBindings['l'][1]z = moveBindings['l'][2]th = moveBindings['l'][3]elif voice_command[0] == "小車停":print("語音控制小車停", voice_command[0])x = moveBindings['k'][0]y = moveBindings['k'][1]z = moveBindings['k'][2]th = moveBindings['k'][3]voice_command[0] = Noneelse:x = 0.0y = 0.0z = 0.0th = 0.0if (key == '\x03'):breakif stamped:twist_msg.header.stamp = node.get_clock().now().to_msg()twist.linear.x = x * speedtwist.linear.y = y * speedtwist.linear.z = z * speedtwist.angular.x = 0.0twist.angular.y = 0.0twist.angular.z = th * turnpub.publish(twist_msg)# Print timestamp every secondtime.sleep(1)print("時間戳:", time.time())except Exception as e:print(e)finally:if stamped:twist_msg.header.stamp = node.get_clock().now().to_msg()twist.linear.x = 0.0twist.linear.y = 0.0twist.linear.z = 0.0twist.angular.x = 0.0twist.angular.y = 0.0twist.angular.z = 0.0pub.publish(twist_msg)rclpy.shutdown()spinner.join()restoreTerminalSettings(settings)if __name__ == '__main__':main()
5. 編譯運行

// xufen3_ws工作空間下
// 終端1:
colcon build. install/setup.bashros2 launch ros2_stm32_bridge driver.launch.py// 終端2:
. install/setup.bashros2 run teleop_twist_keyboard teleop_twist_keyboard// 終端3 ~/xufen3_ws/voice_ros2$ 目錄下 :python3 voice.py 

然后就可以通過語音控制小車
在右側終端按1進行語音識別,此時將識別到小車前進的命令并打印,在左側終端按回車健獲取result中的命令,將輸出voice_command 小車前進,此時再按鍵ctrl+c,將輸出語音控制小車前進 小車前進并且小車開始移動。
目前的代碼需要按鍵才能加載進來語音的命令并控制小車移動,但好在實現了功能,后續還會繼續優化。

?

終端3中,輸入數字1? ? 然后 語音輸入指令 “小車前進” 或“? 小車后退”? 或 “小車左轉” 或“”小車右轉”?

等到終端3中,打印了語音指令后,鼠標移動到終端2,按下回車鍵即可小車移動。

需要按鍵控制,感覺發出語音指令后,要等好幾秒才能移動小車,還需要按鍵,不過還是初步實現了語音控制,后期優化,實現更實用的語音控制

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/44816.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/44816.shtml
英文地址,請注明出處:http://en.pswp.cn/web/44816.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開發指南048-前端模塊版本

平臺前端框架內置了一個文件version.vue <template> <div> <br> 應用名稱: {{name}} <br> 當前版本&#xff1a;{{version}} <br> 服務網關: {{gateway}} </div> </template> <scrip…

qt 創建一個包含兩按鈕,且安裝和自定義控件間沒有間距

在 Qt 中創建一個包含兩個按鈕且按鈕之間沒有間距的自定義控件&#xff0c;你可以使用 QHBoxLayout 或 QVBoxLayout&#xff08;取決于你希望按鈕是水平排列還是垂直排列&#xff09;&#xff0c;并設置布局的間距為 0。以下是一個簡單的示例&#xff0c;展示了如何創建一個水平…

Dataset for Stable Diffusion

1.Dataset for Stable Diffusion 筆記來源&#xff1a; 1.Flickr8k數據集處理 2.處理Flickr8k數據集 3.Github&#xff1a;pytorch-stable-diffusion 4.Flickr 8k Dataset 5.dataset_flickr8k.json 1.1 Dataset 采用Flicker8k數據集&#xff0c;該數據集有兩個文件&#xff…

Node.js_mongodb用戶名和密碼操作

mongodb用戶名和密碼操作 查看用戶密碼創建管理員用戶和密碼mongodb的目標是實現快速簡單部署,所以存在很多安全問題 默認配置下沒有用戶和密碼,無需身份驗證即可登錄,不像mysql那樣需要登錄才能操作數據庫本身安全問題:升級3.0以上版本查看用戶密碼 密碼是加密存儲的,并且…

前端工程化10-webpack靜態的模塊化打包工具之各種loader處理器

9.1、案例編寫 我們創建一個component.js 通過JavaScript創建了一個元素&#xff0c;并且希望給它設置一些樣式&#xff1b; 我們自己寫的css,要把他加入到Webpack的圖結構當中&#xff0c;這樣才能被webpack檢測到進行打包&#xff0c; style.css–>div_cn.js–>main…

速盾:ddos高防ip哪里好用?

隨著互聯網的飛速發展&#xff0c;DDoS攻擊問題逐漸突出。DDoS攻擊是一種通過在網絡上創建大量請求&#xff0c;使目標網絡或服務器過載而無法正常工作的攻擊方式。為了應對DDoS攻擊&#xff0c;提高網絡的安全性和穩定性&#xff0c;使用高防IP成為了一種常見的解決辦法。 DD…

Flower花所比特幣交易及交易費用科普

在加密貨幣交易中&#xff0c;選擇一個可靠的平臺至關重要。Flower花所通過提供比特幣交易服務脫穎而出。本文將介紹在Flower花所進行比特幣交易的基礎知識及其交易費用。 什么是Flower花所&#xff1f; Flower花所是一家加密貨幣交易平臺&#xff0c;為新手和資深交易者提供…

【C++】開源:drogon-web框架配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 這篇文章主要介紹drogon-web框架配置使用。 無專精則不能成&#xff0c;無涉獵則不能通。——梁啟超 歡迎來到我的博客&#xff0c;一起學習&#xff0c;共同進步。 喜歡的朋友可以關注一下&#xff0c;…

Linux系統編程-線程同步詳解

線程同步是指多個線程協調工作&#xff0c;以便在共享資源的訪問和操作過程中保持數據一致性和正確性。在多線程環境中&#xff0c;線程是并發執行的&#xff0c;因此如果多個線程同時訪問和修改共享資源&#xff0c;可能會導致數據不一致、競態條件&#xff08;race condition…

面試題008-Java-SpringBoot

面試題008-Java-SpringBoot 目錄 面試題008-Java-SpringBoot題目自測題目答案1. Spring 和 Spring Boot有什么區別&#xff1f;2. Spring Boot 的主要優點是什么&#xff1f;3. 什么是Spring Boot Starter&#xff1f;4. 介紹一下SpringBootApplication注解&#xff1f;5. Spri…

【密碼學】消息認證

你發送給朋友一條消息&#xff08;內容&#xff1a;明天下午來我家吃飯&#xff09;&#xff0c;這一過程中你不想讓除你朋友以外的人看到消息的內容&#xff0c;這就叫做消息的機密性&#xff0c;用來保護消息機密性的方式被叫做加密機制。 現在站在朋友的視角&#xff0c;某一…

使用PyQt5實現添加工具欄、增加SwitchButton控件

前言&#xff1a;通過在網上找到的“電池電壓監控界面”&#xff0c;學習PyQt5中添加工具欄、增加SwitchButton控件&#xff0c;在滑塊控件右側增加文本顯示、設置界面背景顏色、修改文本控件字體顏色等。 1. 上位機界面效果展示 網絡上原圖如下&#xff1a; 自己使用PyQt5做…

springboot異常(一):springboot自定義全局異常處理

&#x1f337;1. 自定義一個異常類 自定義一個異常&#xff0c;有兩個變量異常代碼、異常消息&#xff0c;定義了兩個構造方法&#xff0c;一個無參構造方法&#xff0c;一個所有參數構造方法。 在構造方法中要掉用父類的構造方法&#xff0c;主要目的是在日志或控制臺打印異…

【Linux】多線程_3

文章目錄 九、多線程3. C11中的多線程4. 線程的簡單封裝 未完待續 九、多線程 3. C11中的多線程 Linux中是根據多線程庫來實現多線程的&#xff0c;C11也有自己的多線程&#xff0c;那它的多線程又是怎樣的&#xff1f;我們來使用一些C11的多線程。 Makefile&#xff1a; te…

Linux - 探索命令行

探索命令行 Linux命令行中的命令使用格式都是相同的: 命令名稱 參數1 參數2 參數3 ...參數之間用任意數量的空白字符分開. 關于命令行, 可以先閱讀一些基本常識. 然后我們介紹最常用的一些命令: ls用于列出當前目錄(即"文件夾")下的所有文件(或目錄). 目錄會用藍色…

面試經典題型:調用HashMap的put方法的具體執行流程

在調用put方法時時&#xff0c;有幾個關鍵點需要考慮&#xff1a; 哈希沖突的發生與解決&#xff1a; 哈希沖突指不同的鍵通過哈希函數計算得到相同的哈希值&#xff0c;導致它們應該存放在哈希表的同一個位置。解決沖突的常用方法包括開放尋址法和鏈表法&#xff08;或其升級形…

CSIP-FTE考試專業題

靶場下載鏈接&#xff1a; https://pan.baidu.com/s/1ce1Kk0hSYlxrUoRTnNsiKA?pwdha1x pte-2003密碼&#xff1a;admin123 centos:root admin123 解壓密碼&#xff1a; PTE考試專用 下載好后直接用vmware打開&#xff0c;有兩個靶機&#xff0c;一個是基礎題&#x…

【CTF-Crypto】數論基礎-02

【CTF-Crypto】數論基礎-02 文章目錄 【CTF-Crypto】數論基礎-021-16 二次剩余1-20 模p下-1的平方根*1-21 Legendre符號*1-22 Jacobi符號*2-1 群*2-2 群的性質2-3 阿貝爾群*2-4 子群2-11 群同態2-18 原根2-21 什么是環2-23 什么是域2-25 子環2-26 理想2-32 多項式環 1-16 二次剩…

打造智慧校園德育管理,提升學生操行基礎分

智慧校園的德育管理系統內嵌的操行基礎分功能&#xff0c;是對學生日常行為規范和道德素養進行量化評估的一個創新實踐。該功能通過將抽象的道德品質轉化為具體可量化的指標&#xff0c;如遵守紀律、尊師重道、團結協作、愛護環境及參與集體活動的積極性等&#xff0c;為每個學…

醫療器械FDA |FDA網絡安全測試具體內容

醫療器械FDA網絡安全測試的具體內容涵蓋了多個方面&#xff0c;以確保醫療器械在網絡環境中的安全性和合規性。以下是根據權威來源歸納的FDA網絡安全測試的具體內容&#xff1a; 一、技術文件審查 網絡安全計劃&#xff1a;制造商需要提交網絡安全計劃&#xff0c;詳細描述產…