Go Down

### Topic: Arduino AC Power Shield! (Read 48142 times)previous topic - next topic

#### caff

#75
##### 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.

#### Zhengxuanlai

#76
##### 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.

#### Zhengxuanlai

#77
##### Jul 23, 2009, 10:09 pmLast Edit: Jul 23, 2009, 10:15 pm by bluefish Reason: 1
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.

#### Ill Mill

#78
##### 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,

#### caff

#79
##### 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.

#### caff

#80
##### 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

#### koyaanisqatsi

#81
##### 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.*/// Generalvolatile unsigned long int ZeroXTime1 = 0;             // Timestamp in micros() of the latest zero crossing interruptvolatile unsigned long int ZeroXTime2 = 0;             // Timestamp in micros() of the previous zero crossing interruptvolatile unsigned long int XTimePeriod;                // The calculated micros() between the last two zero crossingsbyte TriacFireWidth = 2;                               // How many microseconds to leave the triac trigger highunsigned int DimChangeDelay = 500;                     // How many millis() between changes of dimmer levelunsigned 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 triacsunsigned 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_detectvoid 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        }    }  }}`
What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

#### seanreynolds

#82
##### 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?

#83
##### Jul 27, 2009, 10:47 pm
That's what a Solid State Relay (SSR) is.

#### Zhengxuanlai

#84
##### Jul 28, 2009, 07:44 pmLast Edit: Jul 28, 2009, 07:59 pm by bluefish Reason: 1
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.

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.

Have a nice day

#### Zhengxuanlai

#85
##### 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.

#### mowcius

#86
##### Sep 22, 2009, 01:03 pm
bump*

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

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

#### koyaanisqatsi

#87
##### 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.
What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

#### Emonroe7

#88
##### Sep 24, 2009, 08:38 pm
That looks awesome. I could think of a number of uses for that, such as lighting automation.

#### mungbean

#89
##### 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.

Go Up

Please enter a valid email to subscribe