L298N可以控制两个电机,具体原理为IN1、IN2、IN3、IN4四个输入端口接收控制器发出的电信号,两个输出端分别控制两组直流电机转动。输入端的逻辑控制表如下:
GPIOGPIO.0GPIO.1GPIO.2GPIO.3DC MotorMotionIN1IN2IN3IN4M1ForwardHighLow//M1ReverseLowHigh//M1StopLowLow//M2Forward//HighLowM2Reverse//LowHighM2Stop//LowLow注意:一般选择12V电源供电,但L298N最大工作电压高达46V,电压越大,输出给电机的电压也越大,转速越快。在芯片电压足够大的情况下应考虑电机的最大工作电压。
代码简化:需要一次性设置多个引脚的输入输出时,可以创建列表,一次性执行setup。
IN1 = 12 IN2 = 11 IN3 = 13 IN4 = 15 pinlist=[IN1,IN2,IN3,IN4] GPIO.setup(pinlist, GPIO.OUT) 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. 本次实验由于一些客观因素存在,误差可能比较大,又由于一些奇奇怪怪的意外(传感器失踪),现在实验无法继续进行,后续可能会更新数据。