Sunday, March 28, 2010

Controllable AC Power

This project is a sub-assembly in a larger project. I have a requirement to be able to command a number of AC powered devices via an Arduino. My approach was to take a spare power strip and splice in a relay and drive the relay via an Arduino.

Before we begin, I'd like to point out that we're working with household AC power. If you're the sort of person that is routinely told to get your parent's permission before embarking on a course of action that is considered dangerous, do so before attempting anything you read here.

I happen to be an engineer. Which means that either I know what I'm doing or I should've known better.

We begin by striping the outer layer of insulation away and exposing the inner wires.

Photobucket


A standard VAC cord has three wires: black (AC Hot), white (AC Neutral), and green (Ground). In deciding which wire to cut, I summoned the power of the internet. I found an authoritative reference that indicated that the safest arrangement is to splice the AC Neutral across the relay. In the photo above, one can see that I've already cut the white wire and crimped terminal contacts to the ends. To this, we're going to add our relay. I've elected to use a PVC electrical box to house the relay and splice. This is for safety. Once we've connected the AC Neutral, we wire the DC line to the relay. This particular relay requires 12 VDC to close the circuit. Note: the Arduino puts out 5VDC to control devices. We'll need an abstraction layer between out Arduino and the relay to supply it with the required input. We'll get to that in a moment.

Photobucket


Here we've folded and fed our AC power cord into the electrical box and connected the AC Neutral line. We've also connected our DC power line to the coil contacts. All the remains is to plug in the relay and stuff it all into the box.

Photobucket

With our relay nice and snug, it's time to close up the box and deliver our product.


Photobucket


Ordinarily, it is a good practice to test the product before one buttons it up. In this case, I had already tested the assembly before beginning this instructional series. To demonstrate the product, we'll use a 120 W flood light. Here's everything connected:

Photobucket

We have the relay attached to a driving circuit that will, at a time of our choosing, close the relay and power the flood light. I will describe this circuit at the close of this post. Here's the test of our product:

Photobucket

Obviously, it works. Here is a close up of the driving circuit:

Photobucket

To describe what one is seeing here: At the left, lower corner is the attachment point for two 9V batteries hooked to a line of four screw terminal connectors (0.3 spacing). The actual batteries are omitted here for clarity. We've used breadboard connectors to hook the batteries in series to provide +18 VDC. I input this into a LM7812 regulated power supply. The output is run to the lower bus line to provide a +12 VDC bus. I also crossed the +12 VDC output to the other side of the breadboard as an input to a LM7805 regulated power supply. The output of this device is run into the upper bus line to provide a +5 VDC bus line. My practice is to use this to simulate the TTL input that would ordinarily be fed forward by the Arduino. I've cross connected the grounds between the two buses via the regulated power supplies.

The key to stepping up our TTL logic to +12 VDC is the ULN2803A Darlington Transistor Array (DTA). A quick description of the DTA is that it accepts TTL input and outputs a substantially higher voltage / current than the controlling device can provide. The limit of this device is 50V / 0.5A. The chip contains 8 individual arrays. We need only one. I've added a pull down resistor (2.2 K ohm) to the port we're using. This is redundant. The DTA contains internal pull down resistors. I do this for practical reasons -- it makes it easy to discern which port to jump a wire from the +5 VDC bus. I've connected the output port to the relay via the test probe (black). The return from the relay coil (red) is connected to the common line of the DTA, which provides +12 VDC. When the input is set high, the DTA allows power to flow through the relay coil to ground an closes the relay.

Sunday, March 14, 2010

Using the Arduino to replace chip logic


Doug and Kay of submarineboat.com have created a control circuit to drive their ROV. They use chip logic to map joystick inputs to motor output. They use two motors positioned left & right of the vehicle center line. Motion is achieved by selectively powering the motors singularly or in pairs, forward or reverse to achieve the desired effect. Forward - both motors fire forward, rotating - one fires forward, one fires aft, moving and turning - one motor fires while asymmetric thrust and drag achieves the desired action. Here we use an Arduino and software logic to replace their chip logic.

Link to their original design.

The code:


/*
ROV Controller Proof of Concept, created by Stephan, 20100306-01
*/

// map the inputs

#define JA 12
#define JB 9
#define JC 6
#define JD 4

// map the outputs

#define LED_LF 13
#define LED_LR 10
#define LED_RF 7
#define LED_RR 5

bool nand(bool A, bool B);
bool nand(bool A, bool B, bool C);
void logic_circuit (bool A, bool B, bool C, bool D, bool &LF, bool &LR, bool &RF, bool &RR);

int a,b,c,d;

bool LF,LR,RF,RR;

bool A = true;
bool B = true;
bool C = true;
bool D = true;

void setup() {

// setup the input pins
pinMode(JA, INPUT);
pinMode(JB, INPUT);
pinMode(JC, INPUT);
pinMode(JD, INPUT);
// assign the LED pin as an output

pinMode(LED_LF, OUTPUT);
pinMode(LED_LR, OUTPUT);
pinMode(LED_RF, OUTPUT);
pinMode(LED_RR, OUTPUT);
}

