無論是驅動小車馬達還是控制機械手,都是通過輸出PWM來控制的,隻是控制PWM輸出的方式有些不同而已,我們先介紹一下小車馬達的控制。
由于驅動馬達需要相對比較大的電流,是以主晶片的IO是無法直接驅動的,中間需要連接配接一個驅動器。也就是說主晶片輸出PWM控制驅動器,由驅動器輸出大電流來驅動馬達。
一般情況下一個驅動器可以驅動兩路馬達,而驅動一個馬達一般需要兩路信号,通過控制兩路PWM的輸出,來控制馬達的轉速和方向。我們這款小車選用的是一個帶光電隔離,高功率的一個驅動器,一路馬達,需要三路IO控制,其中2路是控制方向,一路輸出PWM控制小車的轉速。
一個驅動器子產品,需要4個GPIO(控制方向)2路PWM,加上一路3V3和GND,共8路,我們采用标準.NETGadgeteer接口進行連接配接(10個pin:1個3V3,1個5V,1個GND,7個GPIO通道),可以直接插入淩霄開發闆上的兩個.NET Gadgeteer接口上,接線顯的簡單直接(上圖所示的兩個扁平電纜就是)。
機械手控制就更為容易了,一個舵機三根線,電源(5V),地和信号線(PWM),三個舵機,一共需要3路PWM輸出控制。注意電源也需要特别提供。PWM由淩霄開發闆IO直接輸出。
下面介紹一下.NETMicro Framework的PWM接口函數類。
public class PWM : IDisposable
{
publicPWM(Cpu.PWMChannelchannel, uint period, uintduration, PWM.ScaleFactorscale, 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, doublefrequency_Hz, double dutyCycle, bool invert);
channel – 通道,不同的系統,支援的通道個數不同,比如淩霄系統支援16路,應該算比較多的。
frequency_Hz – 頻率,機關是Hz,發出脈沖的頻率值。
dutyCycle – 占空比, 一個0~1之間的數,表示一個周期中,高電平持續時間和整個周期的比值。
Invert – 信号翻轉,高低電平翻轉切換,一般底層都沒有處理該參數,是以一般設定為false。
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 = newOutputPort[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] = newOutputPort(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] = newPWM(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)
{
PS2ps2 = (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];
UInt32x = (UInt32)(System.Math.Abs(e.x- 128));
UInt32y = (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]);
}
//設定占空比
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();
舵機控制:
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);
{
//閉合鉗子
value -= 10;if (value < 0) value = 0;
}
C、視訊示範
<a href="http://v.youku.com/v_show/id_XNjY2MTE1NjQ0.html"></a>
小結:
1、 .NET Micro Framework PWM類的設計,非常符合使用者的認知和使用習慣,可以非常友善地實作相應功能。
2、 通過VS2010/VS2012線上調試,可以快速地測試出合适的控制值。
3、 以上代碼大概十幾分鐘就可以完成,充分展現了.NET Micro Framework快速開發的特性。
<a href="http://weibo.com/1804832611?s=6uyXnP"></a>