Arduino AC Power Shield!

I boiled it down to one channel in order to figure out the timing. But to expand it out to N channels is just a matter of establishing the control/input for each and then duplicating some of the math and certain variables and running some loops. I'm going to play with it some more tonight and I'll see where I can get with multi-channel stuff.

Ironically, I'm not so good on the software part either, which is why I started messing with your code. :wink: You had some interrupt stuff I wanted to become familiar with and I was intrigued by how you handled the zero-crossing requirements of triacs. For my current Arduino project, I considered using triacs to control the output of a 3-phase alternator but couldn't wrap my head around how they work. But after seeing the opto-trigger chip you're using and the IC that senses the line signal - man that's a life saver - I now understand how to handle them! So maybe I'll reconsider them as a solution.

Looks quite useful. I wonder if the danger is really that great.

Looks quite useful. I wonder if the danger is really that great.

There you have it.
Someone who does not understand the danger thinks it "looks quite useful".

110v isn't quite as lethal as the 240v single phase mains (as used conventionally in much of the world outside North America).
In the UK, pro building site power tools etc are actually stepped down to 110v to reduce the risk.
But even so, 110v is not 'playful' stuff.
And 240 volts is deadly serious.

Good design keeps people and control logic well isolated from power.
This shield concept flies directly in the face of that.
As the original poster put it: -

I understand what you mean about doing a seperate box, however then there is no point of a shield at all, the only actual logic on the board is the arduino pins to drive the opto-couplers

So the only point of doing this as a shield is to deliberately bring power and logic (and by implication power and people) closer together. :-?

Much much much better to parcel up ALL the mains stuff in its own box with a mains inlet and outlet(s), plus neat connectors to take logic-level control inputs. And inside the box, on their way direct to the opto-isolators, keep those logic-level conductors physically isolated from the mains electric stuff.
A 'mains is live' neon indicator on the box would be good, too. And an isolation switch certainly wouldn't be a bad idea.

Then you have made yourself a general-purpose mains-controlling box for your projects.
With minimal risk of qualifying for an internet Darwin Award.

However if you were being sensible about it, you'd just buy SSRs to go inside the box, rather than building your own.
They are actually pretty cheap on eBay.
Well, I reckon as little as US $8 including delivery is pretty cheap for a nominal 25 amp unit ... (I went $10 for the Fotek one) ... the heat sink is actually more expensive than the SSR - but for switching only a few amps the heat sink isn't needed.

And for the truly prudent, its worth pointing out that you'd be even safer if you supplied the mains power to your project through an RCD (sometimes called ELCB) safety breaker plug.
Here's one UK example from B&Q http://nextday.diy.com/app/jsp/product/productPage.jsp?productId=16930
You'd probably never notice such a device, until it saves your life.

PS - People who write

I've been looking at doing some lighting control myself and have been researching building something like this.
...
I agree an SSR would be ideal, except in this particular instance I'd like the ability to dim lighting.

do not inspire me with confidence in their research!
I'd strongly advise such people NOT to "build something like this".
Especially when an SSR should be ideal for dimming lighting.
This thing is basically a homebrew quad SSR, but 100% exposed and bringing mains electricity intimately close to the Arduino (and anyone 'interacting' with the Arduino).

Is there a danger? Yes.

I'm I worried? No. Partially, because in previous jobs I have worked with 240V 400A 3-phase power while it is live. So I know how to work with 120V. Should the general hobbyist that has never worked with AC before use this, maybe not.

If you have ever replaced a light switch is is no more dangerous. This being a PROTOTYPE! Shows me the concerns, and peoples' opinion. The final version will obviously be very different. An hopefully add some more features.

that_chap, Please don't discourage people from doing the research and trying to build their own designs and tinker. That is the whole point of the Arduino platform. I love input, but hate when people try to crush ideas just because they do not like it.

I love input, but hate when people try to crush ideas just because they do not like it.

He wasn't criticizing because he didn't like it, he was criticizing because it is potentially lethal. Of course you are welcome to play around with live 120/240 volts if you feel so inclined, but IMO suggesting that it's safe for people to tinker with live AC power is not responsible.

Tinkering is about having fun and exploring possibilities – it is an essential element of Arduino. But it has no place where potentially lethal voltages can be exposed.

Should the general hobbyist that has never worked with AC before use this? absolutly not!

Is there a danger? Yes.

I'm I worried? No. ...

Ryamjmclaughlan, in those few words you have crystallised my concerns perfectly.

PS - People who write
...
do not inspire me with confidence in their research!
I'd strongly advise such people NOT to "build something like this".
Especially when an SSR should be ideal for dimming lighting.
This thing is basically a homebrew quad SSR, but 100% exposed and bringing mains electricity intimately close to the Arduino (and anyone 'interacting' with the Arduino).

Thanks for mentioning me. Actually I do quite a lot of research. As you imply I mustn't be very good at it since I've not found anything remotely close to an example of using a solid state relay to do Arduino controlled dimming.

Hads, its not difficult. Or Arduino specific.
Its actually pretty 'standard'.
You just need to switch the mains-powered light on and off "fast" (many times a second) so that it seems to be 'partly on'.
How much on? That depends on how the 'on' timeslice compares to the 'off' timeslice. And that is down to your software.

Regarding the actual switching - what is 'fast' for us is desperately slow for the Arduino.

UK mains is 50 Hz.
So each second there are 100 half cycles, making each 10ms.
Now, if you switch exactly on the end of the half cycle (when the voltage is zero, whether its going positive or negative) its all round better for the components (and the disruption to the mains), and that's what a zero-crossing SSR (or the Darwin shield) allows you to to.
So there are 100 time slices per second, in each of which you can have the lamp on or off.
An SSR should have no problem switching at that rate.
10ms allows ages for Arduino thinking.

Incidentally, the reason that one can't just use the LED-dimming PWM outputs to drive the SSR is because the pulses are way too fast for the mains-frequency-locked SSR to react to.

But the Arduino digital outputs are a perfect ("logic level") match for what most SSRs need as a control signal. Almost as though they are both designed to the same 'interface' spec...

Don't run away with the idea that a whole second (or 100 half cycles) is automatically a sensible base for your on/off scale. On for 1, off for 99 is going to seem very flickery.
Exactly how you program the different 'duty cycles' (on/off intervals) is where you can have some fun. Try different ideas and tinker!
But tinkering with exposed mains voltage conductors is likely to, as Darwin would say, "die out".

