2019-09-21 | UNLOCK

嵌入式机器人(复习)

项目1 (控制LED,从这里开始使用Arduino“下位机”,编程语言C/C++)

Arduino 实现LED闪烁(0.5s)

C\C++ Arduino

1
2
3
4
5
6
7
8
9
10
11
12
13
void setup()
{
pinMode(13,OUTPUT); //设置13口为输出模式
}


void loop()
{
digitalWrite(13,HIGH); //将13口的电平置高
delay(500); //延时500毫秒
digitalWrite(13,LOW); //将13口的电平拉低
delay(500); //延时500毫秒
}

项目1拓展

LED亮1秒灭0.5秒,并循环往复

C\C++ Arduino

1
2
3
4
5
6
7
8
//在项目1的基础上修改loop函数
void loop()
{
digitalWrite(13,HIGH); //将13口的电平置高
delay(1000); //延时500毫秒
digitalWrite(13,LOW); //将13口的电平拉低
delay(500); //延时500毫秒
}

总结:运行原理是通过Arduino板控制LED灯,在有之前单片机的基础上,arduino对新手来说非常友好。
这里认识了2个函数,第一个是setup()初始化,loop()是循环体,也是主体,相当之前所学的于main()函数。
先在setup()函数初始IO口13为输出口,然后在loop函数里将它置高(低)电平,就能使灯亮起来。delay()函数是Arduino里面自带的一个库里的函数,不用手写delay()函数非常方便。

项目2-1(使机器人动起来)

通过Arduino板和驱动电路控制电机的转动,使机器人运动起来:前进— 停止循环。

C\C++ Arduino

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
#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);
}

void Forward(int Speed) //小车前进子函数 Speed范围0到255
{
digitalWrite(Left1, HIGH); //左轮逆时针旋转(面向轮子外侧观察)
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH); //右轮顺时针旋转(面向轮子外侧观察)
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, Speed); //左轮速度,Speed为0时停止,为255时最大
analogWrite(Right_PWM, Speed); //右轮速度,Speed为0时停止,为255时最大
}

void Stop(void) //小车停止函数
{
digitalWrite(Left1, LOW);
digitalWrite(Left2, LOW);
digitalWrite(Right1, LOW);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, 0); // Speed为0,左轮停止
analogWrite(Right_PWM, 0); // Speed为0,右轮停止
}

void Back(int Speed)
{
digitalWrite(Left1, LOW); //左轮逆时针旋转(面向轮子外侧观察)
digitalWrite(Left2, HIGH);
digitalWrite(Right1, LOW); //右轮顺时针旋转(面向轮子外侧观察)
digitalWrite(Right2, HIGH);
analogWrite(Left_PWM, Speed); //左轮速度,Speed为0时停止,为255时最大
analogWrite(Right_PWM, Speed); //右轮速度,Speed为0时停止,为255时最大
}

void loop() //Arduino将循环执行的代码
{
Forward(255); //全速前进
delay(5000); //延时5秒
Stop(); //停止
delay(5000); //延时5秒
}

//注:HIGH即为1,LOW即为0。

项目2-1拓展

前进—后退-停止循环往复

C\C++ Arduino

1
2
3
4
5
6
7
8
9
10
11
12
//在上面的基础上修改loop函数里的执行体内容
void loop()
{
Forward(255);
delay(5000);

Back(255);
delay(5000);

Stop();
delay(5000);
}

总结:这里需要根据原理图和一些理论知识,然后使小车的车轮转起来。一言难尽…

项目2-2(使轮子有5种状态)

使机器人这样运动起来:前进5秒-后退5秒-左转5秒-右转5秒-停止5秒-循环往复。

C\C++ Arduino

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
#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);
}

void Forward(int Speed) //前进子函数 Speed范围0到255
{
digitalWrite(Left1, HIGH); //左轮逆时针旋转(面向轮子外侧观察)
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH); //右轮顺时针旋转(面向轮子外侧观察)
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, Speed); //左轮速度,Speed为0时停止,为255时最大
analogWrite(Right_PWM, Speed); //右轮速度,Speed为0时停止,为255时最大
}

void Stop(void) //停止函数
{
digitalWrite(Left1, LOW);
digitalWrite(Left2, LOW);
digitalWrite(Right1, LOW);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, 0); // Speed为0,左轮停止
analogWrite(Right_PWM, 0); // Speed为0,右轮停止
}

void Backword(int Speed) //后退函数 Speed范围0到255
{
digitalWrite(Left1, LOW);
digitalWrite(Left2, HIGH);
digitalWrite(Right1, LOW);
digitalWrite(Right2, HIGH);
analogWrite(Left_PWM, Speed); //speed
analogWrite(Right_PWM, Speed);
}

void Turn_left(int Speed) //左转函数 Speed范围0到255
{
digitalWrite(Left1, HIGH);
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, 0); //左右轮速度差引起转弯
analogWrite(Right_PWM, Speed);
}

void Turn_right(int Speed) //右转函数 Speed范围0到255
{
digitalWrite(Left1, HIGH);
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH);
digitalWrite(Right2, LOW);
analogWrite(Left_PWM, Speed); //左右轮速度差引起转弯
analogWrite(Right_PWM, 0);
}

void loop()
{
Forward(255);
delay(5000);
Backword(255);
delay(5000);
Turn_left(200);
delay(5000);
Turn_right(200);
delay(5000);
Stop();
delay(5000);
}

项目2-2拓展(矩形运动)

使机器人运动的轨迹为一个矩形

C\C++ Arduino

1
2
3
4
5
6
7
8
9
10
11
void loop()
{
Forward(255);
delay(1500);
Stop();
delay(1000);
Turn_right(255);
delay(1550);
Stop();
delay(1000);
}

总结:需要多次试验,多次烧入代码,才能完成测试。(影响小车的转角方向为90°的原因,有很多种,例如小车的动力、地板的粗糙程度、小车向下的重力等等),需要耐心多调试。

