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)是个好东西,只有信用卡大小,却有电脑的功能。 自问世以来,受众多计算机发烧友和创客的追捧,曾经一“派”难求。别看其外表“娇小”,内“心”却很强大,视频、音频等功能通通皆有,可谓是“麻雀虽小,五脏俱全”。
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使非常好的从小孩入手的教育类工具。
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的人会培养出编程的思维,另外还有熟练度的提升,从而使学习获得更大的助力。由此可见,本门课的开展对于提升我们的动手能力和实践能力使非常有帮助的。
同二不同,这里我们采用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端口接地没用之外,这也是我第一次接触这么多线,高中毕业以来,对于工学的追求没有这么苛刻,但是动手能力在这一次实验中得到了充分的展现,光是接线的错误,就已经让我焦头烂额,而且又经历了三轮超声波测距,结果返回只有一毫米的情况,调了几次单位也无济于事,相比较第一节课风扇都不会结的情况来说,我的能力已经有了很大的进步,这门课的效果可见一斑。所幸最后成功实现了输出,并且真正第一次掌握了地线、导线、不同端口的意义。
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 功能简述:
小车先是全速前进,停止五秒,左转,停止五秒,右转,停止五秒,停止,清除端口信息。
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的便利和工程学的魅力。
最后感谢孙老师这几周的努力和孜孜不倦的教诲,把我们领进了一扇大门。
那迷人的世界,尽在我眼前