【.NET 與樹莓派】控制舵機

不管是小馬達,還是大馬達,嗯,也就是電機,相信大夥伴們也不會陌生。四驅車是一種很優秀的玩具,從老周小時候就開始流行(動畫片《四驅兄弟》估計很多大朋友都看過),直到現在還能看到很多賣四驅車的。為啥會想起四驅車呢?因為小時候玩四驅車讓老周認識了很多奇葩馬達,什麼「紅魔鬼」、「藍芯」、「紫魔鬼」……也不知道是什麼邏輯的命名方式,反正那時候大家都這麼叫。

這些馬達的結構有一個轉軸,繞有紅色或橙色的線圈(記憶中是這些顏色),有四塊磁鐵。金屬外殼,上部開有兩個散熱孔。整體形狀有圓的也有扁的,許多遙控車的馬達是圓的。還有一馬達像個竹筒似的,一些太陽帽小風扇裏面有。

一般的馬達的特點,就是一通電就往一個方向轉(正負接反它就反向轉),但舵機比普通馬達更好玩。360度的舵機與一般馬達相似,加電後會往一個方向轉動,信號線控制其轉動方向和轉速;不過我們常說的舵機一般是指 180 度的舵機,這種舵機可以通過信號線讓它轉動一定的角度,當到達指定的角度後舵機會停下來。

180 度舵機可以:

1、機械人各個關節的運動,可模擬人的關節活動。因為程序可以控制舵機轉到指定的角度。

2、遙控小車可以用舵機來拐彎。

3、機械臂 / 機械爪。

4、製作可以轉動的攝像頭。

5、3D 打印的零部件。

……

只要需要控制轉動方向的,都用得上。

 

舵機依據其工作負荷以及扭力可以有很多種,咱們用來開發做實驗的,最好選 9 克舵機。儘管這種舵機力氣不大,但是開發板可以直接供電,不用外加電源補電。就是這種,藍色透明外殼的。

 

 正因為外殼是透明的,所以你能看到裏面有什麼。當然了,你如果像老周這樣喜歡搞破壞的,可以把拆開玩玩。

 

 拆的時候最好戴個手套,畢竟這是電機,你拆過就知道,裏面有很多潤滑油的。裝回去的時候要注意那幾個減速齒輪,有的大夥伴一時衝動拆了,然後裝不回去。雖然這種舵機一般幾塊錢一個,但你也不能這麼浪費。

 

 舵機裏面主要這幾個部件:

1、馬達。這個肯定有的,不然怎麼轉。

2、電位器。不同角度會改變不同的電阻值,使控制板能驅動馬達轉多少圈。

3、控制板。

4、N 個減速齒輪。

 

上面只是了解一下舵機,接下來看重點——怎麼控制角度。一般的教程會跟你說,通過 PWM 設置不同占空比來控制舵機轉動角度。這並不算錯,因為控制舵機確實是用 PWM 實現的。不過,這樣說其實不準確。實際上,讓舵機轉動多少度是通過高電平的持續時間來控制的。

通常情況下,控制脈衝的周期時長是 20 毫秒,即 20000 微秒。故用PWM時,頻率設定 50 Hz(1 / 0.02秒 = 50 Hz)。舵機識別高電平的時間範圍為 0.5 ms 到 2.5 ms,即 500 us 到 2500 us。下圖是老周盜來的動圖。

這就是為什麼PWM能控制舵機的原因,在 0.5ms 之前的時間舵機不關心,所以這段時間無論輸出信號是高電平還是低電平都可以,因此關注的核心變為高電平什麼時候關閉(變為低電平)。

 

 如上圖,如果高電平持續到 0.5 毫秒時變為低電平,則舵機旋轉至 0 度。

 

 

 如果高電平在 1.5 毫秒時關閉,則舵機旋轉到 90 度。

 

 

 如果高電平在 2.5 毫秒時關閉,舵機旋轉至 180 度。

 

綜上所述,將控制舵機的信號換算為PWM的占空比,需要準備以下條件:

1、周期時間長度,一般為 20000 us,換算為PWM頻率為 50Hz。

2、高電平有效的持續時間,一般值為:min = 500us,max = 2500us。

3、500 – 2500 us,其時間段為 2500-500 = 2000us,用180度平分這2000微秒,即每一度角對應的時間為 2000 / 180 ≈ 11.11 us / deg。

綜合一下,占空比可這樣算:

假設要旋轉 90 度,即占空比:

 

 

 把公式翻譯成中文,就是這樣

 

 

有了上面的基礎,寫代碼就好辦了。這裡老周寫了一個測試程序,這個命令行程序可以通過輸入命令來修改參數,這樣方便大家做實驗。命令幫助信息如下:

        using static System.Console;

        static void ShowHelps()
        {
            WriteLine("{0,-15}{1}", "h", "顯示幫助信息");
            WriteLine("{0,-15}{1}", "x", "退出");
            WriteLine("{0,-15}{1}", "d n", "設置周期(微秒)");
            WriteLine("{0,-15}{1}", "t n", "高電平起始時間(微秒)");
            WriteLine("{0,-15}{1}", "p n", "高電平結束時間(微秒)");
            WriteLine("{0,-15}{1}", "a n", "角度");
            WriteLine("{0,-15}{1}", "o", "發送脈衝信號");
            WriteLine("{0,-15}{1}", "s", "停止脈衝");
            WriteLine();
        }
        

下面的代碼是計算 1 度角對應的時間長度(微秒)。

        static void ComputeMicroToAngle()
        {
            microForAngle = (maxMicrosec - minMicrosec) / 180.0d;
        }

minMicrosec 是高電平持續的最小時間:500us;maxMicrosec 是高電平持續的最大時間:2500us。

這幾個變量的聲明如下:

        /// <summary>
        /// 高電平持續的最小時間,一般為 500us
        /// </summary>
        static int minMicrosec = 500;

        /// <summary>
        /// 高電平持續的最大時間,一般為 2500us
        /// </summary>
        static int maxMicrosec = 2500;

        /// <summary>
        /// 一度角對應的持續時間,單位為微秒(us)
        /// </summary>
        static double microForAngle = 0d;

 

主體代碼如下,其餘的可以下載源代碼查看。

            // 創建PWM通道實例
            PwmChannel ch = PwmChannel.Create(0, 0);
            ShowHelps(); //運行後打印一次幫助信息
            bool working = true; //用來跳出循環的標誌變量
            while(working)
            {
                Write(">>>");
                // 讀取鍵盤輸入的一行文本
                string line = ReadLine();
                // 讀取第一個字符
                char first = line[0];
                // 分析命令
                switch(first)
                {
                    case 'h': //顯示幫助信息
                        ShowHelps();
                        break;
                    case 'x': //跳出循環,退出程序
                        working = false;
                        break;
                    case 'd': //設置周期,一般是20000us
                        ch.Frequency = ParseFreq(line[1..].Trim());
                        break;
                    case 't': //設置高電平持續的最小時間
                        ParseMinMicrosecond(line[1..].Trim());
                        ComputeMicroToAngle();
                        break;
                    case 'p': //設置高電平持續的最大時間
                        ParseMaxMicrosecond(line[1..].Trim());
                        ComputeMicroToAngle();
                        break;
                    case 'a': //設置要旋轉的角度
                        double angle = ParseAngle(line[1..].Trim());
                        ch.DutyCycle = ComputeDuty(angle, ch.Frequency);
                        break;
                    case 'o': //開始發送脈衝
                        ch.Start();
                        break;
                    case 's': //停止發送脈衝
                        ch.Stop();
                        break;
                    default:
                        WriteLine("<<< 無效命令");
                        break;
                }
            }
            ch.Dispose();

 

編譯,發佈,上傳到樹莓派。注意舵機有三條線:

1、紅線(一般在中間),接樹莓派 5V 引腳(供電正極)。

2、黑線或棕色線,接樹莓派任意一個 GND 引腳(供電負極)。

3、黃色(有的是白色)是信號線,用來控制舵機,接樹莓派的 GPIO 18,這個是樹莓派全系列通用的默認 PWM 引腳。

 

運行程序,第一步,輸入 d 20000,設定周期(為了統一,所有時間參數都是以微秒為單位)。

 

 輸入 t 500 設置高電平控制角度的起始時間,就是持續最小值,取500。

 

 輸入 p 2500,設置高電平的結束時間,即持續的最大值,一般取 2500。

 

 輸入小寫字母 o,開始PWM。

 

 輸入 a 120,旋轉至 120 度。

 

輸入 a 30 ,旋轉至 30 度。

 

 輸入小寫字母 s ,停止PWM信號,輸入 x 退出。

 

看看效果。

 

相關源代碼,請點這裡下載