目錄
這里使用樹莓派來操作sg90的舵機。先看一下這個舵機的樣子:
這就是傳說中的SG90舵機啦,轉角是0~180.
SG90舵機接線:
SG90舵機有三條線:黃線,紅線和灰(還是黑?)線。
這三條線的作用是:紅線VCC,灰線GND,黃線控制線。所以我們這里主要是操控黃線來控制舵機。
然后這里有個非常非常坑的地方,就是這個舵機是需要5V電壓輸入的。所以你在把VCC接到樹莓派上時你得接5V的引腳而不是3.3V的。這個情況我當時在stm32也遇到過:明明程序寫的是對的,但是舵機就是轉不起來。。。因為stm32的GPIO一般都是3.3V的,我也就沒能幸免🙃(誰讓我是硬件白痴呢😢)。所以一開始接線要接對了(或者買個繼電器轉成5V也行)。
PWM介紹
我們如何通過一根操作線來操作舵機呢?答案就是使用PWM脈沖寬度調制技術。那么啥叫PWM呢?這里我簡單的說一下我的理解:
我們樹莓派或者是其他單片機一個引腳只能輸出兩個特定的電平——高電平和低電平。在樹莓派上大多的GPIO都是高電平3.3V,低電平0V。但是如果我想要輸出3.3~0V之間的電壓怎么辦呢?比如輸出一個2V?樹莓派(以及stm32,C51之類的)是沒有辦法直接設置引腳的電平來達到輸出2V的。因為通過樹莓派來說,你的GPIO.setup(channel,state)里的state只能是GPIO.HIGH和GPIO.LOW,沒有什么GPIO.twoV之類的東西。那么我們就要使用PWM來輸出介於低電平和高電平之間的電壓。
那么PWM是怎么做到的呢?很簡單:我們不能直接輸出2V,那我們換一種方式——通過給引腳一個周期脈沖,然后看這個脈沖的高電平部分占整個脈沖的比例,從而計算這個輸出的電平。舉個栗子🌰:比如我給出一個周期為20s的周期脈沖,然后讓其中的高電平為12s,這樣的話輸出的電平就是(12/20)*3.3V≈2V,那么2V就輸出了😀。
也就是說,PWM是根據周期脈沖中高電平所占的比例來確定GPIO輸出的電壓的。這里,高電平所占周期脈沖的周期的比例稱為占空比。這是個很重要的概念,要記住了。
下面這個GIF就說明了PWM產生的結果。代碼如下:
1 import RPi.GPIO as GPIO
2 import time 3 4 if __name__=='__main__': 5 GPIO.setmode(GPIO.BOARD) 6 GPIO.setup(33,GPIO.OUT,initial=GPIO.LOW) 7 GPIO.setup(35,GPIO.OUT) 8 GPIO.setup(37,GPIO.OUT,initial=GPIO.HIGH) 9 p=GPIO.PWM(35,150) 10 p.start(0) 11 try: 12 while True: 13 for dc in range(0,101,1): 14 p.ChangeDutyCycle(dc) 15 time.sleep(0.1) 16 for dc in range(100,-1,-1): 17 p.ChangeDutyCycle(dc) 18 time.sleep(0.1) 19 except KeyboardInterrupt: 20 pass 21 p.stop() 22 GPIO.cleanup()
這個本來是我做PWM呼吸燈的代碼,是循環輸出0~3.3V的程序,這里我用電表測量了35(PWM輸出)腳。通過電表的示數可明顯看到引腳輸出的電壓的確在變化。
接下來說說樹莓派里面如何實現PWM。主要就是在第9,10,14,21行:
- 首先只要想使用GPIO,就一定要初始化GPIO,這里的第7行先初始化35腳的GPIO為輸出
- 然后要說明哪個引腳使用PWM功能。第9行的GPIO.PWM(channel,frequency)指定channel腳使用PWM功能,這個PWM的頻率為frequency。所謂頻率就是周期的倒數嘛,也就是你的周期脈沖的周期的倒數啦。然后這個函數返回一個PWM對象,這里為p
- 然后開始PWM,第10行p.start(initdutycycle)說明現在開始PWM輸出啦,這里的initdutycycle是在開始時指定的占空比。這里為0也就是說0/frequency*5V為0V,暫時不輸出電平。由於是指定占空比,所以initdutycycle在[0,100]區間之內。超出這個區間Python會報錯。
- 那么如何更改占空比呢?使用第14行的p.ChangeDutyCycle(dutycycle)來改變占空比。
- 最后你用完PWM了需要將PWM停掉,也就是第21行的p.stop()
如何使用PWM操控舵機?
我們查看SG90的文檔可以看見其占空比與轉動角度的關系:
在周期20ms下:
角度 占空比
0.5ms-------------0度; 2.5%
1.0ms------------45度; 5.0%
1.5ms------------90度; 7.5%
2.0ms-----------135度; 10.0%
2.5ms-----------180度; 12.5%
這里直接給出了占空比與角度的關系,我們就不用關系電壓的大小了。
這里SG90舵機的參考周期是20ms,也就是50KHZ。那么按照這個方法我們可以寫出如下代碼:
import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BOARD) In_Pin=35 #操控線(黃線)
#VCC接在5V腳上,GND接在GND腳上
GPIO.setup(Vcc_Pin,GPIO.OUT,initial=GPIO.HIGH) GPIO.setup(In_Pin,GPIO.OUT,initial=GPIO.LOW) p=GPIO.PWM(In_Pin,50) #設置頻率為50KHz p.start(0) str1="please input the degree(0<=a<=120)\nor press q to quit\n" r=input(str1) try: while not r=="q": if r.isdigit(): #判斷輸入的字符串是不是數字 r=int(r) #是數字轉換成數字 else: print("please input a number(0<=num<=120)") continue if r<0 or r>180: #越界提示 print("a must be [0,120]") continue p.ChangeDutyCycle(2.5+r/360*20) #通過用戶輸入的角度來改變舵機的角度 time.sleep(0.02) r=str(input(str1)) except KeyboardInterrupt: pass p.stop() GPIO.cleanup()
這個程序讓用戶輸入舵機轉動的角度,從而轉動舵機到相應的角度。
這里的p.ChangeDutyCycle(2.5+r/360*20)中的2.5+r/360*20是我推導的公式,用於轉動舵機到指定的角度。這個公式使用比例來推導,很簡單的。
最后的成果如下: