Arduino Forum

Forum 2005-2010 (read only) => General => News => Topic started by: ryanjmclaughlin on Mar 14, 2009, 03:49 am

Title: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 14, 2009, 03:49 am
Hi All,

After some work I did with triacs and dimming, I have made a AC power shield!  It has 4 triac driven outputs, my current prototype can only handle about 1A per channel, but The final version I am hoping for 2.5A or more (300W).  It also includes a zero-cross detection circuit to be able to use an interrupt and dim AC devices. I have 2 or 3 prototypes for sale (will work fine for testing and simple use) for $25.  Please let me know if you are interested an have the time in the next week to test this and let me know if I should make any changes before I order a first production batch.  I am hoping to keep the price around $30.

The only problem I had with the prototype batch is the routing of the pins...  I am not sure if I should do a separate female header row (like the prototype shield) or find some long tail female headers to go through.  

Please let me know if you are interested in testing one of the prototypes (only charging to recoup some of my cost - I will make sure you get a big discount on the final version!).

http://picasaweb.google.com/lh/photo/7iQ0pX2SD8FITkhaYWesrg?authkey=Gv1sRgCKmvsNPa09u83AE&feat=directlink
http://picasaweb.google.com/lh/photo/Ftbgdp2FY0f2EkxjATcp6g?authkey=Gv1sRgCKmvsNPa09u83AE&feat=directlink
http://picasaweb.google.com/lh/photo/7JUzjbmLYT0cptQ-YmwgmA?authkey=Gv1sRgCKmvsNPa09u83AE&feat=directlink
http://picasaweb.google.com/lh/photo/SRG1O1kYR1qw0RmrRe2YXQ?authkey=Gv1sRgCKmvsNPa09u83AE&feat=directlink
http://picasaweb.google.com/lh/photo/I3srijjnzyYpC4Ix3vn8nQ?authkey=Gv1sRgCKmvsNPa09u83AE&feat=directlink

