I’ve been converting my ST4i workshop from Arduino to Node.js/Raspberry Pi and one of limitations is a lack of built-in PWM pins. PWM or Pulse Width Modulation can be used to fade LEDs up and down rather than just turn them on and off. If you’re new to PWM, here’s a full explanation at Sparkfun.
On the Pi Zero, you can only enable 2 hardware PWM pins at one time, and the library I’m using to control the GPIO pins doesn’t support PWM at all! (The ubiquitous onoff node module).
After a bit of searching, I found the pigpio Node.js module, and this, in turn is a wrapper for the Pigpio C library.
As far as I can tell, it manages the PWM duty cycle in software, so it’s not as performant as the built-in hardware PWM pins, but as it’s written in C I’m sure it’s fast and certainly my experience so far suggests it’s super smooth.
If you want to try it for yourself, follow the instructions on the github page. I had a slight amount of weirdness, it didn’t seem to install straight away, but I deleted everything and started again and it seemed better.
I also had another problem – somehow I had started the pigpiod daemon and this clashed with the Node.js module code. Either the installer for pigpio did it or else I ran in manually while trying to get things running. sudo killall pigpiod
should sort it out.
And a final thing to look out for – if you have node 0.10.29 on your Raspberry Pi (the version that comes with Raspbian Jesse) you’ll have a problem running any Node.js module that uses Nan, the native addon library. I first encountered this when I updated the LED matrix library to work with newer versions of Node.js, but it’s simple enough to fix. See this thread on github for solutions.
Once you have it installed you can do PWM output on any GPIO pin, here’s a set up for 9 LEDs like in the image above.
You can then use this code to get the nice pulsing effect in the animation.
var Gpio = require('pigpio').Gpio; // change these to match your LED GPIO pins : var ledPins = [21,20,16,12,26,19,13,6,5]; var leds = []; // initialise all the pins for (var i = 0; i<ledPins.length; i++) { var led = new Gpio(ledPins[i], {mode: Gpio.OUTPUT}); leds.push(led); } // get a loop running 60 times a second (1000/60 = 16.6) setInterval(loop, 16); function loop() { for(var i = 0; i<leds.length; i++) { var led = leds[i]; // calculate a sin wave for brightness dependent on time and // position in the row of LEDs var brightness = Math.sin(((Date.now()/16)+(i*5))*0.2)*0.5 + 0.5; // a quick way to do a cubic ease in - it means the LEDs get brighter // slower. It compensates for the fact that LEDs get bright quick. brightness*=brightness*brightness; // the pigpio library complains if you send it a floating point number // so we have to round it down. brightness = Math.floor(brightness*255); led.pwmWrite(brightness); } }
Note the issue with sending floating point numbers – I’m surprised that this isn’t handled at the other end but it’s easy enough to fix with a Math.floor.
And also notice how I’m using cubic easing to smooth out the brightness curve on the LEDs.
You can also use the pigpio library to control hobby servo motors. That’s what I’ll be doing next!
2 replies on “Fading LEDs with PWM on all pins with Pi Zero & Node.js”
Although some software is used by the pigpio module to control the PWM duty cycle it’s mostly harware that’s used, a combination of DMA and PWM hardware in this case. The details of how this is achieved can be found at //github.com/richardghirst/PiBits/tree/master/ServoBlaster
onoff doesn’t support PWM because it was written to function on multiple platforms, for example, the Raspberry Pi or BeagleBone Black. These Linux platforms and many others follow the same conventions for accessing GPIO hardware. Unfortunately there doesn’t appear to be a common convention for accessing PWM hardware or at least the author of onoff (me :)) wasn’t able find such a convention if it does exist.
Thanks so much for commenting Brian, it’s so useful and interesting to get some more background information about onoff and pigpio. I really appreciate it.