在上一篇《遙控篇》文章中,咱們介紹了Sony PS2手柄信號的採集和編程,經過簡單的封裝,以事件的方式向咱們提供按鍵信息。本篇文章主要介紹.NET Micro Framework系統接受到按鍵信息後,如何驅動小車馬達和控制機械手的。html
不管是驅動小車馬達仍是控制機械手,都是經過輸出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接口上,接線顯的簡單直接(上圖所示的兩個扁平電纜就是)。ui
機械手控制就更爲容易了,一個舵機三根線,電源(5V),地和信號線(PWM),三個舵機,一共須要3路PWM輸出控制。注意電源也須要特別提供。PWM由凌霄開發板IO直接輸出。spa
下面介紹一下.NET Micro Framework的PWM接口函數類。.net
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路,應該算比較多的。code
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
文章導航:
二、【樹莓派+.NET MF打造視頻監控智能車】控制篇(.NET MF)
三、【樹莓派+.NET MF打造視頻監控智能車】控制篇(樹莓派)
四、【樹莓派+.NET MF打造視頻監控智能車】視頻篇
小結:
一、 .NET Micro Framework PWM類的設計,很是符合用戶的認知和使用習慣,能夠很是方便地實現相應功能。
二、 經過VS2010/VS2012在線調試,能夠快速地測試出合適的控制值。
三、 以上代碼大概十幾分鍾就能夠完成,充分體現了.NET Micro Framework快速開發的特性。