一、认识树莓派

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的便利和工程学的魅力。

最后感谢孙老师这几周的努力和孜孜不倦的教诲,把我们领进了一扇大门

那迷人的世界,尽在我眼前