树莓派间通信-socket通信

    上篇文章已经尝试过使用mongo作为介质,来实现消息的传递;今天这篇文章将尝试socket,来实现消息传递;具体scoket的详细信息,可以网上搜索查看,这篇文章主要是讲解两个树莓派之间如何使用socket通信。
    使用mongo文章:https://www.shumeijiang.com/2021/01/24/多个树莓派之间实现通信对话/
两个树莓派,一个3b+,一个zero
#上图可见,实验用到一个树莓派zero(上),一个树莓派3b+(下);
#server服务端代码

#!/usr/bin/env python
#coding:utf-8

import socket
import time

host = '192.168.0.118'  #本机(主机)ip
port = 1026   # 自定义端口

server = socket.socket() #默认AF_INET、SOCK_STREAM
server.bind((host, port)) #连接主机
server.listen(5) #连接最多5个设备

while True:
    connect, address = server.accept() #开始接收客户端连接请求

    #处理连接交互信息
    while True:
        data = connect.recv(1024) #接收客户端发送的信息
        if not len(data):
            print('链接已断开')
            break
        else:
            print('收到信息:%s'%data)

        #信息回复
        connect.send('ok')

server.close()
#client客户端

#!/usr/bin/env python
#coding:utf-8

import socket
import time

host = '192.168.0.118' #主机地址
port = 1026

client = socket.socket()
client.connect((host, port)) #连接主机

while True:
    s = raw_input(">>")   #接收输入
    client.send(s)   #发送给主机信息
    data = client.recv(1024)  #接收主机回复信息

    #主机回复信息处理
    if data=='ok':
        print('命令传输完成')

client.close()
    从上面代码可知,客户端接收用户输入,然后发送给服务端,服务端将信息处理,然后发送给客户端处理状态。
#实验过程:
1、首先启动server端,执行Python server.py;
2、接着启动client端,执行Python client.py;
3、client端,提示">>",输入指令,然后回车发送给服务端;
4、服务端接收到数据,然后处理后将处理状态发送给客户端;
#效果如下图:
客户端发送命令
服务端接收处理

四驱小车循迹实验-循迹实现

    前两篇文章已经介绍了如何组装四驱小车以及小车的驱动类封装;接下来这篇文章将尝试驱动类调用以及小车循迹测试。
    小车组装文章:https://www.shumeijiang.com/2021/09/23/四驱小车循迹实验-小车组装/。
    小车驱动类封装文章:https://www.shumeijiang.com/2021/09/23/四驱小车循迹实验-直流电机驱动封装/
#循迹实验效果
#实现效果:
    从上面gif图以及视频可看到,小车遇到直线会直行前进,由于手工贴的胶带不是很直所以小车会实时调整前进的角度;当遇到转弯时,同样会一点点进行转弯直到寻找到黑线线条;
传感器示例
    上图模拟小车前面并排的三个红外避障传感器,分别是ONE,TWO,THREEE;默认黑线位于TWO传感器正下方为直行;由于小车要不停向前移动,但是黑线有弯曲或者转弯的情况,所以小车会出现三个传感器分别接触黑线的情况;通过不同的传感器被触发事件,从而得出小车现在的行走方向以及判断是否要做方向调整,具体原理如下(1为检测到黑线触发事件,0为未检测到黑线):

1、ONE=1,THREE=0 说明黑线偏转右侧,此时小车应向右转向;
2、ONE=0,THREE=1 说明黑线偏转左侧,此时小车应向左转向;
3、ONE=0,TWO=1,THREE=0 说明黑线在中心方向,小车需直行;
4、ONE=1,TWO=1,THREE=1 说明遇到横线,小车需停顿;
5、ONE=0,TWO=0,THREE=0 说明小车失去黑线,此时需寻找或者停止。
#实现代码

#!/usr/bin/env python
#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
http:://www.shumeijiang.com
'''

import RPi.GPIO as GPIO
import time

GPIO.setwarnings(False)

#引入驱动类
from baseAct import baseAct
#实例化驱动类并赋值四个电机所占引脚值
act = baseAct(17, 16, 13, 12, 19, 18, 21, 20)

#三个传感器检测黑线
senseOne = 22
senseTwo = 23
senseThree = 24

#一个检测障碍物
checkPin = 25

GPIO.setmode(GPIO.BCM)
GPIO.setup(senseOne, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(senseTwo, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(senseThree, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(checkPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#事件注册 注意不同传感器触发事件不同
GPIO.add_event_detect(senseOne, GPIO.RISING, bouncetime=200)
GPIO.add_event_detect(senseTwo, GPIO.FALLING, bouncetime=200)
GPIO.add_event_detect(senseThree, GPIO.RISING, bouncetime=200)
GPIO.add_event_detect(checkPin, GPIO.FALLING, bouncetime=200)

#检测事件
def check_event(pin):
    status = GPIO.event_detected(pin)
    return status

#检测状态
def check_status(pin):
    status = GPIO.input(pin)
    return status

#find
done = False
try:
    while not done:
   
        #障碍物检测
        front_status = check_event(checkPin)
        print("front status is %d"% front_status)
        if front_status == 1:
            print('有障碍物 停止')
            act.act_backward(0.5, 50, 50)
            done = True
            break

        #检测各传感器状态
        #status = find_way(senseOne, senseTwo, senseThree)
        sOne = check_event(senseOne)
        sTwo = check_event(senseTwo)
        sThree = check_event(senseThree)

        print('sOne is %d'% sOne)
        print('sTwo is %d'% sTwo)
        print('sThreee is %d' % sThree)
       
        way_type = 'forward'
        #继续前行
        if sOne == 0 and sThree==0:
            act.act_forward(0.15, 50, 40, True)
            print('forward')

        #遇到横线停顿
        elif sOne == 1 and sThree == 1:
            time.sleep(0.5)
            print('wait')

        #向右侧转弯调整
        elif sOne == 1 and sThree == 0:
            #act.turn_right(0.15, 50, 40)

            #检测是否居中
            find = False
            while not find:
                oneStatus = check_event(senseOne)
                twoStatus = check_event(senseTwo)
                threeStatus = check_event(senseThree)
                print('run right---->>')
                print('one status is %d'% oneStatus)
                print('two status is %d'% twoStatus)
                print('three status is %d'% threeStatus)

                if oneStatus==0 and twoStatus==1 and threeStatus==0:
                    find = True
                    break

                act.turn_right(0.15, 55, 45, True)
                time.sleep(0.2)
                   
            print('right')
            way_type = 'right'

        #向左侧转弯调整
        elif sOne == 0 and sThree == 1:

            find = False
            while not find:
                oneStatus = check_event(senseOne)
                twoStatus = check_event(senseTwo)
                threeStatus = check_event(senseThree)
                print('run left<<----')
                print('one status is %d'% oneStatus)
                print('two status is %d'% twoStatus)
                print('three status is %d'% threeStatus)

                if oneStatus==0 and twoStatus==1 and threeStatus==0:
                    find = True
                    break

                act.turn_left(0.15, 55, 45, True)
                time.sleep(0.2)

            print('left')
            way_type = 'left'
        else:
            pass

        print('once')
        #time.sleep(0.2)

        #if sOne==0 and sTwo==0 and sThree==0:
            #act.act_break()
            #print('stop!!!!')
            #break

except KeyboardInterrupt:
    pass

GPIO.cleanup()
从上面的代码可以看到循迹的策略和流程如下:

1、首先注册one和three分别一个RISING(低变高)事件,因为默认情况下这两个传感器没有遇到黑线而是地板,所以触发低电平事件(传感器低电平触发检测);

2、two注册一个FALLING(高变低)事件,因为默认two传感器红外被黑色线条吸收,从而不产生障碍物检测,所以检测状态为高电平;

3、checkPin为小车前方障碍物检测,如果遇到前方障碍物,小车停车并后退,这个不是重点不做详细介绍;

4、one、two、three传感器的防抖时间bouncetime,异或说检测间隔为200毫秒,这个可以自己调节,主要用于探测黑线的频率;

5、紧接着进入一个while循环,每次都检测三个传感器状态,当发现:
(1)one和three都没有触发RISING事件,我们认为此时黑线还在中间,所以直行;
(2)one和three都触发RISING事件,说明遇到横线,所以停顿;
(3)one触发,three没有触发,说明直行后黑线弯曲,触发了右侧one传感器;为了黑线居中,这个时候小车就需要右转,但是由于不知道黑线弯曲程度(后续可实验图像识别),所以小车进入一个找线环节,以0.15秒的步伐,一点点右转,同时占空比调为55,赫兹设置为45,降低右转速度;当two传感器触发FALLING事件,说明小车归正,则继续触发直行策略,以此类推;
(4)one没有触发,three触发,说明直行后黑线向左弯曲,触发左转动作,具体细节同右转相似;

6、如此,小车便会直行、停顿、左转和右转;当然程序还有很多不足的地方,后续还会继续优化。
#事件检测(边沿检测)部分可参考文章:https://www.shumeijiang.com/2020/03/15/gpio之event_detected系列函数/

四驱小车循迹实验-直流电机驱动封装

    上篇文章已经介绍了四驱小车如何组装,这篇文章我们将继续介绍如何驱动小车前进后退以及左转右转;因为小车循迹的过程中,会遇到左转线、直线、右转线以及停顿标示;这个时候就需要小车能实现左转、右转、直行、停车、后退等动作。
#直流电机驱动板L298N驱动原理:
直流电机转动效果IN1IN2IN3IN4
MOTOR-A正向(调速)高电平/PWM低电平
反向(调速)低电平高电平/PWM
停止低电平低电平
刹车高电平高电平
MOTOR-B正向(调速)高电平/PWM低电平
反向(调速)低电平高电平/PWM
停止低电平低电平
刹车高电平高电平
    从上面表格可见,motorA连接引脚IN1和IN2,当IN1高电平IN2低电平的时候,电机正向转动,其中IN1输入PWM进行调速和扭矩变化;反之IN1低电平和IN2高电平的时候电机反向转动,从而实现倒车;其他电机以此类推。
#其中PWM控制转速和扭矩,示例如下:
1、创建PWM实例:p = GPIO.PWM(channel, frequency);
2、开始PWM:p.start(duty_cycle)  #duty_cycle为占空比;
3、更改频率,更改扭矩:p.ChangeFrequency(frequency);
4、更改占空比,更改转速:p.ChangeDutyCycle(duty_cycle);
5、PWM停止:p.stop()
#代码示例

#!/usr/bin/env python
#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
https:://www.shumeijiang.com
'''

import RPi.GPIO as GPIO ##引入GPIO模块
import time    ##引入time库
GPIO.setmode(GPIO.BCM)

#驱动类
class baseAct:
    def __init__(self, ain1, ain2, ain3, ain4, bin1, bin2, bin3, bin4):
        self.ain1 = ain1
        self.ain2 = ain2
        self.ain3 = ain3
        self.ain4 = ain4
        self.bin1 = bin1
        self.bin2 = bin2
        self.bin3 = bin3
        self.bin4 = bin4
        GPIO.setup(self.ain1, GPIO.OUT)
        GPIO.setup(self.ain2, GPIO.OUT)
        GPIO.setup(self.ain3, GPIO.OUT)
        GPIO.setup(self.ain4, GPIO.OUT)
        GPIO.setup(self.bin1, GPIO.OUT)
        GPIO.setup(self.bin2, GPIO.OUT)
        GPIO.setup(self.bin3, GPIO.OUT)
        GPIO.setup(self.bin4, GPIO.OUT)

    #结束动作
    def act_stop(self, duration, slow_time=0.15):

        #执行时间
        duration = float(duration)-slow_time
        time.sleep(duration)
   
        #self.init_move('forward', duration, 50, 50)

        if slow_time:
            #执行缓冲慢行
            self.apwm1.ChangeDutyCycle(20)
            self.apwm3.ChangeDutyCycle(20)
            self.bpwm1.ChangeDutyCycle(20)
            self.bpwm3.ChangeDutyCycle(20)
            time.sleep(slow_time)

        #结束动作
        self.apwm1.stop()
        self.apwm3.stop()
        self.bpwm1.stop()
        self.bpwm3.stop()
        GPIO.output(self.ain2, GPIO.LOW)
        GPIO.output(self.ain4, GPIO.LOW)
        GPIO.output(self.bin2, GPIO.LOW)
        GPIO.output(self.bin4, GPIO.LOW)

    ##PWM初始化
    def init_move(self, act_type, duration, duty_ratio, hz_num):

        if act_type == 'forward':
            hpin1 = self.ain1
            lpin1 = self.ain2
            hpin2 = self.ain3
            lpin2 = self.ain4
            hpin3 = self.bin1
            lpin3 = self.bin2
            hpin4 = self.bin3
            lpin4 = self.bin4
        elif act_type == 'backward':
            hpin1 = self.ain2
            lpin1 = self.ain1
            hpin2 = self.ain4
            lpin2 = self.ain3
            hpin3 = self.bin2
            lpin3 = self.bin1
            hpin4 = self.bin4
            lpin4 = self.bin3
        elif act_type == 'turn_left':
            hpin1 = self.ain1  
            lpin1 = self.ain2  #右前电机前进 pin2低电平则前进
            hpin2 = self.ain3
            lpin2 = self.ain4  #右后电机前进
            hpin3 = self.bin2
            lpin3 = self.bin1  #左前电机后退 pin2高电平则后退
            hpin4 = self.bin4
            lpin4 = self.bin3  #左后电机后退
        elif act_type == 'turn_right':
            hpin1 = self.ain2
            lpin1 = self.ain1  #右前电机后退  pin2高电平则后退
            hpin2 = self.ain4
            lpin2 = self.ain3  #右后电机后退
            hpin3 = self.bin1
            lpin3 = self.bin2  #左前电机前进  pin2高电平则前进
            hpin4 = self.bin3
            lpin4 = self.bin4  #左后电机前进
        else:
            print "不支持的类型"
            pass

        #挨个实例化每个电机的PWM实例
        self.apwm1 = GPIO.PWM(hpin1, hz_num) #实例PWM 并可自定义hz
        self.apwm1.start(0)           #初始占空比为0
        GPIO.output(hpin1, GPIO.HIGH) #设置单个电机一个高电压
        GPIO.output(lpin1, GPIO.LOW)  #另一个低电压
        self.apwm1.ChangeDutyCycle(duty_ratio) #设置用户自定义占空比

        #驱动第二个电机
        self.apwm3 = GPIO.PWM(hpin2, hz_num)
        self.apwm3.start(0)
        GPIO.output(hpin2, GPIO.HIGH)
        GPIO.output(lpin2, GPIO.LOW)
        self.apwm3.ChangeDutyCycle(duty_ratio)

        #驱动第三个电机
        self.bpwm1 = GPIO.PWM(hpin3, hz_num)
        self.bpwm1.start(0)
        GPIO.output(hpin3, GPIO.HIGH)
        GPIO.output(lpin3, GPIO.LOW)
        self.bpwm1.ChangeDutyCycle(duty_ratio)

        #驱动第四个电机
        self.bpwm3 = GPIO.PWM(hpin4, hz_num)
        self.bpwm3.start(0)
        GPIO.output(hpin4, GPIO.HIGH)
        GPIO.output(lpin4, GPIO.LOW)
        self.bpwm3.ChangeDutyCycle(duty_ratio)

    ##前进
    def act_forward(self, duration, duty_ratio, hz_num=50, close_slow=False):
        self.init_move('forward', duration, duty_ratio, hz_num)

        if close_slow:
            slow_time = 0
        else:
            slow_time = 0.15

        #停止动作 并执行缓冲
        self.act_stop(duration, slow_time)

    ##后退
    def act_backward(self, duration, duty_ratio, hz_num):
        self.init_move('backward', duration, duty_ratio, hz_num)
        #停止动作 并缓冲执行
        self.act_stop(duration)

    ##向左转
    def turn_left(self, duration, duty_ratio, hz_num, serial=False):
        self.init_move('turn_left', duration, duty_ratio, hz_num) #左转执行
        slow_time = 0.05  #减速时间
        if serial==True:
            slow_time = 0
        self.act_stop(duration, slow_time)  #动作停止

    ##向右转
    def turn_right(self, duration, duty_ratio, hz_num, serial=False):
        self.init_move('turn_right', duration, duty_ratio, hz_num) #右转执行
        slow_time = 0.05  #减速时间
        if serial==True:
            slow_time = 0 #连续不减速
        self.act_stop(duration, slow_time)  #动作停止

    ##刹车
    def act_break(self):
        GPIO.output(self.ain1, GPIO.HIGH)
        GPIO.output(self.ain2, GPIO.HIGH)
        GPIO.output(self.ain3, GPIO.HIGH)
        GPIO.output(self.ain4, GPIO.HIGH)

        GPIO.output(self.bin1, GPIO.HIGH)
        GPIO.output(self.bin2, GPIO.HIGH)
        GPIO.output(self.bin3, GPIO.HIGH)
        GPIO.output(self.bin4, GPIO.HIGH)
    如上代码可见,封装了直流电机驱动类baseAct,以及直行、后退、左转、右转和刹车等方法;实例化类后便可直接调用,其中ain1、ain2、ain3、ain4为左侧电机驱动板引脚,bin1、bin2、bin3、bin4为右侧电机驱动板引脚,分别对应即可。