项目2-3(轮子加速)

使机器人这样运动起来:从0速加速前进至全速–减速后退至停止–停止0.5秒,循环往复。

C\C++ Arduino

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
#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);
}

void forward() //从0速加速前进至全速
{
digitalWrite(Left1, HIGH);
digitalWrite(Left2, LOW);
digitalWrite(Right1, HIGH);
digitalWrite(Right2, LOW);
for (int Speed=0; Speed<255; Speed++)
{
analogWrite(Left_PWM, Speed); //speed
analogWrite(Right_PWM, Speed);
delay(50);
}
}



void backward() //从全速减速后退至停止
{
digitalWrite(Left1, LOW);
digitalWrite(Left2, HIGH);
digitalWrite(Right1, LOW);
digitalWrite(Right2, HIGH);
for (int Speed=255; Speed>50; Speed--)
{
analogWrite(Left_PWM, Speed); //speed
analogWrite(Right_PWM, Speed);
delay(50);
}
}
void stop() //停止
{
analogWrite(Left_PWM, 0);
analogWrite(Right_PWM, 0);
}

void loop()
{
forward();
backward();
stop();
delay(500);
}

项目2-3拓展

使机器人这样运动起来:从0速加速前进至全速0.5秒—左转–减速后退至停止—右转–循环往复。

C\C++ Arduino

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 void loop()
{
forward();
stop();
delay(1000);
Turn_left(255);
delay(1550);
stop();
delay(1000);

backword();
stop();
delay(1000);

Turn_left(255);
delay(1550);

stop();
delay(1000);
}

项目2-4(串口的应用)

在Arduino IDE中打开串口监视器(工具—串口监视器),向串口分别发送“w”、“s”、“a”、“d”、及其他字符,使得机器人分别“前进”、“后退”、“左转”、“右转”、“停止”。

C\C++ Arduino

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;
}
}
}

项目2-4拓展

在Arduino IDE中打开串口监视器(工具—串口监视器),向串口分别发送“w”、“s”、“a”、“d”字符,使得机器人分别“前进”、“后退”、“左转”、“右转”,发送 “q” 字符,使得机器人“停止”。

C\C++ Arduino

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
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;
case 'q':
Stop(); //停止指令
break;
default:
Stop(); //停止指令
break;
}
}
}

总结:利用串口所接收回来的字符,做判断然后执行相对应的函数。这个项目后面还会继续用到,跟“上位机”树莓派所结合。

项目3-1(控制LED,从这里开始使用树莓派“上位机”,编程语言Python)

用树莓派的GPIO17控制一个LED,使LED闪烁。

Python Python2

1
2
3
4
5
6
7
8
9
10
import RPi.GPIO as GPIO  #导入树莓派的GPIO库
import time #导入时间库
GPIO.setwarnings(False) #消除GPIO输出警告
GPIO.setmode(GPIO.BCM) #设置GPIO排布方式
GPIO.setup(17,GPIO.OUT) #设置GPIO17为输出模式
while True:
GPIO.output(17,GPIO.HIGH) #设置GPIO17为高电平
time.sleep(.5) #延时500毫秒
GPIO.output(17,GPIO.LOW) #设置GPIO17为低电平
time.sleep(.5) #延时500毫秒

项目3-1拓展

LED闪烁3次后长亮

Python Python2

1
2
3
4
5
6
7
8
9
10
11
import RPi.GPIO as GPIO
import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17,GPIO.OUT)
for i in range(3):
GPIO.output(17,GPIO.HIGH)
time.sleep(.5)
GPIO.output(17,GPIO.LOW)
time.sleep(.5)
GPIO.output(17,GPIO.HIGH)

总结: 这里控制小灯,需要自己提前先接好线,准备工具有:若干杜邦线、电阻1k欧、LED灯一个、面包板。 然后接入相对应的IO口、VCC和GND口即可。

项目3-2(通过外设控制LED)

通过互感模块(触摸按键)控制LED:每触摸一次按键,则LED改变一次亮灭状态。

Python Python2

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
#每触摸一次按键,则改变一次LED的亮灭状态
import RPi.GPIO as GPIO #导入RPi.GPIO库命名为GPIO
import time #导入时间库
GPIO.setwarnings(False) #消除GPIO输出警告
GPIO.setmode(GPIO.BCM) #设置GPIO排布方式
GPIO.setup(17, GPIO.OUT) #设置GPIO17位输出模式
GPIO.setup(27, GPIO.IN) #设置GPIO27位输入模式
bit = True #新建一个布尔类型的全局变量
while True:
value = GPIO.input(27) #读取GPIO27的引脚电平
if (value == True): #判断引脚电平是否为高,表示有按键按下
print("监听到触摸") #打印字符
time.sleep(0.5) #延时
if (bit==True): #判断bit位是真还是假,是真则
print("亮") #打印“亮”
GPIO.output(17, GPIO.HIGH) #点亮LED
#bit = -bit #bit位取反 看不懂就看下一行
bit = False
else:
print("灭") #打印“灭”
GPIO.output(17, GPIO.LOW) #熄灭LED
# bit = -bit #bit位取反
bit = True
while(GPIO.input(27)==True): #未松手时,则执行循环体
pass #空指令

项目3-2拓展

通过互感模块(触摸按键)控制LED:每触摸一次按键,则LED闪烁2次然后熄灭

Python Python2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import RPi.GPIO as GPIO	#导入RPi.GPIO库命名为GPIO
import time #导入时间库
GPIO.setwarnings(False) #消除GPIO输出警告
GPIO.setmode(GPIO.BCM) #设置GPIO排布方式
GPIO.setup(17, GPIO.OUT) #设置GPIO17位输出模式
GPIO.setup(27, GPIO.IN) #设置GPIO27位输入模式
while True:
value = GPIO.input(27) #读取GPIO27的引脚电平
if (value == True): #判断引脚电平是否为高,表示有按键按下
print("监听到触摸") #打印字符
time.sleep(0.5) #延时
print("亮") #打印“亮”
GPIO.output(17, GPIO.HIGH) #点亮LED
time.sleep(0.5) #延时
GPIO.output(17, GPIO.LOW) #熄灭LED
time.sleep(0.5) #延时
GPIO.output(17, GPIO.HIGH) #点亮LED
time.sleep(0.5) #延时
GPIO.output(17, GPIO.LOW) #熄灭LED
while(GPIO.input(27)==True): #未松手时,则执行循环体
pass

总结:之前所学的一直都是输出设备,这里,多学一个新的设备,输入设备。就是将IO口设置为输入口。 输入口信号进来后,判断其状态,用个变量记录本次状态后面来判断使灯亮还是灭。项目单上的 bit=-bit 如果理解不了的话,可以看我修改的(其实就是记录小灯当前状态),如上项目3-2。

项目3-3(向下位机发送串口信号,下位机串口接收后执行相对应动作)

通过树莓派的键盘上的按键,控制小车的运动:按下“w”键,则小车“前进”;按下“a”键,则小车“左转”;按下“d”键,则小车“右转”;按下“s”键,则小车“后退”;按下其他键,小车“停止”。

Python Python2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
import serial
import string

ser = serial.Serial('/dev/ttyUSB0',9600,timeout=1)

while True:
tmp = raw_input("please input:")
if tmp=='w':
print("Forward")
ser.write('w')
elif tmp=='a':
print("Turn Left")
ser.write('a')
elif tmp=='s':
print("Back")
ser.write('s')
elif tmp=='ad':
print("Turn Right")
ser.write('d')
else:
print("Stop")
ser.write('t')

项目3-3拓展

通过树莓派的键盘上的按键,控制小车的运动:按下“w”键,则小车“前进”;按下“a”键,则小车“左转”;按下“d”键,则小车“右转”;按下“s”键,则小车“后退”;按下“q”键,小车“停止”。

Python Python2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
import serial
import string

ser = serial.Serial('/dev/ttyUSB0',9600,timeout=1)

while True:
tmp = raw_input("please input:")
if tmp=='w':
print("Forward")
ser.write('w')
elif tmp=='a':
print("Turn Left")
ser.write('a')
elif tmp=='s':
print("Back")
ser.write('s')
elif tmp=='d':
print("Turn Right")
ser.write('d')
elif tmp=='q':
print("Stop")
ser.write('t')

总结:
目前有Arduino和树莓派,原理如下:Arduino烧入了项目2-4的代码到下位机里,能使小车接收到串口的时候,小车能动起来就行了。然后再执行上位机树莓派的python代码,这里向下位机Arduino发送串口数据,下位机接收到后,执行相对应的小车的轮子状态。小车就动起来了,就这么简单。
但是发现,python的raw_input()函数有2个问题,第一需要输入字符后按回车键,第二如果想要用键盘上的上下左右(方向键)和空格控制小车(上下左右和停止这5个状态的话),无法实现,因为方向键不是字符。
所以我上百度找了很久,找了一节课还是没有找到,但是周末的时候我一直在找,这个肯定是可以做的,然后找到了一个库叫keyboard库,顾名思义就是键盘库,当然能监听到键盘的动作,然后根据检测到键盘的方向键和空格就执行相对应的操作。这里可以看我下一篇文章。

项目4-1(摄像头拍摄)

树莓派通过摄像头获取一张大小为 320x240 的图片,并将图片显示到树莓派的显示屏上。

python python2

1
2
3
4
5
6
7
from SimpleCV import Camera, Display #从 SimpleCV 中导入 Camera 和 Display 的库
import time #导入时间库

cam = Camera() #打开摄像头
while True:
img = cam.getImage().resize(320,240) #从摄像头获取一张大小为 320x240 的图片
im g.show() #将图片显示到屏幕

把摄像头连接到树莓派 Camera 接口。 然后在小车的Linux系统运行程序。

项目4-2(键盘遥控机器人并摄像头拍摄(多线程))

树莓派实现多线程运行:树莓派键盘遥控小车运动和摄像头拍摄同时进行。

python python2

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
from SimpleCV import Camera,Display #从 SimpleCV 中导入 Camera 和 Display 的库
import time #导入时间库
import serial #导入串口库
import thread #导入线程库

cam = Camera() #打开摄像头
dis = Display(resolution=(320,240))
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=1)
def Camera(threadname): #定义名为 Camera 的函数,在函数中实现摄像头拍摄并显示的功能
print "%s is run!" % threadname
while True:
img = cam.getImage()
img.save(dis)

def Remote_control(threadname): #定义 Remote_control 函数,控制小车运动
print "%s is run!" % threadname
while True:
tmp = raw_input("please input :")
if tmp=='w':
print("Forward")
ser.write('w')
elif tmp=='a':
print("Turn Left")
ser.write('a')
elif tmp == 's':
print("Back")
ser.write('s')
elif tmp == 'd':
print("Turn Right")
ser.write('d')
else:
print("Stop")
ser.write('t')

thread.start_new_thread(Camera,("Camera",)) #开启一个新线程,开启摄像头
thread.start_new_thread(Remote_control,("Remote control",)) #开启一个新线程遥控小车
while True:
pass

1、把摄像头连接到树莓派的 Camera 接口。
2、Arduino 板通过 USB 数据线连接到树莓派的一个 USB 端口。

项目4-2拓展

1)键盘遥控小车的运动:
“w”—前进;“s”—后退;“a”—左转;“d”—右转;“q”—停止;
同时,屏幕上分别显示提示语:前进、后退、左转、右转、停止。
2) 小车头前安装一个摄像头,在小车行进的过程中能够即时地捕捉车前面沿途的图像,并以大小为
380x380 显示到树莓派的显示屏上。

python python2

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
from SimpleCV import Camera,Display #从 SimpleCV 中导入 Camera 和 Display 的库
import time #导入时间库
import serial #导入串口库
import thread #导入线程库

