The best kittens, technology, and video games blog in the world.
Showing posts with label raspberrypi. Show all posts
Showing posts with label raspberrypi. Show all posts
Tuesday, September 13, 2016
Adventures with Raspberry Pi: RGB Led Take 2
Once upon a time I tried to do software PWM to set different colors in a RGB Led. It failed.
LEDs are generally either on or off, with no intermediate states - so to get LED at half the intensity, you just turn it fully on for half the time, and blink it fast enough that human eye won't be able to tell the difference.
The problem was that the blinking wasn't fast enough. So now it's time for the long overdue debugging.
First, what the hell is the gem doing? Apparently it's simply writing to files like /sys/class/gpio/gpio17/value. So what if we just write to this file in a loop, skipping the gem? It turns out that's also just not fast enough.
So fallback plan, let's get wiringPi library (git clone git://git.drogon.net/wiringPi) and write it in C:
#include <stdio.h>
#include <wiringPi.h>
int main(int argc, char **argv)
{
int r = atoi(argv[1]);
int g = atoi(argv[2]);
int b = atoi(argv[3]);
int i;
printf("Raspberry RGB %d %d %d blink\n", r, g, b);
if (wiringPiSetup () == -1)
return 1;
pinMode(0, OUTPUT); // R
pinMode(2, OUTPUT); // G
pinMode(3, OUTPUT); // B
for (;;)
{
digitalWrite(0, rand() % 256 <= r);
digitalWrite(2, rand() % 256 <= g);
digitalWrite(3, rand() % 256 <= b);
}
return 0;
}
Then compile with gcc -o rgbled rgbled.c -lwiringPi, and run like sudo ./rgbled 255 127 0
And it works!
Now obviously I don't want to write C programs for every trivial thing, so next step would presumably be using ffi interface to wiringPi instead of what PiPiper does with file-based interface.
LEDs are generally either on or off, with no intermediate states - so to get LED at half the intensity, you just turn it fully on for half the time, and blink it fast enough that human eye won't be able to tell the difference.
The problem was that the blinking wasn't fast enough. So now it's time for the long overdue debugging.
First, what the hell is the gem doing? Apparently it's simply writing to files like /sys/class/gpio/gpio17/value. So what if we just write to this file in a loop, skipping the gem? It turns out that's also just not fast enough.
So fallback plan, let's get wiringPi library (git clone git://git.drogon.net/wiringPi) and write it in C:
#include <stdio.h>
#include <wiringPi.h>
int main(int argc, char **argv)
{
int r = atoi(argv[1]);
int g = atoi(argv[2]);
int b = atoi(argv[3]);
int i;
printf("Raspberry RGB %d %d %d blink\n", r, g, b);
if (wiringPiSetup () == -1)
return 1;
pinMode(0, OUTPUT); // R
pinMode(2, OUTPUT); // G
pinMode(3, OUTPUT); // B
for (;;)
{
digitalWrite(0, rand() % 256 <= r);
digitalWrite(2, rand() % 256 <= g);
digitalWrite(3, rand() % 256 <= b);
}
return 0;
}
Then compile with gcc -o rgbled rgbled.c -lwiringPi, and run like sudo ./rgbled 255 127 0
And it works!
Now obviously I don't want to write C programs for every trivial thing, so next step would presumably be using ffi interface to wiringPi instead of what PiPiper does with file-based interface.
Saturday, February 13, 2016
Adventures with Raspberry Pi: RGB Led
I've done regular LEDs before, so I wanted to try RGB Led now.
RGB Led is like red, green, and blue RED in one package, sharing common ground (so 4 pins total), supposedly allowing any color.
Now your first idea might be to use analog output and set diode intensity to control red, blue, and green, and that would work with a regular lamp, more or less, but diodes are really just on or off, so we need to do pulse width modulation.
Unfortunately it turns out that Raspberry Pi, ruby and pi_piper gem are not fast enough for that. This code really ought to work:
With iterations being done at a bit oven 1300 iterations per second, it should provide half intensity white light. Instead it's flashing all the colors randomly, so presumably something downstream from ruby is being really slow.
There's also minor problem of green LED component being much brighter than others (all use 220 hm resistors, and changing I/O ports or resistors around doesn't change that).
All that is a shame, as software PWM is a pretty useful building block for a lot of things, and if that doesn't work, I won't be able to do a ton of other thing. If anybody has any ideas, please tell me.
RGB Led is like red, green, and blue RED in one package, sharing common ground (so 4 pins total), supposedly allowing any color.
Now your first idea might be to use analog output and set diode intensity to control red, blue, and green, and that would work with a regular lamp, more or less, but diodes are really just on or off, so we need to do pulse width modulation.
Unfortunately it turns out that Raspberry Pi, ruby and pi_piper gem are not fast enough for that. This code really ought to work:
class RGBLed
def initialize
@blue = PiPiper::Pin.new(:pin => 17, :direction => :out)
@red = PiPiper::Pin.new(:pin => 22, :direction => :out)
@green = PiPiper::Pin.new(:pin => 27, :direction => :out)
end
def display(r,g,b)
while true
@red.send(if rand < r then :on else :off end)
@green.send(if rand < g then :on else :off end)
@blue.send(if rand < b then :on else :off end)
end
end
def on
@blue.on
@red.on
@green.on
end
def off
@blue.off
@red.off
@green.off
end
end
led = RGBLed.new
led.display(0.5,0.5,0.5)
With iterations being done at a bit oven 1300 iterations per second, it should provide half intensity white light. Instead it's flashing all the colors randomly, so presumably something downstream from ruby is being really slow.
There's also minor problem of green LED component being much brighter than others (all use 220 hm resistors, and changing I/O ports or resistors around doesn't change that).
All that is a shame, as software PWM is a pretty useful building block for a lot of things, and if that doesn't work, I won't be able to do a ton of other thing. If anybody has any ideas, please tell me.
Thursday, April 23, 2015
Adventures with Raspberry Pi: Weather in London
Welcome to another of my Raspberry Pi adventures.
Previously, I connected raspberry pi to monitor and keyboard and blinked some diodes.
It's time to go a lot further. The first step was removing monitor and keyboard, installing sshd, and just controlling the pi from a regular computer. That leaves two cables - ethernet, and USB power (currently coming from the computer).
I'll replace ethernet with wifi at some point, and reroute power to standalone charger so it doesn't need to be anywhere near the computer.
I also got new multimeter - the old one was totally broken, it wasn't just the battery.
Shift registers
Project for today is driving two 8-segment displays. Even ignoring 8th segment on each which is used for decimal dot (and only really included because 7 segments is a silly number), that's 14 wires. Raspberry Pi presumably has that many usable pins (I'm not entirely sure how many of 40 pins it has can be used for full I/O), but we really don't want to spend out entire pin budget on this.Instead - we're going to use shift registers. Shift register I use - 74HC595 - has 3 inputs: data, clock, and latch. Whenever clock pin goes from low to high, it reads data pin, pushes data it has left by one, and puts whatever it got in newly emptied bit slot. In 8 such cycles, we can set the whole 8 bit register, one bit at a time.
While we're sending the register data, it is temporarily in inconsistent state, with mix of old and new data. To make sure that's never output, there's a separate latch pin - whenever it goes from low to high, register snapshots its state, and keeps that an the output unless we tell it to get new value.
This way we reduced number of required pins per display from 8 to 3.
74HC595 has a few extra pins (clear, output enable, etc.), but we just hardwire them as we don't rely on that functionality.
Here's a photo of work in progress: data is sent to shift register, and from there to 8-sigment panel, but it's just random bits.
Here's the code:
require "pi_piper"
attr_reader :data, :clk, :latch
def initialize(data, clk, latch)
@data = data
@clk = clk
@latch = latch
end
def out_bit(bit)
@clk.off
@data.send(bit == 1 ? :on : :off)
sleep 0.001
@clk.on
end
def out(byte)
@latch.off
byte.each do |bit|
out_bit(bit)
end
sleep 0.001
@latch.on
end
end
Eight-Segment Display
Next step is really simple - instead of sending random data telling segments to turn on/off, we want to send it data corresponding to shapes of digits:The code is really simple:
class EightPanelDisplay < ShiftRegister
def out_symbol(symbol)
# DOT, LR, L, LL, UR, U, UL, M
case symbol
when "0"
out [0,1,1,1,1,1,1,0]
when "1"
out [0,1,0,0,1,0,0,0]
when "2"
out [0,0,1,1,1,1,0,1]
when "3"
out [0,1,1,0,1,1,0,1]
when "4"
out [0,1,0,0,1,0,1,1]
when "5"
out [0,1,1,0,0,1,1,1]
when "6"
out [0,1,1,1,0,1,1,1]
when "7"
out [0,1,0,0,1,1,0,0]
when "8"
out [0,1,1,1,1,1,1,1]
when "9"
out [0,1,1,0,1,1,1,1]
else
warn "Don't know how to output symbol #{symbol.inspect}"
end
end
end
We could even extend that to some simple letters or such symbols - not everything can be distinguished, for example B and 8 will look the same, but it might be useful.
Two digits
So we got down from 2x8 to 2x3 pins. We can do better - we can use same clock and data lines for both shift registers, and only have separate latch pins for each. As registers output whatever was the data inside them at the time they got the most recent rising edge on their latch pin, as long as register's latch pin is steady (doesn't matter even matter if high or low), it doesn't matter what they get on other pins.There are other ways to connect registers, including daily chaining shift registers so they shift into each other thanks to their extra pins, and we could get away with just 3 instead of 4 raspberry pi pins, but this simple setup is good enough.
And corresponding code:
pin4 = PiPiper::Pin.new(:pin => 4, :direction => :out)
pin17 = PiPiper::Pin.new(:pin => 17, :direction => :out)
pin22 = PiPiper::Pin.new(:pin => 22, :direction => :out)
pin27 = PiPiper::Pin.new(:pin => 27, :direction => :out)
register_a = EightPanelDisplay.new(pin4, pin27, pin17)
register_b = EightPanelDisplay.new(pin4, pin27, pin22)
Weather in London
After we had the hardware going, software is really simple - a simple JSON request to OpenWeather API, convert Kelvin to Celsius scale, and send it to our display.And here's current weather in London, +9C (there's no need for sign, as London never has winters):
And the code:
require "json"
require "open-uri"
url = "http://api.openweathermap.org/data/2.5/weather?q=London,uk"
weather = JSON.parse(open(url).read)
temp_c = weather["main"]["temp"] - 273.15
temp_display = "%02d" % temp_c
register_b.out_symbol temp_display[0]
register_a.out_symbol temp_display[1]
Friday, April 17, 2015
Adventures with Raspberry Pi: basic blinkenlights
Every adventure starts with hello world, and that one took forever.
Here's the setup:
- Raspberry Pi 2 model B
- Sunfounder starter kit
- latest raspbian
- pry
- pi_piper gem
- a lot of cables
Sunfounder GPIO extension board + breadboard make it so much easier - instead of wiring everything manually I just plug the whole damn thing, and it even has printed pin numbers on the board - Raspberry Pi decided to have insane randomly assigned pin numbers, and then every library for it uses its own different insane randomly assigned pin numbers - I remember back in the days when people numbered pins from 1 to 40 starting in one corner and going clockwise. What the hell happened?
I ran into a lot of annoying issues:
- My old raspberry Pi (model B+, not 2 B) was not compatible with the kit, so I had to get new one
- SD card I used for old Pi was of the big kind, so I had to take small one out of my phone instead
- I needed to install confusingly named ruby1.9.1-dev apt package (which actually contains 1.9.3) before any gems would install.
- And my voltmeter seems dead, it's probably just batteries, but it uses 9V batteries which I don't have spares for so I won't be able to check that until tomorrow.
- Why do resistors have to use this ridiculous color coding system instead of just printing damn values as numbers? I get it that back in the 1950s printing numbers would be hard, but come on. Figuring out which resistor is which was pain, and I didn't have voltmeter to test them. (I never learned this damn color coding, as it was way easier to just check them with a meter).
- It took a few tries to figure out which pin numbering system Pi Piper uses - apparently the same one as is printed on Sunfounder expansion board. That will make it a lot easier.
The first program is:
require "pi_piper"
pin4 = PiPiper::Pin.new(:pin => 4, :direction => :out)
pin17 = PiPiper::Pin.new(:pin => 17, :direction => :out)
loop { pin4.on; pin17.off; sleep 0.25; pin17.on; pin4.off; sleep 0.25 }
Can you guess what it does? No prizes.
It's not much, but with all hardware projects just getting basic hello world typically takes really long time and runs into a lot of annoying problems. Now that's behind me, I might be able to do some cooler stuff.
3D printer adventures and Raspberry Pi adventures will at some point join, but it will take a while.
Subscribe to:
Posts (Atom)









