I’ve just discovered the processing.io library, and I’m having a tough time with PWM. I’m running Processing on a Raspberry Pi Zero, and I’m wanting to interface with it’s IO pins.
The page says to “Use the SoftwareServo class below for the time being. Hardware PWM has yet to be made available by the hardware platforms we support.” Does that mean that this code doesn’t work anywhere, and that I should be working with the SoftwareServo class instead?
I’ve used the SoftwareServo class to dim a light with the following code:
import processing.io.*;
SoftwareServo servo;
int count = 0;
void setup() {
frameRate(0.5);
servo = new SoftwareServo(this);
servo.attach(4);
// On the Raspberry Pi, GPIO 4 is pin 7 on the pin header,
// located on the fourth row, above one of the ground pins
}
void draw() {
// Here we are using the Software Servo class as a Kludge (as recommended by Processing) for PWM.
// The only software PWM available in the processing.io library is
// SoftwareServo, intended for servo motors, not LEDs, or DC motors.
// Therefore:
// 100% PWM == 180 degrees.
// 50% PWM == 90 degrees.
// 0% PWM == 0 degrees.
float angle = 0 + count;
servo.write(angle);
println(angle);
updateCount();
}
void updateCount() {
count = count + 45;
if (count > 180) {
count = 0;
}
}
It works reasonably well, but 100% PWM (190 degrees) is nowhere near the LED’s full capacity, and at 0% PWM (0 degrees) the LED is still on/dimly lit.
Furthermore, the light visibly pulsates.
Contrast this with the steps I followed in this tutorial to do Hardware PWM, and the LED goes to 100% brightness, to 0% (off), with no issues, and the light doesn’t pulsate.
Suggestions below are for a PWM hack using SoftwareServo and not for an actual servo motor. :)
Try setting the defaults to match your frameRate; be sure to display this to see what the actual frameRate is.
Otherwise there is (see note at bottom) a long gap between servo writes; default state of GPIO pin may be a LOW on RPi (TBD I do not know at this time).
Defaults (sending servo write once per frame):
T = 2400 µs
f = 1/T = 416 Hz
Assuming frameRate is 60 fps:
f = 60 Hz
T = 1/60 = 0.01666666666 s = 16666 µs
Try:
minPulse = 0; //Use a higher value if it does not like 0
maxPulse = 16666;
Note:
I have not tried this and do not use Processing on a RPi; I may just fire it up and try this.
When I work with hardware I always like to see the the actual outputs on an oscilloscope.
I will try this tomorrow.
I need an excuse to clean my workstation and fire up my RPi.
Thanks so much for your help! I’ve implemented what you’ve suggested, and here’s what I’ve found:
Your suggestion completely solved the brightness issue: at 100% (180 degrees) the light is as bright as it can be.
minPulse = 0; doesn’t solve the problem of a low light being emitted when there should be none. I tried minPulse = 1 and minPulse = 10. Still the same issue.
The visible pulsating problem is solved for anything at or above about 45 degrees. Below that you can notice pulsating still.
I printed out the actual frameRate and it fluctuates in the neigbourhood of 60.
Any suggestions on how to solve the two remaining issues?
I increased the maxPulse to 20000µs (incrementally) while watching the oscilloscope output to get a full sweep. You are doing a servo.write() every frame (16666 µs) and this is < 20000 µs.
I modified the SoftwareServoSweep example that comes with Processing.
This works and sweeps through a duty cycle of 0% to 100% as seen on oscilloscope.
Code
import processing.io.*;
SoftwareServo servo2;
void setup()
{
size(100, 300);
servo2 = new SoftwareServo(this);
servo2.attach(4, 0, 20000);
}
void draw()
{
background(0);
stroke(255);
strokeWeight(3);
//0 to 180
float angle = 180*(0.5+0.5*sin(frameCount/100.0)); // This provides a nice sinusoidal sweep between 0 to 180
servo2.write(angle);
float y = map(angle, 0, 180, 0, height);
line(0, y, width, y);
if (frameCount%10 == 0)
println(frameRate);
}
It also works with an LED and I do not perceive any flicker at 60 Hz.
Make sure you are using a current limiting resistor.
Thanks so much for this! In the interim I started looking for other possible solutions and found that Arduino now (as of November 2019) has affordable nano WiFi and BLE boards which, in theory, will be better for my application. I’m going to give that a shot first and see if that works.
Another thing that I found that was a huge pain in working with the Raspberry Pi Zero was that even just typing the code in Processing was maxing out its capabilities. There was a delay with everything I typed.
It is good to explore your options and chose the best one (SBC, microcontroller or hybrid) based on your project requirements: Raspberry Pi 3 vs Arduino Uno Rev3 < One link of many on this subject.
I typically use my Arduino for dedicated hardware and use Processing (or other hardware and software) to communicate with it (serial, ethernet, etc) if I want an HMI, GUI or data visualization; it is just so much easier for me.
I have many RPis but they are not required in most of my projects at this time.
Some “rough cuts”:
I only posted these as examples and they were not intended as instructional videos.
Yes, this project started several years ago, and as I’ve discovered limitations in my ability to carry it out due to my own knowledge limits as well as hardware limits, I’ve responded by changing the scope along the way. And what’s been interesting is that over the course of the project as I stumble through and learn more, some of the hardware limitations have been eliminated. Technology marches on.