Raspberry
coshep 发布于2018-01 浏览:6200 回复:5
1
收藏
快速回复
最后编辑于2022-04

先生们女士们,我又回来了,还是我。上一次用了REST API把百度语音搞到树莓派上,但是识别的过程太慢了,大概8秒多,所以这次换成了android手机输入语音,在联通4G网络下,速度大概是3秒。还算不错的,下面是主要实现过程。

需要用到的东西如上图所示,一个手机,一个装有树莓派的小车,和一个电脑。此项目的运行原理以及主要代码如所示。

主要原理如上图所示,下面分三步来解决实现。

1、无线局域网
手机,小车和大电脑三个设备都是处于同一无线局域网内,你可以使用一个无线路由器或者手机热点来创建这个网络。

我推荐使用手机热点方式,这样就可以不受地域限制,拿着小车电脑到户外玩。对未来后期的扩展很有用,比如太阳能供电,物体人像辨别这些可能会添加的功能。

2、手机端代码
本文采用的是百度语音的最简代码来运行,这部分的代码已经在本站的下面文章做过较详细的讲解

《Android * 使用Android Studio运行百度语音的Hello World精简版》地址:

http://endback.com/2018/01/24/raspberry-pi-使用android手机语音控制树莓派小车/

如果没有看过上文的读者,请先到那边看一下。如果已经看过的读者,请直接来看重点。我们只需要把上文里提到的MainActivity.java代码里先添加一个函数:sendCommand(……),具体代码如下:

private void sendCommand(final String host, final int port, final String data) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    Socket socket = new Socket(host, port);
                    OutputStream outputStream = socket.getOutputStream();
                    outputStream.write((data).getBytes());
                    outputStream.flush();
                    System.out.println(socket);

                    InputStream is = socket.getInputStream();
                    byte[] bytes = new byte[1024];
                    int n = is.read(bytes);
                    System.out.println(new String(bytes, 0, n));
                    Handler handler = new Handler();
                    Message msg = handler.obtainMessage(0x124, new String(bytes, 0, n));
                    msg.sendToTarget();

                    is.close();
                    socket.close();
                } catch (Exception e) {}
            }
        };

        thread.start();
    }

然后再在回调函数:public void onEvent(……)  里找到这句代码“txtResult.append(recogs[i]);”我们在这个代码的下面添加上面这个新建函数:

@Override
    public void onEvent(String name, String params, byte[] data, int offset, int length) {


        String logTxt = "name: " + name;


        if (params != null && !params.isEmpty()) {
            logTxt += " ;params :" + params;
            try {
                    JSONObject json = new JSONObject(params);
                    
                    if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL) && json.getString("result_type").equals("final_result")) {
                    
                        //txtLog.append("final test::" + "\n" + json.getString("result_type"));
                    
                        JSONArray arr = json.optJSONArray("results_recognition");
                        if (arr != null) {
                            int size = arr.length();
                            String[] recogs = new String[size];
                            for (int i = 0; i < size; i++) {
                                recogs[i] = arr.getString(i);
                                txtResult.append(recogs[i]);
////////添加到这里
                                sendCommand("192.168.43.57",18888,recogs[i]);
////////添加到这里
                            }
                    
                        }
                    }
            }catch (JSONException e) {
                e.printStackTrace();
            }

        }
        if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
            if (params.contains("\"nlu_result\"")) {
                if (length > 0 && data.length > 0) {
                    logTxt += ", 语义解析结果:" + new String(data, offset, length);
                }
            }
        } else if (data != null) {
            logTxt += " ;data length=" + data.length;
        }
        printLog(logTxt);

    }

上面这个函数,第一个参数“192.168.43.57”就是服务器端的IP地址,第二个参数“18888”是端口号,自己设定的,你可以随便设定为88888或者99999什么的。第三个“recogs[i]”就是语音识别得到的最终结果。

设定好这一步之后,就可以先用android studio编译运行到手机上看看,只要运行成功,你可以先试着说话,不影响后续步骤。

3、服务器端代码
无线网弄好后,我们进入树莓派小电脑里设置无线网。先给树莓派小电脑插上鼠标键盘显示器,我安装的系统是带有图形界面的那个版本。本来我装的是没有图形界面的那个版本,但后来总是奔溃,很奇怪,还以为是sd卡的问题,但后来重装成图形界面版本以后就不会奔溃了。暂时无解。不管,先打开终端输入以下命令:

pi@raspberrypi:~ $ ifconfig

注意,这一步我是在把树莓派安装固定到小车上之前就完成了。得到IP地址,最后就可以把鼠标键盘显示器拔了。然后再在大电脑上通过SSH方式远程登录到树莓派小电脑上。

r0ck:~$ ssh 192.168.43.57 -l pi

上面的IP就是手机自动分配给树莓派小电脑的。登录进去以后,新建一个名为goSpeech.py的python文件并执行:

pi@raspberrypi:~/raspSpeech $ sudo nano goSpeech.py 

输入以下服务器端的代码:

# -*- coding: utf-8 -*-
from socket import *  
from time import ctime
#准备调用树莓派GPIO接口
import RPi.GPIO as GPIO
#可以在python中执行Linux命令行
import os
import time
import json
#使用BCM方式来调用树莓派针脚
GPIO.setmode(GPIO.BCM)

#初始化树莓派的IP地址和端口
#准备从安卓手机客户端发送消息
HOST = '192.168.43.57'  
PORT = 18888  
BUFSIZ = 1024  
ADDR = (HOST, PORT) 


#初始化小车四个电机和轮子所使用的针脚
right_IN1 = 20
right_IN2 = 21
left_IN3  = 19
left_IN4  = 26
#全部设置为电频输出
GPIO.setup(right_IN1,GPIO.OUT)
GPIO.setup(right_IN2,GPIO.OUT)
GPIO.setup(left_IN3,GPIO.OUT)
GPIO.setup(left_IN4,GPIO.OUT)
#频率都设置为100%
move_right_1  = GPIO.PWM(right_IN1,100) 
move_right_2  = GPIO.PWM(right_IN2,100)
move_left_3   = GPIO.PWM(left_IN3,100) 
move_left_4   = GPIO.PWM(left_IN4,100)

#开始启动时都设为0%
move_right_1.start(0)
move_right_2.start(0)
move_left_3.start(0)
move_left_4.start(0)

def forword():
    #让小车前进
    move_right_1.start(70)
    move_right_2.start(0)
    move_left_3.start(70)
    move_left_4.start(0)
    
    
def reverse():
    #让小车后退
    move_right_1.start(0)
    move_right_2.start(70)
    move_left_3.start(0)
    move_left_4.start(70)
    
def turnLeft():
    #让小车左转弯
    move_right_1.start(100)
    move_right_2.start(0)
    move_left_3.start(30)
    move_left_4.start(0)

def turnRight():
    #让小车右转
    move_right_1.start(30)
    move_right_2.start(0)
    move_left_3.start(100)
    move_left_4.start(0)

def stop():
    #小车停止
    move_right_1.start(0)
    move_right_2.start(0)
    move_left_3.start(0)
    move_left_4.start(0)

try:
    while True:

        tcpSerSock = socket(AF_INET, SOCK_STREAM)  
        tcpSerSock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)  
        tcpSerSock.bind(ADDR)  
        tcpSerSock.listen(5)  
        print '服务器运行中...'  
        tcpCliSock, addr = tcpSerSock.accept()  
        print '已连接地址:', addr    
        data = tcpCliSock.recv(BUFSIZ)  
        if not data:  
            break
        tcpCliSock.send('get your data:%s\n[%s]' % (data, ctime()))     
        print data
        tcpSerSock.close

        if data == '前进' :
            print "接收到前进指令"
            forword()
            print "正在执行前进指令"
            
        if data == '后退' :
            reverse()
            
        if data == '左转' :
            turnLeft()
            
        if data == '右转' :
            turnRight()   
            
        if data == '停下':
            stop() 


except KeyboardInterrupt:
    GPIO.cleanup()

这个代码一旦运行后,就会随时等着接收来自android手机的消息,然后通过接收到的消息来进行GPIO的输出,从而控制小车行动。如下:

pi@raspberrypi:~/raspSpeech $ sudo python goSpeech.py
服务器运行中...

4、运行
此时,你可以通过安卓手机发出指令,然后服务器端收到消息后,在大电脑终端上会显示下面消息:

pi@raspberrypi:~/raspSpeech $ sudo python goSpeech.py 
服务器运行中...
已连接地址: ('192.168.43.219', 45007)
开始
接收到前进指令
正在执行前进指令
服务器运行中...
已连接地址: ('192.168.43.219', 38276)
后腿
服务器运行中...
已连接地址: ('192.168.43.219', 53038)
后退
......

到了这一步,就可以拿着个手机控制小车玩啦,耶耶~

 

收藏
点赞
1
个赞
共5条回复 最后由用户已被禁言回复于2022-04
#6用户已被禁言回复于2021-05

上海
http://xasgkfp.diytrade.com/
https://xasgkfp.diytrade.com/
http://cdfapiao.simplesite.com/
http://xakfp.simplesite.com/

0
#5wangwei8638回复于2021-01

赞一个

0
#4smile19973回复于2021-01

我想做一个可以实现语音控制的智能小车,但是代码一直改不好,python基础太差,想找大佬帮助完成代码,报酬合理要求就行,可以帮助一下我吗?微信(电话)18749442710,感谢

0
#3smile19973回复于2021-01

你好

0
#2choleraa回复于2018-07

wow, 这个有意思~~~~电机控制是使用了什么现成的组件吗? 

0
TOP
切换版块