一、认识树莓派
1.1对树莓派的认识
Raspberry Pi是新手用来学习Linux系统的绝佳入门工具,具有便携性、较易操作性、廉价等多种优点,但由于机能不足只能胜任一些简单的工作,在一部分功能上甚至可以达到pc的效果,由于“魔镜”等项目的出现,使我对其产生了兴趣,并自行购入pi400进行pc体验。
入学后,见到有选修课可以学习树莓派,为我开启了全新的旅程。
1.2 材料准备
树莓派4b开发板一块、树莓派IO口扩展板一块、40P排线+连接线若干、4B亚克力外壳、16G SD卡一张、读卡器一只、电源、面包板一块(可选:激光传感器、开关、超声波传感器、小车套装)
1.3 组装树莓派
由于上一届班级的优秀遗留,我们得以不用组装亚克力外壳,只需要把面包板连接并且第一次学习风扇引线即可,我很快组装成功,发现风扇有问题,经过老师帮助了解了面包板电源的分布。
1.4 安装操作系统
操作系统可谓是一波三折,由于第一次安装python后出现较大失误,第二次系统重装装错了镜像 ,最终才算是折腾好了系统,同时注意到pi400的镜像和4b型号是不通用的。
1.5 配置树莓派
利用scaanner查看IP地址
开启VNC服务并进行连接
树莓派官方系统raspbian自带的是国外的软件源,在国内使用经常会遇到无法下载软件的问题。需要修改sources.list文件
sudo nanos/etc/apt/sources.list
将初始化中的代码中默认的官方软件源注释掉 # ,并且添加:
deb http://mirrors.aliyun.com/raspbian/raspbian/ buster main contrib non-free rpi
deb-src http://mirrors.aliyun.com/raspbian/raspbian/ buster main contrib non-free rpi
1.6 启动树莓派
插电即可启动,在此期间连接手机热点,利用scanner搜索IP利用VNC连接
1.7 树莓派上的Linux
这里采用的是树莓派官方镜像老师定制版,基本操作和之前学习过的Ubuntu类似,只不过python最高版本只支持二系,这就意味着编程语法的部分改变,同时由于机能不足,操作略微有些卡顿,汉化不全,这对我来说是个算不得挑战的问题。
1.8 总结
树莓派(Raspberry Pi)是个好东西,只有信用卡大小,却有电脑的功能。 自问世以来,受众多计算机发烧友和创客的追捧,曾经一“派”难求。别看其外表“娇小”,内“心”却很强大,视频、音频等功能通通皆有,可谓是“麻雀虽小,五脏俱全”。
二、通过树莓派控制LED灯
2.1 原理
通过GPIO 库
2.2 实现过程
GPIO.setup(num, GPIO.IN)
GPIO.setup(num, GPIO.OUT)
我们可以通过GPIO.setup方法将相应引脚设置为输入模式或者输出模式
设置完之后,我们就可以通过GPIO.input和GPIO.output来接收或者发送高低电平,要是想点亮LED灯,我们只需要向相应的端口发送高电平即可。
2.3 源码
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(16,GPIO.OUT)
GPIO.output(16,GPIO.HIGH)
time.sleep(3)
GPIO.output(16,GPIO.LOW)
time.sleep(3)
GPIO.output(16,GPIO.HIGH)
time.sleep(3)
GPIO.claenup()
2.4 总结
通过加入延时,我们就可以实现灯的持续亮灭,由此我想到可以控制灯的闪烁频率实现信息摩斯电码传递。
三、设置小游戏
3.1准备工具
3.2 实现过程
由于图形化的页面和简易的控件,这次小实验并不需要编写源码,我们通过拖拽控件并输入相应的步数实现了人物的简单动作
3.3进阶玩法:设计小游戏
通过画图导入人物素材,子弹,战机,编程使按下相应按键的时候,战机发射子弹,通过默认碰撞面积实现击落敌机效果
3.4 总结
非常好玩的一个小游戏,儿童编程的良好引路工具,我觉得它降低了使用门槛,使编程的思想贯彻到孩提时期,而未来的世界编程一定是一项基本的技能,从此不难看出这项工具的易用性和前瞻性,scratch使非常好的从小孩入手的教育类工具。
四、python语言基础
4.1 python语言的历史
实质上是C++代码的封装。Python由荷兰数学和计算机科学研究学会的Guido van Rossum于1990 年代初设计,作为一门叫做ABC语言 的替代品。 Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的编程语言,随着版本的不断更新和语言新功能的添加,逐渐被用于独立的、大型项目的开发。
其特色是一个一个的工具包可以实现非常强大的功能,我同时期选修的人工智能与ai中便用python实现神经网络深度学习,让我体会到了只需要调用工具包即可完成C++中数百行内容的便利。
4.2 Linux系统
学语言逃离不了学习系统,而本门课程不需要太过于艰深的系统知识,只需要掌握诸如 sudo -I apt-get install pip等基本指令即可,对于Linux来说也是一种入门。
4.3 基本语法
打印 print(“ ”)
定义常量 #define
文本注释 # """p"""
布尔类型 True和False
列表赋值 names_python_pc = ['1','2','3','4']
字典 name_dictionary = {'老爸':300,'老婆':1000,'老妈':800,'自己':600,'孩子。':200}
在Python语言中,Python根据缩进来判断代码行与前一行的关系。如果代码的缩进相同,Python认为它们为一个语句块;否则就是两个语句块。一般使用tab按键缩进代码,有的IDE自动缩进代码,比如Pycharm.
条件有 if else
循环有for while
控制中有pass continue break
4.4 总结:
树莓派的编程离不开python语言的助力,在接下来的学习和今后的其他课程的学习,我相信先行学习过python的人会培养出编程的思维,另外还有熟练度的提升,从而使学习获得更大的助力。由此可见,本门课的开展对于提升我们的动手能力和实践能力使非常有帮助的。
五、python控制LED灯
同二不同,这里我们采用PWM调光等操作。
5.1 原理:
我们用到了一个保护电阻用来保护led灯的安全,剩下的事情便是学习pwm频率调光
具体语法是引用GPIO库里的pwm功能,期中需要两个参数,第一个是GPIO的引脚,第二个是频率,当然过高的频率可能会让CPU难以运算,一般会取到人眼观测范围内进行测试学习。
5.2 源码:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPI0.setup(17,GPI0.0UT)
GPIO.setup(18,GPIO.OUT)
GPIO.output(19,False)
pwm.start(O)
while True:
for i in range(0,101,1):
pwm.ChangeDutyCycle((i)
time.sleep(.02)
for i in range(100,-1,-1):
pwm.ChangeDutyCycle(i)
time.sleep(.02)
5.3 总结:
我将端口设置好输入输出格式后,便全然调用pwm模块进行控制,由于python库的简便性,我控制pwm自动递增递减频率,利用了changedutycycle的功能,最终的效果比直接控制端口输出更加精细化的控制和自动化的调节, 获得了极大的收获和乐趣。
六、红外避障传感器
测试图:
6.1原理:
红外线检测模块可以识别模块前方是否有物体阻挡,并在有物体阻挡时输出信号并亮起绿色灯光,并且值得一提的是,无论输出端是否有接入,绿灯独立亮起。
6.2 目的:
不难猜到,这样的一个模块如果装在小车上,对其的避障功能是一种很大的提升,通过程序设计,可以实现检测物体从而自动避障。
6.3 源码:
import RPi.GPIO as GPIO
ObstaclePin = 18
def setup():
GPIO.setmode(GPIO.BOARD) # Numbers GPIOs by physical location
GPIO.setup(ObstaclePin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def loop():
while True:
if (0 == GPIO.input(ObstaclePin)): #当检测到障碍物时,输出低电平信号
print "Barrier"
else :
print "Nothing"
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt:e
destroy()
6.4 代码解释及总结:
由于模块本身便可显示预知障碍能力,在加上本节课的机器失误较大,没能完成,后期补完代码,发现加了一些输出的功能,具体就是用起了输送的高低电平型号输出是否有障碍,可谓是非常有趣。
七、超声波测距
7.1 原理:
在超声波发射装置发出超声波,它的根据是接收器接到超声波时的时间差。超声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以计算出发射点距障碍物面的距离s,即:s=340t/2
7.2 源码:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO_TRIGGER = 17
GPIO_ECHO = 18
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)
def distance():
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
start_time = time.time()
stop_time = time.time()
# 记录发送超声波的时刻1
while GPIO.input(GPIO_ECHO) == 0:
start_time = time.time()
# 记录接收到返回超声波的时刻2
while GPIO.input(GPIO_ECHO) == 1:
stop_time = time.time()
# 计算超声波的往返时间 = 时刻2 - 时刻1
time_elapsed = stop_time - start_time
# 声波的速度为 343m/s, 转化为 34300cm/s。
distance = (time_elapsed * 34300) / 2
return distance
if __name__ == '__main__':
try:
while True:
dist = distance()
print("Measured Distance = {:.2f} cm".format(dist))
time.sleep(1)
# Reset by pressing CTRL + C
except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup()
7.3 模块展示:
7.4 总结:
除掉4端口接地没用之外,这也是我第一次接触这么多线,高中毕业以来,对于工学的追求没有这么苛刻,但是动手能力在这一次实验中得到了充分的展现,光是接线的错误,就已经让我焦头烂额,而且又经历了三轮超声波测距,结果返回只有一毫米的情况,调了几次单位也无济于事,相比较第一节课风扇都不会结的情况来说,我的能力已经有了很大的进步,这门课的效果可见一斑。所幸最后成功实现了输出,并且真正第一次掌握了地线、导线、不同端口的意义。
八、遥控小车
成品图:
PART 1
8.1 原理:
通过对于两个电机步进的调整,实现小车的前进、停止、左转、右转功能。具体来说,便用DC调整频率,使电机不断转动,带动轮子转动,而左右电机的指令不同,小车便能完成转弯和旋转的动作。同时定义速度功能,即通过dc频率控制运动速度。
8.2 源码:
import RPi.GPIO as GPIO
from time import sleep
EN1 = 17
IN1 = 16
IN2 = 13
EN2 = 20
IN3 = 19
IN4 = 18
def setup():
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN1,GPIO.OUT)
GPIO.setup(IN1,GPIO.OUT)
GPIO.setup(IN2,GPIO.OUT)
GPIO.setup(EN2,GPIO.OUT)
GPIO.setup(IN3,GPIO.OUT)
GPIO.setup(IN4,GPIO.OUT)
def speed(i1,i2):
dc1=i1
dc2=i2
p1.ChangeDutyCycle(dc1)
p2.ChangeDutyCycle(dc2)
def forward():
GPIO.output(IN1,GPIO.HIGH)
GPIO.output(IN2,GPIO.LOW)
GPIO.output(IN3,GPIO.HIGH)
GPIO.output(IN4,GPIO.LOW)
def backward():
GPIO.output(IN1,GPIO.LOW)
GPIO.output(IN2,GPIO.HIGH)
GPIO.output(IN3,GPIO.LOW)
GPIO.output(IN4,GPIO.HIGH)
def left():
GPIO.output(IN1,GPIO.HIGH)
GPIO.output(IN2,GPIO.LOW)
GPIO.output(IN3,GPIO.LOW)
GPIO.output(IN4,GPIO.HIGH)
def right():
GPIO.output(IN1,GPIO.LOW)
GPIO.output(IN2,GPIO.HIGH)
GPIO.output(IN3,GPIO.HIGH)
GPIO.output(IN4,GPIO.LOW)
def stop():
GPIO.output(EN1,0)
GPIO.output(EN2,0)
def clean():
GPIO.cleanup()
if __name__=="__main__":
setup()
p1 = GPIO.PWM(EN1,250)
p1.start(0)
p2 = GPIO.PWM(EN2,250)
p2.start(0)
try:
forward()
speed(100,100)
sleep(5)
left()
speed(30,30)
sleep(5)
right()
speed(30,30)
sleep(5)
speed(0,0)
stop()
clean()
except KeyboardInterrupt as e:
clean()
8.3 功能简述:
小车先是全速前进,停止五秒,左转,停止五秒,右转,停止五秒,停止,清除端口信息。
PART 2
8.4 原理
在上述程序的基础上,调用python的多线程的对键盘映射实现读取,从而调动指令,控制小车。
8.5 源码
!!注意不能直接用idle运行,要到存放目录采用 python 1.py运行
import RPi.GPIO as GPIO
from time import sleep
import threading
import sys
import sys, tty, termios
def getch():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
class KeyEventThread(threading.Thread):
def run(self):
print("thread");
Fun()
def Fun():
print("Fun")
while True:
key=getch()
if key=='q':
funExit()
exit()
return
elif key=='1':
print('speed 1')
funSpeed(100,100)
elif key=='2':
print('speed 2')
funSpeed(70,70)
elif key=='3':
print('speed 3')
funSpeed(20,20)
elif key=='w':
print('forward')
GPIO.output(MotorIN1,GPIO.HIGH)
GPIO.output(MotorIN2,GPIO.LOW)
GPIO.output(MotorIN3,GPIO.HIGH)
GPIO.output(MotorIN4,GPIO.LOW)
funSpeed(50,50)
elif key=='x':
print('backward')
GPIO.output(MotorIN1,GPIO.LOW)
GPIO.output(MotorIN2,GPIO.HIGH)
GPIO.output(MotorIN3,GPIO.LOW)
GPIO.output(MotorIN4,GPIO.HIGH)
funSpeed(50,50)
elif key=='a':
print('left')
GPIO.output(MotorIN1,GPIO.HIGH)
GPIO.output(MotorIN2,GPIO.LOW)
GPIO.output(MotorIN3,GPIO.LOW)
GPIO.output(MotorIN4,GPIO.HIGH)
funSpeed(50,50)
elif key=='d':
print('right')
GPIO.output(MotorIN1,GPIO.LOW)
GPIO.output(MotorIN2,GPIO.HIGH)
GPIO.output(MotorIN3,GPIO.HIGH)
GPIO.output(MotorIN4,GPIO.LOW)
funSpeed(50,50)
elif key=='s':
print('stop')
funSpeed(0,0)
else:
print("key="+key)
return
def funSpeed(i1,i2):
dc1=i1
dc2=i2
p1.ChangeDutyCycle(dc1)
p2.ChangeDutyCycle(dc2)
def funInit():
GPIO.setmode(GPIO.BCM)
GPIO.setup(MotorIN1,GPIO.OUT)
GPIO.setup(MotorIN2,GPIO.OUT)
GPIO.setup(MotorEN1,GPIO.OUT)
GPIO.setup(MotorIN3,GPIO.OUT)
GPIO.setup(MotorIN4,GPIO.OUT)
GPIO.setup(MotorEN2,GPIO.OUT)
def funExit():
print ("Stopping motor")
GPIO.output(MotorEN1,GPIO.LOW)
GPIO.output(MotorEN2,GPIO.LOW)
GPIO.cleanup()
MotorIN1 = 16
MotorIN2 = 13
MotorEN1 = 17
MotorIN3 = 19
MotorIN4 = 18
MotorEN2 = 20
print("Press 'q' to exit")
print("'w'=forward,'x'=backward,'a'=left,'d'=right,'s'=stop")
print("'1','2','3' motor speed")
funInit()
p1 = GPIO.PWM(MotorEN1,250)
p1.start(0)
p2 = GPIO.PWM(MotorEN2,250)
p2.start(0)
kethread = KeyEventThread()
kethread.start()
8.6 实现:
最终小车能根据键盘指令实时启动,不过由于部分原因,我组装的小车并不完善,颇有赶工的嫌疑,而且调速之后小车直接启动,也是一个不尽人意的小bug,但是能看见自己的小车能按照自己的指令如臂使指的运动,还是有非常大的成就感。
结课总结
课程结束了,但是工程的那种务实和动手精神深深地眷刻在了我的脑海中,对于实现自动化控制小车,还有之前的一系列小实验,我都感到非常的欣喜。虽然这只是一项入门,甚至说,树莓派的机能不足以实现复杂的功能,但是通过这次入门,我深深切切的感受到了python的便利和工程学的魅力。
最后感谢孙老师这几周的努力和孜孜不倦的教诲,把我们领进了一扇大门。
那迷人的世界,尽在我眼前