2019-12-06 | UNLOCK

基于Siri语音唤醒操控小车

项目效果

对着iPhone手机喊一句:“hey Siri 小车前进”,智能小车就前进了;“hey Siri 开灯”,树莓派连接的LED灯就亮了。可以对智能小车做一系列的操作。

硬件连接

课上的智能小车,主要的是有WiFi的树莓派板和Arduino板。
树莓派:主要是来当作一个中间者,来控制小车前进后退和开灯等操作。且当做一台服务器来处理接收到的数据,并做出相对于的操作(小车前进等)。
Arduino:主要是用来控制小车前进、后退、左转和右转。

所需材料

  1. Arduino板
  2. 树莓派(必须有WiFi功能)
  3. 智能小车
  4. iPhone手机 ios11系统及以上(主要是可以在APP store 下载“快捷指令”)
  5. 快捷指令APP(重头戏)

实验原理

iPhone手机开启一个热点(当然处于同一局域网就行了,比如连接了同一个WiFi),小车的树莓派去连接这个热点,然后通过linux命令“ip addr”去查询当前的ip地址 一般是“172.xxx.xxx.xxx”,然后他们就处于同一个局域网内,可以进行http局域网 通信了。

(“hey Siri 小车前进”——发起“发起请求访问了 http://172.20.10.3:5050/forward ”——树莓派服务器响应收到——然后进行串口通信给下位机发送一个字符——下位机接收到字符——小车前进成功)

172.xx.xx.xx为内网地址,所以必须要在同一局域网,否则通信失败。

然后手机打开快捷指令app,添加一个快捷指令,然后添加以下模块“URL模块、获取网页内容模块,朗读文本模块”,主要是用url模块去模拟打开一个网页,比如url里是 “http://172.20.10.3:5050/forward” ,树莓派上面跑的服务器程序就会接收到响应,然后直接操作小车进行前进就可以了。



然后打开右上角,来到下面这张图

再者可以添加一个Siri指令,对他进行一个录制比如说 “小车前进”。
这样快捷指令就完成了,你说一句“hey Siri 小车前进”,开始运行快捷指令,他就前进了。

下位机代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#define Left1 6   //左前轮由Arduino的数字口D6控制
#define Left2 7 //左后前轮由Arduino的数字口D7控制
#define Right1 9 //右前轮由Arduino的数字口D9控制
#define Right2 8 //右后轮由Arduino的数字口D8控制
#define Left_PWM 5 //左轮速度由Arduino的脉宽调制输出引脚D5控制
#define Right_PWM 10 //右轮速度由Arduino的脉宽调制输出引脚D10控制

void setup() //Arduino的初始化
{
pinMode(Left1,OUTPUT); //设置Arduino控制电机的6个引脚均为输出模式
pinMode(Left2,OUTPUT);
pinMode(Right1,OUTPUT);
pinMode(Right2,OUTPUT);
pinMode(Left_PWM,OUTPUT);
pinMode(Right_PWM,OUTPUT);
Serial.begin(9600); //Arduino串口初始化,并设置波特率9600
}
void Forward(int Speed) //小车前进子函数 Speed范围0到255
{
digitalWrite(Left1, HIGH);
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, Speed);
analogWrite(Right_PWM, Speed);
}
void Backward(int Speed) //小车后退子函数 Speed范围0到255
{
digitalWrite(Left1, LOW);
digitalWrite(Left2, HIGH);
digitalWrite(Right1, LOW);
digitalWrite(Right2, HIGH);
analogWrite(Left_PWM, Speed);
analogWrite(Right_PWM, Speed);
}
void Turn_Left(int Speed) //小车左转子函数 Speed 50到255 通过两侧车轮速度差转向
{
digitalWrite(Left1, HIGH);
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, 50);
analogWrite(Right_PWM, Speed);
}
void Turn_Right(int Speed) //小车右转子函数 Speed 50到255 通过两侧车轮速度差转向
{
digitalWrite(Left1, HIGH);
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, Speed);
analogWrite(Right_PWM, 50);
}
void Stop() //小车停止函数
{ analogWrite(Left_PWM, 0);
analogWrite(Right_PWM, 0);
}
void loop()
{
int Receive_dat;
if (Serial.available() > 0) //判断串口接收缓存是否有数据
{
Receive_dat = Serial.read(); //从串口读一个字节数据
switch (Receive_dat) //判断接收到的数据并作出相应动作
{
case 'w': //前进指令
Forward(255);
break;
case 'a': //左转指令
Turn_Left(255);
break;
case 's': //后退指令
Backward(255);
break;
case 'd': //右转指令
Turn_Right(255);
break;
default:
Stop(); //停止指令
break;
}
}
}

上位机代码(当服务器,在树莓派上跑服务):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from flask import Flask
import time
import os
import RPi.GPIO as GPIO
import serial
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
ser = serial.Serial("/dev/ttyUSB0", 9600, timeout=0.1)
bit = True

app = Flask(__name__)

@app.route('/')
def index():
#如果访问主页根目录 则跳转到前端页面
return "连接成功!Coded by ROT 罗泽涛"

@app.route('/forward', methods=['GET'])
def forward():
ser.write(bytes('w', 'utf-8'))
return "你的小车正在前进" #这里的返回值,可以任意更改,只是返回到html页面上,快捷指令APP能接收到这里返回的值,可以将字符串进行朗读,下面的也是这样,以此类推。

@app.route('/forback', methods=['GET'])
def forback():
ser.write(bytes('s', 'utf-8'))
return "你的小车正在后退"

@app.route('/left', methods=['GET'])
def left():
ser.write(bytes('a', 'utf-8'))
return "你的小车正在左转"

@app.route('/right', methods=['GET'])
def right():
ser.write(bytes('d', 'utf-8'))
return "你的小车正在右转"

@app.route('/stop', methods=['GET'])
def stop():
ser.write(bytes('q', 'utf-8'))
return "你的小车停止了"

@app.route('/lightOn', methods=['GET'])
def lightOn():
GPIO.output(17, GPIO.HIGH) # 常亮
return "灯亮了"

@app.route('/lightOff', methods=['GET'])
def lightOff():
GPIO.output(17, GPIO.LOW)
return "灯灭了"

app.run(host = '0.0.0.0', port = 5050, debug = False) #端口号为5050,其实也可以改成其他的,只要端口号不被占用即可。

视频效果

点击播放