If you want to get into dangerous mains stuff, you could make a mains zero-crossing detector (something like Ryan's -watching out for your higher UK voltage) mount it within your mains electricity switching enclosure) and take the safe (physically and) opto-isolated 5v logic-level output signal as an interrupt input to the Arduino.
Then you can pick up most of Ryan's code - but use it to drive SSR's in a box rather than bare triacs almost touching the Arduino.
The alternative to using the zero-crossing-interrupt is just to count out a delay of about 9ms or so. The zero-crossing SSR won't switch until the next end of a half cycle. With counting, you're going to get the odd extra half cycle as you drift out of sync, but that really shouldn't matter except to the perfectionist and at extreme dimness... and tweaking the actual time delayed should minimise that effect.

The point that I and so many other posters here are trying to flag up is that handling mains on a close-mounted Arduino shield is wilfully courting disaster.
The potential is not just killing the Arduino (and any attached computer - I wouldn't back the little polyfuse to protect against mains) but also the risk really does go as far as potentially killing the user.
There are simpler, MUCH safer and barely more expensive ways of getting an Arduino to control a small mains (incandescent) lamp, or four.

I'm not saying that people shouldn't ever switch mains with an Arduino.
I'm not criticising the prototype.
I am criticising the basic concept of putting mains electricity on an Arduino shield. That seems lethally daft.

I do wonder who provides "McLaughlin Engineering" with their product liability insurance?

that_chap,

Thank you for your explanation, quite useful. I had assumed that basing the switching on timing without zero crossing detection that it would drift. I guess I should just pick up an SSR, have a play with it and see what happens.

Thanks that_chap for the pointers.

I will post again when I get another design going.

Wow, Ryan! You really shook people up with your project. :slight_smile:

I'm still working on the code to get the relationship between the zero-cross timing and the triac pulse right. It's working well on one channel, but the way I'm doing it right now I think the arithmetic overhead of four channels may be introducing just a little too much of a delay to be useful. So I've been trying to figure out how to slim down the math a bit and lighten the processor load.

Cheers!

That_Chap earlier posted a cautionary note about controlling mains power on a shield. That's hard to argue with. About the idea of dimming by cycle switching? It really might be flickery, that way.

The lighting dimmers that were the source of this idea can switch at some point into each cycle using thyristors. which leaves a smooth dimming effect. That's what the original shield designer has in mind, I expect. But I really like that idea of keeping the line power switching elements in a secure box with a ground current sensing power socket. It would be so safe and GCIs are cheap.

Meanwhile, here I am with an LCD hooked up to a duemilanove and a button that steps up a displayed time duration per push, or faster if held, and when I hook up just one switch to command this pulse and one output to drive an SSR with it, I will be in business. Bang bang control is so much easier in my application!

Brian W

Betwys-

About the idea of dimming by cycle switching? It really might be flickery, that way.
The lighting dimmers that were the source of this idea can switch at some point into each cycle using thyristors. which leaves a smooth dimming effect.

You may have heard the saying "To a man with a hammer, every problem looks like a nail". Well, I've got this zero-crossing SSR, and Ryan was using zero-crossing detection ... ::slight_smile:

For power switching, like the heater I want to use my SSR with, zero-crossing seems to be the best the time to switch, on and off, not least because it minimises electrical noise ('interference'), and a zero-crossing ssr is the seriously easy way to achieve that.
However, for the smoothest possible lighting dimming, yes indeed Betwys is quite right that you should switch during the cycle. I believe the ideal is to switch on at a zero-crossing and then off a controlled (ie variable) time through the cycle, going off at the same time through each half cycle for steady (non-flickering) brightness.
Now, for that you can still use an off-the-shelf ssr BUT you should select one that does NOT boast of zero-crossing switching!
One of the descriptions these go by is 'random switching' ssrs. (But "not-zero-crossing-switching" should explain to a vendor what you are after.) These can switch (on or off) whenever you tell them to, at any point in the cycle. Switching time being about 0.1 ms. (10ms for the half cycle on European (etc) 50Hz mains remember.) So plenty fast enough switching!
Betwys is absolutely right that using a zero-cross detector and a 'random' SSR would be much better than using the integral number of half-cycles that MY ssr lead my thinking towards!

At least some of the $8 (inc worldwide delivery) eBay ssr's make no mention of zero-crossing in their description, so could well be the 'random' type. But if 'random' is what you are after, check with the vendor before buying!

Hads -

I had assumed that basing the switching on timing without zero crossing detection that it would drift. I guess I should just pick up an SSR, have a play with it and see what happens.

With a zero-crossing ssr like mine, it doesn't matter so much if you slip in an extra half cycle on or off very occasionally. That's all that would happen.
BUT if you are using a 'random' ssr (or a triac board), and trying to do the switching-on at the start of the half cycle, then off at a set time into the cycle (for the smoothest dimming) then you really DO want a zero-crossing interrupt signal to tell the Arduino exactly where you are in the cycle.

I have seen alot of heater, fan, etc dimming doing exactly what you are describing. SSR with a specific duty cycle, however I have not seen much lighting this way.

When I was doing some testing, I tried this without doing the zero crossing, but with lighting I could never the the flickering (which was major flickering) to go away. But, this could just because I could not find the right duty cycle.

There two main types of light dimming. These are the two found in your house. Forward-phase control and Reverse-phase control. Phase-fired controller - Wikipedia

Forward phase control is waiting a specific amount of time after a zero cross, then turning on the device to let the remaining part of the wave power the load. This is exactly what this project is doing. Wait a specific amount of time after a zero cross and momentarily fire the triac to power the load. Using zero-crossing triacs the triac will stay latched until the next zero cross. This makes the device easy to control because you only have to control the firing once, and not ensure you turn off again at zero, which can be hard to time right.

Reverse phase control is the opposite where you turn on the triac at the zero cross and cut the power after a specified interval, cutting the trailing end of the wave. This type of control is not as common, but the technology used to dim low voltage transformers for LV lighting in houses. It is not as common because it is more expensive and only used where needed. Go on Lutron or another lighting switch company and you will see that most of the high-end dimmers have an electronic low voltage style dimmer that uses this type of control.

Zero crossing SSR's are more popular because of this reason and they are cheaper. I am not an EE, but if you look at the theroy behind a triac, it is setup to latch until a zero cross. You need to find a special random-phase SSR to be able to turn off the power mid wave.

Switching time being about 0.1 ms. (10ms for the half cycle on European (etc) 50Hz mains remember.) So plenty fast enough switching!

Remember that that is only the 1/2 cycle, you still need to have the dimming resolution within that half cycle. If you want smooth light dimming you are talking about > 50 divisions = 156 microseconds. But, if you are doing element, fan dimming, this resolution can be far less as that_chap suggested

Some countries run at 400Hz, which is the high end that I've been testing against. That's a 1.25ms (1250us) half-period - not very much time to work with. For one channel of dimming control, I've gotten the minimum delay down to about 50us. That's referenced to the falling edge of the previous half-period, so it gives a little wiggle room.

So I guess my research isn't that bad after all.

I just connected a couple dots.... :smiley:

that_chap kept talking about SSRs (Solid State Relays) and I kept reading it as SCRs (Silicon Controlled Rectifiers).

To clear things up a little: SSRs are made from a back-to-back pair of opto-controlled triacs, which means they are functionally the same as the triacs on Ryan's board. So yes, you could use SSRs to do the load switching. However, when I look up the cost of SSRs vs. the cost of triacs with similar specs, the SSRs are an order of magnitude more expensive and considerably larger.

SCRs are sort of similar to triacs, but only conduct on one half of the wave, so you need two of them in inverse parallel to work like a triac. But that would be pointless since you can just use a triac.

EDIT: NEW CODE IS FINISHED!!

OK, it works great at 50/60Hz but it's range isn't all that good at 400Hz. The problem is that it takes about 500us to do all the timing calculations on four channels, which is about 2/5 of the half-period at 400Hz. If you wanted just one channel, you could scale down the code and 400Hz would work fine with about 125us minimum dim. But the dimming is smooth and more-or-less frequency agnostic. The lower the frequency, the better.

I intentionally did not use loops to cycle through the channels. Loops added processing overhead and with four channels, it really wasn't that hard to keep track of. Another weird-but-intentional thing is the placement of the OKToFire=0; lines. I did this because it really didn't matter where these lines went in each section and it adds a little time delay between the digitalWrite lines without using delayMicroseconds() :wink:

You can see the code in action if you have a dual trace oscilloscope. Attach one input to the interrupt pin and another to an output pin. Sync to the interrupt pin and you will see how all the timing works together.

I fought with this code for days until I re-read the attachInterrupt() doc. It states that millis() and delay() don't work in the ISR function. That was key to success since I was trying to calculate all the timing in the ISR function, but was getting weird and inconsistent results. Once I took all that out and put it in void loop(), all was better.

/*
  AC Light Control
  
  Ryan McLaughlin <ryanjmclaughlin@gmail.com>
  
  The hardware consists of an Triac to act as an A/C switch and
  an opto-isolator to give us a zero-crossing reference.
  The software uses two interrupts to control dimming of the light.
  The first is a hardware interrupt to detect the zero-cross of
  the AC sine wave, the second is software based and always running
  at 1/128 of the AC wave speed. After the zero-cross is detected
  the function check to make sure the proper dimming level has been
  reached and the light is turned on mid-wave, only providing
  partial current and therefore dimming our AC load.
  
  Thanks to http://www.andrewkilpatrick.org/blog/?page_id=445
    and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm
 */
 
/*
  Modified by Mark Chester <mark@chesterfamily.org>
  
  to use the AC line frequency (half-period) as a reference point 
  and fire the triacs based on that plus a dimmer delay value.
  I removed the second timer-based interrupt and replaced it with a
  means to reference the zero-crossing point as per interrupt 0.
*/

// General
unsigned long int ZeroXTime1 = 0;                      // Timestamp in micros() of the latest zero crossing interrupt
unsigned long int ZeroXTime2 = 0;                      // Timestamp in micros() of the previous zero crossing interrupt
unsigned long int NextTriacFire[4];                    // Timestamp in micros() when it's OK to fire the triacs again.
unsigned long int DimStep;                             // How many micros() in each step of dimming
int Dimmer[4];                                         // The dimmer input variable. One for each channel
byte TriacPin[4] = {4,5,6,7};                          // Which digital IO pins to use
boolean OKToFire[4];                                   // Bit to say it's OK for the triacs to fire
volatile boolean zero_cross = 0;                       // Boolean to store a "switch" to tell us if we have crossed zero

void setup() {                                         // Begin setup
  pinMode(TriacPin[0], OUTPUT);                        // Set the Triac pin as output
  pinMode(TriacPin[1], OUTPUT);                        // Set the Triac pin as output
  pinMode(TriacPin[2], OUTPUT);                        // Set the Triac pin as output
  pinMode(TriacPin[3], OUTPUT);                        // Set the Triac pin as output
  attachInterrupt(0, zero_cross_detect, FALLING);      // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  delay(50);                                           // Give the interrupt time to capture a few AC cycles
}                                                      // End setup
  
void zero_cross_detect() {                             // function to be fired at the zero crossing
  zero_cross = 1;                                      // All we do is set a variable that's picked up later in the code
}

void loop() {                                              // Main Loop
  if ( zero_cross ) {                                      // Did we detect a zero cross?
    ZeroXTime2 = ZeroXTime1;                               // shift the current zero cross value to the previous
    ZeroXTime1 = micros();                                 // set the new current zero cross time in micros()
    DimStep = (ZeroXTime1 - ZeroXTime2)/1024;              // Calc the duration of each dimming step
    Dimmer[0] = analogRead(0);                             // Read in a dimmer value (change to suit needs)
    Dimmer[1] = analogRead(1);
    Dimmer[2] = analogRead(2);
    Dimmer[3] = analogRead(3);
    NextTriacFire[0] = ZeroXTime1 + (Dimmer[0] * DimStep); // Calc the next triac fire time
    NextTriacFire[1] = ZeroXTime1 + (Dimmer[1] * DimStep);
    NextTriacFire[2] = ZeroXTime1 + (Dimmer[2] * DimStep);
    NextTriacFire[3] = ZeroXTime1 + (Dimmer[3] * DimStep);
    OKToFire[0] = 1;                                       // Tell us it's OK to fire the triacs
    OKToFire[1] = 1;
    OKToFire[2] = 1;
    OKToFire[3] = 1;
    zero_cross = 0;                                        // Done.  Don't try again until we cross zero again
  }
  if ( OKToFire[0] && micros() >= NextTriacFire[0] ) { // Are we OK and past the delay time?
    digitalWrite(TriacPin[0], HIGH);                   // Fire the Triac mid-phase
    OKToFire[0] = 0;                                   // We fired - no longer OK to fire
    digitalWrite(TriacPin[0], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
  }
  if ( OKToFire[1] && micros() >= NextTriacFire[1] ) { // Are we OK and past the delay time?
    digitalWrite(TriacPin[1], HIGH);                   // Fire the Triac mid-phase
    OKToFire[1] = 0;                                   // We fired - no longer OK to fire
    digitalWrite(TriacPin[1], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
  }
  if ( OKToFire[2] && micros() >= NextTriacFire[2] ) { // Are we OK and past the delay time?
    digitalWrite(TriacPin[2], HIGH);                   // Fire the Triac mid-phase
    OKToFire[2] = 0;                                   // We fired - no longer OK to fire
    digitalWrite(TriacPin[2], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
  }
  if ( OKToFire[3] && micros() >= NextTriacFire[3] ) { // Are we OK and past the delay time?
    digitalWrite(TriacPin[3], HIGH);                   // Fire the Triac mid-phase
    OKToFire[3] = 0;                                   // We fired - no longer OK to fire
    digitalWrite(TriacPin[3], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
  }
}

Thanks koyaanisqatsi that looks great, the code is so short! I will try this on my own board soon.

My only question is what do you do about if you need to run other code? If you are using the Arduino for anything else (LCD, I/O, etc) won't it mess with the timing? I just ask because this was why I started to use Timer1 so I ensured the dimming function worked as a software interrupt and my regular code would not interfere.

Let me know your thoughts. Great work! I guess I should get working on a final design now. In your testing were you getting much buzz from the Triac? I am trying to figure out how to silence it a bit, maybe an inductor but I need to pick a few up to try it.

koyaanisquatsi -

Some countries run at 400Hz ...

Domestic mains electricty at 400 Hz? Really? Where about would that be??
I think that all large populations get their mains notionally at either 50 or 60 Hz (though it always varies slightly with the supply/demand balance varying).

Regarding SSRs (Solid State Relays), my thinking of their usefulness is that :

  • they are a sealed module, even the terminals are usually well-shrouded
  • they provide excellent opto-isolation of the controller from the mains
  • they can be immediately usable (driven absolutely direct from an Arduino digital-out pin)
  • their 'pinout' encourages the physical separation of mains and logic-level control voltages

They aren't tiny. The "25 amp" units I mention are about the same footprint as a standard Arduino.
But with mains, size and space are good for you. Cramming mains things tightly together is not a great idea. Space allows heat dissipation and physical isolation.

I don't think SSRs need be very expensive. (Even though I admit to being 'cost-conscious'!) Searching eBay.com turned up a few vendors seemingly competing at the US$8 price point including delivery worldwide - for units able to switch a nominal 25 amps (with a suitably big heatsink). They should switch 5 amps (or run 3 amps pretty continuously) of resistive load, happily without any heatsink.
You can find (smaller) lower power rated devices, but probably not much cheaper.

IMHO, SSRs are a great way for "Arduino tinkerers" to explore mains control with a massively greater degree of safety than with Ryan's shield. Even so, I'd still advise great care be taken.
But, as I said to Ryan, his quad-triac with sensing of mains timing could be a neat unit to have, as long as it was really well isolated from the Arduino (or other tinkerers' platform) and from the fingers (etc) of the 'tinkerers' themselves.
Absent that, an SSR seems to me to tick the right boxes.

Domestic mains electricty at 400 Hz? Really? Where about would that be??

Well, you got me on that one. It seems my memory has misled me. 400Hz is used in certain systems, but not as a municipal/utility power grid due to efficiency issues. So with 400Hz support, this project can be used in certain aerospace applications. :smiley:

It's just as well. The performance of the code at 400Hz wasn't very good, and now I don't have to be annoyed about it.

Ryan, I am concerned about the performance of the code with other things going on too - and it will suffer if much more than a few very simple tasks are being done. I hadn't thought of a good way to handle that as of last night. But since you mentioned the software interrupt, I'm rolling that around in my head now. We'll see what I can come up with over the weekend. I should know better than to say "NEW CODE IS FINISHED!!" Is software every really finished? :wink: