基于树莓派的追光系统(python)

目录

前言

一、材料

二、硬件--控制逻辑

1.主设备的准备

1.启用树莓派的i2c设备

2.安装python-smbus

2.从设备的准备

1.BH1750

2.L298N驱动芯片

3.云台的准备

1.增加电机固定模块

2.增加bh1750固定模块

三、软件--程序逻辑

1.总程序逻辑

2.光强检测程序逻辑

3.电机驱动代码

四、本系统的缺点和改进空间

缺点1:使用的是直流电机

改进1:更换舵机

缺点2:转动方式不妥当

改进2:更换转轴(?)

五、学习经验

六、一点感慨

七、参考文章



前言

由于小组做的沙盘模型需要使用到追光系统,在展示时需要一个prototype(原型机),查阅一些资料后,决定以手头现有的树莓派和一些简单的材料制作了一个简单的太阳能追光系统。对于其中使用的原理(包括i2c通讯协议的具体内容),文末会给出一些比较好的参考文章,本人其实不甚精通。第一次写,也是第一次接触这类东西(此前还是一个连VCC、GND是什么都不知道的小白),如有不足之处,敬请指正。

目前还是第一代原型机,后续可能还会继续迭代。

展示:

基于树莓派的追光系统(python)

注:此系统使用的是bh1750,ADDR引脚的改变最多获得两个地址,因此树莓派只能同时控制两个(或许可以通过物理方式,从硬件上改变器件的从设备地址?暂未继续研究),所以本系统注定是单自由度的追光,需要做双自由度的追光系统的朋友请注意了。


一、材料

树莓派*1

光传感器(BH1750FVI)*2

直流电机(使用舵机更好)*1

L298N电路板(容易烧坏,可以多准备几个)*1

电池盒(用于供电)*1

云台(3D打印,包含bh1750保护盒*2)

面包板(环氧实验板亦可)

开关、导线、杜邦线若干


二、硬件--控制逻辑

1.主设备的准备

主设备当然是我们的树莓派,由于需要与光传感器bh1750交换信息(即从bh1750处获取光强信息),因此需要通过i2c协议来完成信息交流过程。L298N没有这样的需求,直接用GPIO口输出即可。

1.启用树莓派的i2c设备

        打开树莓派的终端

        输入

sudo raspi-config

        选择Interfacing Options高级设置

        将SPI和I2C设置为Enable

        重启系统

完成i2c设备的启用后,我们需要安装python-smbus,帮助我们更容易的书写树莓派与bh1750交互信息的程序。

2.安装python-smbus

        打开终端

        输入

sudo apt-get install python-smbus

(这个安装会附带安装i2c-tools,就不必再单独安装了)

2.从设备的准备

从设备就是我们的bh1750和L298N,进行的准备主要就是接线。这里进行一些简单的介绍。

1.BH1750

bh1750总共有五个引脚,分别是VCC、GND、SCL、SDA以及ADDR。

VCC连接树莓派输出3.3V电压的引脚

GND 连接树莓派的GND口

SCL和SDA分别是i2c时钟线和数据线,连接树莓派对应端口即可

ADDR是i2c的地址线,当这个引脚接GND时器件地址为0100011(0x23),接VCC时器件地址为1011100(0x5c)。

(注意:SDA和SCL连接要注意组合,要么都连.1,要么都连.0)

接线时注意ADDR一个接GND,一个接3.3V电压。

(图中树莓派VCC口代表3.3V电压口,写的时候没注意。。。)

检查:

        打开树莓派终端

        输入(注意:若SCL SDA接的都是.1则此处末尾写1,若为.0则将下面这行末尾的1改为0)

sudo i2cdetect -y 1

        出现如下结果,说明连接成功。

2.L298N驱动芯片

由于树莓派引脚输出的电流太小,并不能驱动直流电机转动,更不要说控制直流电机的转速了,所以我们需要加这样一个驱动芯片,协助我们控制电机。

preview

“上面为最常见的一款L298N芯片,值得注意的是,它已经内置的5V供电,所以不必从外面再接5V输入。届时5V端子将成为5V输出,为了保证L298N供电的稳定性(供电不足可能引起L298N的烧毁),不建议使用此5V供电作为单片机的电源。”

                                                                               ----《电机驱动芯片-L298N介绍》知乎北鸮

                                                                                                             (文末有该文章链接)

如同引文所说,我们不直接使用其5V供电,而是外接电池为其供电,本人使用的是两节3.7V的电池,焊上一个小开关,必要时方便关闭。

L298N有4个输出口,4个输入口,由于我们只需要控制一个电机,其实输出输入口只需各用两个即可。

 具体接线如上图。

当输入的引脚一个为高电平(1),一个为低电平(0)时,电机就会转动,转动方向与具体哪个引脚为高电平有关。

3.云台的准备

原云台是用于sg90舵机,且是有两个自由度(文末会放来源)。

由于我们项目比较赶,没有办法等到舵机到,只能先用手边的电机。

因此需要对这个模型进行一些更改。

1.第一代

1.增加电机固定模块

首先要说明使用电机随着旋转板转动的思路是不太好的,可惜当时没有意识到。

考虑到要将电机与旋转板固定起来,由于电机存在一个可以拧螺丝的凸起部分,由此设计了一个固定电机的结构。

然后电机主体就很无脑地用双面胶和旋转板固定的。。

现在想想当时设计确实不太合理,不过就测试来说,还是固定的比较牢固的,在测试过程和展示过程中都不会掉落。

2.增加bh1750固定模块

我们的光传感器上有两个可以拧螺丝的部位,按理来说是可以设计一个相同大小的螺丝孔直接固定在旋转板上的。但是在上网找bh1750模型参数的时候,刚好找到了“bh1750保护盒”,遂本着拿来主义,直接拿来用了,只需在旋转板上加装固定此保护盒的模块。

2.第二代

1.底座支架

2.固定光缆配件

3.线路梳理设计

4.固定舵机结构

(因为很快就装到沙盘里了,就没有一一拍照了……)


三、软件--程序逻辑

1.总程序逻辑

总程序逻辑讲起来比较简单,目标就是希望我们的追光器能实时监测光照环境,并做出响应。

为了我们的追光器不会过于敏感,我们需要设置一个阈值,当两个光照传感器光强之差的绝对值大于我们这个阈值的时候,再进行调整。

总程序逻辑如下:

        开始计次

        进入循环:{

        处理光传感器的数据

        若光强差大于阈值(20lx):

                往光照强的方向转动

        若光强小于阈值:

                计次加一

        检查计次,若计次为三:

                程序休息3s

                计次重置

                              }        

可以看到,这个程序还是比较简单的,但其中有两点值得一提:

        第一,往光照强的方向运动。我们希望我们的追光器能够比较准确地进行转动,不是以一个恒定的速度转动。而我们手中又可以得到比较精确的光强差,所以我们希望设置一个参数调整函数,在光强差较大时,以一个较快的速度进行转动,光强差较小的时候则以较小的速度进行微调,更快的达到平衡状态。

        第二,计次。此处计次的主要目的是展示要求,当计次达到三,也就是说,程序连续三次检测到两侧光强小于阈值,此时可以认为我们的追光器的光环境已经比较稳定了,因此我们让程序休息三秒,再进行后续的循环,这样设计的目的之一是我们有展示需求,并不是什么关键的逻辑。。。

2.光强检测程序逻辑

直接上代码:(逻辑详见注释)

import smbus
import time

#BH1750地址
__DEV_ADDR_1=0x23
__DEV_ADDR_2=0x5c

#控制字(都是bh1750的一些命令,可以在芯片手册上查到)
__CMD_PWR_OFF=0x00  #关机
__CMD_PWR_ON=0x01   #开机
__CMD_RESET=0x07    #重置
__CMD_CHRES=0x10    #持续高分辨率检测
__CMD_CHRES2=0x11   #持续高分辨率模式2检测
__CMD_CLHRES=0x13   #持续低分辨率检测
__CMD_THRES=0x20    #一次高分辨率
__CMD_THRES2=0x21   #一次高分辨率模式2
__CMD_TLRES=0x23    #一次分辨率
__CMD_SEN100H=0x42  #灵敏度100%,高位
__CMD_SEN100L=0X65  #灵敏度100%,低位
__CMD_SEN50H=0x44   #50%
__CMD_SEN50L=0x6A   #50%
__CMD_SEN200H=0x41  #200%
__CMD_SEN200L=0x73  #200%

bus=smbus.SMBus(1)

#
bus.write_byte(__DEV_ADDR_1,__CMD_PWR_ON)
bus.write_byte(__DEV_ADDR_1,__CMD_RESET)
bus.write_byte(__DEV_ADDR_1,__CMD_SEN100H)
bus.write_byte(__DEV_ADDR_1,__CMD_SEN100L)
bus.write_byte(__DEV_ADDR_1,__CMD_PWR_OFF)

#
bus.write_byte(__DEV_ADDR_2,__CMD_PWR_ON)
bus.write_byte(__DEV_ADDR_2,__CMD_RESET)
bus.write_byte(__DEV_ADDR_2,__CMD_SEN100H)
bus.write_byte(__DEV_ADDR_2,__CMD_SEN100L)
bus.write_byte(__DEV_ADDR_2,__CMD_PWR_OFF)


#获得第一台bh1750的光照强度(单位:lx)
def getIlluminance_1():
    bus.write_byte(__DEV_ADDR_1),__CMD_PWR_ON)
    bus.write_byte(__DEV_ADDR_1,__CMD_THRES2)
    time.sleep(0.2)
    res=bus.read_word_data(__DEV_ADDR,0)
    #read_word_data
    res=((res>>8)&0xff)|(res<<8)&0xff00
    res=round(res/(2*1.2),2)#根据芯片手册可知计算光强公式
    result="光照强度: "+str(res)+"lx"

    #可以在测试时去掉下一行的注释符号,观察是否正常输出
    #print(result)

    return res

#获得第二台bh1750的光照强度(单位:lx)
def getIlluminance_2():
    bus.write_byte(__DEV_ADDR_2),__CMD_PWR_ON)
    bus.write_byte(__DEV_ADDR_2,__CMD_THRES2)
    time.sleep(0.2)
    res=bus.read_word_data(__DEV_ADDR,0)
    #read_word_data
    res=((res>>8)&0xff)|(res<<8)&0xff00
    res=round(res/(2*1.2),2)#根据芯片手册可知计算光强公式
    result="光照强度: "+str(res)+"lx"

    #可以在测试时去掉下一行的注释符号,观察是否正常输出
    #print(result)

    return res

#其实也可以用一个参数输入第一台第二台地址,就不用俩函数了,不过问题不大。。

(文末有源代码,这是我略微进行了一点改动和注释后的代码)

3.电机驱动代码

import RPi.GPIO as GPIO
import time

#这里填树莓派上对应端口,注意这里的编号规则是BOARD,你也可以使用BCM,不过需要在程序setmode中进行一些相应改动。
IN1 = 11
IN2 = 12

#初始化
def init():
    Pinlist = [IN1,IN2]
    GPIO.setup(Pinlist,GPIO.OUT,initial = GPIO.LOW)
    
def reset():
    p1.start(0)
    p2.start(0)


def run():
     p1.start(80)#设置duty cycle
     p2.start(0)
     time.sleep(1)
     print("done")
     reset()

def des_run():
     p1.start(0)
     p2.start(80)
     time.sleep(0.5)
     reset()

if __name__ == "__main__":
    
    GPIO.setmode(GPIO.BOARD)#设为BOARD编号规则
    GPIO.setwarnings(False)#关闭由于引脚被设为非默认值时的警告提示
    init()#初始化
    
    p1 = GPIO.PWM(IN1,50)#将此引脚初始化为PWM实例,频率为50Hz
    p2 = GPIO.PWM(IN2,50)

    run()#动起来!!
    des_run()#反方向动起来!



    GPIO.cleanup()#清除定义的引脚




四、本系统的缺点和改进空间

缺点1:使用的是直流电机

(你看这个电机真的是太逊了!)

我们并不能从直流电机那里获取到任何信息,因此,我们设计的程序必然是存在问题的,例如当电机已经旋转到死角的时候,它还会继续转动,因为我们对于其转动状态一无所知。电机内置的减速带也让电机的旋转非常不丝滑,观赏效果也不太好。

改进1:更换舵机

如果更换为舵机,一定程度上可以解决这个问题,我们的程序逻辑会更加准确,对于追光器的限位就可以不仅于物理层面(云台)。旋转起来也可以更加顺畅,而不是像现在这样一顿一顿的,减小对于光强检测的影响。

(更新:换用舵机后,由于sg90依然不能给我们返回信号,仅仅依靠sg90闭环控制不现实,所以旋转依旧是一顿一顿的,但是比原来稳定一些,关于是否使用pid的问题还在进一步探索,初步打算加装一个mpu6050的角度传感器检测姿态角。)

缺点2:转动方式不妥当

这是本人的问题,在设计的时候考虑不够周到,最后选择的方式是让电机转动,从力学结构来说,这样的结构缺乏稳定性,而且电机相对笨重,惯性也许也需要考虑在内,导致最后旋转的调整十分不精确。

改进2:更换转轴(?)

想了想如果换成舵机好像也不是不能让舵机和云台一起转,下周我将尝试使用舵机制作第二代模型,到时候再做定夺。

(更新:换用舵机后,sg90体型较小,也比较轻盈,转动板与舵机一起转动结构经测试还算稳定,如果舵机固定,就涉及到加长旋转轴的问题,对于比较不够精确的3D打印件来说不太合适,所以最后没有更换。)

五、学习经验

1.排错逻辑:

在进行一次测试的时候发现电机转得非常吃力,当时刚换上一个新的卡扣,怀疑是卡扣的问题。进行检查的时候,发现在测试程序中能很自然的转动,但在总程序中转动很吃力,怀疑是程序问题,经过一行一行更改注释,排除了程序问题。而后开始检查硬件,最后确定是电池电量不足导致,更换电池后解决问题。

2.3D打印设计预留孔隙:

在制作卡扣的时候,设计的过于精确,虽然在solidworks上装配的时候是可以的,但是实际打印出来没有办法卡上去。返回文件检查时,发现当时已经考虑过了这个问题,预留了0.1mm,但是是自己随便想的,后得知学校3D打印机的误差在0.2mm,应当至少留0.2mm比较合适,更改后打印,顺利装配完成。

3.

六、一点感慨

最后,还是再感慨一下,通过自己完成这样一个样品真的很有意思。虽然头疼很多次,踩了不少坑,好几次更改方案,而且还顶着限时的压力,最后居然真的做出来了!非常自豪哈哈哈!

刚开始接任务的时候我就说,我对这个感兴趣,但我担心我做不来。组长就和我说,这个不难,肯定能做得出来。挺感谢组长的鼓励的,最后一边查资料,一边做。每个东西也不学太深,做多少,学多少。学得不够了,再学一点,做一点,也可以算是真正的学以致用了罢。

四天时间,几乎是从零开始,除了一点python基础以外什么都没有。一步一步,学了i2c通信协议,学了树莓派GPIO的输入输出,学了L298N驱动电机的方式,甚至自己学了如何焊接。

在学习过程中,浏览了不知道多少帖子,如果没有这些帖子,不知道要多花费我多少时间和精力。故而也写一篇制作过程和一些经验,权当是一种传承,也是对自己这段时间的一个记录。希望大家都能够一路披荆斩棘,完成任务的同时学到知识,与大家共勉!

七、参考文章

由于参考文章众多,我也不能全部记住和列出来,对于所有无私分享经验的前辈(就算比我年轻也权叫一声前辈,达者为先嘛哈哈!)表示衷心的敬佩和感谢!

以下写了一些个人觉得帮助最大的参考文章,希望也能对看这篇文章的人有所帮助:

1.对于bh1750光传感器的详解,其中也讲述了i2c通讯协议的原理,对本人帮助极大;对于bh1750的解释也非常到位,常用的命令和程序都有包括,不过i2c的驱动代码不是用python写的。强烈建议将使用bh1750的朋友看一看:

BH1750光照传感器超详细攻略(从原理到代码讲解,看完你就懂了)_ShenZhen_zixian的博客-CSDN博客_bh1750

2.对于驱动电机的L298N电路板的介绍:

电机驱动芯片-L298N介绍 - 知乎 (zhihu.com)

3.光强检测程序源代码:

Raspberry Pi开发之旅-光照强度检测(BH1750) - 走看看 (zoukankan.com)

4.第一代云台的原型来自这里(好像是在评论区):

基于Arduino的太阳能板追光装置设计_秦学毅的博客-CSDN博客

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值