cam = Camera() #打开摄像头
dis = Display(resolution=(380,380))
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=1)
def Camera(threadname): #定义名为 Camera 的函数,在函数中实现摄像头拍摄并显示的功能
print "%s is run!" % threadname
while True:
img = cam.getImage()
img.save(dis)

def Remote_control(threadname): #定义 Remote_control 函数,控制小车运动
print "%s is run!" % threadname
while True:
tmp = raw_input("please input :")
if tmp=='w':
print("前进")
ser.write('w')
elif tmp=='a':
print("左转")
ser.write('a')
elif tmp == 's':
print("后退")
ser.write('s')
elif tmp == 'd':
print("右转")
ser.write('d')
else:
print("停止")
ser.write('t')

thread.start_new_thread(Camera,("Camera",)) #开启一个新线程,开启摄像头
thread.start_new_thread(Remote_control,("Remote control",)) #开启一个新线程遥控小车
while True:
pass

项目4-3(人脸识别)

树莓派连接摄像头,进行人脸检测,判断是否有已检测到的人脸。若有,则在检测到的人脸上画一个
红色的圈,打印人脸所在的坐标;若没有检测到人脸,则打印“No Face!”

python python2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from SimpleCV import Camera,Display #从 SimpleCV 库中导入 Camera 和 Display 库
from time import sleep #从 time 库中导入 sleep 库
cam=Camera() #打开摄像头
dis = Display(resolution=(320,240)) #设置显示窗口大小 320x240
while 1:
img = cam.getImage() #从摄像头获取一帧图像
faces = img.findHaarFeatures('face.xml') #从这帧图像中寻找是否存在人脸
if faces: #判断是否有已识别到的人脸
for face in faces:
faces.draw(color=(255,0,0),width=3) #在识别到的人脸上画一个红色的圈
print "Find Face!"+str(face.coordinates()) #打印人脸所在的坐标
else:
print "No Face!" #打印没有人脸
img.save(dis)

项目4-3拓展

树莓派连接摄像头,进行人脸检测,摄像头画面窗口尺寸为 480*480,若检测到人脸,则在检测到
的人脸上画一个绿色的圈,打印人脸所在的坐标;若没有检测到人脸,则打印“No Face!”

python python2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from SimpleCV import Camera,Display #从 SimpleCV 库中导入 Camera 和 Display 库
from time import sleep #从 time 库中导入 sleep 库
cam=Camera() #打开摄像头
dis = Display(resolution=(480,480)) #设置显示窗口大小 320x240
while 1:
img = cam.getImage() #从摄像头获取一帧图像
faces = img.findHaarFeatures('face.xml') #从这帧图像中寻找是否存在人脸
if faces: #判断是否有已识别到的人脸
for face in faces:
faces.draw(color=(0,255,0),width=3) #在识别到的人脸上画一个红色的圈
print "Find Face!"+str(face.coordinates()) #打印人脸所在的坐标
else:
print "No Face!" #打印没有人脸
img.save(dis)

项目5-1(树莓派UI界面控制机器人运动)

在树莓派上进行 UI 界面设计,创建五个按钮,分别控制小车的前进、后退、左转、右转、停止。
在下位机写入项目2-4代码让小车能接收串口并执行对应操作

python python2

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
import tkinter
import serial
import time
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
def hitup():
print('前进')
ser.write(bytes('w','utf-8'))
def hitdown():
print('后退')
ser.write(bytes('s','utf-8'))
def hitleft():
print('左转')
ser.write(bytes('a','utf-8'))
def hitright():
print('右转')
ser.write(bytes('d','utf-8'))
def hitstop():
print('停止')
ser.write(bytes('q','utf-8'))

if __name__ == '__main__':
root = tkinter.Tk()
root.geometry("300x180")
root.title("my Car")

button_up=tkinter.Button(root,text='前进',width=15,heigh=2,command=hitup)
button_up.pack()
button_up.place(x=20,y=40,width=40,height=40)

button_down=tkinter.Button(root,text='后退',width=15,heigh=2,command=hitdown)
button_down.pack()
button_down.place(x=80,y=40,width=40,height=40)

button_left=tkinter.Button(root,text='左转',width=15,heigh=2,command=hitleft)
button_left.pack()

button_left.place(x=140,y=40,width=40,height=40)

button_right=tkinter.Button(root,text='右转',width=15,heigh=2,command=hitright)
button_right.pack()
button_right.place(x=200,y=40,width=40,height=40)

button_stop=tkinter.Button(root,text='停止',width=15,heigh=2,command=hitstop)
button_stop.pack()
button_stop.place(x=260,y=40,width=40,height=40)
root.mainloop()

项目5-1拓展

请完善下列代码,绘制如右图 UI 界面,并实现按钮的相应功能(控制小车前进、后退、左转、右转、停止),并将窗体名称改为myRobot。


Pulpit rock

python python2

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
# -*- coding: utf-8 -*-
from tkinter import * #导入图形库 tkinter
import serial
import time
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)

root = Tk() #标题
root.geometry('260x260') #建立尺寸为 260*260 的窗体
root.title("myRobot")

label_f = Frame(root) #窗体框架
Temp_Label = Label(label_f,text="00 度",width=10,height=2) #建立标签显示温度,在窗体内
Temp_Label.pack() #获取温度函数
Distance_Label = Label(label_f,text="00cm",width=10,height=2) #建立标签显示距离,在窗体内
Distance_Label.pack()#获取距离的函数
RunTime_Label = Label(label_f,text="Run time:0s",width=10,height=2)#建立标签显示时间,在窗体内
RunTime_Label.pack()#获取时间的函数
label_f.pack(side=TOP)#顶部居中
RunTime_Count = 0 #
def Runtime(): #定义函数,1 秒进入一次此函数,相当于定时器中断函数
global RunTime_Count #声明全局变量
RunTime_Count+=1 #加 1
RunTime_Label.config(text="Run times:"+str(RunTime_Count)+"s") #显示运行时间
root.after(1000,Runtime) #1000 毫秒之后,调用函数 Runtime

def Forward(): #定义前进函数
print("Forward")
ser.write(bytes('w','utf-8'))
def TurnLeft(): #定义左转函数
print("TurnLeft")
ser.write(bytes('a','utf-8'))
def TurnRight():
print("TurnRight")
ser.write(bytes('d','utf-8'))
def Back():
print("Back")
ser.write(bytes('s','utf-8'))
def Stop():
print("Stop")
ser.write(bytes('q','utf-8'))

button_f = Frame(root)
B1=Button(button_f,text="Up",command=Forward,bg='green',width=10,height=2)#在窗体里创建按钮 up
B1.pack(side=TOP)
B2=Button(button_f,text="Down",command=Back,bg='green',width=10,height=2)#在窗体里创建按钮
B2.pack(side=BOTTOM)
B3=Button(button_f,text="Left",command=TurnLeft,bg='green',width=10,height=2) #在窗体里创建按钮
B3.pack(side=LEFT)
B4=Button(button_f,text="Right",command=TurnRight,bg='green',width=10,height=2)
B4.pack(side=RIGHT)
B5=Button(button_f,text="Stop",command=Stop,bg='red',width=10,height=2)
B5.pack(anchor=CENTER)
button_f.pack(side=BOTTOM)
root.after(1000,Runtime) #每 1000 毫秒之后,调用函数 Runtime
root.mainloop()#死循环

项目5-2

通过树莓派上的 UI 界面上的按钮控制或键盘上的按键控制机器人运动。

python python3

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import RPi.GPIO as GPIO
import tkinter #python3 下,库名小写
import serial
import time
import _thread
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
bit = True
Down_Count=0
Up_Count=0
Time_Count=0
Key_Val =" "
Last_Key_Val=" "
Down_Flag=0
def Dth():
#button.StringVar().set(' ')
ser.write(bytes('w','utf-8'))
print("现在是前进")
def Dth1():
#button.StringVar().set(' ')
ser.write(bytes('q','utf-8'))
print("现在是停止")
def Dth2():
#button.StringVar().set(' ')
ser.write(bytes('s','utf-8'))
print("现在是后退")
def Dth3():
#button.StringVar().set(' ')
ser.write(bytes('a','utf-8'))
print("现在是左转")
def Dth4():
#button.StringVar().set(' ')
ser.write(bytes('d','utf-8')) #python3 下,需要将字符转成 8bit 的编码 utf-8
print("现在是右转")

def led():
global bit
if (bit==True):
print("led 亮")
GPIO.output(17, GPIO.HIGH)
bit = -bit
else:
print("led 灭")
GPIO.output(17, GPIO.LOW)
bit = -bit


if __name__ == '__main__':
root = tkinter.Tk()
root.geometry("520x200")
root.title("请点击以下按钮或按动键盘(w、s、a、d、q)")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth)
button.pack()
button.place(x=150,y=150,width=50,height=40)
button.config(text="前进")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth2)
button.pack()
button.place(x=210,y=150,width=50,height=40)
button.config(text="后退")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth3)
button.pack()
button.place(x=270,y=150,width=50,height=40)
button.config(text="左转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth4)
button.pack()
button.place(x=320,y=150,width=50,height=40)
button.config(text="右转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth1)
button.pack()
button.place(x=240,y=100,width=50,height=40)
button.config(text="停止")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=led)
button.pack()
button.place(x=240,y=50,width=50,height=40)
button.config(text="led")
root.mainloop()


def Key_Down(event):
global Time_Count,Key_Val,Last_Key_Val,Down_Flag
Key_Val = event.char
if (Last_Key_Val!=Key_Val):
Last_Key_Val = Key_Val
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
if (Key_Val=='w'):
print("前进")
ser.write(bytes('w','utf-8'))
elif(Key_Val=='a'):
print("左转")
ser.write(bytes('a','utf-8'))
elif(Key_Val=='d'):
print("右转")
ser.write(bytes('d','utf-8'))
elif(Key_Val=='s'):
print("后退")
ser.write(bytes('s','utf-8'))
elif(Key_Val=='q'):
print("停止")
ser.write(bytes('q','utf-8'))
ser.close()
Down_Flag=1

root.bind("<Key>",Key_Down)

结合项目2-4一起做

项目5-2

在上述程序基础上,再在 UI 界面上加上一个按钮控制 LED 亮灭

python python3

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import RPi.GPIO as GPIO
import tkinter #python3 下,库名小写
import serial
import time
import _thread
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
bit = True
Down_Count=0
Up_Count=0
Time_Count=0
Key_Val =" "
Last_Key_Val=" "
Down_Flag=0
def Dth():
#button.StringVar().set(' ')
ser.write(bytes('w','utf-8'))
print("现在是前进")
def Dth1():
#button.StringVar().set(' ')
ser.write(bytes('q','utf-8'))
print("现在是停止")
def Dth2():
#button.StringVar().set(' ')
ser.write(bytes('s','utf-8'))
print("现在是后退")
def Dth3():
#button.StringVar().set(' ')
ser.write(bytes('a','utf-8'))
print("现在是左转")
def Dth4():
#button.StringVar().set(' ')
ser.write(bytes('d','utf-8')) #python3 下,需要将字符转成 8bit 的编码 utf-8
print("现在是右转")

def led():
global bit
if (bit==True):
print("led 亮")
GPIO.output(17, GPIO.HIGH)
bit = -bit
else:
print("led 灭")
GPIO.output(17, GPIO.LOW)
bit = -bit


if __name__ == '__main__':
root = tkinter.Tk()
root.geometry("520x200")
root.title("请点击以下按钮或按动键盘(w、s、a、d、q)")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth)
button.pack()
button.place(x=150,y=150,width=50,height=40)
button.config(text="前进")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth2)
button.pack()
button.place(x=210,y=150,width=50,height=40)
button.config(text="后退")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth3)
button.pack()
button.place(x=270,y=150,width=50,height=40)
button.config(text="左转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth4)
button.pack()
button.place(x=320,y=150,width=50,height=40)
button.config(text="右转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth1)
button.pack()
button.place(x=240,y=100,width=50,height=40)
button.config(text="停止")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=led)
button.pack()
button.place(x=0,y=0,width=50,height=40)
button.config(text="led")
root.mainloop()


def Key_Down(event):
global Time_Count,Key_Val,Last_Key_Val,Down_Flag
Key_Val = event.char
if (Last_Key_Val!=Key_Val):
Last_Key_Val = Key_Val
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
if (Key_Val=='w'):
print("前进")
ser.write(bytes('w','utf-8'))
elif(Key_Val=='a'):
print("左转")
ser.write(bytes('a','utf-8'))
elif(Key_Val=='d'):
print("右转")
ser.write(bytes('d','utf-8'))
elif(Key_Val=='s'):
print("后退")
ser.write(bytes('s','utf-8'))
elif(Key_Val=='q'):
print("停止")
ser.write(bytes('q','utf-8'))
elif(Key_Val=='l'):
print("LED")
led()
ser.close()
Down_Flag=1

root.bind("<Key>",Key_Down)

项目5-2 自己拓展

通过上下左右空格控制小车+L键控制灯

python python3

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import RPi.GPIO as GPIO
import tkinter #python3 下,库名小写
import serial
import time
import _thread
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
bit = True
Down_Count=0
Up_Count=0
Time_Count=0
Key_Val =" "
Last_Key_Val=" "
Down_Flag=0
def Dth():
#button.StringVar().set(' ')
ser.write(bytes('w','utf-8'))
print("现在是前进")
def Dth1():
#button.StringVar().set(' ')
ser.write(bytes('q','utf-8'))
print("现在是停止")
def Dth2():
#button.StringVar().set(' ')
ser.write(bytes('s','utf-8'))
print("现在是后退")
def Dth3():
#button.StringVar().set(' ')
ser.write(bytes('a','utf-8'))
print("现在是左转")
def Dth4():
#button.StringVar().set(' ')
ser.write(bytes('d','utf-8')) #python3 下,需要将字符转成 8bit 的编码 utf-8
print("现在是右转")

def led():
global bit
if (bit==True):
print("led 亮")
GPIO.output(17, GPIO.HIGH)
bit = -bit
else:
print("led 灭")
GPIO.output(17, GPIO.LOW)
bit = -bit


if __name__ == '__main__':
root = tkinter.Tk()
root.geometry("520x200")
root.title("请点击以下按钮或按动键盘(上下左右空格和L)")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth)
button.pack()
button.place(x=150,y=150,width=50,height=40)
button.config(text="前进")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth2)
button.pack()
button.place(x=210,y=150,width=50,height=40)
button.config(text="后退")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth3)
button.pack()
button.place(x=270,y=150,width=50,height=40)
button.config(text="左转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth4)
button.pack()
button.place(x=320,y=150,width=50,height=40)
button.config(text="右转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth1)
button.pack()
button.place(x=240,y=100,width=50,height=40)
button.config(text="停止")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=led)
button.pack()
button.place(x=0,y=0,width=50,height=40)
button.config(text="led")
root.mainloop()


def Key_Down(event):
global Time_Count,Key_Val,Last_Key_Val,Down_Flag
Key_Val = event.keycode
if (Last_Key_Val!=Key_Val):
Last_Key_Val = Key_Val
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
if (Key_Val==111):#up
print("前进")
ser.write(bytes('w','utf-8'))
elif(Key_Val==113):#left
print("左转")
ser.write(bytes('a','utf-8'))
elif(Key_Val==114):#right
print("右转")
ser.write(bytes('d','utf-8'))
elif(Key_Val==116):#down
print("后退")
ser.write(bytes('s','utf-8'))
elif(Key_Val==65):#space
print("停止")
ser.write(bytes('q','utf-8'))
elif(Key_Val==46):#L
led()
return
ser.close()
Down_Flag=1

root.bind("<Key>",Key_Down)

项目5-3

UI 界面或蓝牙键盘控制机器人运动并伴有运动改变提示 LED(或转向 LED)。自行设计完成。
python python3

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import RPi.GPIO as GPIO
import tkinter
import serial
import time
import _thread
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(27, GPIO.OUT)
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)

bit = True
Key_Val =" "
Last_Key_Val=" "
def Dth():
ser.write(bytes('w','utf-8'))
print("现在是前进")
doublelight()
def Dth1():
ser.write(bytes('q','utf-8'))
print("现在是停止")
doublelight()
def Dth2():
ser.write(bytes('s','utf-8'))
print("现在是后退")
doublelight()
def Dth3():
ser.write(bytes('a','utf-8'))
print("现在是左转")
leftshorled()
def Dth4():
ser.write(bytes('d','utf-8'))
print("现在是右转")
rightshorled()

def led():
global bit
if (bit==True):
print("led亮")
GPIO.output(17, GPIO.HIGH)
bit=-bit
else:
print("led 灭")
GPIO.output(17, GPIO.LOW)
bit = -bit

def shortled():
GPIO.output(17, GPIO.HIGH)
GPIO.output(27, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(17, GPIO.LOW)
GPIO.output(27, GPIO.LOW)
def doublelight():
shortled()
time.sleep(0.3)
shortled()
time.sleep(0.3)
shortled()
def leftshorled():
GPIO.output(17, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(17, GPIO.LOW)
time.sleep(0.3)
GPIO.output(17, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(17, GPIO.LOW)
def rightshorled():
GPIO.output(27, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(27, GPIO.LOW)
time.sleep(0.3)
GPIO.output(27, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(27, GPIO.LOW)

if __name__ == '__main__':
root = tkinter.Tk()
root.geometry("400x200")
root.title("点击按钮或键盘带变向 led 闪烁")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth)
button.pack()
button.place(x=0,y=150,width=50,height=40)
button.config(text="前进")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth2)
button.pack()
button.place(x=60,y=150,width=50,height=40)
button.config(text="后退")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth3)
button.pack()
button.place(x=120,y=150,width=50,height=40)
button.config(text="左转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth4)
button.pack()
button.place(x=180,y=150,width=50,height=40)
button.config(text="右转")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=Dth1)
button.pack()
button.place(x=90,y=100,width=50,height=40)
button.config(text="停止")
button = tkinter.Button(root,text='按钮',width=10,height=2,command=led)
button.pack()
button.place(x=90,y=50,width=50,height=40)
button.config(text="led")
root.mainloop()

def Key_Down(event):
global Key_Val,Last_Key_Val
Key_Val = event.char
if (Last_Key_Val!=Key_Val):
Last_Key_Val = Key_Val
ser = serial.Serial("/dev/ttyUSB0",9600,timeout=0.1)
if (Key_Val=='w'):
print("前进")
ser.write(bytes('w','utf-8'))
doublelight()
elif(Key_Val=='a'):
print("左转")
ser.write(bytes('a','utf-8'))
leftshorled()
elif(Key_Val=='d'):
print("右转")
ser.write(bytes('d','utf-8'))
rightshorled()
elif(Key_Val=='s'):
print("后退")
ser.write(bytes('s','utf-8'))
doublelight()
elif(Key_Val=='q'):
print("停止")
ser.write(bytes('q','utf-8'))
doublelight()
ser.close()

root.bind("<Key>",Key_Down)#监听到有按键则执行函数 Key_Down

项目6-1

Arduino 连接超声波传感器,实现测距,树莓派通过串口获取 Arduino 测的距离值。

c c++

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
#define Echo 3
#define Trig 2
#define Min_Distance 20
int distance;
char Now_status = 0;
void setup()
{
pinMode(3, INPUT);
pinMode(2, OUTPUT);
Serial.begin(9600);
}

void Distance() {
digitalWrite(2, LOW);
delayMicroseconds(2);
digitalWrite(2, HIGH);
delayMicroseconds(10);
digitalWrite(2, LOW);
distance = pulseIn(3, HIGH) / 58;
}
void loop() {
unsigned char Serial_Dat = 0;
while (1)

{
if (Serial.available() > 0)

{
Serial_Dat = Serial.read();
Distance();
switch (Serial_Dat)
case 'r':
Serial.print(distance);
break;

}

}
}

python python3

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
import serial
import time
import threading
ser = serial.Serial("/dev/ttyUSB0", 9600, timeout=0.1)
Ser_Data = ' '
def Save_To_File(file_name, contents):
fh = open(file_name, 'w')
fh.write(contents)
fh.close()
def Get_Distance():
global ser
global Ser_Data
if (ser.inWaiting()>0):
Ser_Data += str(ser.readline(), "utf-8")
if (Ser_Data !=' '):
print("Distance:"+str(Ser_Data)+"cm")
Save_To_File("Distance.txt", Ser_Data)
Ser_Data=' '
def Request_Distance():
global ser
ser.write(bytes('r', 'utf-8'))
if __name__ == '__main__':
while True:
Get_Distance()
Request_Distance()
time.sleep(1)

项目6-1拓展

实现“倒车报警系统”,要求如下:(可参考项目 5-1 拓展 1,部分功能可能要在项目 6-2 之后实现)
1)树莓派屏幕上进行简单的 UI 设计:
开个窗体(标题可为:倒车报警系统);
设置两个标签,一个用于显示实时的车尾与障碍物之间的距离值,
一个用于显示倒车警示语:倒车,请注意!
同时,倒车影像显示在屏幕上;
报警灯 LED 熄灭。
2)当车尾与障碍物之间的距离小于 5cm 时,启动报警提示:
(1) 报警灯 LED 高频闪烁;
(2) 距离值显示为红色字体;
(3) 倒车警示语变为:停车!停车!(红色字体)

c c++ arduino

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#define Echo 3
#define Trig 2
#define Min_Distance 20
/*---------xm2-4----------*/
#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控制
/*---------xm2-4----------*/

int distance;
char Now_status = 0;
void setup()
{
pinMode(3, INPUT);
pinMode(2, OUTPUT);
/*---------xm2-4----------*/
pinMode(Left1, OUTPUT); //设置Arduino控制电机的6个引脚均为输出模式
pinMode(Left2, OUTPUT);
pinMode(Right1, OUTPUT);
pinMode(Right2, OUTPUT);
pinMode(Left_PWM, OUTPUT);
pinMode(Right_PWM, OUTPUT);
/*---------xm2-4----------*/
Serial.begin(9600);

}
void Distance() {
digitalWrite(2, LOW);
delayMicroseconds(2);
digitalWrite(2, HIGH);
delayMicroseconds(10);
digitalWrite(2, LOW);
distance = pulseIn(3, HIGH) / 58;
}
/*---------xm2-4----------*/
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);
}
/*---------xm2-4----------*/

void loop() {
unsigned char Serial_Dat = 0;
while (1)
{
if (Serial.available() > 0)
{
Serial_Dat = Serial.read();
Distance();
switch (Serial_Dat) {
case 'r': //串口监视器输出距离值
Serial.print(distance);
break;
/*---------xm2-4----------*/
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;
/*---------xm2-4----------*/
}
}
}
}

由于库的问题和小车上的python版本问题,最终选择了python2

python python2

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# coding:utf-8

#python2 code by ROT 真机可以直接运行,不能保证一定运行顺利

from SimpleCV import Camera,Display
import time # 导入时间库
import serial #导入串口库
import thread # 导入线程库
import Tkinter as tkinter

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(27, GPIO.OUT)

bit = True
Key_Val = " "
Last_Key_Val = " "
distanceValue = "10" #data loading

