L298N芯片驱动电机

2023-11-08

L298N芯片驱动电机

一、控制原理

  L298N可以控制两个电机,具体原理为IN1、IN2、IN3、IN4四个输入端口接收控制器发出的电信号,两个输出端分别控制两组直流电机转动。输入端的逻辑控制表如下:

GPIO GPIO.0 GPIO.1 GPIO.2 GPIO.3
DC Motor Motion IN1 IN2 IN3 IN4
M1 Forward High Low / /
M1 Reverse Low High / /
M1 Stop Low Low / /
M2 Forward / / High Low
M2 Reverse / / Low High
M2 Stop / / Low Low

注意:一般选择12V电源供电,但L298N最大工作电压高达46V,电压越大,输出给电机的电压也越大,转速越快。在芯片电压足够大的情况下应考虑电机的最大工作电压。

二、Python代码实现基础驱动

  1. PWM 控制(命令行输入控制电机转向)
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
IN1 = 12
IN2 = 11
IN3 = 13
IN4 = 15

GPIO.setup(IN1, GPIO.OUT)
GPIO.setup(IN2, GPIO.OUT)
GPIO.setup(IN3, GPIO.OUT)
GPIO.setup(IN4, GPIO.OUT)
p1 = GPIO.PWM(IN1, 50)
P2 = GPIO.PWM(IN28, 50)
P3 = GPIO.PWM(IN3, 50)
p4 = GPIO.PWM(IN4, 50)

def forward(time_sleep,speed):
    p1.start(speed)
    p2.start(0)
    p3.start(speed)
    p4.start(0)
    time.sleep(time_sleep)
print("forward")
    
def reverse(time_sleep,speed):
    p1.start(0)
    p2.start(speed)
    p3.start(0)
    p4.start(speed)
    time.sleep(time_sleep)
    print("reverse")

def left(time_sleep,speed): #单轮左转
    p1.start(speed)
    p2.start(0)
    p3.start(0)
    p4.start(0)
    time.sleep(time_sleep)
    print("single-left")
    
def right(time_sleep,speed):#单轮右转
    p1.start(0)
    p2.start(0)
    p3.start(speed)
    p4.start(0)
    time.sleep(time_sleep)
    print("single-right")
    
def left_0(time_sleep,speedF,speedR):#双轮左转 
    p1.start(speedF)
    p2.start(0)
    p3.start(0)
    p4.start(speedR)
    time.sleep(time_sleep)
    print("double-left")
    
def right_0(time_sleep,speedF,speedR):
    p1.start(0)
    p2.start(speedR)
    p3.start(speedF)
    p4.start(0)
    print("double-right")
    time.sleep(time_sleep)

def stop(time_sleep):#双轮右转
    p1.start(0)
    p2.start(0)
    p3.start(0)
    p4.start(0)
    print("stop")
    time.sleep(time_sleep)


try:
    while True:
        cmd = str(input("按以下键后回车(w,前进;x,后退;s,停止):"))
        direction = cmd
        if direction == "w" or "s" or "a" or "d" or "q" or "e":
            if direction == "w":  # 前进
                forward(1,100)
                stop(0.1)
            elif direction == "s":  # 后退
                reverse(1,30)
                stop(0.1)
            elif direction == "a":  # 单轮左转
                left(1,50)
                stop(0.1)
            elif direction == "d":  # 单轮右转
                right(1,50)
                stop(0.1)
            elif direction == "q":  # 双轮左转
                left_0(1,50,50)
                stop(0.1)
            elif direction == "e":  # 双轮右转
                right_0(1,50,50)
                stop(0.1)
            elif direction == "x":  # 停止移动
                stop(0.1)
            else:
                print("命令无法识别")
                break

except KeyboardInterrupt:
    GPIO.cleanup()  

代码简化:需要一次性设置多个引脚的输入输出时,可以创建列表,一次性执行setup。

IN1 = 12
IN2 = 11
IN3 = 13
IN4 = 15

pinlist=[IN1,IN2,IN3,IN4]
GPIO.setup(pinlist, GPIO.OUT)
  1. Robot库主要方法
from gpiozeros import Robot

robot = Robot(left=(18, 17), right=(27, 22))  #传参为控制对应电机IN口接通的GPIO引脚的BCM值 
robot.forward
robot.backward
robot.right
robot.left
robot.stop

三、光耦对射传感器+测速码盘实现精确控制

  上面的代码只能通过time.sleep()挂起进程,推迟执行后续代码,从而控制电机转动时间。那么如何较为精确地按照圈数控制电机运动?


  第一幅图为一个简单的测速码盘,第二幅图为FC-33对射测速传感器。当FC-33模块槽中有遮挡时,输出端口OUT输出高电平;无遮挡时,OUT输出低电平。FC-33有一个指示灯,槽口无遮挡时指示灯亮,有遮挡时灯灭,可用于工作状态检查。

  将测速码盘与电机同轴固定,电机工作过程中,码盘透光孔转过对射槽时OUT输出低电平,不透光的部分经过时输出高电平。(转为数字信号后就是一连串010101010101)

  将OUT输出端口连接GPIO引脚,设置该GPIO引脚为输入。GPIO.add_event_detect方法对一个引脚添加监听,当引脚输入发生改变时,GPIO.event_detected方法返回TRUE。该方法有三种detect模式,GPIO.RISING是当监听到引脚输入由低电平变为高电平时,返回TRUE;GPIO.FALLING当监听到引脚输入由高电平变为低电平时返回TRUE;注意,GPIO.BOTH是监测到一组电平高→低,低→高时返回TRUE。

  这个测速码盘有20个透光孔,所以电机每转一圈会经历20次GPIO.RISING/GPIO.FALLING/GPIO.BOTH,以此为思路写代码。

GPIO_in=40;  # BOARD 40引脚
GPIO.setup(ENCODE, GPIO.IN) 
GPIO.add_event_detect(GPIO_in,GPIO.RISING)
GPIO.add_event_detect(GPIO_in,GPIO.FALLING)
GPIO.add_event_detect(GPIO_in,GPIO.BOTH)

def revforward(speed):
if(speed>100):
        speed=100
    p1.start(speed)
    p2.start(0)
    p3.start(speed)
    p4.start(0)
def revstop():    
p1.start(0)    
p2.start(0)    
p3.start(0)    
p4.start(0)

while True:
rev=int(input("Enter number of revolution:"))
counter = 0
    revforward(50)
   	GPIO_in=40;
    	event = GPIO.add_event_detect(GPIO_in,GPIO.BOTH)
    while(counter < int(20*rev)):
        if(GPIO.event_detected(GPIO_in)):
            counter = counter + 1
GPIO.remove_event_detect(GPIO_in)
revstop()
break

四、测速

  在之前代码的基础上,如何测出当前电机转速,从而得出小车运行速度?思路很简单,获取两次系统时间,用圈数除以运行时间差值,得到电机转速,再获取小车轮胎直径,即可简单地计算当前运行速度。

  我们模拟一个加速过程,PWM值从90到100,每转5圈加速一次(PWM值加1)。

for i in range(90,110,1):  
#之前的方法有写,超过100的pwm值设为100,这里只是为了延长最大速度的时间
    rev = 5
    cnt = 0
    revforward(i)
    GPIO_in=40;
    event = GPIO.add_event_detect(GPIO_in,GPIO.BOTH)
    t0 = time.time()
    while(cnt< int(20*rev)):
        if(GPIO.event_detected(GPIO_in)):
            cnt = cnt + 1
    t1 = time.time()
    print("speed_pwm ",i,"rotate speed ",rev / (t1-t0))
    GPIO.remove_event_detect(GPIO_in)
revstop()
break

数据如下图:
在这里插入图片描述
用MATLAB绘制图像。

clear all; close all; clc;
rotate_speed=[ ~~~ ]; %省略,数据如上图
rs=rotate_speed.'; 
t=zeros(1,20);
for i=1:1:20
    if i==1
       t(1,1)=5/rs(1,1);
    end
    if i~=1
        t(1,i)=5/rs(1,i)+t(1,i-1);
    end
end

t=[0,t];
rs=[rs,0];
figure

for i=1:20
    plot([t(1,i),t(1,i+1)],[rs(1,i),rs(1,i)],'r','linewidth',2)
    hold on
    plot([t(1,i+1),t(1,1+i)],[rs(1,i),rs(1,i+1)],'k')
    hold on
end
xlabel("time(s)")
ylabel("rotate speed(r/s)")

在这里插入图片描述
  可以很明显的看到,在PWM值到100之后,转速数据是有问题的。这时候转速本应稳定维持一个较大的数值,实际却在一段突变后稳定维持在15附近。第一反应是电机在快要停止时会有减速过程,会拖慢那一段的平均转速,但是不应该有这么长时间的误差。其次想到的是光耦对射传感器分辨率不足。

  为了验证猜测,又进行了第二组试验,一直以PWM=100的转速运行,每转20圈求取一次平均转速。数据如下:
在这里插入图片描述
  同样方法用MATLAB绘图。发现这次的转速稳定在了17左右。几乎可以认定是传感器分辨率不足的原因。在这里插入图片描述
  P.S. 本次实验由于一些客观因素存在,误差可能比较大,又由于一些奇奇怪怪的意外(传感器失踪),现在实验无法继续进行,后续可能会更新数据。

五、Further Questions

  1. 两侧电机的传感器数据很可能不一致,如何同步?
  2. More and more precise experiments to verify whether the problem is caused because of low-resolution of sensor?
  3. Resolution of sensor can’t be find on Internet.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

L298N芯片驱动电机 的相关文章

随机推荐