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.rhkb.cn/news/375697.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

npm install 报错:PhantomJS not found on PATH

npm install 报错&#xff1a;PhantomJS not found on PATH 整体报错内容 npm ERR! code 1 npm ERR! path G:\work-learn\open-coding\bruno\node_modules\phantomjs-prebuilt npm ERR! command failed npm ERR! command C:\Windows\system32\cmd.exe /d /s /c node install.…

Python应用爬虫下载QQ音乐歌曲!

目录&#xff1a; 1.简介怎样实现下载QQ音乐的过程&#xff1b; 2.代码 1.下载QQ音乐的过程 首先我们先来到QQ音乐的官网&#xff1a; https://y.qq.com/&#xff0c;在搜索栏上输入一首歌曲的名称&#xff1b; 如我在上输入最美的期待&#xff0c;按回车来到这个画面 我们首…

Ubuntu 22.04.4 LTS (linux) Auditd 安全审计rm命令 记录操作

1 audit增加rm 规则 #sudo vim /etc/audit/rules.d/audit.rules -w /bin/rm -p x -k delfile #重新启动服务 sudo systemctl restart auditd #查看规则 sudo auditctl -l -w /bin/rm -p x -k delfile 2 测试规则 touch test.txt rm test.tx 3 查看日志 sudo ausear…

配置Redis时yml的格式导致报错

报错如下 java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98) at org.springframework.test.context.su…

SpringCloud集成kafka集群

目录 1.引入kafka依赖 2.在yml文件配置配置kafka连接 3.注入KafkaTemplate模版 4.创建kafka消息监听和消费端 5.搭建kafka集群 5.1 下载 kafka Apache KafkaApache Kafka: A Distributed Streaming Platform.https://kafka.apache.org/downloads.html 5.2 在config目录下做…

家政服务小程序:提高家政服务,新商机!

当下&#xff0c;社会生活的节奏非常快&#xff0c;人们忙于工作&#xff0c;在日常生活家务清洁中面临着时间、精力不足的问题&#xff0c;因此对家政服务的需求日益增加&#xff0c;这也推动了家政行业的迅速发展。目前不少年轻人都开始涌入到了家政行业中&#xff0c;市场的…

C# .net6使用Hangfire

首先我们先来了解什么是Hangfire&#xff1f; Hangfire 是一个用于 .NET 的任务调度库&#xff0c;允许你在后台运行任务&#xff0c;而不需要依赖外部的任务队列服务或复杂的基础设施。它简化了后台任务的创建、调度和管理过程&#xff0c;使得在 .NET 应用程序中处理长期运行…

基于SpringBoot的校园疫情防控系统

你好&#xff0c;我是专注于计算机科学与技术的研究者。如果你对我的工作感兴趣或有任何问题&#xff0c;欢迎随时联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架&#xff0c;B/S架构 工具&#xff1a;Eclipse&#xff0c;Mav…

FastAPI 学习之路(四十七)WebSockets(三)登录后才可以聊天

之前我们是通过前端自动生成的token信息&#xff0c;这次我们通过注册登录&#xff0c;保存到本地去实现。首先&#xff0c;我们实现一个登录页面&#xff0c;放在templates目录下。 <!DOCTYPE html> <html lang"en"> <head><meta charset&quo…

html5——CSS3_文本样式属性

目录 字体样式 字体类型 字体大小 字体风格 字体的粗细 文本样式 文本颜色 排版文本段落 文本修饰和垂直对齐 文本阴影 字体样式 字体类型 p{font-family:Verdana,"楷体";} body{font-family: Times,"Times New Roman", "楷体";} …

线性代数|机器学习-P23梯度下降

文章目录 1. 梯度下降[线搜索方法]1.1 线搜索方法&#xff0c;运用一阶导数信息1.2 经典牛顿方法&#xff0c;运用二阶导数信息 2. hessian矩阵和凸函数2.1 实对称矩阵函数求导2.2. 线性函数求导 3. 无约束条件下的最值问题4. 正则化4.1 定义4.2 性质 5. 回溯线性搜索法 1. 梯度…

Android --- Kotlin学习之路:自己写一个SDK给别的APP用(暴漏一个接口,提供学生的身高数据)

今天又来肝kotlin了&#xff0c;主题是&#xff1a;用kt写一个SDK给其他人用&#xff0c;这个小技能在项目中会经常用到&#xff0c;应该有很多小伙伴还不会用&#xff0c;不会的请往下看—⬇ 在项目里面新建一个module 选择Android library&#xff0c;然后点击finish就行了 …

css横向滚动条支持鼠标滚轮

在做视频会议的时候&#xff0c;标准模式视图会有顶部收缩的一种交互方式&#xff0c;用到了横向滚动&#xff1b;一般情况下鼠标滚轮只支持竖向滚动&#xff0c;这次写个demo是适配横向滚动&#xff1b; 效果图展示 实现横向滚动条顶部显示 <div className{style.remote_u…

FakeNewsGPT4:通过知识增强的大规模视觉语言模型推进多模态假新闻检测

FakeNewsGPT4: Advancing Multimodal Fake News Detection through Knowledge-Augmented LVLMs 论文地址:https://arxiv.org/abs/2403.01988https://arxiv.org/abs/2403.01988 1.概述 当前,多模态假新闻的大量涌现导致了显著的分布差异,这一现状亟需我们开发具备广泛适用性…

OpenGL笔记一之基础窗体搭建以及事件响应

OpenGL笔记一之基础窗体搭建以及事件响应 总结自bilibili赵新政老师的教程 code review! 文章目录 OpenGL笔记一之基础窗体搭建以及事件响应1.运行2.目录结构3.main.cpp4.CMakeList.txt 1.运行 2.目录结构 01_GLFW_WINDOW/ ├── CMakeLists.txt ├── glad.c ├── main…

映美精黑白相机IFrameQueueBuffer转halcon的HObject

映美精黑白相机&#xff0c;用wpfhalcon开发取图 1.到官网下载&#xff0c;开发包 1sdk 2c开发例子 3c#开发例子 引入TIS.Imaging.ICImagingControl35.dll 3.ICImagingControl使用这个类控制相机 /// <summary> /// 相机控制 /// </summary> public ICImagingC…

使用DeepWalk 和Word2Vec实现单词Embedding

0、准备“边”数据集Wiki_edgelist import pandas as pddf pd.read_csv(./data/wiki/Wiki_edgelist.txt, sep , headerNone, names["source", "target"]) df.head() 1、读入 起点-终点 边数据&#xff0c;构建图 # 1、读入 起点-终点 边数据&#xff0c…

代码随想录-暑假算法第一天(数组篇)

代码随想录-暑假算法第一天(数组篇) 1. 二分查找 力扣题目链接(opens new window) 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否…

无人机之摄影及录像技术篇

无人机摄影和录像技术利用飞行器搭载的摄像机在空中进行拍摄&#xff0c;以捕捉独特的视角和高质量的图像。这种技术在多个领域得到应用&#xff0c;如新闻报道、电影制作和广告拍摄等。下面将具体介绍无人机摄影和录像的技术要点&#xff1a; 一、设备选择 无人机型号&#…

Intel 和 ARM 对ROP/COP/JOP的缓解措施

文章目录 前言一、ROP1.1 Intel1.2 ARM 二、COP/JOP2.1 Intel2.2 ARM 前言 前向转移(forward)&#xff1a;将控制权定向到程序中一个新位置的转移方式, 就叫做前向转移, 比如jmp和call指令。这里我们主要保护的间接跳转&#xff0c;间接跳转是运行时才知道函数地址&#xff0c…