#参考文章:https://www.shumeijiang.com/2020/05/04/直流电机驱动变速实验/

四驱小车循迹实验-小车组装

    从本篇文章开始,我们将进行四驱小车的循迹实验;因为曾经看到过相关的比赛,所以想着自己能不能组装一个可以循迹的四驱小车,花了中秋假期三天的时间,从组装到代码开发调试,小车终于可以循迹跑起来了;下面先从组装开始说起。
#材料准备
1、四驱小车底盘,网上都有卖,包含四个直流电机以及一个亚克力板;
2、树莓派3B+一个,这个不做限制,只要能跑代码即可;
3、四路红外避障传感器,当然也可以用其他循迹传感器;原理是一样,都是利用红外线遇到黑线,红外线被吸收,从而不产生反射的原理。
4、两个L298N直流电机驱动模块,用于四个电机的驱动;
5、两个供电充电宝,分别给树莓派和直流电机供电;
6、一个数显降压稳压模块,用于电机电压的控制;
7、一个船型开关,用于小车电源的开关(非必须);
8、一个降温小风扇,一方面用于给树莓派降温,另一方面防止充电宝供电中断;
9、一卷黑色胶带,后续循迹实验用于铺设循迹轨道;
10、雪糕棒以及热熔枪用于粘合;
11、扎带用于固定充电宝以及其他物品;
#组装效果
前面
侧面
后面
上面
#其中第一张图,三个并列的红外传感器,需要注意间距和高低位置;高低校准是放置在地面检测灯亮起,遇到黑线红灯熄灭即可,如果发现红灯不亮或者不灭可以调节可调电阻调整探测距离;彼此间距,校准是当黑线不在中间探测器下方时,左右传感器在N个移动周期内能检测到黑线即可。
#接线部分:
1、左侧电机L298N驱动板
(1)IN1接18;
(2)IN2接19;
(3)IN3接20;
(4)IN4接21;
2、右侧电机L298N驱动板
(1)IN1接17;
(2)IN2接16;
(3)IN3接13;
(4)IN4接12;
3、四路红外避障传感器
(1)IN1接22;
(2)IN2接23;
(3)IN3接24;
(4)IN4接25;
(5)GND接GND;
(6)VCC接3.3V;
组装和接线完成后,下一篇文章会讲解我自己封装的驱动程序。
#传感器参考文章:https://www.shumeijiang.com/2021/09/02/四路红外避障传感器实验/

振动马达电机模块实验

    振动马达电机模块,可以实现手机或者游戏手柄的振动手感效果;它是在主板上增加了一个直流有刷电机,电机上内置一个偏心轮,当马达高速转动时由于圆心点不在中心的原因,所以出现振动效果。
接线示例:
接线示例
#触发原理:高电平触发振动,低电平停止振动。
#模块参数:
1、工作电压:+3.3V/+5v
2、尺寸大小:30mm x 25mm
3、振动马达:直径10mm, 高2.7mm
4、重量大小:3g
5、信号类型:数字信号
6、额定转速:最小9000转每分
7、额定电流:最大60毫安
8、起动电流:最大90毫安
#实验代码:

#!/usr/bin/env python
#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
https:://www.suhmeijiang.com
'''

import RPi.GPIO as GPIO  ##引入GPIO模块
import time              ##引入time库

#信号引脚
detectPin = 17

GPIO.setmode(GPIO.BCM)   ##此处采用的BCM编码
GPIO.setup(detectPin, GPIO.OUT) ##设置为输出模式

#先停止后振动
GPIO.output(detectPin, GPIO.LOW)
time.sleep(0.5)
GPIO.output(detectPin, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(detectPin, GPIO.LOW)
time.sleep(0.5)
#再振动
GPIO.output(detectPin, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(detectPin, GPIO.LOW)

GPIO.cleanup()
#实验效果:
1、代码保存到jiujiang.py文件;
2、执行代码 python jiujiang.py;
3、可见马达先振动0.5秒后停止,然后再次振动0.5秒,然后结束。

KY-032避障红外传感器实验

    最近入手了几个ky-032避障红外传感器,这个传感器不同于以前红外避障传感器,它包含了灵敏度和检测范围的调节以及EN引脚;其中EN引脚要启用需要先拿掉跳线帽。
#接线示例:
接线示例
#其中EN引脚,实验中处于启用状态;移除跳线帽后,NE555芯片定时器的引脚 4 由 22K 下拉电阻 R3 保持低电平(复位)。当高电平条件应用于 EN 引脚时,复位条件解除,555 定时器将开始振荡。由于 IR 接收器中的 AGC 很快饱和,因此 EN 引脚一次不应保持高电平(启用)超过 2 毫秒。EN 必须在短时间内变为低电平,然后再次变为高电平。由此定期关闭38kHz信号并让AGC电路放松,可使设备达到最大灵敏度。
#实验代码:

继续前进
#!/usr/bin/env python
#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
https:://www.shumeijiang.com
'''

import RPi.GPIO as GPIO  ##引入GPIO模块
import time              ##引入time库

sensePin = 22 #检测引脚
enablePin = 23 #en引脚

GPIO.setmode(GPIO.BCM)   ##此处采用的BCM编码
GPIO.setup(sensePin, GPIO.IN) ##设置为接收模式
GPIO.setup(enablePin, GPIO.OUT) ##设置en为输出模式

try:
    while True:
        #复位条件解除 传感器开始工作
        GPIO.output(enablePin, GPIO.HIGH)
        status = GPIO.input(sensePin) ##检测传感器状态
        if status == GPIO.LOW:  ##低电平触发
            print '有障碍物!!'
        else:
            print '继续前进'

        #复位EN引脚
        GPIO.output(enablePin, GPIO.LOW)
        time.sleep(0.05)  ##检测频率

except KeyboardInterrupt:
    pass

GPIO.cleanup()
#不启用EN引脚常规检测代码:

#!/usr/bin/env python
#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
https:://www.shumeijiang.com
'''

import RPi.GPIO as GPIO  ##引入GPIO模块
import time              ##引入time库

sensePin = 22

GPIO.setmode(GPIO.BCM)   ##此处采用的BCM编码
GPIO.setup(sensePin, GPIO.IN, pull_up_down=GPIO.PUD_UP) ##设置为接收模式

#添加事件检测
GPIO.add_event_detect(sensePin, GPIO.FALLING, bouncetime=500)

try:
    while True:
        status = GPIO.event_detected(sensePin)
        if status == GPIO.HIGH:
            print '发现障碍物!!'
        else:
            print '继续前进'

        time.sleep(0.05)  ##检测频率

except KeyboardInterrupt:
    pass

GPIO.cleanup()
#参考文章:http://irsensor.wizecode.com/

四路红外避障传感器实验

    最近入手了一个一拖四的红外避障传感器,想用于小车的障碍物检测;以前曾写过单个的红外避障传感器的使用实验,今天来测试一下四路红外避障传感器如何使用。同时这篇文章还会使用边沿检测方法,检测传感器的状态改变事件。
#接线示例
#边沿检测部分可以参考:边沿检测函数

#实验代码:


#!/usr/bin/env python
#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
https:://www.suhmeijiang.com
'''

import RPi.GPIO as GPIO  ##引入GPIO模块
import time              ##引入time库

pinOne = 22
pinTwo = 23
pinThree = 24
pinFour = 25

GPIO.setmode(GPIO.BCM)   ##此处采用的BCM编码 因为T型扩展板也是BCM编码 方便统一
GPIO.setup(pinOne, GPIO.IN, pull_up_down=GPIO.PUD_UP) ##设置检测引脚我输入状态 并初始化为高电平
GPIO.setup(pinTwo, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pinThree, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pinFour, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#注册一个检测电压下降事件 检测间隔时间600毫秒(防抖时间)
GPIO.add_event_detect(pinOne, GPIO.FALLING, bouncetime=600)
GPIO.add_event_detect(pinTwo, GPIO.FALLING, bouncetime=600)
GPIO.add_event_detect(pinThree, GPIO.FALLING, bouncetime=600)
GPIO.add_event_detect(pinFour, GPIO.FALLING, bouncetime=600)

try:
    while True:
        #事件检测
        if (GPIO.event_detected(pinOne)):
            print("右边发现有人!")

        if (GPIO.event_detected(pinTwo)):
            print("上边发现有人!")

        if (GPIO.event_detected(pinThree)):
            print("左边发现有人!")

        if (GPIO.event_detected(pinFour)):
            print("下边发现有人!")

except KeyboardInterrupt:
        pass

GPIO.cleanup()
#试验效果:
1、保存代码为jiujiang.py;
2、执行代码,如果没有触发事件则屏幕无信息打印;
3、当物体或者用手遮挡任一方向的传感器;
4、可见屏幕打印出这个方向的信息,如果发现打印多次,则是因为停留时间大于间隔检测时间,可以按需调试间隔时间;
实验效果

多个PCA9685舵机驱动板一起执行实验(含地址修改)

    以前的实验我们实验过了单个pca9685驱动板,同时驱动多个舵机的实验;但是有些情况下,可能一个板子无法满足我们的驱动需求;我们知道一个板子最大可驱动16个舵机,但是如果我们想同时驱动 17个舵机,这个时候就遇到问题;本篇文章就实验一下如何解决这个问题。
    为了解决这个问题,先得解决地址冲突问题;因为板子默认地址都是0x40,那么我们无法辨别哪个是哪个板子,这个时候就需要修改板子的地址;如下图:
地址修改
 地址修改后,连接树莓派,执行如下命令:

i2cdetect -y 1
    可见下图,由于树莓派连接了两个pca9685驱动板,所以可见两个地址,分别为0x40和修改地址后的0x41;
地址修改后效果
#解决地址冲突后,接下来看一下树莓派如何同时接多块板子,见下图:
接线效果
    由上图可见,由于板子默认没有焊接尾部扩展针脚,因此需要我们先焊接针脚;然后用杜邦线连接第二个板子;电源部分两者共用即可。
 #实验代码:

#coding:utf-8

'''
from JiuJiang
树莓酱的操作实例
http:://www.shumeijiang.com
'''

import time
from board import SCL, SDA
import busio

from adafruit_pca9685 import PCA9685
from adafruit_motor import servo

#引入i2c
i2c = busio.I2C(SCL, SDA)

#控制第一块板子
pca = PCA9685(i2c, address=0x40)  #地址可以修改  默认0x40
pca.frequency = 50

print("执行第一块板子")

for i in [0]:

    servo_o = servo.Servo(pca.channels[i]) #i是舵机在pca9685上的编号

    #设置脉冲宽度 500到2500是正常的 这个可以自己调整 不设置默认只到135度
    servo_o.set_pulse_width_range(min_pulse=500, max_pulse=2500)

    #先0度
    servo_o.angle = 0
    time.sleep(1)

    #再执行90度
    servo_o.angle = 90
    time.sleep(1)

    #再执行180度
    servo_o.angle = 180
    time.sleep(1)

    #再恢复90度
    servo_o.angle = 90
    time.sleep(1)

pca.deinit()

#控制第二块板子
pca = PCA9685(i2c, address=0x41)
pca.frequency = 50

print("执行第二块板子")

for i in [0, 1]:
    servo_o = servo.Servo(pca.channels[i]) #i是舵机在pca9685上的编号

    #设置脉冲宽度 500到2500是正常的 这个可以自己调整 不设置默认只到135度
    servo_o.set_pulse_width_range(min_pulse=500, max_pulse=2500)

    #先0度
    servo_o.angle = 0
    time.sleep(1)

    #再执行90度
    servo_o.angle = 90
    time.sleep(1)

    #再执行180度
    servo_o.angle = 180
    time.sleep(1)

    #再恢复90度
    servo_o.angle = 90
    time.sleep(1)

pca.deinit()
#实验效果,可见三个舵机依次转动,如下图: