本帖最后由 andsen 于 2023-8-12 13:54 编辑
众所周知,树莓派可玩性比较高。服务器方向:个人博客、临时中转站、爬虫脚本、提供web服务;多媒体方向:家庭音影中心、家庭监控;智能家居方向:智能家庭控制中心。其实上面说了这么多树莓派的用途,但是其实很多应用的场景都有相应的产品了。 那为什么还要玩树莓派? 因为,就是玩,就是要折腾。 何不发挥想象力,diy做些东西呢? 接下来,我将带大家一起来做一辆小车。
需求采用双轮差速方式移动 双轮方式需要的零件相对较少 通过网络远程控制小车 可通过wifi远程控制,或者配置内网穿透实现任意地点控制。 能够实时传送图像 安装摄像头模块 超声波测距 安装超声波测距模块 小车的结构大致仿照微雪电子的alphabot2
材料树莓派4b n20减速电机 x 2 43mm橡胶轮胎 x 2 小车万向轮 x 2 tb6612fng驱动模块 摄像头模块 超声波测距模块 导线、面包板等 tb6612fng驱动接口
vm:电机驱动电源输入(2.74-10.8v) vcc:逻辑电平输入(5.0v) ao1和ao2:接直流电机a bo2和bo1:接直流电机b pwma:控制电机a的转速 ain1和ain2:控制电机a(停止、正转、反转) stby:正常工作/待机状态控制端 pwmb:控制电机b的转速 bin1和bin2:控制电机b(停止、正转、反转) gnd:接地 ain1和ain2用于控制电机a停止、正转、反转,真值表如下
接线树莓派40pin引脚对照表
树莓派gpio和tb6612fng的接线情况如下表
电机驱动和树莓派4b共用一个5v 3a的电源 实际接线图
测试代码小车需要有前进、后退、左转、右转、停止等5个动作,使用python编写测试代码如下 测试结果将上述代码保存到motortest.py中,运行测试脚本python3 motortest.py #motortest.py #导入 gpio库 import rpi.gpio asgpio import time #设置 gpio 模式为 bcm gpio.setmode(gpio.bcm) #定义引脚 stby = 27 pwma = 18 ain1 = 14 ain2 = 15 pwmb = 19 bin1 = 23 bin2 = 24 #设置 gpio 的工作方式 gpio.setup(stby,gpio.out) gpio.setup(pwma,gpio.out) gpio.setup(ain1,gpio.out) gpio.setup(ain2,gpio.out) gpio.setup(pwmb,gpio.out) gpio.setup(bin1,gpio.out) gpio.setup(bin2,gpio.out) pwma =gpio.pwm(pwma,300) pwmb =gpio.pwm(pwmb,300) # 前进或后退(大于零前进,小于零后退) defgoforward(speed): if(speed>=0): gpio.output(ain1,gpio.low) gpio.output(ain2,gpio.high) gpio.output(bin1,gpio.low) gpio.output(bin2,gpio.high) pwma.start(speed) pwmb.start(speed) time.sleep(0.02) else: gpio.output(ain2,gpio.low) gpio.output(ain1,gpio.high) gpio.output(bin2,gpio.low) gpio.output(bin1,gpio.high) pwma.start(-speed) pwmb.start(-speed) time.sleep(0.02) # 左转或右转(大于零左转,小于零右转) def turnleft(speed): if(speed>=0): gpio.output(ain2,gpio.low) gpio.output(ain1,gpio.high) gpio.output(bin1,gpio.low) gpio.output(bin2,gpio.high) pwma.start(speed) pwmb.start(speed) time.sleep(0.02) else: gpio.output(ain1,gpio.low) gpio.output(ain2,gpio.high) gpio.output(bin2,gpio.low) gpio.output(bin1,gpio.high) pwma.start(-speed) pwmb.start(-speed) time.sleep(0.02) def motorstop(): gpio.output(ain1,gpio.low) gpio.output(ain2,gpio.low) gpio.output(stby,gpio.high) #以60%的速度前进 goforward(60) time.sleep(2) #以60%的速度后退 goforward(-60) time.sleep(2) #左转 turnleft(60) time.sleep(2) #右转 turnleft(-60) time.sleep(2) #停止 motorstop() pwma.stop() pwmb.stop() gpio.cleanup() 摄像头模块安装摄像头我使用的是csi视频接口的摄像头,500万像素,实图如下
摄像头的排线如下,需要将有金属条纹的一面(左图)朝向树莓派的hdmi接口,具有蓝色胶带的一面(右图)朝向usb接口
具体连接方式可参考下图
使树莓派支持摄像头sudo raspi-config 依次选择:interfaceoptions---camera---yes---finish---yes 测试拍照:以下命令将使树莓派拍摄一张照片,命名为image.jpg,保存到当前目录下 raspistill -oimage.jpg 录像:以下命令使树莓派拍摄一段5000毫秒的视频,命名为video.h264,保存到当前目录下 raspivid -ovideo.h264 -t 5000 raspivid 的输出是一段未压缩且不含声音的 h.264 视频流,可以使用gpac将其转为常用的mp4格式,以便播放 安装gpac sudo apt installgpac -y 将上述video.h264视频转换为video.mp4,帧率为24 mp4box -fps 24 -addvideo.h264 video.mp4 通过网页查看视频输出使用motion可以实现简单的远程视频监控 安装motion sudo apt installmotion -y 编辑/etc/default/motion文件,开启守护进程 sudo nano/etc/default/motion 取消注释:start_motion_daemon=yes 编辑/etc/motion/motion.conf文件 sudo nano/etc/motion/motion.conf 部分配置,详细见 #将deamon off 改成deamon on deamon on #设置视频分辨率 width 800 height 600 #视频帧率 framerate 24 stream_maxrate 30 #允许非本机访问总控制页面 webcontrol_localhostoff #允许非本机查看视频监控 stream_localhost off 启动motion sudo systemctl startmotion sudo motion 打开浏览器,输入如下url查看视频输出 http://树莓派ip:8080/ 或 http://树莓派ip:8081/
结束motion进程 sudo killall -termmotion hc-sr04超声波模块hc-sr04实图如下,其有四个引脚,分别为vcc、trig、echo、end
hc-sr04模块具体参数如下图
hc-sr04模块的工作原理(1)树莓派向 trig 脚发送一个10us 的脉冲信号。 (2) hc-sr04 接收到信号,开始发送超声波,并把 echo置为高电平,然后准备接收返回的超声波。 (3) hc-sr04 接收到返回的超声波,把 echo 置为低电平。 (4)echo 高电平持续的时间就是超声波从发射到返回的时间间隔。 (5)计算距离: 距离(单位:m) = (starttime - endtime) * 声波速度 / 2 声波速度取 343m/s 。 接线hc-sr04只有4个引脚
代码#导入 gpio库 import rpi.gpio asgpio import time #设置 gpio 模式为 bcm gpio.setmode(gpio.bcm) #定义 gpio 引脚使用bcm编码 trig = 5 echo = 6 #设置 gpio 的工作方式(in / out) gpio.setup(trig,gpio.out) gpio.setup(echo,gpio.in) # 获取距离信息 def getdistance(): # 向trig引脚发送10us的脉冲信号 gpio.output(trig, gpio.high) time.sleep(0.00001) gpio.output(trig, gpio.low) # 开始发送超声波的时刻 while gpio.input(echo)==0: pass starttime=time.time() # 收到返回超声波的时刻 while gpio.input(echo)==1: pass endtime=time.time() # 计算距离 距离=(声波的往返时间*声速)/2 timedelta = endtime - starttime distance = (timedelta * 34300) / 2 return distance if __name__ =='__main__': try: while true: dist = getdistance() print("distance = {:.2f}cm".format(dist)) time.sleep(1) # 每间隔1秒测量一次 except keyboardinterrupt: print("stopped") gpio.cleanup() 运行结果
外壳安装完成后的小车
web控制安装bottle库安装pip3 sudo apt installpython3-pip -y 安装bottle pip3 install bottle 代码1. 超声波测距模块# 超声波测距模块 hc-sr04 import rpi.gpio asgpio import time classmeasure(object): def __init__(self, gpio_trig, gpio_echo)-> none: super().__init__() self.gpio_trig = gpio_trig self.gpio_echo = gpio_echo gpio.setmode(gpio.bcm) #设置 gpio 的工作方式 (in / out) gpio.setup(gpio_trig, gpio.out) gpio.setup(gpio_echo, gpio.in) def getdistance(self): # 向trig引脚发送10us的脉冲信号 gpio.output(self.gpio_trig, true) time.sleep(0.00001) gpio.output(self.gpio_trig, false) # 开始发送超声波的时刻 while gpio.input(self.gpio_echo)==0: pass starttime=time.time() # 收到返回超声波的时刻 while gpio.input(self.gpio_echo)==1: pass endtime=time.time() # 计算距离距离=(声波的往返时间*声速)/2 timedelta = endtime - starttime distance = (timedelta * 34300) / 2 return round(distance,2) 2. 电机驱动模块# motorcontrol.py # tb6612fng电机驱动 # 电机控制 import rpi.gpio asgpio ''' self.gpio_pwm self.gpio_in1 self.gpio_in2 self.freq self.last_pwm self.pwm ''' class motor(object): def __init__(self, gpio_pwm, gpio_in1,gpio_in2, freq=300) -> none: super().__init__() self.gpio_pwm = gpio_pwm self.gpio_in1 = gpio_in1 self.gpio_in2 = gpio_in2 self.freq = freq gpio.setmode(gpio.bcm) #gpio.setwarnings(false) gpio.setup(self.gpio_pwm, gpio.out) gpio.setup(self.gpio_in1, gpio.out) gpio.setup(self.gpio_in2, gpio.out) self.pwm = gpio.pwm(self.gpio_pwm,self.freq) self.last_pwm = 0 self.pwm.start(self.last_pwm) ''' 静态方法 tb6612fng的stby引脚 1. gpio_stby int bcm编码号 2. status bool 为true则tb6612fng工作,反之待机默认为false ''' @staticmethod def standby(gpio_stby,status=false): gpio.setmode(gpio.bcm) #gpio.setwarnings(false) if status: gpio.setup(status, gpio.out) gpio.output(status, true) else: gpio.output(status, false) ''' 设置pwm占空比 1. dc 占空比 [0,100] ''' def __setpwm(self, dc): if dc != self.last_pwm: self.pwm.changedutycycle(dc) self.last_pwm = dc ''' 启动 1. speed int 范围[-100,100] 正数则正转,负数则反转 ''' def run(self, speed): if(speed>=0): gpio.output(self.gpio_in1, false) gpio.output(self.gpio_in2, true) self.__setpwm(speed) else: gpio.output(self.gpio_in1, true) gpio.output(self.gpio_in2, false) self.__setpwm(-speed) '''停止''' def stop(self): gpio.output(self.gpio_in1, false) gpio.output(self.gpio_in2, false) self.__setpwm(0) def cleanup(self): self.stop() self.pwm.stop() 3. 小车控制# carcontrol.py # 控制小车移动 (前进 后退 左转 右转) # 驱动:tb6612fng import rpi.gpio asgpio from motorcontrolimport motor from distance importmeasure ''' tb6612fng 接口 # stby gpio_stby = 27 # 左边电机 gpio_pwma = 18 gpio_ain1 = 14 gpio_ain2 = 15 # 右边电机 gpio_pwmb = 19 gpio_bin1 = 23 gpio_bin2 = 24 hc-sr04 接口 gpio_trig = 5 gpio_echo = 6 小车功能 1. 微调 2. 变速 3. 前进 4. 后退 5. 左转 6. 右转 7. 停车 8. 测距 ''' class car(object): def __init__(self) -> none: super().__init__() '''电机模块''' # stby引脚定义 self.gpio_stby = 27 gpio.setmode(gpio.bcm) #gpio.setwarnings(false) gpio.setup(self.gpio_stby, gpio.out) # 左右两个电机 self.motor_left = motor(18,14,15) self.motor_right = motor(19,23,24) # stby = true tb6612fng开始工作 motor.standby(self.gpio_stby,true) # 速度 占空比 self.motor_speed = 60 self.motor_left_speed = 60 self.motor_right_speed = 60 # 速度系数用于微调 self.motor_left_coefficient = 1.0 self.motor_right_coefficient = 1.0 '''超声波测距模块''' self.measure = measure(5, 6) # 微调 使两个电机转速一致 left=true向左微调 反之向右 def finetuning(self, left): if left: # 向左微调 左边的电机减速 右边的电机加速 self.motor_left_coefficient -= 0.05 self.motor_right_coefficient =0.05 else: # 向右边微调 左边的电机加速 右边的电机减速 self.motor_left_coefficient = 0.05 self.motor_right_coefficient -=0.05 # 更改速度 [0,100] def setspeed(self, speed): if speed>100: speed = 100 if speed<0: speed = 0 self.motor_speed = speed self.motor_left_speed =self.motor_left_coefficient * speed self.motor_right_speed =self.motor_right_coefficient * speed # 前进 def forward(self): self.motor_left.run(self.motor_left_speed) self.motor_right.run(self.motor_right_speed) # 后退 def backward(self): self.motor_left.run(-self.motor_left_speed) self.motor_right.run(-self.motor_right_speed) # 左转 def turnleft(self): self.motor_left.run(-self.motor_left_speed) self.motor_right.run(self.motor_right_speed) # 右转 def turnright(self): self.motor_left.run(self.motor_left_speed) self.motor_right.run(-self.motor_right_speed) # 停止 def stop(self): self.motor_left.stop() self.motor_right.stop() # 测距 def getdistance(self): return self.measure.getdistance() def getspeed(self): return self.motor_speed # 释放资源 def cleanup(self): self.motor_left.cleanup() self.motor_right.cleanup() gpio.cleanup() 4. 获取树莓派信息以下代码用于获取树莓派cpu温度、cpu使用率、ram使用率 # raspberryinfo.py # 获取树莓派 cpu温度 内存使用率 cpu使用率 import os # cpu温度 def getcputemp(): res = os.popen('vcgencmdmeasure_temp').readline() return(res.replace("temp=","").replace("'c\n","")) # cpu使用率 def getcpuusage(): return(str(os.popen("top -n1 | awk'/cpu\(s\):/ {print $2}'").readline().strip())) # ram信息 def getraminfo(): p = os.popen('free') i = 0 while 1: i = i 1 line = p.readline() if i==2: return(line.split()[1:4]) # 内存使用率 def getramusage(): ram_stats = getraminfo() return round(int(ram_stats[1]) /int(ram_stats[0])*100,1) 5. 小车web控制面板通过按钮或者键盘来控制小车移动
raspberry car controlpanel #front { margin-left: 55px; margin-bottom: 3px; } #rear{ margin-top: 3px; margin-left: 55px; } .btn{ background: #62559f; } 控制
6. 树莓派小车信息页面此页面嵌入到小车web控制面板页面中,显示小车速度(pwm占空比)、距离、cpu温度、cpu使用率、内存使用率 此页面1秒刷新一次
</font><font face="宋体">信息 7. 启动# start.py from bottle importget,post,run,request,template from carcontrolimport car from raspberryinfoimport * car = car() def main(status): print("event: " status) if status == "forward": car.forward() elif status == "backward": car.backward() elif status == "turnleft": car.turnleft() elif status == "turnright": car.turnright() elif status == "speedup": car.setspeed(car.getspeed() 5) elif status == "slowdown": car.setspeed(car.getspeed() - 5) elif status == "leftfinetuning": car.finetuning(true) elif status == "rightfinetuning": car.finetuning(false) elif status == "stop": car.stop() # 控制台 @get("/") def index(): print("request index.html") return template("index.html") # 控制小车 @post("/cmd") def cmd(): adss=request.body.read().decode() main(adss) return "ok" # 小车信息 @get("/info") def info(): print("update statusinformation") return template("info.html",speed=car.getspeed(), distance=car.getdistance(), cputemp=getcputemp(),cpuusage=getcpuusage(), ramusage=getramusage()) run(host='0.0.0.0',port=8088, debug=false) car.cleanup() 实测启动 sudo motion # 打开摄像头 python3 start.py 在浏览器中输入url进入树莓派小车控制页面 http://树莓派ip:8088 视频演示
(4 mb, 下载次数: 0)
|