(http://lh3.ggpht.com/_liDL5ZFNsxs/SbsXd13Y86I/AAAAAAAADjA/Y9hG6lxhHg0/s400/IMGP1549.JPG)
Title: Re: Arduino AC Power Shield!
Post by: nkcelectronics on Mar 14, 2009, 03:24 pm
Hmmmm, this shield looks more dangerous than the DANGER shield.  With such number of electronics newbies out there, you need to add a HUGE disclaimer in the board, and start counting the number of casualties.
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 14, 2009, 03:28 pm
Yes this is true!  There is a warning, although I may need to increase the text size!  All the HV contacts on the bottom are going to be covered...  liquid electrical tape, hot glue, something like that...  I will try to post some vids of it in action tonight.
Title: Re: Arduino AC Power Shield!
Post by: madworm on Mar 14, 2009, 04:10 pm
I don't think that will be good enough.

Looking at all the traces, there is really no separation between 5V and the possibly fatal 120V part. And there's always the odd user that fiddles with the circuit and forgets to unplug the power. I know because I've done that when I thought I was 'in control' and was lucky a few times.

With all the opto couplers it should be possible to move the HV part to a different PCB, box it, and only have safe voltages on the shield. This lacks the coolness factor, but you surely don't want arduino users to end up on the 'darwin awards' list ?
Title: Re: Arduino AC Power Shield!
Post by: nkcelectronics on Mar 14, 2009, 04:58 pm
Yes, something like the RELAY SQUID http://www.liquidware.com/shop/show/RS/RelaySquid
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 14, 2009, 05:28 pm
Actually there is a good amount of spacing between the HV and 5V.  I have a few products that have the traces of voltage much closer!  Everyone I work with in electronics is very careful and I am used to up to 480V power, so HV doesn't bother me at all, I just know to be careful.

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.  Everything else is HV, so those traces are very small and only 5 of them and a few grounds.  Maybe I will play around with the idea of a seperate board, I am already building one for a different project.

I personally like the idea of having everything on one circuit.  I can put this shield on a arduino and put it in an enclosure and I have 4 circuit control in a very compact package with dimming too.

I like the relay squid, but for simple things it is just too darn expensive for me!
Title: Re: Arduino AC Power Shield!
Post by: madworm on Mar 14, 2009, 06:54 pm
I wasn't talking about trace spacing !

More like:

left side of PCB: safe
right side: hands off

Of course this is hard to do on such a small area.
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 14, 2009, 07:12 pm
Ahhh, yes.  I am looking into encasing that end in epoxy for that reason.  I will let you know how it goes.
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 14, 2009, 07:13 pm
Anyone interested in one can buy here http://ryanjmclaughlin.com/arduino/ also post, PM, or email if you have interest in a final version so I know how many to make.
Title: Re: Arduino AC Power Shield!
Post by: betwys on Mar 16, 2009, 12:19 am
I'm working up a spot-welder of the microwave transformer variety.
It was a 1500 W unit, and I wound on  3 turns of #1 flex welding cable, so the current capability should be useful at 3.1 V off load..
I thought I'd do a cycle counter with a DueMilanove, using one d/o to drive an SSR I had on hand. The SSR uses an optoisolator, so its a safe approach.    Still thinking about the way to set a pulse between 0.5 and 3 seconds repeatably.
A 2 line LCD and push button inputs seem a little over the top though....

Brian W
Title: Re: Arduino AC Power Shield!
Post by: dwentz on Mar 16, 2009, 04:31 pm
Ryan,

Nice idea, but I agree with the others about mixing the AC with the lower voltage stuff. Many do not know the dangers of AC voltage, and the Arduino is all about experimentation, and making this stuff easy for people just starting out.

Just a suggestion. Build the AC stuff with the opto's on on a 2nd board, then use a small data cable to connect the two. Then the HV section could be put in a external box and protected.


Dale

Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 16, 2009, 05:04 pm
Makes sense...  I am working on a separate board as well.  With a remote connection.  The shield is working good though, I tested it with some light bulbs last night.

Any thoughts on the AC breakout?  Molex connectors? Solder your own?  Standard Outlets?
Title: Re: Arduino AC Power Shield!
Post by: dwentz on Mar 17, 2009, 03:16 am
I would use screw terminals, or maybe you could build it into a power strip that uses standard outlets, then the end user does not have to use anything. They are cheaper than any box you could buy.

Dale

Title: Re: Arduino AC Power Shield!
Post by: anachrocomputer on Mar 17, 2009, 10:52 am
Quote
Standard Outlets?


Standard sockets for which country?  And will the shield work properly on 240V, 50Hz power?
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 17, 2009, 11:59 am
120v 60hz. The board needs to be setup differently for 240v.
Title: Re: Arduino AC Power Shield!
Post by: hads on Mar 22, 2009, 08:51 am
If you have the time, I'm curious what would need to be changed for this to work with 240V/50Hz. Are you sill using the same schematic from your other post?

I've been looking at doing some lighting control myself and have been researching building something like this.

Cheers,

hads
Title: Re: Arduino AC Power Shield!
Post by: betwys on Mar 22, 2009, 03:24 pm
I know you are not directing this query to me, but using ONE Arduino digital output to drive a SEPERATE bolt down SSR means you buy just one thing - a 120 volt or a 240 volt SSR at whatever rating you need: 10A, 25A  or 40A

This would be a safe, no brainer approach except for one small detail:
opto-isolated zero crossing SSRs don't come cheap.
Sadly.

Brian Whatcott
Title: Re: Arduino AC Power Shield!
Post by: hads on Mar 22, 2009, 09:44 pm
I agree an SSR would be ideal, except in this particular instance I'd like the ability to dim lighting.
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 22, 2009, 11:13 pm
hads,

240V/50Hz...  is that 120V on 2 legs?  I am not that familiar with that power.

Check out the data sheet for the opto-triac drivers.  http://www.fairchildsemi.com/ds/MO%2FMOC3020M.pdf it has some 240V examples.  Basically the same setup with some different resistor values between the opto-coupler and triac.  The zero-cross can stay the same, just ensure you adjust the resistor value for the rating of the H11AA1 maybe 50k?

Remember, if you want to switch high current loads with this, your PCB needs to have large traces and a heavy copper layer to handle the current, even though the triac may be rated for 12A make sure the interconnects are as well!
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 22, 2009, 11:17 pm
betwys,  I agree I use alot of SCR's at work.  Like you said, the big downside is cost, and sometimes space.  I really built this for someone that needs something low cost and simple to hook up.  AC is a strange world.

This circuit is just about the same thing that goes inside a SCR, it is really just making the cost less by breaking it down and giving some more control.

I am working on the final version and am leaning towards a separate board rather than working with a shield.  I personally love the shield idea, but I know it can strick some high voltage fears in people.
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 22, 2009, 11:37 pm
Here is the current UNTESTED code...  let me know if you have any better ideas of doing this...  I hope to test this tonight or tomorrow.

Code: [Select]
/*
 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
 
*/

#include <TimerOne.h>           // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i[4], j;               // Variable to use as a counter
volatile boolean zero_cross[4] = {0,0,0,0};  // Boolean to store a "switch" to tell us if we have crossed zero
int AC[4] = {4,5,6,7};          // Setup the AC output pins
int ACenable[4] = {1,1,1,1};    // Enable dimming for this output
int output[4] = {64,64,64,64};  // Create output vars for Dimming level (0-128)  0 = on, 128 = 0ff
int dim = 0;                    // Dimming level (0-128)  0 = on, 128 = 0ff
int freqStep = 65;              // Set the delay for the frequency of power (65 for 60Hz, 78 for 50Hz) per step (using 128 steps)
                               // freqStep may need some adjustment depending on your power the formula
                               // you need to us is (500000/AC_freq)/NumSteps = freqStep
                               // You could also write a seperate function to determine the freq

void setup() {                                      // Begin setup
 pinMode(AC[0], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[1], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[2], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[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
 Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
 Timer1.attachInterrupt(output_check, freqStep);   // Use the TimerOne Library to attach an interrupt
                                                   // to the function we use to check to see if it is
                                                   // the right time to fire the triac.  This function
                                                   // will now run every freqStep in microseconds.  
 Serial.begin(9600);                                        
}                                                   // End setup
 
void zero_cross_detect() {                 // function to be fired at the zero crossing                          
   zero_cross[0] = 1;                     // set the boolean to true to tell our dimming function that a zero cross has occured
   zero_cross[1] = 1;
   zero_cross[2] = 1;
   zero_cross[3] = 1;
}                                          // End zero_cross_detect

void output_check() {                      // Function will fire the triac at the proper time

for( j=0; j<4; j++ ) {                     // Loop this function for each one of the outputs
 if(zero_cross[j]) {                      // First check to make sure the zero-cross has happened else do nothing
   if(i[j] >= output[j] && ACenable[j]) { // Check and see if i has accumilated to the dimming value we want
     digitalWrite(AC[j], HIGH);             // Fire the Triac mid-phase
     delayMicroseconds(2);                // Pause briefly to ensure the triac turned on
     digitalWrite(AC[j], LOW);              // Turn off the Triac gate (Triac will not turn off until next zero cross)  
     i[j]=0;                              // If we fired the triac, reset the counters
     zero_cross[j] = 0;                   // Reset the zero cross detection
   } else {
     i[j]++;                              // if nothing is done incriment th counter
   }
 }                                       // End zero_cross check
}                                         // End each loop
}                                         // End output_check function

void loop() {                        // Main Loop

 output[0] = 75;                    // Set output values for dimming
 output[1] = 25;
 output[2] = 50;
 output[3] = 100;

 Serial.print("Output Values:   ");
 Serial.print(output[0]);
 Serial.print("\t");
 Serial.print(output[1]);
 Serial.print("\t");
 Serial.print(output[2]);
 Serial.print("\t");
 Serial.print(output[3]);
 Serial.print("\n");
}

Title: Re: Arduino AC Power Shield!
Post by: hads on Mar 22, 2009, 11:45 pm
ryanjmclaughlin,

Thanks for the pointer, I should have read the data sheet more carefully - you're right the info is there.

To clarify, it's 230-240V/50Hz, used in New Zealand, Australia and the Pacific.

I've done a little work with HV before but not a huge amount, I'd be installing on a separate board in a box isolated from the Arduino. More than happy to work together if you're interested.

Cheers,

hads
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 23, 2009, 01:18 am
hads,

Let me know if you can do any testing.  there may be a good resistor combination for both power systems.  e-mail me an I can show you some of the designs for the next board.  I am used to doing HV, but new at micros.

what is the voltage on the line for you?  I know in US what we call 220V is actually 4-conductors...  120V, 120V, Neutral, GND.  Is your power the same way? or 240V, Neutral, Ground?
Title: Re: Arduino AC Power Shield!
Post by: hads on Mar 23, 2009, 01:24 am
ryanjmclaughlin,

Our 240V is 3 conductor, 240V, Neutral, Ground.

I'll drop you an email regarding testing.

Cheers,

hads
Title: Re: Arduino AC Power Shield!
Post by: betwys on Mar 23, 2009, 01:24 am
Another red herring (probably) for the person that wants to dim lighting with no drama.....
All the stores carry light dimmers - around 700 watts for around $10.
This is relatively attractive pricing. The potentiometer dimmer control would not be hard to automate with a smoothed analog output, I suspect!

Brian W
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 23, 2009, 01:30 am
The components on this board are exactly what is in the hardware store dimmers...  My current prototype...  800W * 4 channel ~$30
Title: Re: Arduino AC Power Shield!
Post by: DarkStar on Mar 23, 2009, 01:56 am
I would suggest trying to design the shield so that another of the same type could be stacked on top. That would give the user the ability to control 8 lights, in a 4 x 2 configuration (with 2 AC inputs).

Otherwise, I'll be definitely putting this on my "shields to buy" list!
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 24, 2009, 02:34 am
Here is the modified and tested code, it works good!  I just need to add an inductor to the board to get rid of some of the triac buzz.

Code: [Select]
/*
 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
 
*/

#include <TimerOne.h>                        // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i[4], j;                        // Variable to use as a counter
volatile boolean zero_cross[4] = {0,0,0,0};  // Boolean to store a "switch" to tell us if we have crossed zero
int AC[4] = {4,5,6,7};                       // Setup the AC output pins
int ACenable[4] = {1,1,1,1};                 // Enable dimming for this output
int output[4] = {0,0,0,0};                 // Create output vars for Dimming level (0-128)  0 = on, 128 = 0ff
int dim = 0;                                 // Dimming level (0-128)  0 = on, 128 = 0ff
int freqStep = 59;                           // Set the delay for the frequency of power (65 for 60Hz, 78 for 50Hz) per step (using 128 steps)
                                            // freqStep may need some adjustment depending on your power the formula
                                            // you need to us is (500000/AC_freq)/NumSteps = freqStep
                                            // You could also write a seperate function to determine the freq

void setup() {                                      // Begin setup
 pinMode(AC[0], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[1], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[2], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[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
 Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
 Timer1.attachInterrupt(output_check, freqStep);   // Use the TimerOne Library to attach an interrupt
                                                   // to the function we use to check to see if it is
                                                   // the right time to fire the triac.  This function
                                                   // will now run every freqStep in microseconds.  
 Serial.begin(9600);                                        
}                                                   // End setup
 
void zero_cross_detect() {                 // function to be fired at the zero crossing                          
   zero_cross[0] = 1;                     // set the boolean to true to tell our dimming function that a zero cross has occured
   zero_cross[1] = 1;
   zero_cross[2] = 1;
   zero_cross[3] = 1;
}                                          // End zero_cross_detect

void output_check() {                        // Function will fire the triac at the proper time

 for( j=0; j<4; j++ ) {                     // Loop this function for each one of the outputs
   if(zero_cross[j]) {                      // First check to make sure the zero-cross has happened else do nothing
     if(i[j] >= output[j] && ACenable[j]) { // Check and see if i has accumilated to the dimming value we want
       digitalWrite(AC[j], HIGH);           // Fire the Triac mid-phase
       delayMicroseconds(2);                // Pause briefly to ensure the triac turned on
       digitalWrite(AC[j], LOW);            // Turn off the Triac gate (Triac will not turn off until next zero cross)  
       i[j]=0;                              // If we fired the triac, reset the counters
       zero_cross[j] = 0;                   // Reset the zero cross detection
     } else {
       i[j]++;                              // if nothing is done incriment th counter
     }
   }                                        // End zero_cross check
 }                                          // End each loop
}                                            // End output_check function

void loop() {                        // Main Loop
 for( int k=0; k < 128; k++ ) {     // Slowly fade out all channels at the same time
   output[0] = k;
   output[1] = k;
   output[2] = k;
   output[3] = k;
   
   Serial.print("Output Level:\t"); // Print the current output level over serial
   Serial.println(output[0]);
   
   delay(200);                      // Delay after each step to slow down the fade
 }
}

Title: Re: Arduino AC Power Shield!
Post by: audin on Mar 24, 2009, 03:46 am
How about boxing it so that only the arduino pins are accessible?  You could possibly even pot the whole board so that the header pins stick out the bottom and the next-layer header sockets stick slightly out the top.  Then one ac power cord sticks out the 'in' side and four ac power cords stick out the 'out side'.  Nothing says shields have to be bare circuit boards.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Mar 24, 2009, 10:58 am
Ryan,

OK, this is my first time ever offering a big code change to someone so I hope this works out.    :)

I took your latest posted code and modified it to fire the triacs based on the zero crossing moment plus some delay as calculated by the dimmer level and a dimmer resolution value (all in microseconds).  This removed the software timer-based interrupt.  I felt that statically dividing the line frequency would drift over time and the dimmer would slowly get lower or brighter, depending on the slight variance in the Arduino's clock and possible line frequency fluctuations. This change also allows support for almost any line frequency, even if it's changing radically and you don't have to think about it.

I'd _really_ like it if one of the more seasoned programmers would take a look at this and make sure I didn't do anything obviously wrong (which I'm pretty sure I did).  I know there is some issue with variables used in interrupt-triggered functions as needing to be declared as volatile or something.  But I'm not sure when that need to be done.

Enjoy!

UNTESTED CODE!!  (but it does compile)
Code: [Select]
/*
 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.
 It also tracks the rollover of the internal microseconds counter
 to avoid the glitch that would arise about every 70 minutes otherwise.
 
 THIS CODE IS UNTESTED!!!
 Use at your own risk.

 But I would love to hear whether/how well this works!  :)
*/

#include <TimerOne.h>                        // Avaiable from http://www.arduino.cc/playground/Code/Timer1

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
int uRollover;                               // A value that can go negative when micros() rolls over
unsigned long int XTimePeriod;               // The calculated micros() between the last two zero crossings
int DimResolution = 128;                     // How many levels of dimming
unsigned int DimStep;                        // The number of micros() in each step of DimResolution
unsigned long int LastTriacFire;             // Timestamp in micros() of the last time the triacs were fired
unsigned long int NextTriacFire;             // Timestamp in micros() when it's OK to fire the triacs again.
boolean WaitForRollover = 0;                 // Used for when the triac fire delay calculates out to a number beyond the rollover value of micros()

volatile int i[4], j;                        // Variable to use as a counter
volatile boolean zero_cross = 0;             // Boolean to store a "switch" to tell us if we have crossed zero
int AC[4] = {4,5,6,7};                       // Setup the AC output pins
int ACenable[4] = {1,1,1,1};                 // Enable dimming for this output
int output[4] = {0,0,0,0};                   // Create output vars for Dimming level (0-128)  0 = on, 128 = 0ff
int DimLevel = 0;                            // Dimming level (high value = more dim, low value = more light)

void setup() {                                      // Begin setup
 pinMode(AC[0], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[1], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[2], OUTPUT);                           // Set the Triac pin as output
 pinMode(AC[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
 Serial.begin(9600);                              
 delay(50);                                        // Give interrupt 0 some time to catch a few AC cycles
}                                                   // End setup
 
void zero_cross_detect() {                                   // function to be fired at the zero crossing
 ZeroXTime2 = ZeroXTime1;                                   // shift the current zero cross value to the previous
 ZeroXTime1 = micros();                                     // set the new current zero cross time in micros()
 if (ZeroXTime2 > ZeroXTime1){                              // Trap when micros() rolls over
   uRollover = ZeroXTime2 - 4294967295;                     // Subtract the rollover value to get a negative number
   XTimePeriod = ZeroXTime1 - uRollover;                    // And calc XTimePeriod from that
 }
 else {                                                     // Otherwise just calc as usual
   XTimePeriod = ZeroXTime1 - ZeroXTime2;                   // Calculate the time since the last zero crossing
 }
 DimStep = XTimePeriod / DimResolution;                     // Determine how many micros() are in each step of dimming level
 if ( (ZeroXTime1 + (DimLevel * DimStep)) > 4294967295 ) {  // If this pushes the value of NextTriacFire past the micros() rollover
   WaitForRollover = 1;                                     // Then set a flag to watch for.
 }
 NextTriacFire = ZeroXTime1 + (DimLevel * DimStep);         // Calc the next triac fire time
 zero_cross = 1;                                            // set the boolean to true to tell our dimming function that a zero cross has occured
}                                                            // End zero_cross_detect

void loop() {                                                // Main Loop

// Set DimLevel in some fashion. This just sets it to random values.
 randomSeed(analogRead(0));                                 // Initialize the randomizer EVERY TIME (this is not a good thing to do)
 DimLevel = random(DimResolution);                          // Pull a number out of the hat that is <= DimResolution
 Serial.print("Output Level:\t");                           // Print the current output level over serial
 Serial.println(DimLevel);

// DimLevel is used to set NextTriacFire in zero_cross_detect

// NextTriacFire is used here
 if ( WaitForRollover && ( micros() < NextTriacFire ) ) {
   WaitForRollover = 0;
 }
 if ( zero_cross && !WaitForRollover ) {                    // Did we cross zero?
   if ( micros() >= NextTriacFire ) {                       // Check to see if it's time to fire the triac
     for( byte j=0; j<4; j++ ) {                            // For each one of the outputs
       digitalWrite(AC[j], HIGH);                           // Fire the Triac mid-phase
       delayMicroseconds(2);                                // Pause briefly to ensure the triac turned on
       digitalWrite(AC[j], LOW);                            // Turn off the Triac gate (Triac will not turn off until next zero cross)
       zero_cross = 0;                                      // Reset the zero cross detection
     }
   }
 }
}
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Mar 25, 2009, 03:47 pm
It occurred to me after my last post that you may not have _wanted_ anyone's help on the code.  I apologize for stealing your fun if that's the case.

I did have a chance last night to build a test harness and test the code I posted.  For the most part it works.  I had to make a few minor changes to stabilize the timings a little, but I was able to get a 2us pulse at pretty much any resolution and dim level, and any reasonable line frequency.  Let me know if you would like the modified code and I'll be glad to post it again.

Cheers!
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 25, 2009, 04:18 pm
Not at all!  Thanks for the help!  I am not really too good on the software side, so I am always looking for help.  

I looked at the code for a bit, but have not been able to test it yet.  How would this work when you want to put different dim levels on 4 different channels?  Thanks for the input!
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Mar 25, 2009, 10:49 pm
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.   ;)   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.
Title: Re: Arduino AC Power Shield!
Post by: oelewapperke on Mar 30, 2009, 02:01 pm
Looks quite useful. I wonder if the danger is really that great.
Title: Re: Arduino AC Power Shield!
Post by: wdh on Mar 30, 2009, 08:13 pm
Quote
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: -
Quote
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
Quote
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).
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 30, 2009, 09:02 pm
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.
Title: Re: Arduino AC Power Shield!
Post by: mem on Mar 30, 2009, 09:27 pm
Quote
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!
Title: Re: Arduino AC Power Shield!
Post by: wdh on Mar 30, 2009, 10:23 pm
Quote
Is there a danger?  Yes.

I'm I worried? No.  ...


Ryamjmclaughlan, in those few words you have crystallised my concerns perfectly.  
Title: Re: Arduino AC Power Shield!
Post by: hads on Mar 30, 2009, 10:33 pm
Quote
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.
Title: Re: Arduino AC Power Shield!
Post by: wdh on Mar 31, 2009, 01:50 am
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?
Title: Re: Arduino AC Power Shield!
Post by: hads on Mar 31, 2009, 02:09 am
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.

Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Mar 31, 2009, 02:44 am
Thanks that_chap for the pointers.  

I will post again when I get another design going.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Mar 31, 2009, 05:08 am
Wow, Ryan!  You really shook people up with your project.  :)

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!
Title: Re: Arduino AC Power Shield!
Post by: betwys on Mar 31, 2009, 05:11 am
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
Title: Re: Arduino AC Power Shield!
Post by: wdh on Apr 01, 2009, 02:01 pm
Betwys-
Quote
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 ...  ::)

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 -
Quote
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.
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Apr 01, 2009, 02:44 pm
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. http://en.wikipedia.org/wiki/Phase_fired_controllers  

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.

Quote
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
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 02, 2009, 08:26 am
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.
Title: Re: Arduino AC Power Shield!
Post by: hads on Apr 02, 2009, 08:39 am
So I guess my research isn't that bad after all.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 02, 2009, 09:57 am
I just connected a couple dots....    :D

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() ;)

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.

Code: [Select]
/*
 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)
 }
}
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Apr 02, 2009, 02:41 pm
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.
Title: Re: Arduino AC Power Shield!
Post by: wdh on Apr 02, 2009, 05:41 pm
koyaanisquatsi -
Quote
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.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 02, 2009, 06:48 pm
Quote
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.   :D

http://en.wikipedia.org/wiki/Utility_frequency#400_Hz

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?   ;)
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 09, 2009, 01:19 pm
OK, I am really stoked with this version of code!  Oddly enough, some of it boiled back down to something similar to what you were doing originally.  But it has the following features now (again):

o Four independent output channels with their own inputs.
o Interrupt driven triggering for timing accuracy, even with other code in loop()
o Tracks changes in the line frequency and adjusts accordingly
o Tested with up to 512 steps of dimming resolution (could go higher? max is dependent on line freq, YMMV)

Here's a couple thoughts that may save a few clock cycles:
1. The triac pulse is 6us in the current code.  Removing the 2us delay reduces it to a 4us pulse.  How long does the pulse need to persist to properly fire the triac?
2. If we can leave the triac pins high until the next zero cross, we can save even more clocks.

Code: [Select]
/*
 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 count of dimming steps.
 Tracks the line frequency and adjusts accordingly.  Can set up to
 an estimated 512 steps of dimmer resolution.
 
*/

#include <TimerOne.h>                                  // http://www.arduino.cc/playground/Code/Timer1

// General
unsigned long int ZeroXTime[4] = {0,0,0,0};            // Timestamp in micros() of the zero crossing interrupts
unsigned long int DimStep;                             // How many micros() in each step of dimming
unsigned long int AvgPeriod;                           // The average line voltage period in micros()
unsigned long int PeriodResync = 3000;                 // Number of milliseconds between line freq measurements
unsigned long int ResetPeriod = PeriodResync;          // The timestamp in millis() when we will measure the period again
unsigned long int DimRes = 256;                        // How many steps of dimmer resolution
volatile unsigned long int DimStepCounter;             // For counting Timer1 interrupts
volatile unsigned long int FireTriac[4] = {0,0,0,0};   // When it's OK to fire the triacs, in counts of DimRes
volatile boolean zero_cross = 0;                       // Tels us we've crossed the zero line
byte TriacPin[4] = {4,5,6,7};                          // Which digital IO pins to use

void setup() {                                         // Begin setup
 Timer1.initialize(DimStep);                          // Start up the Timer1 timer
 attachInterrupt(0, zero_cross_detect, FALLING);      // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
 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
 measure_half_period();                               // Initially measure the half period
}                                                      // End setup

void measure_half_period() {
 zero_cross = 0;                                      // Clearing this here increases the accuracy of the measurement
 byte F = 0;                                          // Frequency counter counter  ;)
 while ( F < 4 ) {                                    // This loop takes 4 zero cross samples
   if ( zero_cross ) {                                // Only run if a zero cross is detected
     ZeroXTime[F] = micros();                         // Set the new current zero cross time in micros()
     zero_cross = 0;                                  // Reset zero_cross
     F++;                                             // Bump the counter for the next sample
   }
 }                                                    // Now we calc the length of each DimStep
 DimStep = (((ZeroXTime[1]-ZeroXTime[0]) + (ZeroXTime[2]-ZeroXTime[1]) + (ZeroXTime[3]-ZeroXTime[2])) / 3) / DimRes;
 Timer1.attachInterrupt(fire_triacs, DimStep);        // (Re)Associate fire_triacs() with the Timer1 interrupt and the latest DimStep period
 ResetPeriod = ResetPeriod + PeriodResync;            // Set the next time when we'll measure the half period again
}
 
void zero_cross_detect() {                             // function to be fired at the zero crossing
 zero_cross = 1;                                      // set a variable that's picked up later
 DimStepCounter = 0;                                  // Reset the step counter for the next round of triac firings
}

void fire_triacs() {                                   // Called every DimStep (Timer1 interrupt, checks FireTriac[n] and fires if it's time
 if ( FireTriac[0] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[0], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[0], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 if ( FireTriac[1] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[1], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[1], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 if ( FireTriac[2] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[2], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[2], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 if ( FireTriac[3] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[3], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[3], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 DimStepCounter++;                                    // This counter increments every time fire_triacs runs
}

void loop() {                                          // Main Loop
 if ( millis() >= ResetPeriod ) {                     // Measure the half period every PeriodResync milliseconds to prevent drift
   measure_half_period();
 }
   FireTriac[0] = (DimRes * analogRead(0)) / 1024;    // Read input and calc the next triac fire time
   FireTriac[1] = (DimRes * analogRead(1)) / 1024;    // Read input and calc the next triac fire time
   FireTriac[2] = (DimRes * analogRead(2)) / 1024;    // Read input and calc the next triac fire time
   FireTriac[3] = (DimRes * analogRead(3)) / 1024;    // Read input and calc the next triac fire time
}
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Apr 10, 2009, 04:39 am
Could I join in you guys?

I am trying to build the similar circuit for my power control project with the arduino. But  I use high current triac (15A MAC15SD) for my power monster. For safe propose, I use two opto-isolators (M11A1 and MOC3063), which one is for zero crossing detector and the other one is for triac, to separate  AC and DC sides, although AC and DC circuits are on the same small solder less breadboard. But AC circuit is AC, and DC is only DC. My reference circuit comes from here.  (Keyword: fairchild  AN-3006.pdf)(Sorry, I can't post web address when my first post is. I will add it later)

I adjusted several pars of this circuit to suit my need. One 555 timer is used in my circuit. I think a outside timer is better than arduino.  According to my previous tests, arduino works at high speed (less 10 microseconds. Min limitation is 3 or 4 usec). I often found a lot noise from circuits. But I am not sure it comes from arduino or not.

Reminder: to use isolator transformer (120v to 120v) before oscilloscope's probes contact your AC circuit, if you are new. Otherwise, the circuit will burn out!!! Due to AC circuit and the oscilloscope don't share the same ground. I burned my circuit three times. :'(

To ryanjmclaughlin: for buzz from the triac, you can probably use a small capacitor to filter it, like the upper reference circuit.  An inductor will let ac phase changed.  Or noise comes from arduino?

To Koyaanisqatsi:  I tried to compile your latest code(Version: April 8).  I got a error from this line.
"ZeroXTime[F] = micros(); "
Could  you please let me know what value of micros() is?

To  that_chap
Your advice is a good ideal for several applications which don't need phase control. Some projects like mine, I have to get continuous power output, not discrete power output. They are totally different. Fast on and off switch doesn't suit for phase control applications, like lamp dimming. I have done this switch circuit with my arduino. I captured zero crossing signal, synchronized the signal, and use PWM function on the arduino to generate a fast on-off switch. I did it. I can even control output power very accurate.  Unfortunately,  I get a flickering light. We need a phase control , not a high speed switch.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Apr 10, 2009, 04:41 am
The reference circuit website is:
www.fairchildsemi.com/an/AN/AN-3006.pdf
:)
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 10, 2009, 05:21 am
Hi bluefish,

Here's the description of micros().  You may need a minimum version of the IDE for it to work.  I'm running 0013.
http://arduino.cc/en/Reference/Micros

Please let us know if you are able to use the code.  That was my first real project and I'm very curious to know how it works for people.

Cheers!
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Apr 10, 2009, 02:47 pm
To koyaanisqatsi:
For DelayMicroseconds function
http://arduino.cc/en/Reference/DelayMicroseconds

"This function works very accurately in the range 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times."

2usec is too small for arduino.  I will try 2usec first and let you know what I get. But I suggest we use 6 usec or up. (Twice of the mini level of arduino)

Although I used 5usec for my previous tests, the strength of pulses is very difficult to trigger triac. Due to weak pulse signal, a lot of noise is observed in my circuit.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 10, 2009, 06:35 pm
I'm assuming you're referring to this statement in one of my previous posts:
Quote
1. The triac pulse is 6us in the current code.  Removing the 2us delay reduces it to a 4us pulse.  How long does the pulse need to persist to properly fire the triac?

I actually measured this on my oscilloscope.  With delayMicroseconds(2), I get a 6us pulse and without it I get a 4us pulse.  It's a pretty small difference, but in this application, every spare clock cycle counts.   ;)   I'm not sure what triacs require for a minimum trigger pulse width and I would not be surprised if we actually need a wider pulse to get a reliable trigger.

The minimum delayMicroseconds() is due to clock cycle rounding and processing latency.  So adding a 1us delay may do some good in some cases because it will "slightly slow down" the surrounding code.  You just can't set a value of 1us and observe an exact 1us delay period.  Down in that low range, you'd have to do a lot of testing to see how the code behaves.  The minimum value they describe in the docs is not a minimum resolution, but rather a lowest usable value.  So any value above 3us should be accurate.

I will be interested to know what your results are on that.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Apr 10, 2009, 10:18 pm
Hi koyaanisqatsi,

I took some time to update my arduino software from 0012 to 0015 and read codes. These codes have been compiled now. I have learned new functions after 0012. ;)

After read codes, I have two points. (If I misunderstand it, please let me know.)

1. Digital pin 02 is used for interrupt. Therefore,digital pin 02 has to be connect with the zero crossing detector.

2. For this lines "FireTriac[1]=(DimRes*analogRead(1))/1024", the reading value of Analog Pin 01 is used to set when triac is triggered. This is a great ideal. Therefore,we can use 4 potentiometers or 4 different values to get 4 different power outputs at the same time. ;D

Only one small problem is here. DimRes is 256. When the value of analogread is 0, the value of firetriac is 0. When the value of analogread is 512, the value of firetriac is 128. Trigger level is from 0 to 128. Therefore, total trigger level is 129.

For next step, I will try these codes with my circuit and let you know what result I get.

Cheers 8-)
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Apr 12, 2009, 10:34 pm
Hi koyaanisqatsi,

I used one 1 to 1 isolator transformer, one oscilloscope, one P3 kill a wall, one 100w lamp and the adjusted circuit from reference circuit.

After I tested codes, it works very good. The range of output power is between 16w and 93w, compared with input value from 1024 to 125. Yes, it's opposite due to my circuit. The 16w mini output is due to one to one isolator transformer. It is a big and heavy power pig. When input value is 100, triac is off.

I have taken five pictures from the oscilloscope: one is ac to zero crossing(zero crossing signal is over 200usec than ac waveform. But it's not a problem.), and the others are different phase control results. (the value of AnalogRead is: 225, 550, 825, 975). For delay 2usc, you are right. It doesn't bother me. 8-)

When I watched the lamp, the lamp doesn't flick. The bright of the lamp is very stable. Of course, I got different bright of the lamp from different input value. I also measured the output power from 100 to 1024 (input value). I made a curve for input value to output power.

If someone can let me know how to attach these pictures on this forum, I will post them.

Hi ryanjmclaughlin,

I did't find a lot of buzz from AC output. I am interested in your AC shield.
Could you please let me know how it is going?

Happy Holiday :)
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 14, 2009, 05:22 am
Cool!  It sounds like the code is behaving the way I hoped it would.  :)

Quote
compared with input value from 1024 to 125. Yes, it's opposite due to my circuit.

That's expected behavior.  A higher analog input value gives a longer triac trigger delay.  So it will be dim at higher values and bright at lower values.

I uploaded a video of what my o-scope shows and a description of what's going on.  It's kinda blurry, but it works.

http://www.youtube.com/watch?v=ZO9kRJdj6gg

To post an image, you have to upload it somewhere like Flickr or whatever.  Then paste a link to the image in between the img tags (a button in the post editor).  Then it will display in your post.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Apr 17, 2009, 04:06 am
Hi ryanjmclaughlin and koyaanisqatsi,

I upload these pictures to my picasa.
Here is hyperlink
http://picasaweb.google.com/bluefishforum/ACShield#

You can watch different input values and different phase outputs.
For sine waveform, curve means lamp is off. Flat means lamp is on.

I also tried these codes with my other codes. They didn't interfere each other. AC phase controlling codes can work with one temperature sensor and one step motor at the same time. This combination can become a prefect computer controlling BBQ machine or oven. 8-)

Cheers
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Apr 17, 2009, 02:21 pm
Wow, awesome work.  This little project is really taking off.  I guess I need to get working with the updated copy of the board!

I think some of my problem with the triac buzz is the small wattage rating of my resistors...  need to test this though.

bluefish, I have one more protoboard left if you want to play around with that, otherwise I hope to order some new boards in another week or so.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 17, 2009, 11:03 pm
I am so stoked to see bluefish's pics!  I've tooled around with my Arduino a lot since I got it.  But this is the first project I've done that actually does something useful!   ;)
Title: Re: Arduino AC Power Shield!
Post by: mdowning on Apr 27, 2009, 08:43 pm
I deal a lot with AC power sources and agree you need to be REALLY careful who and how you expose them.

I think you could probably still do this as one board but enclose the HV portion in a grounded metal can.  You could add MO Varistors to it to add surge protection in the event of a short.

Cool idea though.
Title: Re: Arduino AC Power Shield!
Post by: madworm on Apr 27, 2009, 11:05 pm
So when will the Electrocutor-Shield (TM) be available as a kit ?
Title: Re: Arduino AC Power Shield!
Post by: ryanjmclaughlin on Apr 28, 2009, 12:46 am
Haha, it is going to be a bit longer.  I have the design almost done.  It is going to be enclosed in a box and have a 2x5 header to breakout.  I am also looking into adding a 5V Power supply on board to power the Arduino and anything else you may want off of the 120V ac.  I am going to leave the breakout to AC up to the end use (there will be sets of pads for the outputs, un-terminated).  This way you can configure it any way you want.  My goal about a month or so.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Apr 28, 2009, 09:46 am
Ryan, I just had a couple thoughts:

You could use one of those two-prong power cords/jacks like a boom box uses instead of the computer kind.  That would save some space.  You'd lose your earth ground, but I can't see any reason to have it anyway.

You ought to terminate the AC outputs in some generic way, like screw terminals or those spring-loaded terminals kinda like what's on some speakers.  The right kind will make the contacts difficult to accidentally touch/short but easy to use.\

I like the 5v power supply idea - since you have to plug it in anyway, it might as well power the board too.  ;)

Can't wait to see the new design!
Title: Re: Arduino AC Power Shield!
Post by: bridges-pdp on Apr 29, 2009, 12:15 am
I'm interested. Is there a webpage or email list to subcribe to for updates on availability?

I actually like the name Electrocutor-Shield(TM). Package it with a bracket to mount to a chair or bath tub and include a bite-stick.

I'm fine with it being in an enclosure, but will it still be available as a kit for DIY assembly?

Scott
Title: Re: Arduino AC Power Shield!
Post by: caff on Jul 11, 2009, 09:52 am
This is really interesting - I have been planning a temperature control system and I wanted something with finer control than the usual two state thermostat. I already have a beefy triac and was hoping to drive it with a microcontroller so this is almost exactly what I am looking for.

I was wondering how to display the current wattage (based on knowing the wattage of the heater element beforehand) and I did a bit of research into how to work out the power delivered in a fraction of the sine curve. This also made me realise (what I am sure you already know) that the FireTriac does not map linearly to the power delivered to the load.

Instead of applying a correction to the display value it would be nice to add a correction to the fire_triacs() code.

I am not sure if there is the resolution in the timings to make it accurate (perhaps around the peak the timing difference between say 48% and 52% power might be too small to be accurately applied?) but it would have to lead to an overall improvement in the feel of the linearity.

I believe the power for a pure resistive load should be directly related to the area under the sine curve. I had no idea how to calulate that but some googling led me to integrals.

Here the area under one half cycle is 2:

http://www83.wolframalpha.com/input/?i=integrate+sin+x+dx+from+x%3D0+to+Pi

wolframalpha: integrate sin x dx from x=0 to Pi

And to work out for example if we applied power for the last 25% of one half cycle, how much power would the load get?

http://www83.wolframalpha.com/input/?i=%28integrate+sin+x+dx+from+x%3D%28pi*%281-0.25%29%29+to+Pi%29%2F2*100

wolframalpha: (integrate sin x dx from x=(pi*(1-0.25)) to Pi)/2*100

-> 14.6%

To see that graphed you need to take out the parts that convert it to a percentage:

http://www83.wolframalpha.com/input/?i=integrate+sin+x+dx+from+x%3D%28pi*%281-0.25%29%29+to+Pi


wolframalpha: integrate sin x dx from x=(pi*(1-0.25)) to Pi

I imagine the best way to do this would be a lookup table? to calculate that I want to start with a set of desired output values for lookup table and then need to solve for what portion of Pi the integral domain starts at - but I have no idea of the math for that.

Is anyone else interested in making the output linear?

Does anyone have a stronger grasp on the math than me and knows how to invert that equation to get the time from the area rather than vice versa?

Would that equation be something that might be practical to solve to a point where it is possible to implement on the chip or would you recommend just using it to to make a lookup?
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Jul 11, 2009, 09:51 pm
It would be very useful to have linear and exponential-ish slopes.  I did a little sine function brightness dimmer for an LED a while ago.  I'll look at that and see if it can be adapted.  I'm not real up to speed on the math either.  I sort of just hacked it and it worked.  ;)

Light dimming works best with an exponential slope and something like a heater or motor control would work best with a linear slope.

Once the sine is corrected for linearity, making it exponential is simple.
Title: Re: Arduino AC Power Shield!
Post by: caff on Jul 12, 2009, 05:18 am
I guess if you pretended the sine was a triangle shape it would be closer to accurate and easier math..

Anyway I have emailed an electrical engineer friend - I am pretty sure they studied this kind of math pretty extensively. I'm just hoping real world jobs haven't let him forget all that :)
Title: Re: Arduino AC Power Shield!
Post by: caff on Jul 17, 2009, 06:31 am
I have solved the math I wanted to apply to this.

The equation I came up with, which covers one half cycle is:

time=arccos(power-1)/Pi
where:
t is delay between 0 and 1
power is between 0 and 2 (2 = 100%)

The curve this makes is:
(http://caff.cx/arduino.cc_1236998971/07.gif)

Which looks right because it gets steep at the far left and right where the sine curve does not have much power.

In the code I have implemented this as a lookup table. Some resolution is being lost in a sense. Maybe it would be worth making the timer run faster, of course the map is specific to 256. We could also consider a variable timer - if that is possible.

NOTES:


Code: [Select]

/*
 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 count of dimming steps.
 Tracks the line frequency and adjusts accordingly.  Can set up to
 an estimated 512 steps of dimmer resolution.
 
*/

/*
 Modified by James Orland <ptd@caff.cx>
 
 Apply an adjustment to account for the shape of the sinewave - giving linear power adjustment
 Curve from:
 time=arccos(power-1)/Pi
 where t is delay between 0 and 1 and a power of 2 is 100%
 
 The sense of the input to the dimming is also reversed from the previous version by the power mapping - as the analogue input is controlling
 the power out - not the delay time. 1024 in from an analogue input will set maximum power.
*/

#include <TimerOne.h>                                  // http://www.arduino.cc/playground/Code/Timer1

// General
unsigned long int ZeroXTime[4] = {0,0,0,0};            // Timestamp in micros() of the zero crossing interrupts
unsigned long int DimStep;                             // How many micros() in each step of dimming
unsigned long int AvgPeriod;                           // The average line voltage period in micros()
unsigned long int PeriodResync = 3000;                 // Number of milliseconds between line freq measurements
unsigned long int ResetPeriod = PeriodResync;          // The timestamp in millis() when we will measure the period again
unsigned long int DimRes = 256;                        // How many steps of dimmer resolution
volatile unsigned long int DimStepCounter;             // For counting Timer1 interrupts
volatile unsigned long int FireTriac[4] = {0,0,0,0};   // When it's OK to fire the triacs, in counts of DimRes
volatile boolean zero_cross = 0;                       // Tels us we've crossed the zero line
byte TriacPin[4] = {4,5,6,7};                          // Which digital IO pins to use
byte PowerMap[256] = {
255,245,241,237,235,232,230,228,226,224,223,221,220,218,217,215,214,213,211,210,209,208,207,205,204,203,202,201,200,199,198,197,
196,195,194,193,192,192,191,190,189,188,187,186,185,185,184,183,182,181,181,180,179,178,177,177,176,175,174,174,173,172,171,171,
170,169,168,168,167,166,165,165,164,163,163,162,161,161,160,159,158,158,157,156,156,155,154,154,153,152,152,151,150,150,149,148,
148,147,146,146,145,144,144,143,143,142,141,141,140,139,139,138,137,137,136,135,135,134,134,133,132,132,131,130,130,129,128,128,
127,127,126,125,125,124,123,123,122,121,121,120,120,119,118,118,117,116,116,115,114,114,113,112,112,111,111,110,109,109,108,107,
107,106,105,105,104,103,103,102,101,101,100,99,99,98,97,97,96,95,94,94,93,92,92,91,90,90,89,88,87,87,86,85,84,84,83,82,81,81,80,
79,78,78,77,76,75,74,74,73,72,71,70,70,69,68,67,66,65,64,63,63,62,61,60,59,58,57,56,55,54,53,52,51,50,48,47,46,45,44,42,41,40,38,
37,35,34,32,31,29,27,25,23,20,18,14,10,0
};

void setup() {                                         // Begin setup
 Timer1.initialize(DimStep);                          // Start up the Timer1 timer
 attachInterrupt(0, zero_cross_detect, FALLING);      // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
 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
 measure_half_period();                               // Initially measure the half period
}                                                      // End setup

void measure_half_period() {
 zero_cross = 0;                                      // Clearing this here increases the accuracy of the measurement
 byte F = 0;                                          // Frequency counter counter  ;)
 while ( F < 4 ) {                                    // This loop takes 4 zero cross samples
   if ( zero_cross ) {                                // Only run if a zero cross is detected
     ZeroXTime[F] = micros();                         // Set the new current zero cross time in micros()
     zero_cross = 0;                                  // Reset zero_cross
     F++;                                             // Bump the counter for the next sample
   }
 }                                                    // Now we calc the length of each DimStep
 DimStep = (((ZeroXTime[1]-ZeroXTime[0]) + (ZeroXTime[2]-ZeroXTime[1]) + (ZeroXTime[3]-ZeroXTime[2])) / 3) / DimRes;
 Timer1.attachInterrupt(fire_triacs, DimStep);        // (Re)Associate fire_triacs() with the Timer1 interrupt and the latest DimStep period
 ResetPeriod = ResetPeriod + PeriodResync;            // Set the next time when we'll measure the half period again
}
 
void zero_cross_detect() {                             // function to be fired at the zero crossing
 zero_cross = 1;                                      // set a variable that's picked up later
 DimStepCounter = 0;                                  // Reset the step counter for the next round of triac firings
}

void fire_triacs() {                                   // Called every DimStep (Timer1 interrupt, checks FireTriac[n] and fires if it's time
 if ( FireTriac[0] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[0], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[0], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 if ( FireTriac[1] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[1], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[1], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 if ( FireTriac[2] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[2], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[2], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 if ( FireTriac[3] == DimStepCounter ) {              // Is it time to fire?
   digitalWrite(TriacPin[3], HIGH);                   // Fire the Triac mid-phase
   delayMicroseconds(2);
   digitalWrite(TriacPin[3], LOW);                    // Turn off the Triac gate (Triac will not turn off until next zero cross)
 }
 DimStepCounter++;                                    // This counter increments every time fire_triacs runs
}

void loop() {                                          // Main Loop
 if ( millis() >= ResetPeriod ) {                     // Measure the half period every PeriodResync milliseconds to prevent drift
   measure_half_period();
 }
 
 FireTriac[0] = PowerMap[(DimRes * analogRead(0)) / 1024];    // Read input and calc the next triac fire time
 FireTriac[1] = PowerMap[(DimRes * analogRead(1)) / 1024];    // Read input and calc the next triac fire time
 FireTriac[2] = PowerMap[(DimRes * analogRead(2)) / 1024];    // Read input and calc the next triac fire time
 FireTriac[3] = PowerMap[(DimRes * analogRead(3)) / 1024];    // Read input and calc the next triac fire time
}


Here is the ruby script I used to make the PowerMap array:
Code: [Select]

#!/usr/bin/env ruby
def arccos(x)
 Math.atan2(Math.sqrt(1.0-x*x),x)
end

DimMax=255    #Resolution -1
DimStep=1
TimerMax=255  #Resolution -1
print "{";
0.step(DimMax, DimStep) do |power|
 time=TimerMax*arccos((power/(DimMax/2.0))-1)/Math::PI
 print time.round
 if power!=DimMax then
   print ",";
 end
end
print "}";
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Jul 17, 2009, 07:53 am
Nice work, caff!  You beat me to it.  ;)  I agree the shape of the graph "looks right".  I just fried my FTDI chip, so I can't test your code.  And I'm trying to think of the best way to accurately measure the power output at each dimmer step to see if they are equal.  Not sure if there is a cheap way to do that.

EDIT: Had to remove the rest of this posting because it's late and I brain-farted.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Jul 17, 2009, 08:16 pm
Hello caff and koyaanisqatsi,

I can test your code today or the coming Monday. Then, I will let you know what result I get.

For temperature control, I am doing the similar project now. I want to use computer to control, monitor and record temperature in my project. I use arduino to control AC power in a furnace. If you have an interest in this, I posted my circuit diagrams and results here. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1240690030This will help you to build yours.

For monitor and record AC output power, you can visit below the website.I am trying to redesign it. Therefore, computer can obtain power output value in real time from kill a watt via arduino.
http://
http://www.ladyada.net/make/tweetawatt/

Have a good weekend, ;)

fish
Title: Re: Arduino AC Power Shield!
Post by: caff on Jul 20, 2009, 03:00 pm
Koya - As far as verifying the power curve, it is hard. Though most normal multimeters with True RMS splashed across the front are not really true rms they may still be designed not to be completely useless for non sine waves. At least our wave form is symmetrical about 0. It might be worth just putting a meter across the output voltage and see if the map makes it more linear. Perhaps use different code so that you can step up the dim value in a controlled way rather than using analogue read.

Also remember it will not be accurate down to the single dimres step because the map has the same resolution (255) on both input and output, but over say 5 or 10 steps it would even out to be pretty equal.

Btw here is what seems to be true true rms meter:
http://www.ballantinelabs.com/323meter.htm

Only 2300USD :)

I am pretty confident in the math - the starting point in my first post I was clearly getting the area under the curve graphed (which is the power) and I was able to plug numbers from my solution back into that page and get the right answers.

Here are the steps I went through, my working if you can call it that: http://caff.cx/arduino.cc_1236998971/

If there is a problem I think it will be in implementation not in the formula.

Bluefish - I would be curious to see what your kill-a-watt makes of it - I can sort of see the curve we are trying to straighten in your other post of the pre corrected power output.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Jul 21, 2009, 10:15 pm
Hi caff and koyaanisqatsi,

After I tested your revised code, I didn't find any big different between old and revised codes from my oscilloscope. From my observation, the old code is more stable than the revised code, because the AC voltage waveform sways occasionally when the revised code is using. Thank you very much, koyaanisqatsi. You did a very good job.

For the calculation of AC period, this is depending on how much accuracy you want to achieve.  It is different between 95 and 100% accuracy in math. But it is not a lot of different for non-time-sensitive applications (second or minute level), like home furnace temperature control.
For variable timer, sampling timer and AC waveforms (voltage and current) are variable by time, what factor you want to use for a reference? This will let AC phase control become a complex problem. I believe you can figure it out in math, and phase control can becomes very accuracy. (micro second level ?) But, is it worth for non-time-sensitive applications? The old code using timer from hardware as a reference calculates the average period of AC. Although the period of AC is not 100% accuracy, it is enough to do a lot of applications.

To calculate AC power output, this is a statistic problem. AC voltage and current values are running anytime. I use real time voltage multiply by real time current to obtain real time AC power output for resistor only system, like DC circuit (Power = Voltage * Current).  The difference is that both AC real time voltage and current values are including their phase factors. Therefore, the average of AC power output per unit time is RMS power per unit time.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Jul 23, 2009, 10:09 pm
To Caff,

After I did more test with different loads, you are right. Your revised code can work more accurate than the old one.

Output results of both codes are not different for low load applications (I used 100w bulb) or working with a constant trigger value. When high load (300w or higher) is applied, the old code becomes unstable (the code shifts its trigger value between two random values per 3 second or fixes in a constant) after I changed the value of analogread (from min to max or max to min) several times (3-5 times). The shift period changed when I changed the value of Periodsync. But the revised code doesn't have any problem at the same condition.

For swaying waveform, I checked my circuit again and found that an output wire was loose a little bit. Sorry, this is my mistake.

I would like to say thank you. You let the code becomes more perfect.

Fish

PS: I use Labview to control AC output. Therefore, the value of analogread is sent from Labview. It isn't from a potentiometer.
Title: Re: Arduino AC Power Shield!
Post by: cverink on Jul 24, 2009, 11:11 pm
Hey guys nice work on the project.

Does anyone have a schematic for this? Im thinking about using something like this for some lightning effects and would like to get a general idea of what id be getting into.

Thanks,
Title: Re: Arduino AC Power Shield!
Post by: caff on Jul 25, 2009, 10:35 am
Hi Ill Mill,
The other guys might have more to tell you about this, there are pictures of the power shield which controls four outputs at the start of this topic. The application note PDF linked to earlier in this topic has almost exactly the circuit you need for one output, you would simply replace the 555 section with the Arduino http://www.fairchildsemi.com/an/AN/AN-3006.pdf.

Also see the posts by bluefish in his AC box topic http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1240690030 include some circuit diagrams, you'll need one zero crossing detector and a triac driver for each output.

You probably shouldn't take on something like this unless you feel confident, otherwise you could hassle ryanjmclaughlin to see if he still plans to sell the AC shield prebuilt or as some kind of kit.
Title: Re: Arduino AC Power Shield!
Post by: caff on Jul 25, 2009, 11:14 am
Hi bluefish,

I understand what you mean about the big jumps you will see on the scope with the new code. The reason is the AC waveform has a low voltage at the edges so to get the same amount of change you need to change the timing by a lot. We are also mapping from 255 values to 255 values so for example the step from zero to one in the power setting will mean a jump from 255 down to 245 in the delay value. If you saw it flickering between two values by itself that will be because the analog read was getting slightly different values each time and jumping between two power values. If you are near the start or the end of the range it would look like large jumps even though it only represents small jumps in the amount of power.

This does go back to the loss of resolution because the map has the same resolution on its input and output some output values are no longer possible because they don't match any of the input values. Overall it should still be more accurate i.e. if you set the dimmer value to 25% you should definatly be getting much closer to 25% power in a heater element than with code which does not try to correct for the curve. Did you make a curve with the kill-a-watt yet?

I actually think when I make my hardware I will probably start the code from scratch because I would like try to control the timer directly so that an interrupt happens at exactly the time when I want to trigger the triac. This will mean my map can have much higher resolution on the output time delay value, it also means not triggering the interrupt hundreds of times per cycle. I have not studied how the timers worked yet but I assume this should be possible especially because I only want to control one triac rather than four.

Here is another small improvement to the code. It is designed to ensure that when you set the power to either zero or full you will truly get zero or full activation of the triac even if there are small discrepancies in the timing. If zero power is selected then the trigger pulse will not be sent, if 100% power is set it will hold the triac output pin high.

This replaces the fire_triacs() function:
Code: [Select]

void fire_triac(int TriacNum) {
 if ( FireTriac[TriacNum] == DimStepCounter ) {              // Is it time to fire?
   
   if(FireTriac[TriacNum]!=DimRes)                           //When the power output is 0% never turn the triac on
     digitalWrite(TriacPin[TriacNum], HIGH);                 // Fire the Triac mid-phase

   if(FireTriac[TriacNum]!=DimRes && FireTriac[TriacNum]!=0) //Only bother to add a timing delay when both digitalWrites are active
     delayMicroseconds(2);

   if(FireTriac[TriacNum]!=0)                                //When the power output is 100% never turn the triac off
     digitalWrite(TriacPin[TriacNum], LOW);                  // Turn off the Triac gate (Triac will not turn off until next zero cross)

 }  
}

void fire_triacs() {                                   // Called every DimStep (Timer1 interrupt, checks FireTriac[n] and fires if it's time

 for(int i=0; i<4; i++)                               // Fire each of the triacs
   fire_triac(i);

 DimStepCounter++;                                    // This counter increments every time fire_triacs runs
}


I also have an idea that if you wanted to reduce heating of the triac at 100% power. The highest heat dissipation of the triac will occur when it is 100% on. You could bypass it with a relay which is also activated by the triac trigger pin. Using the the code above the relay could be set up so that it only activates when the line is held high and ignores the small trigger pulses when the triac is partially activated
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Jul 27, 2009, 08:24 am
I'm going out on a limb here because I can't remember what state this code is in and my Arduino is fried so I can't test it.  But last time I tested this code it was very smooth.  I remember the previous version I posted was very jumpy.  This is the code (or a close version of it) I'm using in my YouTube video http://www.youtube.com/watch?v=ZO9kRJdj6gg.

So here it is.  I'm pretty sure this works OK.  But there may be a bug in it regarding the millis() function being used in ISRs.

Try modifying this with the sine correction and see how it behaves.

Cheers!

Code: [Select]
/*
 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.
 It also tracks the rollover of the internal microseconds counter
 to avoid the glitch that would arise about every 70 minutes otherwise.
*/

// General
volatile unsigned long int ZeroXTime1 = 0;             // Timestamp in micros() of the latest zero crossing interrupt
volatile unsigned long int ZeroXTime2 = 0;             // Timestamp in micros() of the previous zero crossing interrupt
volatile unsigned long int XTimePeriod;                // The calculated micros() between the last two zero crossings
byte TriacFireWidth = 2;                               // How many microseconds to leave the triac trigger high
unsigned int DimChangeDelay = 500;                     // How many millis() between changes of dimmer level
unsigned long int DimChangeTime = 0;                   // Timestamp in millis() when the dimmer was changed

// Channel specific
# define Channels 4                                    // How many dimmer channels (triacs) are there?
unsigned long int DimLevel[Channels];                  // Dimming level (high value = more dim, low value = more light)
unsigned long int DimDelay[Channels];         // How many micros() to wait after zero cross to fire the triacs
unsigned long int NextTriacFire[Channels];    // Timestamp in micros() when it's OK to fire the triacs again.
volatile boolean zero_cross[Channels];                 // Boolean to store a "switch" to tell us if we have crossed zero

// Associate pins to each channel (triac)
byte TriacPin[Channels] = {4,5,6,7};

void setup() {                                         // Begin setup
 for ( byte c=0; c<Channels; c++ ) {                  // Loop through and set pin modes
   pinMode(TriacPin[c], 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
 ZeroXTime2 = ZeroXTime1;                             // shift the current zero cross value to the previous
 ZeroXTime1 = micros();                               // set the new current zero cross time in micros()
 XTimePeriod = ZeroXTime1 - ZeroXTime2;               // Calculate the time since the last zero crossing
 for ( byte c=0; c<Channels; c++ ) {
   DimDelay[c] = XTimePeriod / DimLevel[c];          // Calc how long to wait after zero cross to fire the triacs
   NextTriacFire[c] = ZeroXTime1 + DimDelay[c];      // Calc the next triac fire time
   zero_cross[c] = 1;                                 // set the boolean to true to tell our dimming function that a zero cross has occured
 }
}                                                      // End zero_cross_detect

void loop() {                                          // Main Loop
 
// Set DimLevel in some fashion.
 DimLevel[0] = analogRead(0);                      // For testing, we're just reading an analog input
 DimLevel[1] = analogRead(0);                      // For testing, we're just reading an analog input
 DimLevel[2] = analogRead(0);                      // For testing, we're just reading an analog input
 DimLevel[3] = analogRead(0);                      // For testing, we're just reading an analog input

// DimLevel is used to set NextTriacFire in zero_cross_detect()
 for ( byte d=0; d<Channels; d++ ) {                                 // Loop through each channel
   if ( zero_cross[d] ) {
     if ( micros() >= NextTriacFire[d] ) {                         // Check to see if it's time to fire the triac
       digitalWrite(TriacPin[d], HIGH);                            // Fire the Triac mid-phase
       delayMicroseconds(TriacFireWidth);                          // Pause briefly to ensure the triac turned on
       digitalWrite(TriacPin[d], LOW);                             // Turn off the Triac gate (Triac will not turn off until next zero cross)
       NextTriacFire[d] = NextTriacFire[d] + XTimePeriod;
       zero_cross[d] = 0;                                          // Reset the zero cross detection  
     }
   }
 }
}
Title: Re: Arduino AC Power Shield!
Post by: seanreynolds on Jul 27, 2009, 10:41 pm
Hey,
Whats the status of this?

I'd like a small box with a Male Female connector on it, with two pins for Ground and Signal, where Signal is 0 for Off, and +5 for On.

Do you have anything like this?
I guess I could build it, do I need anything other than a RELAY for this?

Title: Re: Arduino AC Power Shield!
Post by: hads on Jul 27, 2009, 10:47 pm
That's what a Solid State Relay (SSR) is.
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Jul 28, 2009, 07:44 pm
To Koyaanisqatsi,

Your code works well. That's why I can't find any difference when I tried your code and the revised code first time. After more detail tests including using high load tests (about 1000 watt) and quickly changed phase trigger value several times from the lowest to the highest or reverse, I lost phase control by using you code. That is because I did an extreme test for both codes. I think the code has a bug about analog read pin when power output is the maximum or minimum output. For normal test, it works very well. You did a good job. ;D

I will try you new code later and then let you know what I get.

To Caff

I agree your argument. The bug comes from analog read pin. I also found that the output suddenly becomes the maximum when the phase value is low than 20 by using the revised code. The output becomes unstable between 20 and 40. The difference between both codes is that the phase will be under control when I increase phase trigger value a little (> 20). But the old code can't be controlled unless I restart Arduino. According to my test, the most stable and lowest value is 40 for your revised code.

Thank you for your advice about maximum output ideal. For my application, I can't use the maximum output. It will melt my furnace immediately. One more thing, which I want to remind everyone on this project, is that power output always is the maximum before Arduino finds the average period first time when you start Arduino. After Arduino gets AC period and then starts to send trigger signal, the output is under control. For some cases, this short time is enough to burn out something. For me, I will add a switch before my furnace to avoid the maximum output.

For your project, I know you don't want to turn on you furnace continuous. You only want to turn it on a couple of seconds or even one AC cycle. This is an interesting AC control project. :)

For Kill a Watt, it isn't ready to be used.  I can't get correct curves from it. :'(

I have connected it with labview through Arduino. I can watch voltage, current and watt waveforms directly in real time on my computer. But the problem is that voltage value is not correct on computer. Basically, AC voltage is always variable when we turn on or off some high load electrical equipments on the same loop, like microwave oven, blender, hair dryer. I can watch the correct voltage value directly from kill a watt, which I had checked it with a voltage meter. But I always get wrong values on my computer when voltage value is changed. For example, the voltage value (ex: 115->110v) will decrease when I turn on microwave oven on the same loop. Kill a watt shows this change correct, but my computer always obtains higher values (115->120v). Oppositely, the voltage (110->115v) value increases. I get lower value (120->115v) on my computer. There should be a math function on kill a watt to let it show a corrected value. I read its data directly from its chip. Therefore, the voltage value is not correct.

I think the analog input always reads slight different values every time, like AC phase control, and I need to add a correct function. I read ladyada's project.  http://www.ladyada.net/make/tweetawatt/ She sets a contact for voltage (Vpp is 170). I will try it when I have free time.

Have a nice day
Title: Re: Arduino AC Power Shield!
Post by: bluefish on Aug 06, 2009, 05:31 pm
Hi my friends,

Due to my circuit was short circuit when I tried to add a switch on AC line. :-[ Everything is ok without triac. I took some time to redesign my circuit. Now, the circuit becomes safer than before. But I need to take extra time to do stable test before I test two codes for you.

To koyaanisqatsi
Before the circuit was short circuit, I put your new code on my Arduino. I observed this code can't work. My lamp is like a candle in the wind. The bright of my lamp always becomes dark or bright randomly. I guess that errors come from new timer.  Oppositely, your old code still works well under the same condition. I will try it again when I finish my stable test.

To Caff
I didn't have time to try your new code due to my circuit death. I will try it later.
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Sep 22, 2009, 01:03 pm
bump*

Any new stuff happened on the board production line? Or has everyone being electrocuted? :D

It looks like an interesting project to me - any chance of a 230V UK version? I would like use this to control the power on my pc...

Mowcius
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Sep 24, 2009, 08:27 am
It would not take much to make the board compatible with 230V line (I think it already is actually)  But you would be better off using a regular switch or relay for a computer.  If you feed dimmed power into a computer power supply, you risk damaging the computer.  At best it will heat up the power supply more than normal.
Title: Re: Arduino AC Power Shield!
Post by: Emonroe7 on Sep 24, 2009, 08:38 pm
That looks awesome. I could think of a number of uses for that, such as lighting automation.
Title: Re: Arduino AC Power Shield!
Post by: mungbean on Oct 07, 2009, 02:45 pm
If anyone's looking for a quick and slightly more newbie-friendly way of dimming mains power lighting, check out the light dimmer kit from Velleman:

http://www.velleman.eu/ot/en/product/view/?id=354314

(available from Maplin in UK)

Works on 110-125V or 230-240V, 50/60Hz so should be universal.

Rated 750W @ 230V or 375W @ 110V.

You give it a single control voltage which varies the voltage output.  I guess this might work OK with a PWM output (possibly with a smoothing capacitor on it), otherwise a simple R-2R ladder should do the trick.

The input voltage is meant to be 0-12V but will work fine on 0-5V if you adjust the threshold voltage.

The control input is opto-isolated.  The schematic is included in the PDF manual linked from the web page, if you want to use it as inspiration.



Title: Re: Arduino AC Power Shield!
Post by: bluefish on Oct 14, 2009, 07:00 pm
Hi my friends,

After I tried and tested, I can control AC output very accurate and stable by using phase and PID control, which can be found on the arduino library. The max AC power output for my system is about 1000 watt. The error of the temperature inside my furnace is lower than 1 degree C.

I found why I randomly lost phase control before. Codes from koyaanisqatsi and caff are not big different. To koyannisqatsi, your original code is work well. But your newest code is not work well for me. The trouble comes from my AC triac circuit design. I missed the limitation of dv/dt before. If AC triac circuit doesn't follow this limitation, you may get phase control at first like me. But the system could lose control later depending on your using. For me, my system lost phase control; the high power output (over 2800 watt) damaged everything.

Unfortunately, different triaces have different limitation for dv/dt. Different AC voltage also infects your AC triac circuit design because dv depends on your using voltage. For example, there are needed different AC triac circuit designs for 120 and 220 Vac. On the other hand, static dv/dt is for resistor only system, like heat coil furnace. Commutating dv/dt is for RCL (resistor, capacitor and inductor) mixed system, like AC motor speed control. Static dv/dt has more range than commutating dv/dt. That is why window fan has only 3 or 4 control speeds.

Therefore, the conclusion is for different applications and AC voltages, different AC triac circuits are needed.

Before do arduino phase control, something which you need to knows.

-      triac which you will use
-      AC voltage which your system will work at
-      The limitation for triac: (dv/dt)s or (dv/dt)c;  for several applications: di/dt
-      Basic circuit knowledge

If someone is still interested in this AC power phase control circuit and can make several PCB for me (3-6; I will pay what I get), I am happy to share my circuit, which can be designed a shield to mount on the arduino, without AC triac part.

AC triac part is needed to design for different systems. It is not a good ideal to mount on the arduino due to high current and voltage. I don't want to become a thanksgiving turkey. The AC triac part is needed to put on a separated metal box.

Cheer  ;D
Title: Re: Arduino AC Power Shield!
Post by: Grumpy_Mike on Oct 14, 2009, 08:06 pm
Hi Bluefish,
I do appreciate that English is not your first language but what you say makes no sense. dv/dt is an other way of saying the rate of change of voltage with time.

Quote
Therefore, the conclusion is for different applications and AC voltages, different AC triac circuits are needed.


I would also disagree with this.
Different loads will affect the phase angle between voltage and current and for some loads you might have to apply phase angle correction but this is not part of the design of the AC dimmer.

What circuit designed changes do you think are needed. Have you any schematics we can look at so we can see where you are misunderstanding things.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Oct 14, 2009, 11:52 pm
Mike and BlueFish,

I think what's being discussed is the slew rate of the AC sine, considering the voltage, frequency and any distortion caused by the type of load.  It sounds like the slew rate made a difference in how reliably the triacs would fire.  But I think that by increasing the time of the trigger pulse, you could overcome any slew rate issues in the triacs.  It's currently somewhere around 2-6 us, but could easily be increased into the ms range to be sure the pulse was still there when the triac finally detected the AC voltage rise.  Your limiting factor will be that the trigger pulse must end on or before the next zero-crossing.

I discussed in a previous post the idea of making the trigger pulse last all the way through to the next zero cross.  That would assure triac firing under weird circumstances.
Title: Re: Arduino AC Power Shield!
Post by: lepluc on Oct 27, 2009, 10:29 am
Guys!
What blue-fish is talking about is that a Triac can latch into a permanent on state under certain conditions when it should turn off at the end of a half cycle. It is all explained here:
in a link that I'm not allowed to post!
Title: Re: Arduino AC Power Shield!
Post by: lepluc on Oct 27, 2009, 10:30 am
so her it goes
www.st.com/stonline/products/literature/an/3577.pdf
Title: Re: Arduino AC Power Shield!
Post by: yzf600 on Dec 12, 2009, 01:25 am
Excellent thread about AC control. I wanted to add this resource to the great info here:

http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=RDLIGHTDIMEFRF

This is a reference design using a freescale micro + capacitive touch sensor to implement a light dimmer. It also has wireless control via RF (802.15.4). In the documentation, they have detailed schematics of the AC circuits.
Title: Re: Arduino AC Power Shield!
Post by: subbaraokommuri on Feb 04, 2010, 09:30 am
Hi Bluefish,

Finally what version of code do you suggest to use. I am also interested in Furnace control. I am using simplified version of code and it is not working for me @ 100% output. I get the same wattage at both 70% output and 100% output. Can anybody suggest whats wrong with this code

#include <TimerOne.h>                                
byte oput=0;
byte cntr=0;
unsigned long int DimStep=1000000/102/256;
long int starttime;
volatile unsigned long int DimStepCounter;            
volatile unsigned long int FireTriac = 0;  
volatile boolean zero_cross = 0;                      
byte TriacPin = 14;                          
byte PowerMap[256] = {
255,245,241,237,235,232,230,228,226,224,223,221,220,218,217,215,214,213,211,210,209,208,207,205,204,203,202,201,200,199,198,197,
196,195,194,193,192,192,191,190,189,188,187,186,185,185,184,183,182,181,181,180,179,178,177,177,176,175,174,174,173,172,171,171,
170,169,168,168,167,166,165,165,164,163,163,162,161,161,160,159,158,158,157,156,156,155,154,154,153,152,152,151,150,150,149,148,
148,147,146,146,145,144,144,143,143,142,141,141,140,139,139,138,137,137,136,135,135,134,134,133,132,132,131,130,130,129,128,128,
127,127,126,125,125,124,123,123,122,121,121,120,120,119,118,118,117,116,116,115,114,114,113,112,112,111,111,110,109,109,108,107,
107,106,105,105,104,103,103,102,101,101,100,99,99,98,97,97,96,95,94,94,93,92,92,91,90,90,89,88,87,87,86,85,84,84,83,82,81,81,80,
79,78,78,77,76,75,74,74,73,72,71,70,70,69,68,67,66,65,64,63,63,62,61,60,59,58,57,56,55,54,53,52,51,50,48,47,46,45,44,42,41,40,38,
37,35,34,32,31,29,27,25,23,20,18,14,10,0
};

void setup()
{                                        
 Serial.begin(9600);
 Timer1.initialize(DimStep);                        
 attachInterrupt(0, zero_cross_detect, FALLING);      
 pinMode(TriacPin, OUTPUT);                        
 Timer1.attachInterrupt(fire_triacs, DimStep);
 Serial.println("Hello");
 oput=100*2.56;
 FireTriac = PowerMap[oput];
}                                                    
 
void zero_cross_detect()
{                                                      
 DimStepCounter = 0;
}

void fire_triacs()
{                                  
 if ( FireTriac == DimStepCounter )                  
 {
   digitalWrite(TriacPin, HIGH);                  
   delayMicroseconds(2);
   digitalWrite(TriacPin, LOW);    
 }
 DimStepCounter++;                
}

void loop()
{                                          

}
Title: Re: Arduino AC Power Shield!
Post by: PaulS on Feb 04, 2010, 04:31 pm
Can you explain these bits of code?

Code: [Select]
byte oput=0;
unsigned long int DimStep=1000000/102/256;


Code: [Select]
oput=100*2.56;
FireTriac = PowerMap[oput];


The oput variable is an integer type variable. The only place it gets assigned a value is in setup. Do you have any idea what value is being stored in oput?

DimStep ends up with a value of 38. Why not just assign it that directly? Do those magic numbers mean something?

The only place PowerMap is referenced is in setup. FireTriac is getting assigned a value here, and nowhere else. Why not just hardcode the value for FireTriac? That would be faster, and require a much smaller memory footprint than this way.
Title: Re: Arduino AC Power Shield!
Post by: subbaraokommuri on Feb 05, 2010, 06:23 am
Hi Paul,

I actually intended to do use the code with combination of PID code to control the furnace temperature. I have started with complex version of code and ended up with the code above as I started debugging. Eventually '100' in 'oput' would get the value of percentage output from PID code and then PowerMap will give me the time step at which triac should fire.

2.56 is multiplied to percentage to convert it into one of 256 levels of Powermap array and to find out the time in micro seconds after which triac should fire.

I was trying to change the values of oput manually and observing the wattage of load(100W bulb). when I give 100% (i.e 100*2.56 = 256 level),I expected the bulb would glow with full brightness, but is not glowing at all.I tried with even 95% also, it also didnot worked.

And about DimStep magic numbers, frequency of AC voltage which we use here is 51Hz, and I want to divide the time between two zero-crossings into 256 levels. so 1e6microseconds/102zerocrossings/256 levels. Instead I could have used 38 as you said.I was not convinced about the idea of using the time required for previous zero-crossings to determine the current DimStep. So I chose to go for constant DimStep. I donot know if it would create problems.

What could be wrong with this code, as it is not working when I give 100*2.56 in oput, Powermap would give me value of 0. So as soon as zero crossing happens, triac should fire. Which I didnot observed. Is it becuase of some time synchronization problem between two interrupts?
Title: Re: Arduino AC Power Shield!
Post by: PaulS on Feb 05, 2010, 03:51 pm
First, about the "magic" numbers. Use something like this:

Code: [Select]
#define FREQ 51
#define STEPS 256
unsigned long int DimStep=1000000/(FREQ*2)/STEPS;


The result will be the same, but the intent is much clearer.

I question that 51, though. If it's AC power you are talking about, the frequency should be either 50 or 60, depending on where you are. 51 seems non-standard.

The oput variable is an integer type. The 2.56 value is not. I was asking if you know what value is actually stored in oput when you assign it a value of 100*2.56. Is it 256, or is it 200?

Since you use oput as an index into the array, the difference is important.

If the value is 256, that is not a valid index into the array. Valid indices are from 0 to 255.

What value is being stored in FireTriac?

Use the Serial.print and Serial.println functions, along with Serial.begin, to write data to the serial port, and open the serial monitor (using the rightmost button in the IDE). You can get answers to all of the questions I am asking, and, perhaps, see for yourself what is happening.
Title: Re: Arduino AC Power Shield!
Post by: joshkp on Feb 12, 2010, 02:29 pm
first post!
Title: Re: Arduino AC Power Shield!
Post by: Tchnclfl on Feb 16, 2010, 01:09 am
Quote
first post!


Couldn't you have at least posted that in Bar Sport or something rather than in the middle of an unrelated thread?  ::)
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Feb 16, 2010, 09:13 pm
Quote
Couldn't you have at least posted that in Bar Sport or something rather than in the middle of an unrelated thread?

That would have been too easy!
Title: Re: Arduino AC Power Shield!
Post by: org00h on Mar 13, 2010, 06:16 pm
It is not good......
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Mar 13, 2010, 06:45 pm
Quote
It is not good......


Can we get you reported cos you have done nothing but post hardly related posts on random topics...
Title: Re: Arduino AC Power Shield!
Post by: jimbo on Mar 17, 2010, 03:44 pm
I'm not sure if this has been covered, but i'd like to give you a heads up that this device is potentially illegal in your country people. It certainly would fail the majority of electrical safety tests here in AUS.

I would highly recommend thinking twice about using this device.

Safety laws are there for a reason.
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Mar 17, 2010, 08:21 pm
Quote
I'm not sure if this has been covered, but i'd like to give you a heads up that this device is potentially illegal in your country people. It certainly would fail the majority of electrical safety tests here in AUS.

I would highly recommend thinking twice about using this device.

Safety laws are there for a reason.

You do not need to get something electrically safety tested if you are using it in your own home. That is probably the majority of people so they'll be fine  :)

If you wanted to use it at work or something then I'm betting that if you stick it in a case then a PAT testing device will say it's fine. Electrical safety laws are pretty slack. They never look inside  8-)
I dunno what there is in other countries but I presume there is something just as rubbish...

Mowcius
Title: Re: Arduino AC Power Shield!
Post by: daveg360 on Mar 18, 2010, 09:55 am
Jimbo - oh please.  Safety laws are largely there because someone had an agenda.  As mowcius mentioned our laws are amusingly silly.  You're from Aus - I believe you're allowed 240v sockets in your bathroom?  Quite handy if you fancy a slice of toast in the bath.

I've always assumed that anything like this, that I've purchased, is on the basis that it's a prototype for protyping with.  If I wanted someone to sue - I'd buy a commercial product. >:(
Title: Re: Arduino AC Power Shield!
Post by: CSingleton on Mar 18, 2010, 09:56 pm
Dave360,

As someone who has project managed many industrial products and several consumer goods through both the US and Canadian electrical approval process, I can assure you that the agenda in play is nothing more than safety.

Yes the approval process can be tiresome, expensive and time consuming; however in many jurisdictions the sale and/or use of unapproved, mains powered electrical devices is illegal and not only opens the manufacturer, retailer or employer up to personal liability; but in many cases criminal liability.

Just how well the process and these laws work are the very reason that you so rarely hear of cases involving electrocution or fires of new or well maintained consumer and industrial electrical devices.

It is good that you say, "If I wanted someone to sue - I'd buy a commercial product" and I hope that ryanjmclaughlin has you sign a product liability release before you purchase one of his AC Shields. However I doubt that all of his potential customers would be willing to do the same and of course that liability release would be worthless in a court of law anyway.

The cost and complexity of the approvals process is the very reason that so many mains powered devices are now powered by external wall wort supplies. It is far easier and cheaper to purchase a preapproved power supply from a third party than it is to run your whole product through the system. Remember that only the areas or parts of your device that control or handle the mains voltage are required to be approved. So your desktop calculator, answering machine or the battery charger for your electric drill are not approved, but the external power supply and its enclosure are.

Which brings up another potential issue with the AC Shield, if ryanjmclaughlin was to seek UL approval for his AC Shield, he would need to enclose it in a case made of a flame retardant material, that provided electrical isolation. Additionally, the control circuit aka Arduino would now also need to go through the approvals process since it is attached to and controlling the AC Shield. Finally, since the typical use of an Arduino usually involves frequent rewiring and reconfiguration of the device and shield, a safety interlock would be required to prevent electrical operation of the device if the enclosure was opened and then of course, any rewiring or reconfiguration that you make would void the electrical approval.
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Mar 18, 2010, 10:01 pm
Quote
Dave360,

As someone who has project managed many industrial products and several consumer goods through both the US and Canadian electrical approval process, I can assure you that the agenda in play is nothing more than safety.

Yes the approval process can be tiresome, expensive and time consuming; however in many jurisdictions the sale and/or use of unapproved, mains powered electrical devices is illegal and not only opens the manufacturer, retailer or employer up to personal liability; but in many cases criminal liability.

Just how well the process and these laws work are the very reason that you so rarely hear of cases involving electrocution or fires of new or well maintained consumer and industrial electrical devices.

It is good that you say, "If I wanted someone to sue - I'd buy a commercial product" and I hope that ryanjmclaughlin has you sign a product liability release before you purchase one of his AC Shields. However I doubt that all of his potential customers would be willing to do the same and of course that liability release would be worthless in a court of law anyway.

The cost and complexity of the approvals process is the very reason that so many mains powered devices are now powered by external wall wort supplies. It is far easier and cheaper to purchase a preapproved power supply from a third party than it is to run your whole product through the system. Remember that only the areas or parts of your device that control or handle the mains voltage are required to be approved. So your desktop calculator, answering machine or the battery charger for your electric drill are not approved, but the external power supply and its enclosure are.

Which brings up another potential issue with the AC Shield, if ryanjmclaughlin was to seek UL approval for his AC Shield, he would need to enclose it in a case made of a flame retardant material, that provided electrical isolation. Additionally, the control circuit aka Arduino would now also need to go through the approvals process since it is attached to and controlling the AC Shield. Finally, since the typical use of an Arduino usually involves frequent rewiring and reconfiguration of the device and shield, a safety interlock would be required to prevent electrical operation of the device if the enclosure was opened and then of course, any rewiring or reconfiguration that you make would void the electrical approval.

Meh  :)
Title: Re: Arduino AC Power Shield!
Post by: carp on Mar 18, 2010, 10:35 pm
What does "Meh" have to contribute? Someone took the time to give a thoughtful answer. Whether or not you agree with it, I think they deserve better. +1 to your post count though.
Title: Re: Arduino AC Power Shield!
Post by: daveg360 on Mar 18, 2010, 10:40 pm
My previous reply was rather harsh.  Could you explain to me, being an expert, how this falls into a separate category to say a manufacturer supplying an IC or relay?  Neither of those devices are intrinsically safe yet they are allowed for sale.  I see a shield as a the same.  On it's own it is useless, it doesn't come in a pretty shiny plastic box and it is not a device that would be purchased by someone without a least some knowledge.
Title: Re: Arduino AC Power Shield!
Post by: koyaanisqatsi on Mar 19, 2010, 12:43 am
Can we _please_ get off the subject of safety?  This area has been covered numerous times in this thread and the OP is well aware of the problems of exposed AC.

Please review previous posts and understand what has already been BEATEN TO DEATH before posting any more about safety.

Thanks.
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Mar 19, 2010, 09:51 am
Ok, last thing on safety, if you sell it as a kit then I think you can get round most of these electrical safety law things.

Mowcius
Title: Re: Arduino AC Power Shield!
Post by: mowcius on Mar 19, 2010, 05:00 pm
Quote
What does "Meh" have to contribute? Someone took the time to give a thoughtful answer.

Well, I could have put, well I kind of agree but I thought that meh summed up my views quite nicely  ;)

Mowcius