paulofreitasnobrega
Posts: 1
Joined: Fri Apr 13, 2018 7:18 pm

Node.js Code Dimmer AC

Sat Apr 14, 2018 12:27 am

Good afternoon! Sorry for the mild question that is probably being posted in an incorrect location. But I do not know where to publish.

I am using my raspberry pi to control the power of a 60W bulb in an AC network, 127V, 60Hz. To help raspberry in this task, I've developed a PCB that has a TRIAC BTA41600 and some other components. This PCB synchronizes with the network and manipulates the sine wave, cutting it and obtaining different voltages at the end.

I have run several tests and the PCB seems to work perfectly. My problem is with the javascript code.

I am using, in my raspberry, the nodejs and the onoff module. I make a time routine using setTimeout ().

Before the code, I'd like to quickly explain how it should work:
My network frequency is 60Hz, so each sine wave has a period of 16.66 milliseconds. Each wave has two cycles (positive / negative). In this way, each cycle has a period of 8.33 ... milliseconds. To size this wave, I need to divide it into the number of desired graduations, in my case I used 100 (which would represent 100%). Therefore, for each wave graduation I have a period of 0.083 milliseconds. To summarize: When I set a 30% graduation, I receive a period of 2.49 milliseconds. This period is the time that my TRIAC will wait, within the cycle, to be activated.

Follow the code:

Code: Select all

//onoff
const gpio = require('onoff').Gpio;
const zc = new gpio(17, 'in', 'falling');
const dimmer = new gpio(27, 'out') //shot triac

//time
const frequency = 60
const drivingTRIAC = 8.33 * 0.001
const wave = (((1 / frequency) * 1000) / 2)
const resolution = (wave - drivingTRIAC) / 100

//power for time
var power = 30
var powertime = resolution * (100 - power)

//zero crossing
zc.watch(function (err, value) {    
    setTimeout(() => {
        // ON TRIAC
        dimmer.writeSync(1)
        setTimeout(() => {
            // OFF TRIAC
            dimmer.writeSync(0)
        }, drivingTRIAC)
    }, powertime)
});
When turning this code, my lamp receives a non-linear flashing effect. However, my timing system is working normally. When doing a test with the code below, I get as a result: 120 (with some variations of 119 or 121):

Code: Select all

/**
 * Monitora a senóide durante 1 segundo (1000ms). Para cada passagem pelo zero,
 * em semiciclos positivos, incrementa 1 na variável pulses. Após 1 segundo
 * retorna o valor final de pulses (passsagens por zero).
 * Este teste permite monitorar a frequência da rede, possibilitando o
 * sincronismo com a mesma
 */
const gpio = require('onoff').Gpio;
const zc = new gpio(4, 'in', 'falling'); //zero crossing
var pulses = 0;
var iv;

/**
 * Escuta a GPIO definida em zc. Se o valor recebido for 0 incrementa pulses
 */
zc.watch(function (err, value) {
    if (value == 0) {
        pulses += 1;
    }
});

/**
 * Define um loop que se repetirá a cada 1 segundo (1000ms). Ao final de cada
 * período, imprime o valor final de pulses e o zera
 */
iv = setInterval(function () {
    console.log(`pulses: ${pulses}`);
    pulses = 0;
}, 1000);

/**
 * Quando o script é interropido (ctrl + C), limpa os processos
 */
process.on('SIGINT', function () {
    clearInterval(iv);
    zc.unexport();
});
I guess my problem is related to the misuse of setTimeout or some function. can you help me?

A similar code for arduino in C language:

Code: Select all

#define loadR 4    
 
volatile int power = 100;  
 
