树莓派4B-Python-控制舵机

一时失言乱红尘 2022-11-29 12:20 691阅读 0赞

树莓派4B-Python-控制舵机

  • SG90舵机
  • 参数介绍
  • 工作原理
  • 与树莓派4B连接
  • 使用gpiozero库的代码
  • 使用RPI.GPIO库的代码
    • 再补充一下

本文采用的是SG90型号、转动角度为90°/180°的舵机和树莓派4B4G版,主要是实现对舵机的控制、问题的解决。

SG90舵机

SG90舵机,常用在小型机器人、智能小车、机械臂、固定翼等小型模型上,因为内部的齿轮多数为塑料的,承受不了太大的扭力。
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的基准信号,有一个比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。

与树莓派4B连接

舵机连接树莓派
红色:5V—— +
黑色:GND—— -
黄色:GPIO14——信号端

另外说明一下:如果舵机不是由树莓派供电的话,需要将该电源与树莓派共地,也就是说电源的负极必须与树莓派任意一个GND连接,否则会出现舵机控制失常等现象。

使用gpiozero库的代码

以下为使用gpiozero库写的,转动的范围为90°

  1. from gpiozero import Servo
  2. from time import sleep
  3. myGPIO = 14
  4. myCorrection = 0
  5. maxPW = (2.0 + myCorrection) / 1000
  6. minPW = (1.0 - myCorrection) / 1000
  7. servo = Servo(myGPIO, min_pulse_width=minPW, max_pulse_width=maxPW)
  8. while True:
  9. print("Set value range -1.0 to +0.0")
  10. for value in range(0,11,1):
  11. value2 = (float(value) - 10) / 10
  12. servo.value = value2
  13. print(value2)
  14. sleep(0.1)
  15. print("Set value range +0.0 to -0.9")
  16. for value in range(11,20,1):
  17. value2 = (float(value) - 10) / 10
  18. servo.value = value2
  19. print(value2)
  20. sleep(0.1)

使用RPI.GPIO库的代码

以下用RPI.GPIO库写的四自由度云台控制(两个舵机),转动的范围可为180°。

该程序全为本人参考其他程序后转变而来的,自身技术还些欠缺,所以此程序多多少少会出现一些BUG,还请各位大佬见谅,例如:
1.不能太频繁的发送信号给舵机,因为舵机内部转动和调整都是需要时间的;
2.有时候会像接收不到控制信号似的,发送了两三次信号才转动(有点像信号不好那样),但转动的角度应该是正确;
3.有时候可能存在一下子的抖动

所以呢,以下代码可以作为参考

  1. import RPi.GPIO as GPIO
  2. from time import sleep
  3. def tonum(num): # 用于处理角度转换的函数
  4. fm = 10.0 / 180.0
  5. num = num * fm + 2.5
  6. num = int(num * 10) / 10.0
  7. return num
  8. servopin1 = 15 #舵机1,方向为左右转
  9. servopin2 = 18 #舵机2,方向为上下转
  10. GPIO.setmode(GPIO.BCM)
  11. GPIO.setup(servopin1, GPIO.OUT, initial=False)
  12. GPIO.setup(servopin2, GPIO.OUT, initial=False)
  13. p1 = GPIO.PWM(servopin1,50) #50HZ
  14. p2 = GPIO.PWM(servopin2,50) #50HZ
  15. p1.start(tonum(85)) #初始化角度
  16. p2.start(tonum(40)) #初始化角度
  17. sleep(0.5)
  18. p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  19. p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  20. sleep(0.1)
  21. a = 0 #云台舵机1的执行次数
  22. c = 9 #云台舵机1初始化角度:90度
  23. b = 0 #云台舵机2的执行次数
  24. d = 4 #云台舵机2初始化角度:40度
  25. q = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
  26. 100, 110, 120, 130, 140, 150, 160, 170, 180] #旋转角度列表
  27. def left():
  28. global a, c #引入全局变量
  29. a += 1
  30. if c > 2: #判断角度是否大于20度
  31. c = c-1
  32. g = q[c] #调用q列表中的第c位元素
  33. print('当前角度为',g)
  34. p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
  35. sleep(0.1)
  36. p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  37. sleep(0.01)
  38. else:
  39. print('\n**超出范围**\n')
  40. c = 9
  41. g = 85 #调用q列表中的第c位元素
  42. p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
  43. sleep(0.1)
  44. p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  45. sleep(0.01)
  46. def right():
  47. global a, c #引入全局变量
  48. if c < 16:
  49. c = c+1
  50. g = q[c] #调用q列表中的第c位元素
  51. print('当前角度为',g)
  52. p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
  53. sleep(0.1)
  54. p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  55. sleep(0.01)
  56. else:
  57. print('\n****超出范围****\n')
  58. c = 9
  59. g = 85 #调用q列表中的第c位元素
  60. p1.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第c位元素的角度
  61. sleep(0.1)
  62. p1.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  63. sleep(0.01)
  64. def up():
  65. global b, d #引入全局变量
  66. b += 1
  67. if d > 2:
  68. d = d-1
  69. g = q[d] #调用q列表中的第d位元素
  70. print('当前角度为',g)
  71. p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
  72. sleep(0.1)
  73. p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  74. sleep(0.01)
  75. else:
  76. print('\n**超出范围**\n')
  77. d = 4
  78. g = q[d] #调用q列表中的第d位元素
  79. p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
  80. sleep(0.1)
  81. p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  82. sleep(0.01)
  83. def down():
  84. global b, d #引入全局变量
  85. if d < 11:
  86. d = d+1
  87. g = q[d] #调用q列表中的第d位元素
  88. print('当前角度为',g)
  89. p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
  90. sleep(0.1)
  91. p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  92. sleep(0.01)
  93. else:
  94. print('\n****超出范围****\n')
  95. d = 4
  96. g = q[d] #调用q列表中的第d位元素
  97. p2.ChangeDutyCycle(tonum(g)) #执行角度变化,跳转到q列表中对应第d位元素的角度
  98. sleep(0.1)
  99. p2.ChangeDutyCycle(0) #清除当前占空比,使舵机停止抖动
  100. sleep(0.01)
  101. if __name__ == '__main__':
  102. while True:
  103. a = input('输入:')
  104. if a == 'a':
  105. left()
  106. elif a == 'd':
  107. right()
  108. elif a == 'w':
  109. up()
  110. elif a == 's':
  111. down()

再补充一下

补充一下关于舵机抖动和消抖的方法(仅是个人观点哈):
舵机会发生抖动是因为它自身认为自己还没有真正转到要求的角度,所以会不断的左右纠正,最终产生抖动。一般抖动是因为占空比没有清零,所以当舵机转到指定的角度后,稍微给一端很短的时间停留后,就将当前的占空比清零,如:

  1. p2.ChangeDutyCycle(0)
  2. sleep(0.01)

##2020.8.22
有写得不好、写得不对的地方还请各位指出,谢谢!

发表评论

表情:
评论列表 (有 0 条评论,691人围观)

还没有评论,来说两句吧...

相关阅读

    相关 STM32 控制

    平台:stm32F429 +HAL 库+数字舵机 控制舵机体现在控制舵机的角度,通常舵机角度是0-180°。 如果设置为高电平有效,那么当定时器比较匹配之后,输出口输出高电

    相关 单片机控制

    项目描述: 通过按键控制MCU输出不同占空比的PWM信号来控制舵机旋转不同角度; 同时在LCD1602实时显示当前舵机的角度。 仿真原理图如下: ![在这里插入