IAN LANG ELECTRONICS

As I created this page I noticed a slightly disturbing thing- this is page number 666 of the website. If it all goes wrong then you know who to blame. It's also the first page I've written since I got my membership of the IET. I don't want to brag but......oh wait yes I do. I bragged all day Friday at work. I am now officially Mr Ian Lang, TMIET and I made sure everybody at work knew about it including making myself a new badge and thrusting it in people's faces all day. Nice. Funnily enough last week I did an English test too. I got the top mark you could possibly get and consequently have been insufferable since. Snnrk.

 

Anyway,demonic influences and personal vanities aside, this time we are going to severely inconvenience some electrons by making them turn a motor. Here at Lang Towers we have a design that works with an Arduino that we use time and again for controlling robot arms and the wheels on platforms. We don't normally stick a potentiometer or a button  on it (though we have done before) but what it does is controls the speed by a Darlington transistor and the direction by a relay. You could do it without the Arduino if you wanted but with the Arduino you have room to expand as it acts as a voltage regulator, poller and switch and you can easily stick sensors on if you want. I've just recently made one for a teaching piece, hooking it up to a motor stuck into a multi ratio gearbox, and I thought it might make a good addition to the site. Here's a drawing:

Go Back

A Simple Motor Driver

 

This is another one of those that looks more complicated than it actually is. The two controls are S1, which controls the direction, and R2, the potentiometer, which controls the speed. Q1 is a Darlington transistor, and I used a BDX33, Q2 is a 2N3904 and the relay is a type 47 equivalent. Make sure your motor is a kind that works well over 3V and preferably at 5 or 6V.

 

Having slapped all your hardware together, you'll now need some code to work it. Here it comes and as usual you can get it as a text file by the link on the left:

 

//Simple motor driver board

//relay actuation pin 8

//Darlington controlpin 9

//Button on 4

//Pot read A0

unsigned long timethen =0;boolean pressdown=false;

void setup() {

Serial.begin(9600);

pinMode(8,OUTPUT);

 

}

void loop() {

Serial.println();

 Serial.print(digitalRead(4)); Serial.print("   "); Serial.print(analogRead(A0));

int outPut = analogRead(A0)/4;analogWrite(9,outPut);

if (digitalRead(4)==HIGH&&pressdown==false){

timethen=millis();pressdown=true;

if (digitalRead(8)==HIGH){digitalWrite(8,0);Serial.println("FORWARD");}

else{digitalWrite(8,1);Serial.println("REVERSE");}

}

if (pressdown==true&&millis()-timethen>250&&digitalRead(4)==LOW){pressdown=false;}

 

}

So what do we have here? Those of you having sat through one of magnum opuses (opi? I dunno, I was hopeless at Latin at school) will know by now that on this website we tend to waffle on at length like an elderly physics teacher who knows he's got you all afternoon and he's going to spin it out for that time even though it should take ten minutes. This is because he's not allowed to go behind the bike sheds and have a John Player Special like he wants to and you have been doing immediately before the lesson and now it's time for Karma to pay out.

breaktime

We aren't quite as gleefully malicious as the elderly physics teachers because we always offer you a JPS Blue and a nice cuppa before we delve in and there they are on the left. Dig in then and buckle up and we must get around to drawing in some ginger nuts on there.

 

Here's the idea: When you turn the pot the motor goes slower or faster, and when you push the button it changes direction. When you shove that button,it signals to the Arduino to change the relay state.The relay can be in one of  two states;energised or not energised

and when it's not energised (which is the default state when you apply power to the Arduino or reset it) the normally closed switches are active and conducting. Current goes in and out of motor one way and makes it whirry - let's say clockwise. If the relay gets energised then the normally closed switches open and don't conduct, and the normally open ones close

SMDB

and do conduct. Current goes in the other way, making it whirry  again but this time anti-clockwise. The technical term for something like this an H-Bridge as you'd sometimes make it out of transistors placed in an H shape, but a DPDT relay does the job just as well.

BUT - an Arduino can't work a relay directly for two reasons. Firstly, the output from an Arduino does not provide enough current. That's why the relay's coil is attached to the 9V supply via a 100 ohm resistor, and the ground path is controlled by the Arduino by switching that 2N3904 on and off from conductivity; when there's a current at the base the 2N3904 conducts, when not it doesn't. Where there's no ground path (ie the transistor's not conducting) the relay can't energise.

The pot works as a voltage divider and the result from the wiper is sent  to A0. It can be anywhere from 0 to 5V but the Arduino measures these as steps as approximately 5mV and assigns a digital value between 0 and 1023. 0 = 0V, 1023 = 5V, 510 = 2.5V or thereabouts and so on. Knowing the output from the pot, we can tell Arduino to put the equivalent output to the base of the Darlington using PWM techniques. PWM in short:  PWM stands for pulse width modulation and if you switch the 5V output off and on about 500 times a second and carefully measure the time on per cycle you can fool an attached analogue device into thinking it's got a continual  lower voltage than the actual 5V it's got chopped up into fast switching pieces. In even shorter terms you can make it think that 5V is actually 1V, or 2.5V, or 4V or any other voltage lower than 5V.

But once again it's only in discrete steps and this time between 0 and 255. Feeding that to the base of the Darlington causes a current and the magnitude of the current gets amplified at the collector and chucked out at the emitter where it passes through the relay and into the motor causing the latter to whir round and then back to the relay and off to ground. Splendid. So how does this translate into coding terms?  Well, let's dive in. We begin the code (apart from some REM statements) with:

 

unsigned long timethen =0;boolean pressdown=false;

 

So here we declare two variables for global consumption. It's not that necessary in a sketch this size but I always like to do this when I've got plenty of space to play with as it saves horrible messes later. An unsigned long is a variable that can hold a number up to the value of 4,294,967,295 which for the mathematically inclined amongst you is 2 to the 32nd power - 1. It's a big number and if I had that many pounds in my bank account I'd employ an army of uniformed flunkies and conquer the planet, which is probably why I never get the pay rises I'm hoping for, but that not withstanding the reason it's such a big number is that it's going to count milliseconds. Given that there are 60,000 milliseconds in one minute, and 3,600,000 in one hour. Something like an int variable will topple over and produce strange results in about 30 seconds, and using an unsigned long will mean that we can use the device for forty days or so before it runs out of counting talent and has to reset. The boolean is going to measure the instant the button gets pressed and will help to combat button bounce. The next two lines are the whole of the setup:

 

void setup() {

Serial.begin(9600);

pinMode(8,OUTPUT);

 

Serial.begin(9600) tells the Arduino we want to communicate with it through the PC, or Mac, or Unix Box, or whatever else is capable of talking to it through serial data. In this case we'll be using a Baud rate (ie how fast data goes up and down) of 9600 which is not as fast as it gets but plenty fast enough for this game and better still has a high degree of accuracy. The only thing we'll be using serial comms for here is to get the Arduino to tell us what it's seeing from the pot and button and if you're sure that it's doing what it ought to you can scrub these from the final sketch; I generally leave them in unless I'm running out of memory space. So now we have pinMode(8,OUTPUT); which tells the Arduino that pin D8 is going to be an output pin. It's the one that the 2N3904 is going to be attached to. OUTPUT sets the internal bypass resistor inactive, if we don't do it there won't be any current to drive that transistor into conduction.

So now to the code in the loop:

 

Serial.println();

 Serial.print(digitalRead(4)); Serial.print("   "); Serial.print(analogRead(A0));

 

All of the above sends human-readable data to the Serial Monitor Terminal which is handy for me to look at whilst I'm testing the thing. It does nothing to run the motor and we can ignore it. If I was running out of memory space I could scrub it, but for such a short sketch I might as well just leave it. The next line is where the meat is:

 

int outPut = analogRead(A0)/4;analogWrite(9,outPut);

 

There's two tasks for the Arduino to do here.The first is int outPut = analogRead(A0)/4; which in plain English is "set up a variable to hold a number please, and then assign to it the value you read from the output of the potentiometer attached to pin A0. Once you have done that be so kind as to divide that value by 4, and then assign that  result to the variable instead. Thank you."

Why divide by four? Because the Arduino reads an analogue voltage 0-5V as being between 0 and 1023.It writes them as being 0-255 and 1023/4 = 255.75  and er.........look, nothing's perfect. It's good enough for this game. So having got our equivalent out value for the in, we say analogWrite(9,outPut); and the pratical upshot is the more we wind the pot on, the faster the motor goes. Up to a point, because there's a weakess in the Darlington that we'll address later. So we've set the motor to go whirry (or not if the input's 0) but in one direction only. Now we need to control the way of the whirriness. Here's the next few lines:

 

if (digitalRead(4)==HIGH&&pressdown==false){

timethen=millis();pressdown=true;

if (digitalRead(8)==HIGH){digitalWrite(8,0);Serial.println("FORWARD");}

else{digitalWrite(8,1);Serial.println("REVERSE");}

}

 

What we have here is a nested conditional, that is a conditional inside a conditional. These three lines:

 

timethen=millis();pressdown=true;

if (digitalRead(8)==HIGH){digitalWrite(8,0);Serial.println("FORWARD");}

else{digitalWrite(8,1);Serial.println("REVERSE");}

 

will not even be looked at unless this line's arguments are all met:

 

 

if (digitalRead(4)==HIGH&&pressdown==false){

 

motordriver 2n3904 bdx33

5V

0V

10k

to input pin

Here comes a story.  You can get floating voltages on an Arduino pin, or indeed on any logic chip pin and these can give you a false reading.To get a button to work properly we have to make sure the pin we attach it to is set either reliably high or reliably low, and I prefer the latter. It's done by bleeding off to ground through a resistor as on the right. When the button is pressed the 5V sees an easier path to the Arduino pin than the resistor and it thunders down the former turning that pin

high. When the button is released, the pin goes low again. BUT- electronics is all about problems and here comes another one. The button works by mechanical contacts and when it's pressed it can contact and de-contact in the space of a couple of milliseconds. These means you may get two, three, possibly fourteen readings for the price of one and it won't be reliable. It's because of the bouncing of contacts and is called button bounce. So we need to combat it and here's how:

 

if (digitalRead(4)==HIGH&&pressdown==false){

 

digitalRead(4) can only be high if the button has been pressed and pressdown can only be false if the button has not hitherto been pressed or has been pressed and released again. So in plain English what we are saying is: "if the button is pressed and it wasn't before........"

 

timethen=millis();pressdown=true; ........set the timecounter to whatever the run time is now and set the

                                                                        boolean to true so this line and the following ones won't  run        

                                                                        again until further notice,please.

 

if (digitalRead(8)==HIGH){digitalWrite(8,0);Serial.println("FORWARD");}

else{digitalWrite(8,1);Serial.println("REVERSE");}

 

Or in English:  if you find the pin to which the base of the transistor is attached to on, turn it off. If it's off, turn it on. Then outside the loop we see:

 

if (pressdown==true&&millis()-timethen>250&&digitalRead(4)==LOW){pressdown=false;} .........if you think the button's been pressed, but 250 mS have passed and you look and the button's been released again, set the boolean pressdown to false to unlock the previous nested conditional please.

 

And that's it.Piece o'cake. Or possibly ginger nuts. But not Arrowroot biscuits. They're horrible. You can use this (and we have here) for moving joints on robot arms or controlling the drive speeds on remote vehicle platforms. If you aren't using the components and voltages specified, test your BDX33 for heat. You may need a heatsink. Wow, one page? Must be the effects of that English test.

 

Ian Lang, TMIET  April 2016