tweak .net micro framework to drive a dc motor · tweak .net micro framework to drive a dc motor...

18
Tweak .NET Micro Framework to drive a DC Motor Requirements - Visual Studio 2008 Professional, Standard or Express Edition with SP1installed - .NET Micro Framework SDK 3.0 installed - GHI Embedded Master Board (Non TFT or TFT) with installed .NET Micro Framework 3.0 (in detail: GHI Embedded Master SDK 1.0.7, GHI Firmware version 03.00.000, TinyBooter for Embedded Master Version 03.00.000) - Or other hardware providing PWM and .NET Micro Framework 3.0 Introduction Everywhere, where wheels are turning the interfacing of one or mostly more dc motors are necessary. For autonomous robots, wheel or crawler driven vehicles, for RC cars and boats for example, you need to control the motion of these crafts in a very precise manner from very slow to very fast. Breaking the motor is sometimes a design constrain, too. How to do this and how easy it is to implement the stuff with the .NET Micro Framework, this article is about. At first I don’t want to explain the whole stuff in deep, because there are better sources where you can read something about PWM and H-Bridges in detail listed at the summarized links at the end of this article. But a short introduction should be useful for the understanding of the motor driver and .NET Micro Framework code explained here. What offers the native Micro .NET environment? Some .NET Micro Framework modules have on-board and in hardware pulse-width modulators. But currently, PWM can be used on only these few controllers through special integration by device vendors. In addition, using PWM requires native and managed drivers on your platform. Devices that support PWM through proprietary libraries and on-board hardware are the Meridian CPU from Device Solutions, Embedded Master Module from GHI Electronics and Embedded Development Kit (EDK) from SJJ Embedded Micro Solutions, LCC (see the links at the end of this article) and many over vendors, too. Some .NET Modules respectively Hardware

Upload: duongthien

Post on 13-Apr-2018

228 views

Category:

Documents


3 download

TRANSCRIPT

Tweak .NET Micro Framework to drive a DC Motor Requirements

- Visual Studio 2008 Professional, Standard or Express Edition with SP1installed - .NET Micro Framework SDK 3.0 installed - GHI Embedded Master Board (Non TFT or TFT) with installed .NET Micro Framework 3.0 (in

detail: GHI Embedded Master SDK 1.0.7, GHI Firmware version 03.00.000, TinyBooter for Embedded Master Version 03.00.000)

- Or other hardware providing PWM and .NET Micro Framework 3.0

Introduction Everywhere, where wheels are turning the interfacing of one or mostly more dc motors are necessary. For autonomous robots, wheel or crawler driven vehicles, for RC cars and boats for example, you need to control the motion of these crafts in a very precise manner from very slow to very fast. Breaking the motor is sometimes a design constrain, too. How to do this and how easy it is to implement the stuff with the .NET Micro Framework, this article is about. At first I don’t want to explain the whole stuff in deep, because there are better sources where you can read something about PWM and H-Bridges in detail listed at the summarized links at the end of this article. But a short introduction should be useful for the understanding of the motor driver and .NET Micro Framework code explained here.

What offers the native Micro .NET environment? Some .NET Micro Framework modules have on-board and in hardware pulse-width

modulators. But currently, PWM can be used on only these few controllers through special

integration by device vendors. In addition, using PWM requires native and managed drivers

on your platform. Devices that support PWM through proprietary libraries and on-board

hardware are the Meridian CPU from Device Solutions, Embedded Master Module from GHI

Electronics and Embedded Development Kit (EDK) from SJJ Embedded Micro Solutions,

LCC (see the links at the end of this article) and many over vendors, too.

Some .NET Modules respectively Hardware

GHI USBizi (Stand Alone)Board

NON TFT Embedded Master TFT Embedded Master

Figure 1: GHI Embedded Boards and modules

PWM Pulse width modulation (PWM) is a very simple and powerful technique to control an analog

signal with a digital device, like a microcontroller. The simplicity is in the control electronics of

a microcontroller that switches an analog signal on or off. When a digital pin port is switched

from off to on and then back to off, a pulse is generated. When the port pin signal is switched

on and off repeatedly, a pulse train is generated. By controlling the period of time from the

start of one pulse to the start of the next pulse in a pulse train, the modulation can be

established and controlled. By controlling the period of time that each pulse of a pulse train is

