SG90舵机,常用在小型机器人、智能小车、机械臂、固定翼等小型模型上,因为内部的齿轮多数为塑料的,承受不了太大的扭力。
舵机类型又分为两种,一种是模拟舵机,另一种是数字舵机,像SG90就是模拟舵机。
模拟舵机和数字舵机的区别
转动角度为360°的舵机与转动角度为90°/180°的舵机工作的方式又是不一样的,360°的舵机相当于是无极变速的减速电机,只能控制转动的速度和转动的方向,不能控制转动到想要的角度,但控制的方式和一般舵机的控制信号相同。
型号 | SG90 |
---|---|
重量 | 9g |
工作扭矩 | 1.6kg/cm |
反应速度 | 0.12-0.13s/60° |
建议使用温度 | -30° ~ +60° |
死区设定 | 5us |
转动角度 | 90°/180°(与程序的写法有关) |
舵机类型 | 模拟舵机 |
使用电压 | 3 ~ 7.2V(推荐用5V) |
结构材质 | 塑料齿 |
舵机的工作原理
控制电路板接受来自信号线的控制信号,控制电机转动,电机带动一系列齿轮组,减速后传动至输出舵盘。舵机的输出轴和位置反馈电位计是相连的,舵盘转动的同时,带动位置反馈电位计,电位计将输出一个电压信号到控制电路板,进行反馈,然后控制电路板根据所在位置决定电机的转动方向和速度,从而达到目标停止。
舵机的控制信号
舵机的控制信号为周期是20ms的脉宽调制(PWM)信号,其中脉冲宽度从0.5ms-2.5ms,相对应舵盘的位置为0-180度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。舵机内部有一个基准电路,产生周期20ms,宽度1.5ms的基准信号,有一个比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。
红色:5V---- +
黑色:GND---- -
黄色:GPIO14----信号端
另外说明一下:如果舵机不是由树莓派供电的话,需要将该电源与树莓派共地,也就是说电源的负极必须与树莓派任意一个GND连接,否则会出现舵机控制失常等现象。
以下为使用gpiozero库写的,转动的范围为90°
from gpiozero import Servo
from time import sleep
myGPIO = 14
myCorrection = 0
maxPW = (2.0 + myCorrection) / 1000
minPW = (1.0 - myCorrection) / 1000
servo = Servo(myGPIO, min_pulse_width=minPW, max_pulse_width=maxPW)
while True:
print("Set value range -1.0 to +0.0")
for value in range(0,11,1):
value2 = (float(value) - 10) / 10
servo.value = value2
print(value2)
sleep(0.1)
print("Set value range +0.0 to -0.9")
for value in range(11,20,1):
value2 = (float(value) - 10) / 10
servo.value = value2
print(value2)
sleep(0.1)
以下用RPI.GPIO库写的四自由度云台控制(两个舵机),转动的范围可为180°。
该程序全为本人参考其他程序后转变而来的,自身技术还些欠缺,所以此程序多多少少会出现一些BUG,还请各位大佬见谅,例如:
1.不能太频繁的发送信号给舵机,因为舵机内部转动和调整都是需要时间的;
2.有时候会像接收不到控制信号似的,发送了两三次信号才转动(有点像信号不好那样),但转动的角度应该是正确;
3.有时候可能存在一下子的抖动
所以呢,以下代码可以作为参考
import RPi.GPIO as GPIO
from time import sleep
def tonum(num): # 用于处理角度转换的函数
fm = 10.0 / 180.0
num = num * fm + 2.5
num = int(num * 10) / 10.0
return num
servopin1 = 15 #舵机1,方向为左右转
servopin2 = 18 #舵机2,方向为上下转
GPIO.setmode(GPIO.BCM)
GPIO.setup(servopin1, GPIO.OUT, initial=False)
GPIO.setup(servopin2, GPIO.OUT, initial=False)
p1 = GPIO.PWM(servopin1,50) #50HZ
p2 = GPIO.PWM(servopin2,50) #50HZ
p1.start(tonum(85)) #初始化角度
p2.start(tonum(40)) #初始化角度
sleep(0.5)
p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.1)
a = 0 #云台舵机1的执行次数
c = 9 #云台舵机1初始化角度:90度
b = 0 #云台舵机2的执行次数
d = 4 #云台舵机2初始化角度:40度
q = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 110, 120, 130, 140, 150, 160, 170, 180] #旋转角度列表
def left():
global a, c #引入全局变量
a += 1
if c > 2: #判断角度是否大于20度
c = c-1
g = q[c] #调用q列表中的第c位元素
print('当前角度为',g)
p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
sleep(0.1)
p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
else:
print('\n**超出范围**\n')
c = 9
g = 85 #调用q列表中的第c位元素
p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
sleep(0.1)
p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
def right():
global a, c #引入全局变量
if c < 16:
c = c+1
g = q[c] #调用q列表中的第c位元素
print('当前角度为',g)
p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
sleep(0.1)
p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
else:
print('\n****超出范围****\n')
c = 9
g = 85 #调用q列表中的第c位元素
p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
sleep(0.1)
p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
def up():
global b, d #引入全局变量
b += 1
if d > 2:
d = d-1
g = q[d] #调用q列表中的第d位元素
print('当前角度为',g)
p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
sleep(0.1)
p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
else:
print('\n**超出范围**\n')
d = 4
g = q[d] #调用q列表中的第d位元素
p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
sleep(0.1)
p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
def down():
global b, d #引入全局变量
if d < 11:
d = d+1
g = q[d] #调用q列表中的第d位元素
print('当前角度为',g)
p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
sleep(0.1)
p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
else:
print('\n****超出范围****\n')
d = 4
g = q[d] #调用q列表中的第d位元素
p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
sleep(0.1)
p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
sleep(0.01)
if __name__ == '__main__':
while True:
a = input('输入:')
if a == 'a':
left()
elif a == 'd':
right()
elif a == 'w':
up()
elif a == 's':
down()
补充一下关于舵机抖动和消抖的方法(仅是个人观点哈):
舵机会发生抖动是因为它自身认为自己还没有真正转到要求的角度,所以会不断的左右纠正,最终产生抖动。一般抖动是因为占空比没有清零,所以当舵机转到指定的角度后,稍微给一端很短的时间停留后,就将当前的占空比清零,如:
p2.ChangeDutyCycle(0)
sleep(0.01)
##2020.8.22
有写得不好、写得不对的地方还请各位指出,谢谢!