def sendDataAndUseTheCamera(threadname):
#这里可以向下位机发送串口数据,并且调用摄像头
global distanceValue
while True:
#模拟接收并改变
value = int(distanceValue)

if(value<5):
value = value + 1
else:
value = value - 1

distanceValue = str(value)
time.sleep(1)
print(distanceValue)

#模拟结束

#发送串口并接收arduino的控制台返回来的信息
ser.write(bytes('r', 'utf-8'))
if (ser.inWaiting() > 0):
distanceValue= str(ser.readline(), "utf-8")
print(distanceValue)
time.sleep(0.5)

#输出摄像头画面
img = cam.getImage().resize(320, 240) # 从摄像头获取一张大小为 320x240 的图片
img.show() # 将图片显示到屏幕

def JudeTheDistanceAndSetIt(threadname):
#这里一直检测值的改变
while True:
root.bind("<Key>", Key_Down) #监听到有按键则执行函数 Key_Down
distanceText.set("目前距离障碍物距离:" + str(distanceValue) + "厘米") # 实时更改距离数据
if int(distanceValue) < 5: #当车尾与障碍物之间的距离小于 5cm 时,启动报警提示
# 改变字体颜色
distanceLabel.configure(fg="red") #距离值显示为红色字体

# 倒车警示语变为:停车!停车!(红色字体)
tipLabel.configure(fg="red")
tipText.set("停车!停车!")

# 报警灯 LED 高频闪烁;
GPIO.output(17, GPIO.LOW)
time.sleep(0.1)
GPIO.output(17, GPIO.HIGH)

else:
# 改变字体颜色
distanceLabel.configure(fg="black")
tipLabel.configure(fg="black")
# 改变label的值 一个用于显示倒车警示语:倒车,请注意!
tipText.set("倒车,请注意!")
GPIO.output(17, GPIO.LOW)# 报警灯 LED 熄灭。

def forward():
print("现在是前进")
ser.write(bytes('w', 'utf-8'))
doublelight()

def carStop():
print("现在是停止")
ser.write(bytes('q', 'utf-8'))
doublelight()

def forback():
print("现在是后退")
ser.write(bytes('s', 'utf-8'))
doublelight()

def turnLeft():
print("现在是左转")
ser.write(bytes('a', 'utf-8'))
leftshorled()

def turnRight():
print("现在是右转")
ser.write(bytes('d', 'utf-8'))
rightshorled()

def led():
global bit
if (bit == True):
print("led亮")
GPIO.output(17, GPIO.HIGH)
bit = -bit
else:
print("led 灭")
GPIO.output(17, GPIO.LOW)
bit = -bit

def shortled():
print("0.1s开启闪烁双灯")
GPIO.output(17, GPIO.HIGH)
GPIO.output(27, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(17, GPIO.LOW)
GPIO.output(27, GPIO.LOW)

def doublelight():
print("led闪两下")
shortled()
time.sleep(0.3)
shortled()
time.sleep(0.3)
shortled()

def leftshorled():
print("左灯闪烁")
GPIO.output(17, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(17, GPIO.LOW)
time.sleep(0.3)
GPIO.output(17, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(17, GPIO.LOW)

def rightshorled():
print("右灯闪烁")
GPIO.output(27, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(27, GPIO.LOW)
time.sleep(0.3)
GPIO.output(27, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(27, GPIO.LOW)

def Key_Down(event):
#检测键盘操控小车
global Key_Val,Last_Key_Val
Key_Val = event.char
if (Last_Key_Val!=Key_Val):
Last_Key_Val = Key_Val
if (Key_Val=='w'):
forward()
elif(Key_Val=='a'):
turnLeft()
elif(Key_Val=='d'):
turnRight()
elif(Key_Val=='s'):
forback()
elif(Key_Val=='q'):
carStop()

root = tkinter.Tk()
#开个窗体(标题可为:倒车报警系统)
root.geometry("520x250")
root.title("倒车报警系统")

cam = Camera()#开启摄像头 倒车影像显示在屏幕上

distanceText = tkinter.StringVar()
tipText = tkinter.StringVar()

tipText.set('倒车,请注意!')
distanceText.set("距离初始化未开始")

root.title("倒车报警系统")

#设置两个标签
#一个用于显示实时的车尾与障碍物之间的距离值,
distanceLabel = tkinter.Label(root, textvariable=distanceText, font=('宋体', 12), width=30, height=2)
distanceLabel.pack()
#一个用于显示倒车警示语:倒车,请注意!
tipLabel = tkinter.Label(root, textvariable=tipText, font=('宋体', 12), width=30, height=2)
tipLabel.pack()

button = tkinter.Button(root, text='前进', width=10, height=2, command=forward)
button.pack()
button.place(x=140, y=200, width=50, height=40)
button = tkinter.Button(root, text='后退', width=10, height=2, command=forback)
button.pack()
button.place(x=200, y=200, width=50, height=40)
button = tkinter.Button(root, text='左转', width=10, height=2, command=turnLeft)
button.pack()
button.place(x=260, y=200, width=50, height=40)
button = tkinter.Button(root, text='右转', width=10, height=2, command=turnLeft)
button.pack()
button.place(x=320, y=200, width=50, height=40)
button = tkinter.Button(root, text='停止', width=10, height=2, command=carStop)
button.pack()
button.place(x=230, y=150, width=50, height=40)
button = tkinter.Button(root, text='led', width=10, height=2, command=led)
button.pack()
button.place(x=230, y=100, width=50, height=40)

thread.start_new_thread(sendDataAndUseTheCamera, ("sendDataAndUseTheCamera",))
thread.start_new_thread(JudeTheDistanceAndSetIt, ("JudeTheDistanceAndSetIt",))
root.mainloop()

总结:判断小车距离障碍物的距离、调用摄像头和发送串口数据并接收,最好开启新的线程来操作。不然主线程会被卡死,陷入死循环。

未完待续,敬请期待更新~