舵机又叫伺服电机,是一个可以旋转特定角度的电机,可转动角度通常是
90°、180°和 360°(360°可以连续旋转)。
我是在一个二轴舵机云台上进行代码验证的。
舵机一般按照转动方式可以分为两种。一种是可调角度但不能调转速的180度舵机,另一种是可调转速但不能调角度的360度舵机。前者虽然叫“180度舵机”,但是你如果用手转动转轴,你会发现它的转角其实可以大于180度,这是为什么呢?我也不是很懂唉~不过有一点可以确定,那便是通电后,它的转角范围确实只有180度。
180°舵机的控制一般需要一个 20ms 左右的时基脉冲,该脉冲的高电平部分一般为 0.5ms-2.5ms 范围内的角度控制脉冲部分,总间隔为 2ms。以 180 度角度伺服为例,在 MicroPython 编程对应的控制关系是从-90°至 90°,示例图如下
而对于 360°连续旋转舵机,上面的脉冲表则对应从正向最大速度旋转到反向最大速度旋转的过程。
看了上面的解释,如果你还是不太懂的话。那么就听听我不太专业的发言吧。
大概就是,你得用单片机输出一种波(叫PWM波)来控制舵机旋转,这种波通常是一束频率为50HZ(周期为20ms)的方波,然后喃,然后就是你得改变输出波形的占空比来使180度舵机转到不同的角度。不同占空比的PWM波对应舵机不同的角度,2.5%占空比对应的是0度,12.5%占空比对应的是180度。举个例子,如果你想让舵机转到135度,那么我们做一个简单的运算
d u t y ( 占 空 比 ) = 12.5 % − 2.5 % 180 ∗ 135 + 2.5 % duty(占空比) = \frac{12.5\%-2.5\%}{180}*135 +2.5\% duty(占空比)=18012.5%−2.5%∗135+2.5%
这样,我们只需要输出一个占空比为duty的PWM波形就好了。
from machine import Timer,PWM
tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
S1 = PWM(tim, freq=50, duty=0, pin=17)
S1.duty(135/180*10+2.5)
PWM 控制 API 参考: PWM API
羡慕像openmv那样固件自带pyb模块的板子,\哭,同为microPython开发,咋差别就那么大呢。于是就上网找相关大佬写的开源库,然后自己效仿写了写。下面是自己乱写的servo库,大佬轻喷~~~~~
代码如下:
from machine import Timer,PWM
import time,sys
class Servo:
def __init__(self, timer_id):
self.pin = None
self.freq = 50
self.duty = 0
self.servo = None
self.interval = 500 # ms
'''all timer default use channel0'''
if timer_id == 0:
self.tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
elif timer_id == 1:
self.tim = Timer(Timer.TIMER1, Timer.CHANNEL0, mode=Timer.MODE_PWM)
elif timer_id == 2:
self.tim = Timer(Timer.TIMER2, Timer.CHANNEL0, mode=Timer.MODE_PWM)
else:
print("erorr timer_id is [0,2]!")
sys.exit(retval=0)
def set_pin(self,pin_num):
self.pin = pin_num
self.servo = PWM(self.tim, freq=self.freq, duty=self.duty, pin=self.pin)
def position(self,angle):
time.sleep_us(self.interval)
self.servo.duty(angle*1.0/180*10+2.5)
def set_speed(self,_interval):
self.interval = _interval
servo1 = Servo(1)
servo2 = Servo(2)
servo1.set_pin(17)
servo2.set_pin(18)
'''button event control'''
from Maix import GPIO
from fpioa_manager import fm
from board import board_info
fm.register(27,fm.fpioa.GPIO0)
fm.register(29,fm.fpioa.GPIO1)
fm.register(30,fm.fpioa.GPIO2)
fm.register(31,fm.fpioa.GPIO3)
key1 = GPIO(GPIO.GPIO0,GPIO.IN)
key2 = GPIO(GPIO.GPIO1,GPIO.IN)
key3 = GPIO(GPIO.GPIO2,GPIO.IN)
key4 = GPIO(GPIO.GPIO3,GPIO.IN)
angle1 = 0
angle2 = 0
dir_flag_1 = 2
dir_flag_2 = 2
while True:
if key1.value()==0:
time.sleep_ms(10)
if key1.value()==0:
if dir_flag_1 != 1:
angle1 = angle1 + 1
if key2.value()==0:
time.sleep_ms(10)
if key2.value()==0:
if dir_flag_1 != 0:
angle1 = angle1 - 1
if angle1 == 180:
dir_flag_1 = 1
elif angle1 == 0:
dir_flag_1 = 0
else:
dir_flag_1 = 2
if key3.value()==0:
time.sleep_ms(10)
if key3.value()==0:
if dir_flag_2 != 1:
angle2 = angle2 + 1
if key4.value()==0:
time.sleep_ms(10)
if key4.value()==0:
if dir_flag_2 != 0:
angle2 = angle2 - 1
if angle2 == 135:
dir_flag_2 = 1
elif angle2 == 0:
dir_flag_2 = 0
else:
dir_flag_2 = 2
servo1.position(angle1)
servo2.position(angle2)
舵机一般需要外接电源的,根据舵机工作电压选择不同的外接电源。听说直接电脑给舵机供电可能会烧,不可轻易尝试啊(试试就逝世)~还有一点,千万不要像我一样蠢,直接把外接电源和舵机正负相接就完事了,还有必须要和单片机共地! 共地! 共地!(就是把外接电源、舵机、maix-bit的GND引脚相连)因为这个,我调了一下午舵机,换了不同的电源,尝试了很多种方法舵机,上电后一直没转。幸亏第二天同组的大佬学弟提醒了我(被自己菜哭)。
这个问题一般是由于在程序中给两种不同的PWM波之间设置了较长的延迟所导致的,可以适当修改延迟时长。
对于二轴云台来说,简单控制舵机转动显得运动相当不稳,后期可以考虑加入PID来使得运动变得更加“丝滑”。