void loop() {
// read the joystick
a = (digitalRead(JA));
b = (digitalRead(JB));
c = (digitalRead(JC));
d = (digitalRead(JD));
// abstract the joystick readings
A = (a == HIGH) ? true : false;
B = (b == HIGH) ? true : false;
C = (c == HIGH) ? true : false;
D = (d == HIGH) ? true : false;
// run the logic circuit

logic_circuit(A,B,C,D,LF,LR,RF,RR);

// write to output

digitalWrite(LED_LF, LF);
digitalWrite(LED_LR, LR);
digitalWrite(LED_RF, RF);
digitalWrite(LED_RR, RR);
}

void logic_circuit (bool A, bool B, bool C, bool D, bool &LF, bool &LR, bool &RF, bool &RR) {

/*
This subroutine simulates a logic circuit created by Doug & Kay (SVSeeker@ymail.com).
The circuit was created to accept switched based joystick inputs and deliver logic signals
to activate power relays to drive a submerged ROV, according to a defined truth table.
Reference:
http://www.submarineboat.com/rov_joystick_for_props.htm#DC_Motors
Truth Table
Input from Joystick switch Output to Relay
A B C D LF LR RF RR
0 0 0 1 1 1
0 0 1 0 1 1
0 0 1 1 1
0 1 0 0 1 1
0 1 1 0 1
1 0 0 0 1 1
1 0 0 1 1
1 1 0 0 1

*/
// Left Forward
LF = nand(nand(A,!C,!D), nand(B,!C,!D));
// Right Forward

RF = nand(nand(!B,!C,D), nand(A,!B,!C));

// Left Reverse
LR = nand(nand(!A,!B,C), nand(!A,!B,D));

// Right Reverse
RR = nand(nand(!A,C,!D), nand(!A,B,!D));
}

/*
Two functions are provided to simulate the behavior of dual-input and triple-input NAND gates.
The function is overloaded based on the number of inputs two or three.
The functions accept bools as inputs and returns a bool.
The NAND gate is simulated using the ternary operator. If the operator evaluates to true,
it returns false and vice versa.

*/

bool nand (bool A, bool B) {

bool result = (A && B) ? false : true;
return (result);
}

bool nand (bool A, bool B, bool C) {

bool result = (A && B && C) ? false : true;
return (result);
}



Thursday, February 18, 2010

New Arduino User

I've recently caught the Arduino bug. Having received my unit, I decided to write my first sketch. Since this is a first sketch, I decided it would be appropriate to do some variant of the "Hello, world" program. The following sketch uses an LED to transmit the message via International Morse Code.




The code:

/*
hello_world

Photos By Stephan
February 15, 2010

The following is an Arduino sketch that expresses the phrase "Hello World" in International Morse Code via an LED.

The code follows the IMC standard for timing. Timing is keyed to a base time unit of n microseconds. Dots are
keyed for a single unit. Dashes are keyed for three units. Dots and Dashes are always followed by intra-character
spacing of a single units. Characters are separated by a short gap of three units. Words are separated by a medium gap
of seven units.

Thanks to Martin Koch for providing the initial code fragment.

http://controlyourcamera.blogspot.com
*/

#define UNIT 100
#define LED 13

void setup() {

// assign the LED pin as an output

pinMode(LED, OUTPUT);

// annouce

annouce();

// send the message

sendthemessage();
}

void loop() {

}

void annouce() {

// light the LED for seconds to signal the beginning of the display

digitalWrite(LED, HIGH); // set the LED on

delay(2000); // wait for 2 seconds

digitalWrite(LED, LOW); // set the LED off

// pause for one second to differentiate between the IMC signal

delay(1000); // wait for a second
}

void sendthemessage() {

// Hello

hotel();
echo();
lima();
lima();
oscar();

// pause between words

mediumgap();

// World

whiskey();
oscar();
romeo();
lima();
delta();

// add trailing gaps in case we're looping

mediumgap();
mediumgap();
mediumgap();
}

void delta() {

// The letter D = -..

dah();
dit();
dit();

shortgap();
}

void echo() {

// The letter E = .

dit();

shortgap();
}

void hotel() {

// The letter H = ....

dit();
dit();
dit();
dit();

shortgap();
}

void lima() {

// The letter L = .-..

dit();
dah();
dit();
dit();

shortgap();
}

void oscar() {

// The letter O = ---

dah();
dah();
dah();

shortgap();
}

void romeo() {

// The letter R = .-.

dit();
dah();
dit();

shortgap();
}

void whiskey() {

// The letter W = .--

dit();
dah();
dah();

shortgap();
}

void dit() {

// short mark

digitalWrite(LED, HIGH); // set the LED on
delay(UNIT); // wait for a unit of time
digitalWrite(LED, LOW); // set the LED off
delay(UNIT); // intra-character gap
}

void dah() {

// long mark

digitalWrite(LED, HIGH); // set the LED on
delay(3 * UNIT); // wait for 3 units of time
digitalWrite(LED, LOW); // set the LED off
delay(UNIT); // intra-character gap
}

void shortgap() {

// A short gap is placed between each individual character. The standard short gap is three units of time. Since
// we've embedded an intra-character gap of one unit in both the long and short marks, we need only wait two additional
// units of time.

delay(2 * UNIT);
}

void mediumgap() {

// A medium gap is placed between each word. The standard medium gap is seven units of time. Since we've embedded both an
// intra-character gap and a short gap at the end of each character, we need only wait four additional units of time.

delay(4 * UNIT);
}