on and the period (P) of time that each pulse of a pulse train is off the duty cycle (D) can be

established and controlled. Pulse width modulation is the creation and control of a pulse

train’s frequency and duty cycle. Pulse width modulation can be used to control power and

current of a device or to transmit information.

Figure 2: Pulse Width Modulation with Time-Varying Duty (D) Cycles in a pulse train

Some very simple - self explaining - math behind Formula

𝒇 = 𝟏

𝑷

f P

frequency Period

𝑷 = 𝒕𝒊+ 𝒕𝒑 ti tp

time period impulse time period pause

𝑫 = 𝑷

𝒕𝒊 D pulse-duty factor

𝒈 =𝟏

𝑫 = 𝒕𝒊

𝑷= 𝟏+

𝒕𝒊

𝒕𝒑

g grade of pulse-duty

This very efficient technique employs pulses which are width modulated to generate the

current through the coil of a motor. A 50% D (duty cycle) results in a perfect square wave

(see below - Figure 3).

Figure 3: PWM Duty Cycles

𝑉𝑒𝑓𝑓 = 1

𝑃 𝑓(𝑡)𝑑𝑡𝑃

0

If the duty cycle is 25% the power reaching the driven device is nearly as high, too. If you drive a 12 Volt DC motor it is the same as if you drive 3 Volts (at 25% duty cycle). At 50% it’s like 6 V effective, at 75% it’s 9 V effective and at 100% are (nearly) the full 12 Volts present.

PWM Effective Voltage

Figure 4: Relationship between duty cycles and effective voltage reaching of the driven device. Motor speed response to this signal shall be a continuous and monotonic function of the duty cycle of the signal, from 100% to the minimum RPM. The motor RPM (as a percentage of maximum RPM) should match the PWM duty cycle within ±5%. The undetermined zone where a PWM signal is present while the motor isn’t turning has to be found through experiments. It depends on the implemented motor or motor type, if it is gearless or not and on the retention force working against the power produced through the cyclic PWM signal.

Speed versus PWM duty cycles

Figure 5: Schematically relationship between RPM and PWM.

H-Bridge theory H-Bridge The H-Bridge is a very simple device. As you

can see in the schematic all you need to build one, are four switches. This is possible with relays, too – but the current that can flow in such a relay application is not so high. A typical relay can drive approximately about 1-5 Amps – depending on the type - and is pretty voluminous. Power MOSFETs like the once used in the H-Bridge design shown later, are much better for high current applications and also smaller. Currents above 5 Amps are possible and we can drive pretty nice and powerful motors with or without gears, too. These motors can be built in robots for motion control or into crawler vehicles. If the H-Bridge is designed with SMDs (Surface Mounted Devices) the whole bridge will be very small and can be build in devices with few space left.

Figure 6: H-Bridge Function System An illegal state in a full quadrant H-bridge is one that turns on the upper source and lower sink on the same side (see Figure 7). This combination causes a direct short circuit to be created between the battery terminals or power source and usually causes one or both of the transistors that are on to go up in smoke. The current has only to flow through the motor (see Figure 8). The H-Bridge design (with friendly permission of Mr. Chuck McManis) shown and used in this article is avoiding this situation and the software can’t produce such an illegal state. Turning the motor motion from clockwise to counter-clockwise or vice versa can lead to this not recommended state, too – but only for the very short time the transistor is switching.

So please be aware of this, if you are changing the H-Bridge design to use other Transistors or POWER MOSFETs. First take a look into the design specifications of your Transistor or FET of choice underneath the switching behavior chapter for the falling and rising edges. The .NET Micro Framework is not very fast in execution of the code for the moment so problems are not expected here for now. But if the hardware get’s more performant the code execution time and the transistor switching time will go down. Then maybe the source code has to be changed and some short wait states are necessary. So be aware of that, if you are using this code on faster hardware or if you are writing an own PWM driver.

Illegal state left Illegal state right

Figure 7: Not recommended – shorting the power source - producing a very high current In Figure 8 you can see, how the rotation can be changed from clockwise to counter-clockwise or vice versa. All we need now for controlling the motion and speed of the motor is the PWM signal – switching on and off.

Rotation clockwise Rotation counter-clockwise

Figure 8: Working H-Bridge

Figure 9 shows how the whole stuff is working together: The .NET Micro Framework system, the H-Bridge and the motor - wired up like shown below.

