项目背景
由于暑期优秀本科生项目需求,开发了一款控制机器人行走的APP,具体要求如下:
- 在第一个界面(连接界面)实现Socket连接,连接成功则跳转到下一个页面(控制界面)。
- 在控制界面中创建5个按钮分别对应前进、后退、左转、右转、捡球,
- 按下每个按钮用TCP的方式发送指令到网络调试助手,比如按下前进,就会发送”FFF”到网络调试助手,按下后退,就会发送”BBB”到网络调试助手,要求在网络调试助手上接收到数据,确保网络调试助手和安卓手机在同一个局域网下(手机电脑连接同一WiFi或者电脑连接手机热点)。
- 实现用语音控制小车运动,达到按钮控制效果。
Android Studio
安卓手机
网络调试助手
设计思路
设计思路大致为:首先获取输入框中输入的IP和端口,点击连接按钮后开启子线程进行连接,连接失败则提示连接失败提示框,连接成功则进行页面切换。在执行连接这个子线程中,让主线程休眠,以便让连接过程顺利从而导致判断连接的标志位发生改变。
切换第二个页面后,利用Buddle对象将IP和端口数据传输进来,在onViewCreated中再次连接,然后五个按钮点击后分别在子线程中执行发送相应的字符串,点击语音按钮时,首先通过设置百度语音识别的json变量,设置为长识别(若要更改,参考百度语音识别文档对json变量进行修改即可),根据命令中是否含有”前”、”后”、”左”、”右”、”捡”来判断是否执行相关命令。再次点击,识别取消。
界面的设计为创建两个Fragment,使用navigation来控制两个页面的切换。关于安卓导航方面的知识,可参照b站教程:安卓导航页面实现以及安卓导航页面数据传输
由于是从输入栏中获取到的字符串类型的数据,因此首先需要对端口的数据进行类型转换。isConnect是标志位,判断是否连接上,连接上就置于True.
fun InitConnect(ip: String, port: String) {
val port1 = port.toInt()
try {
socket = Socket(ip, port1)
socket!!.setSoTimeout(10000)
if (socket != null) {
isConnect = true
} else {
InitConnect(ip, port)
}
} catch (e: Exception) {
when (e) {
is SocketTimeoutException -> {
Log.e("连接超时,重新连接", "dd")
e.printStackTrace()
}
is NoRouteToHostException -> {
Log.e("该地址不存在,请检查", "DD");
e.printStackTrace()
}
is ConnectException -> {
Log.e("连接异常或被拒绝,请检查", "DD");
e.printStackTrace()
}
else -> {
e.printStackTrace()
Log.e("连接结束", e.toString())
}
}
}
}
message 即为需要发送的字符串。
fun SendMessage(message: String?) {
val dout = socket?.getOutputStream()
try {
if (dout != null && message != null) {
dout.write(
"""${message}
""".toByteArray(charset("utf-8"))
)
dout.flush()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
由于在执行主线程时不能跳转到其他耗时较长的函数中,例如socket通信的连接和传输数据,所以将这些统统放入子线程处理。但是子线程中处理导致主线程无法等待连接状态确定后再决定是否跳转,采用Thread.sleep(300)使主线程睡眠,让子线程跑完再判断。注意同时子线程中也不能出现关于界面方面的内容
val josn="{\"accept-audio-data\":false,\"disable-punctuation\":false,\"enable.long.speech\":true,\"accept-audio-volume\":true,\"pid\":1537}"
设置为长语音识别,即按下后,只要不停车,就可以一直处于识别状态。<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Set to long speech recognition, that is, after pressing, as long as you don't stop, you can always be in the recognition state.</font>*</details>
toggle.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
asr!!.send(SpeechConstant.ASR_START,josn, null, 0, 0)
} else {
asr!!.send(SpeechConstant.ASR_STOP, null, null, 0, 0)
}
}
识别结束后,提取识别内容,利用control.contains()函数实现观察字符串中是否包含某个字符,完成多个联想词也能实现命令的效果。
if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
if (params == null || params.isEmpty()) {
return
}
if (params.contains("\"final_result\"")) {
val regrex = "\\[(.*?),"
val pattern: Pattern = Pattern.compile(regrex)
val matcher: Matcher = pattern.matcher(params)
if (matcher.find()) {
val a = matcher.group(0)!!.indexOf("[")
val b = matcher.group(0)!!.indexOf(",")
val control= matcher.group(0)!!.substring(a + 2, b - 3)
val qian="前"
val hou="后"
val zuo="左"
val you="右"
val jian="捡"
textStatus!!.text = control
if(control.contains(qian)){
thread {
SendMessage("FFF")
}
}
源码地址
个人博客
参考资料
Original: https://blog.csdn.net/m0_51735111/article/details/125861092
Author: 世似归尘
Title: 语音控制小车运动APP(基于百度语音识别)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/512382/
转载文章受原作者版权保护。转载请注明原作者出处!