void zero_crosss_int()  
{
  // Cálculo do ângulo de disparo: 60Hz-> 8.33ms (1/2 ciclo)
  // (8333us - 8.33us) / 256 = 32 (aprox)
  int powertime = (32*(256-power));      
  // Mantém o circuito desligado por powertime microssegundos 
  delayMicroseconds(powertime);   
  // Envia sinal ao TRIAC para que ele passe a conduzir 
  digitalWrite(loadR, HIGH);  
  // Espera alguns microssegundos para que o TRIAC perceba o pulso
  delayMicroseconds(8.33);      
  // Desliga o pulso
  digitalWrite(loadR, LOW);   
}
 
void setup()
{
  Serial.begin(9600);
  pinMode(loadR, OUTPUT);
  // Inicializa interrupção. O número zero indica a porta 2 do Arduino,
  // zero_crosss_int é a função que será chamada toda vez que o pino 2
  // "subir" (RISING) de valor de 0 para 1.  
  attachInterrupt(0, zero_crosss_int, RISING);  
}
 
void loop()
{
  // Seta a potência para diferentes níveis. Se o sistema estiver conectado a uma lâmpada,
  // esta vai variar de brilho.
  power=10;
  delay(10000);
  power=60;
  delay(10000);
  power=120;
  delay(10000);
  power=180;
  delay(10000);
  power=240;
  delay(10000);
}

jsimmonds
Posts: 3
Joined: Mon Apr 02, 2018 2:23 am
Location: Australia

Re: Code Dimmer AC

Mon Apr 16, 2018 10:19 am

I agree that there's an issue with the inner setTimeout() . . needs to be scaled to ms. Also I imagine fractional ms are rounded or chopped.

drivingTRIAC 0.00833

The Node.js docs say
https://nodejs.org/dist/latest-v8.x/doc ... delay_args
Note: When delay is larger than 2147483647 or less than 1, the delay will be set to 1.

With a different design, you might be able to employ the pigpio package.

Heater
Posts: 9490
Joined: Tue Jul 17, 2012 3:02 pm

Re: Node.js Code Dimmer AC

Sat Apr 21, 2018 6:44 am

paulofreitasnobrega,

You have a couple of insurmountable problems with your plan:

1) You are using a Linux based operating system. Linux is not designed for high speed, real-time work. Linux is a multi-user, multi-tasking OS. As such your program may well be suspended for unknown amounts of time when the Linux kernel decides to schedule something else to run. There are ways to mitigate this problem to some extent [See below]

2) You are trying to time things to sub-millisecond resolution in Javascript. As much as I love JS and node.js and us it for many things I would not even try to do this. Firstly, you can only schedule things down to a 1 millisecond resolution with setInterval and setTimeout. Even that may not be achievable give 1) above. JS is an interpreted language, node.js is impressively fast but it will still suffer from stalls and stutters due to the need to allocate and free memory. Also if you start to have other functions running in your code they will be competing with your TRIAC driver for time on the JS event loop thus throwing off it's timing.

Personally I would not even try to trigger a TRIAC from a Raspberry Pi like this. Better would be to have an Arduino do it. Why not put a Arduino chip on your custom board and have that trigger the TRIAC? I to could take commands over a serial link to change the drive time. Or use some other tiny, cheap MCU.

Alternatively, write your code in C and take some measures to ensure it runs in real-time. If you have a multi-core Pi, like a Pi 3, then you can tell the Linux kernel not to schedule tasks on some particular core. You can then run your program on that core and it will have 100% of the execution time to itself.

You can use "isolcpus" or "maxcpus" kernel command line option to stop the linux kernel using one or more cores. Then run your program on a free core using "taskset".

There is a discussion on using these techniques to get reliable realtime drive of PWM LED strips here: viewtopic.php?f=63&t=200793

In that thread I show how I managed to toggle a GPIO pin a megahertz rates with only the occasional 10us glitch every millisecond or so. viewtopic.php?f=63&t=200793&start=25#p1252388

Finally, I would be worried about safety issues. I would not want to connect to a TRIAC without an opto-isolator.

Return to “Other programming languages”

Who is online

Users browsing this forum: No registered users and 5 guests