Arrange all together

Figure 9: Block schematic of the whole system What kind of signals do we need to control the motor in speed and motion? Forward (FWD) and Reverse (REV) are necessary for rotation control. Sending a high signal to FWD and a low signal to REV the motor isn’t rotating. Even when the PWM signal is sent out to ENA the motor is going to rotate clockwise. The duty cycle of the pulse is equivalent to the motor speed.

Figure 10: Clockwise motion A low signal at FWD and a high signal at REV in conjunction with a PWM signal at ENA will force the motor to spin counter-clockwise.

Figure 11: Counter-clockwise motion

With the PWM signal (ENA*) the speed of rotation (RPM: Rotations per Minute) can be controlled. The pulse width duty cycles are equivalent to the percentage of the voltage reaching the DC motor – like explained before.

The real H-Bridge If you buy the parts in quantities of 1, all parts together cost less than 10 Euros (excluding

shipping and the DC motor of course) for a 1 to nearly about 8 Ampere capable H-bridge.

This keeps the final circuit "cheap". The complete schematic for the bridge is shown below

(Figure 12). I want to give kudos to the great work done by Mr. Chuck McManis for his

brilliant H-Bridge design. You can read more about this very easy to build bridge on his

wonderful home page: http://www.mcmanis.com/chuck/robotics/tutorial/h-bridge/index.html

Figure 12: H-Bridge schematic (with friendly permission of Mr. Chuck McManis)

The fast recovery diodes (shown in light blue) are optional when you are using the

TIP102/107 as those transistors have a diode assembled. However you can include them for

greater protection at higher currents. If size is an issue, you'll rather go with surface mounted

devices than this type of circuits.

Qty Description

2 TIP107, PNP Power Darlington Transistor (TO-220AB)

2 TIP102, NPN Power Darlington Transistor (TO-220AB)

4 10K Ohm, Resistors

4 470 Ohm, Resistors

4 1K Ohm, Resistors

4 Opto-coupler CNY17 III

4 1N4936, 1A Fast Recovery Rectifier (Optional if included in the transistor or FET)

Table 1) Parts List for the Simple H-Bridge

You can notice that the opto-isolator LEDs are connected to the three previous described wires labeled "FWD" (forward), "REV" (reverse), and "ENA* (enable all)." These wires deserve a little bit more detailed explanation and notice.

Now the Interfacing in detail The FWD, REV, and ENA* lines are the interface between the bridge and the .NET Micro Framework controller. You will notice there is no "ground" signal. When you connect these pins, combinations of 1's and 0's on the line turn on different pairs of transistors. The following table lists all possible combinations of input.

FWD REV ENA* Description

1 0 0 Turn on upper left source and lower right sink. (go forward)

1 0 1 Disable lower right sink. When fed a PWM signal the bridge modulates the "forward" current through the motor.

1 1 0 Turn on both lower left sink and lower right sink, shorting the motor. This causes a rotating motor to stop rotating so this mode is called "Braking."

1 1 1 Disable both lower sinks. When fed a PWM signal the bridge modulates the "braking" of the motor.

0 1 0 Turn on the upper right source and lower left sink. (go backward)

0 1 1 Disable lower left sink. When fed a PWM signal the bridge modulates the "reverse" current through the motor.

0 0 0 Turn off all sources and sinks. "Coast" motor is not engaged at all.

0 0 1 Turn off all sources and sinks in a different way, same effect though.

Table 2) Interfacing the H-Bridge (with friendly permission of Mr. Chuck McManis)

This works because the processor pins become a connection to ground when they are outputting logic 0. When FWD is 1 and ENA is 0, the lower right sink is getting current from FWD which it is returning through the pin connected to ENA. At any given time the pin must be able to supply enough current to turn on two LEDs and when set to zero sink the current of two LEDs. With the 470 ohm resistors and a 3.3V processor like the GHI Embedded Master offers this is not a problem. From the data sheet on the opto-isolator, each LED has a forward voltage drop of 1.2V, so (3.3 - 1.2) / 330 is 6.4mA per LED or 12.8mA of load total. The selected GHI pin is specified to be able to drive 20mA. You can further replace the 330 ohm resistors with 470 ohm resistors to reduce the current through the LEDs. However the LED voltage drop can be as high as 1.4V and the GHI controller operating voltage can be as low as 3.0V, in that condition with 470 ohm resistors you would only put 3.4mA into each LED which is below the 5mA specified in the datasheet. The 470 ohm resistor is the better choice as it maintains a sufficient broad margin.

The interface as designed gives you access to all of the interesting combinations of sinks and sources enable, while not allowed for any "illegal" state (see Figure 7 above). The human ear can hear frequencies up to roughly 20 kHz. When using PWM at frequencies below this, the device being driven can often be heard as a buzz. Higher frequencies avoid this but your cat or dog will probably leave the room, even if you cannot hear the frequency.

Implementation with the GHI Electronics Board The .NET Micro Framework Hardware The schematic of the microcontroller is integrated on the GHI Embedded Master board. The blue marked part is the supplement for the GHI Embedded Master TFT version board. For the here described example the NON TFT version board was used (Figure 1). The module is soldered onto the development board and placed underneath the display. The TFT version offers three more PWM pins.

Figure 13: GHI Embedded Master schematic (courtesy of GHI)

The Port Pins Two (5 with the TFT version) PWM pins are exposed with native PWM function support. Embedded Master PWM pins are clocked by two separate timers (0 and 1). Thus, PWM lines with the same clock can have different pulse widths, but the user must be aware that changing one clock will affect the other PWM channel with the same clock source on the TFT version.

PIN# Name Description

16 PWM0.0 PWM 0 ( PWM Timer 0 ) 17 PWM1.1 PWM 1 ( PWM Timer 1 ) 35 – TFT Version Only PWM1.4 PWM 4 ( PWM Timer 1 ) 39 – TFT Version Only PWM1.3 PWM 3 ( PWM Timer 1 ) 40 – TFT Version Only PWM0.2 PWM 2 ( PWM Timer 0 )

Table 3) GHI Embedded Master PWM pins (white: Non TFT, all pins on TFT module)

The user would first initialize the needed PWM channel and then set the desired frequency and duty cycle which can be set to different values at anytime later. The Duty Cycle value is a percentage of the total period. Valid values are 0% to 100%, inclusive. Frequency can be set to 0 to disable the PWM module. Other values less or equal to PWM.MAX_FREQUENCY are also valid. Currently, the maximum value for the GHI Embedded Master is set to 10MHZ.

Reference – GHIElectronics Namespace GHIElectronics.Hardware.PWM

Example // Initialize PWM 1 channel (PWM1.1 pin 17 – see table 3 above) PWM pwmChannel1 = new PWM(PWM.PWMChannel.Channel_1);

// Set Frequency to 50 kHz and duty cycle to 50% pwmChannel1.Set(50000, 50);

PWM/MISC Header

Figure 14: The header for PWM (blue: PWM/MISC)

PWM/MISC Header PWM and other miscellaneous pins are available on this header (Figure 14). An LED is connected to PWM0 for a quick test of the PWM functionality, too. It’s changing the intensity if the motor speed is going higher or lower.

Header Pin # Function Pin Connected to H-Bridge

1 E13/P3.16/PWM0 (PWM Timer 0) ENA*

2 E14/P3.24/PWM1 (PWM Timer 1) -

3 E16/P1.19/USB_PWR_EN FWD

4 E19/P1.27/USB_OC# REV

5 GND -

Table 4) the pins used for the interface are rendered in red

Figure 15: Wiring up the H-Bridge

<Picture of the whole stuff>

Figure 16: Board + H-Bridge

The Code for the PWM Motor Class File // change this - if you are using other hardware

#define GHIElectronics

using System;

using System.Threading;

using Microsoft.SPOT;

using Microsoft.SPOT.Input;

using Microsoft.SPOT.Hardware;

//Change this namespaces - if you are using other hardware

#if GHIElectronics

using GHIElectronics.Hardware;

using GHIElectronics.System;

#else

// other Namespaces

#endif

namespace SENET.Hardware.Motor

{

class Motor : IDisposable

{

#region speed enums - PWM negative logic for duty cycles

// negative logic

public enum Speed : int

{

Maximum = 0,

Fast = 0,

Percent_100 = 0,

Percent_95 = 5,

Percent_90 = 10,

Percent_85 = 15,

Percent_80 = 20,

Percent_75 = 25,

Percent_70 = 30,

Percent_65 = 35,

Percent_60 = 40,

Percent_55 = 45,

Half = 50,

Percent_50 = 50,

Percent_45 = 55,

Percent_40 = 60,

Percent_35 = 65,

Percent_30 = 70,

Percent_25 = 75,

Percent_20 = 80,

Percent_15 = 85,

Percent_10 = 90,

Percent_5 = 95,

Stopped = 100,

None = 100

}

#endregion

#region motor direction and PWM frequency enums

public enum Direction : int { None, Left, Right, Break};

public enum Frequency : int {

None = 0,

kHz_20 = 20000,

kHz_25 = 25000,

kHz_30 = 30000,

kHz_50 = 50000

};

#endregion

#region initialization

// moving states

private Direction direction = Direction.None;

// motor PWM parameter

private int duty = (int)Speed.None;

private PWM pwm = null;

private Frequency fequency = Frequency.kHz_50;

private PWM.PWMChannel pwmChannel = PWM.PWMChannel.Channel_0;

//stearing ports for motor movement into

//clockwise or counter-clockwise spin direction

private OutputPort moveLeft;

private OutputPort moveRight;

#endregion

#region constructors for motor PWM

/// <summary>

/// Initialization of the PWM stuff to stear a DC motor

/// </summary>

/// <param name="PWMPort">PWM Port Channel</param>

public Motor(PWM.PWMChannel PWMPort)

{

// channel used

this.pwmChannel = PWMPort;

// preset port pins - change this if another hardware is used

// false means: pin is not high!

this.moveLeft = new OutputPort(EmbeddedMaster.Pins.E16, false);

// false means: pin is not high!

this.moveRight = new OutputPort(EmbeddedMaster.Pins.E19x, false);

// the motor is current less

this.duty = (int)Speed.None;

// set PWM freq. to 50 kHz

this.fequency = Frequency.kHz_50;

StartMotorPWM();

System.Threading.Timer timer = new System.Threading.Timer(new

TimerCallback(OnTimer),

null, 0, 200);

}

/// <summary>

/// Initialization of the PWM stuff to stear a DC motor.

/// Use this ctr if other pins for stearing the moting are wished

/// </summary>

/// <param name="PWMPort">PWM port channel</param>

/// <param name="RightPin">Port pin for clokwise motion</param>

/// <param name="LeftPin">Port pin for anti-clockwise motion</param>

public Motor(PWM.PWMChannel PWMPort,

Cpu.Pin RightPin,

Cpu.Pin LeftPin)

: this(PWMPort)

{

// false means: pin is not high! No signal to the pin – no movement…

this.moveLeft = new OutputPort(LeftPin, false);

// false means: pin is not high! No signal to the pin – no movement…

this.moveRight = new OutputPort(RightPin, false);

}

/// <summary>

/// Initialization of the PWM stuff to stear a DC motor.

/// Use this ctr if all possibilities have to be set for

/// stearing a motor and it's behaviour

/// </summary>

/// <param name="PWMPort">PWM port channel</param>

/// <param name="RightPin">Port pin for clokwise motion</param>

/// <param name="LeftPin">Port pin for anti-clokwise motion</param>

/// <param name="Frequency">PWM frequency - use something above 20 kHz</param>

/// <param name="dutyState">PWM duty cycle</param>

public Motor(PWM.PWMChannel PWMPort,

Cpu.Pin RightPin,

Cpu.Pin LeftPin,

Motor.Frequency Frequency,

int dutyState)

: this(PWMPort, RightPin, LeftPin)

{

this.duty = dutyState;

this.fequency = Frequency;

}

#endregion

#region private methods

private void StartMotorPWM()

{

SystemManager.Start(null);

this.pwm = this.pwm ?? new PWM(pwmChannel);

this.pwm.Set((int)this.fequency, this.duty);

}

private void StopMotorPWM()

{

this.Dispose();

SystemManager.Shutdown();

}

/// <summary>

/// direction of motor movement

/// </summary>

/// <param name="direction">direction of movement</param>

private int Velocity(int Speed)

{

if ((Speed >= 0) && (Speed <= 100))

{

this.duty = (int)Speed;

}

return this.duty;

}

private void OnTimer(object state)

{

this.pwm.Set((int)this.fequency, this.duty);

switch (this.direction)

{

case Direction.Right:

this.moveRight.Write(true);

this.moveLeft.Write(false);

break;

case Direction.Left:

this.moveLeft.Write(true);

this.moveRight.Write(false);

break;

case Direction.Break:

this.moveRight.Write(true);

this.moveLeft.Write(true);

break;

case Direction.None:

this.moveLeft.Write(false);

this.moveRight.Write(false);

break;

default:

this.moveLeft.Write(false);

this.moveRight.Write(false);

break;

}

}

#endregion

#region motor properties

/// <summary>

/// get/set the direction of motor movement

/// </summary>

/// <param name="direction">clockwise or anti-clockwise</param>

public Direction Move

{

get { return this.direction; }

set { this.direction = value; }

}

/// <summary>

/// set/get the motor motion speed

/// </summary>

/// <param name="duty">the duty cycle is equivalent to the motor speed</param>

public int MovingSpeed

{

get { return this.duty; }

set { Velocity(value); }

}

#endregion

#region IDisposable Members

public void Dispose()

{

// Dispose PWM

StopMotorPWM();

}

#endregion

}

}

The Test Implementation public Window CreateWindow()

{

// Connect the button handler to all of the buttons.

mainWindow.AddHandler(Buttons.ButtonDownEvent,

new ButtonEventHandler(this.OnButtonDown),

false);

// start the PWM test

this.StartMotor();

return mainWindow;

}

private void StartMotor()

{

this.motor = new Motor(PWM.PWMChannel.Channel_0);

this.motor.MovingSpeed = (int)Motor.Speed.None;

}

private void OnExit()

{

// do shut down here...

this.motor.Dispose();

}

private void OnButtonDown(object sender, ButtonEventArgs e)

{

// Print the button code to the Visual Studio output window.

Debug.Print(e.Button.ToString());

switch (e.Button)

{

case Button.VK_UP:

if (this.motor.MovingSpeed > (int)Motor.Speed.Maximum)

this.motor.MovingSpeed -= 5;

else

this.motor.MovingSpeed = (int)Motor.Speed.Maximum;

break;

case Button.VK_DOWN:

if (this.motor.MovingSpeed < (int)Motor.Speed.Stopped)

this.motor.MovingSpeed += 5;

else

this.motor.MovingSpeed = (int)Motor.Speed.Stopped;

break;

case Button.VK_LEFT:

this.motor.Move = Motor.Direction.Left;

break;

case Button.VK_RIGHT:

this.motor.Move = Motor.Direction.Right;

break;

case Button.VK_MENU:

this.motor.Move = Motor.Direction.Break;

break;

case Button.VK_BACK:

this.motor.Move = Motor.Direction.Break;

break;

case Button.VK_SELECT:

this.motor.Move = Motor.Direction.None;

break;

default:

this.motor.Move = Motor.Direction.None;

break;

}

}

What’s next? - Motor driver designed with the integrated circuit LM298. - A Power Supply steering the output voltage over PWM. - A poor man’s DAC with PWM.

Revision History Revision Description Date

0.5 Initial Release - Internally 2009.23.April

0.8 Internal Release 2009.24.April

0.9 After Revision 2009.04.Mai

1.0 Initial Public Release 2009.10.Mai

Sources:

(1) A Basic Step by Step Guide for .NET Micro Framework Application Development on the iPac 9302 (By Sean Liming &

John R. Malin - SJJ Embedded Micro Solutions, LLC)

(2) Embedded Master User Manual; Rev. 2.03 Date: March 23, 2009

(3) Embedded Master User Manual; Rev. 2.04 Date: April 29, 2009

(4) Device solutions.net (http://devicesolutions.net/default.aspx?id=116)

(5) Expert .NET Micro Framework book by Apress written by Jens Kühner (ISBN-13: 978-1-59059-973-0)

(6) The really great home page of Mr. McManis (http://www.mcmanis.com/chuck/robotics/tutorial/h-bridge/index.html)

(7) Wikipedia, the free encyclopedia (http://en.wikipedia.org/wiki/H-bridge)

(8) http://www.discovercircuits.com/H/hbridge.htm

(9) http://electronicdesign.com/Articles/Index.cfm?AD=1&ArticleID=6199

(10) http://www.4qdtec.com/bridge.html

(11) http://bansky.net/blog/2008/07/dc-motor-driver-and-power-supply-board/