【樹莓派+.NET MF打造視頻監控智能車】控制篇(.NET MF)


在上一篇《遙控篇》文章中,我們介紹了Sony PS2手柄信號的采集和編程,通過簡單的封裝,以事件的方式向我們提供按鍵信息。本篇文章主要介紹.NET Micro Framework系統接受到按鍵信息后,如何驅動小車馬達和控制機械手的。

無論是驅動小車馬達還是控制機械手,都是通過輸出PWM來控制的,只是控制PWM輸出的方式有些不同而已,我們先介紹一下小車馬達的控制。

由於驅動馬達需要相對比較大的電流,所以主芯片的IO是無法直接驅動的,中間需要連接一個驅動器。也就是說主芯片輸出PWM控制驅動器,由驅動器輸出大電流來驅動馬達。

一般情況下一個驅動器可以驅動兩路馬達,而驅動一個馬達一般需要兩路信號,通過控制兩路PWM的輸出,來控制馬達的轉速和方向。我們這款小車選用的是一個帶光電隔離,高功率的一個驅動器,一路馬達,需要三路IO控制,其中2路是控制方向,一路輸出PWM控制小車的轉速。

 

一個驅動器模塊,需要4個GPIO(控制方向)2路PWM,加上一路3V3和GND,共8路,我們采用標准.NET Gadgeteer接口進行連接(10個pin:1個3V3,1個5V,1個GND,7個GPIO通道),可以直接插入凌霄開發板上的兩個.NET Gadgeteer接口上,接線顯的簡單直接(上圖所示的兩個扁平電纜就是)。

機械手控制就更為容易了,一個舵機三根線,電源(5V),地和信號線(PWM),三個舵機,一共需要3路PWM輸出控制。注意電源也需要特別提供。PWM由凌霄開發板IO直接輸出。

下面介紹一下.NET Micro Framework的PWM接口函數類。

public class PWM : IDisposable

    {

        public PWM(Cpu.PWMChannel channel, double frequency_Hz, double dutyCycle, bool invert);

        public PWM(Cpu.PWMChannel channel, uint period, uint duration, PWM.ScaleFactor scale, bool invert);

 

        public uint Duration { get; set; }

        public double DutyCycle { get; set; }

        public double Frequency { get; set; }

        public uint Period { get; set; }

     

        public void Start();

       public void Stop();

      

      //… 省略一些非主要函數

   }

 

兩個構造函數,分別介紹一下。

PWM(Cpu.PWMChannel channel, double frequency_Hz, double dutyCycle, bool invert);

channel – 通道,不同的系統,支持的通道個數不同,比如凌霄系統支持16路,應該算比較多的。

frequency_Hz – 頻率,單位是Hz,發出脈沖的頻率值。

dutyCycle – 占空比, 一個0~1之間的數,表示一個周期中,高電平持續時間和整個周期的比值。

Invert – 信號翻轉,高低電平翻轉切換,一般底層都沒有處理該參數,所以一般設置為false。

 

public PWM(Cpu.PWMChannel channel, uint period, uint duration, PWM.ScaleFactor scale, bool invert);

channel – 通道。

period – 周期。單位和scale的選項一致。

duration – 高電平持續時間,單位和周期一致。

scale – 周期的時間單位,可以是毫秒、微秒、納秒,建議選擇微秒。

Invert – 信號翻轉。

 

第一個構造函數,一般控制馬達用,參數設置顯的比較直觀。頻率可以是1K~250KHz(建議10K左右),通過設置占空比的大小(0就是停止,1就是全速),來進行調速。

第二個構造函數,適合控制舵機用,舵機典型的控制曲線如下:

 

F就是所謂的周期了,如果我們設置scale為微秒,則可以直接設置為20000,所謂的脈寬就是duration的值,你可以設置為1000~2000之間(不同舵機,這個區域的值會有不同,請根據實際進行調整)。

有了以上的介紹,我們就可以很容易地完成馬達驅動和舵機控制了。

A.驅動馬達

馬達驅動控制參數定義:   

 static PWM[] motor_pwm = new PWM[4];

    static double[] frequency = new double[] { 10000, 10000, 10000, 10000 };        

    static double[] dutyCycle = new double[] { 0, 0, 0, 0};                         

    static bool[] states1 = new bool[] { true, false, true, false, true, false, true, false };

    static bool[] states2 = new bool[] { false, true, false, true, false, true, false, true };

    static OutputPort[] In = new OutputPort[8];

馬達驅動初始化:

  

  //初始化馬達控制

    //方向IO

    Cpu.Pin[] pins = new Cpu.Pin[] { Mainboard.Gadgeteer.Socket2.Pin4, Mainboard.Gadgeteer.Socket2.Pin5, Mainboard.Gadgeteer.Socket2.Pin6, Mainboard.Gadgeteer.Socket2.Pin7,

                                        Mainboard.Gadgeteer.Socket1.Pin4, Mainboard.Gadgeteer.Socket1.Pin5, Mainboard.Gadgeteer.Socket1.Pin6, Mainboard.Gadgeteer.Socket1.Pin7};           

    for (int i = 0; i < In.Length; i++)

    {

        In[i] = new OutputPort(pins[i], false);

    }

    //馬達速度PWM輸出

    Cpu.PWMChannel[] motor_chanels = new Cpu.PWMChannel[] { Mainboard.PWM.Channel13, Mainboard.PWM.Channel14, Mainboard.PWM.Channel2, Mainboard.PWM.Channel3 };

    for (int i = 0; i < motor_pwm.Length; i++)

    {

        motor_pwm[i] = new PWM(motor_chanels[i], frequency[i], dutyCycle[i], false);

        motor_pwm[i].Start();

    }

 

馬達控制:

在Sony PS2的事件代碼中,我們填寫如下代碼:

static void ps2_Click(object sender, PS2.ButtonArgs e)

    {

if(e.key == PS2.Key.RRocker)

        {

            PS2 ps2 = (PS2)sender;

            PS2.ButtonArgs button = ps2.GetButton(PS2.Key.L2);

            if (button.state == 1) //L2按下

            {

                byte[] buffer = new byte[] { 0xAA, (byte)e.x, (byte)e.y, 0x55 };

                piPort.Write(buffer, 0, 4);

                piPort.Flush();

 

                //左右旋轉

                steering_pwm[3].Duration = (UInt32)(durations[3] + (128 - e.x) * 5);

                //上下旋轉

                steering_pwm[4].Duration = (UInt32)(durations[4] + (128 - e.y) * 5);

 

            }

            Else  //L2抬起

            {

                //小車運動

                UInt32[] values = new UInt32[4];

                UInt32 x = (UInt32)(System.Math.Abs(e.x - 128));

                UInt32 y = (UInt32)(System.Math.Abs(e.y - 128));

                for (int i = 0; i < values.Length; i++) values[i] = y;

 

                if (e.y < 128)

                {

                    //前進

                    for (int i = 0; i < In.Length; i++) In[i].Write(states2[i]);

                    //拐彎

                    if (x > 30)

                    {

                        if (e.x < 128)

                        {

                            values[2] = x;

                            values[3] = x;

                        }

                        else

                        {

                            values[0] = x;

                            values[1] = x;

                        }

                    }

                }

                else

                {

                    //后退

                    for (int i = 0; i < In.Length; i++) In[i].Write(states1[i]);

                    //拐彎

                    if (x > 30)

                    {

                        if (e.x < 128)

                        {

                            values[0] = x;

                            values[1] = x;

                        }

                        else

                        {

                            values[2] = x;

                            values[3] = x;

                        }

                    }

                }

                //設置占空比

                for (int i = 0; i < motor_pwm.Length; i++) motor_pwm[i].DutyCycle = (values[i] / 128.0);

            }

        }

    }      

B、驅動舵機

舵機參數定義:

static PWM[] steering_pwm = new PWM[5];

    static UInt32[] periods = new UInt32[] { 20000, 20000, 20000, 20000, 20000 };//周期        static UInt32[] durations = new UInt32[] { 1390, 1500, 1390, 1550, 1420 };   //脈寬

舵機初始化:

Cpu.PWMChannel[] steering_chanels = new Cpu.PWMChannel[] { Mainboard.PWM.Channel8, Mainboard.PWM.Channel9, Mainboard.PWM.Channel6, Mainboard.PWM.Channel0, Mainboard.PWM.Channel4 };

    for (int i = 0; i < steering_pwm.Length; i++)

    {

        steering_pwm[i] = new PWM(steering_chanels[i], periods[i], durations[i], PWM.ScaleFactor.Microseconds, false);

        steering_pwm[i].Start();

    }

舵機控制:

static void ps2_Click(object sender, PS2.ButtonArgs e)

    {

       if (e.key == PS2.Key.LRocker) //左搖桿事件

        {

            //控制機械臂左右旋轉

            steering_pwm[0].Duration = (UInt32)(durations[0] + (128 - e.x) * 5);

            //控制機械臂上下旋轉

            steering_pwm[1].Duration = (UInt32)(durations[1] + (128 - e.y) * 5);

        }

        else if (e.key == PS2.Key.R2)  //按下右R2鍵

        {

            //打開鉗子

            value += 10; if (value > 255) value = 255;

            steering_pwm[2].Duration = (UInt32)(durations[2] + (value - 128) * 5);

        }

        else if (e.key == PS2.Key.R1)  //按下右R1鍵

        {  

            //閉合鉗子

            value -= 10;if (value < 0) value = 0;

            steering_pwm[2].Duration = (UInt32)(durations[2] + (value - 128) * 5);

        }

     }

C、視頻演示

 

視頻鏈接:http://v.youku.com/v_show/id_XNjY2MTE1NjQ0.html

文章導航:

1、【樹莓派+.NET MF打造視頻監控智能車】遙控篇

2、【樹莓派+.NET MF打造視頻監控智能車】控制篇(.NET MF)

3、【樹莓派+.NET MF打造視頻監控智能車】控制篇(樹莓派)

4、【樹莓派+.NET MF打造視頻監控智能車】視頻篇

 小結:

1、 .NET Micro Framework PWM類的設計,非常符合用戶的認知和使用習慣,可以非常方便地實現相應功能。

2、 通過VS2010/VS2012在線調試,可以快速地測試出合適的控制值。

3、 以上代碼大概十幾分鍾就可以完成,充分體現了.NET Micro Framework快速開發的特性。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM